Merge "Add test for multiple brightness events" into udc-dev
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e42e526..9eb9d66 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -4156,6 +4156,7 @@
public static class WindowInfosListenerForTest.WindowInfo {
field @NonNull public final android.graphics.Rect bounds;
field public final boolean isTrustedOverlay;
+ field public final boolean isVisible;
field @NonNull public final String name;
field @NonNull public final android.os.IBinder windowToken;
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index afe375c..96118f6 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -616,6 +616,7 @@
/** {@hide} */
public PackageInstaller(IPackageInstaller installer,
String installerPackageName, String installerAttributionTag, int userId) {
+ Objects.requireNonNull(installer, "installer cannot be null");
mInstaller = installer;
mInstallerPackageName = installerPackageName;
mAttributionTag = installerAttributionTag;
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 820bb1b..4f6bcb6 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -185,37 +185,41 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
try {
for (File file : files) {
- if (isApkFile(file)) {
- final ParseResult<ApkLite> result = parseApkLite(input, file, flags);
- if (result.isError()) {
- return input.error(result);
- }
+ if (!isApkFile(file)) {
+ continue;
+ }
- final ApkLite lite = result.getResult();
- // Assert that all package names and version codes are
- // consistent with the first one we encounter.
- if (packageName == null) {
- packageName = lite.getPackageName();
- versionCode = lite.getVersionCode();
- } else {
- if (!packageName.equals(lite.getPackageName())) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent package " + lite.getPackageName() + " in " + file
- + "; expected " + packageName);
- }
- if (versionCode != lite.getVersionCode()) {
- return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Inconsistent version " + lite.getVersionCode() + " in " + file
- + "; expected " + versionCode);
- }
- }
+ final ParseResult<ApkLite> result = parseApkLite(input, file, flags);
+ if (result.isError()) {
+ return input.error(result);
+ }
- // Assert that each split is defined only oncuses-static-libe
- if (apks.put(lite.getSplitName(), lite) != null) {
+ final ApkLite lite = result.getResult();
+ // Assert that all package names and version codes are
+ // consistent with the first one we encounter.
+ if (packageName == null) {
+ packageName = lite.getPackageName();
+ versionCode = lite.getVersionCode();
+ } else {
+ if (!packageName.equals(lite.getPackageName())) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Split name " + lite.getSplitName()
- + " defined more than once; most recent was " + file);
+ "Inconsistent package " + lite.getPackageName() + " in " + file
+ + "; expected " + packageName);
}
+ if (versionCode != lite.getVersionCode()) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Inconsistent version " + lite.getVersionCode() + " in " + file
+ + "; expected " + versionCode);
+ }
+ }
+
+ // Assert that each split is defined only once
+ ApkLite prev = apks.put(lite.getSplitName(), lite);
+ if (prev != null) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Split name " + lite.getSplitName()
+ + " defined more than once; most recent was " + file
+ + ", previous was " + prev.getPath());
}
}
baseApk = apks.remove(null);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index e908ced..48b5cac 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -212,14 +212,7 @@
@GuardedBy("mLock")
private boolean mFoldedDeviceState;
- private final CameraManager.DeviceStateListener mFoldStateListener =
- new CameraManager.DeviceStateListener() {
- @Override
- public final void onDeviceStateChanged(boolean folded) {
- synchronized (mLock) {
- mFoldedDeviceState = folded;
- }
- }};
+ private CameraManager.DeviceStateListener mFoldStateListener;
private static final String TAG = "CameraCharacteristics";
@@ -245,7 +238,18 @@
/**
* Return the device state listener for this Camera characteristics instance
*/
- CameraManager.DeviceStateListener getDeviceStateListener() { return mFoldStateListener; }
+ CameraManager.DeviceStateListener getDeviceStateListener() {
+ if (mFoldStateListener == null) {
+ mFoldStateListener = new CameraManager.DeviceStateListener() {
+ @Override
+ public final void onDeviceStateChanged(boolean folded) {
+ synchronized (mLock) {
+ mFoldedDeviceState = folded;
+ }
+ }};
+ }
+ return mFoldStateListener;
+ }
/**
* Overrides the property value
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 51501b5..85f8ca6 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1836,6 +1836,7 @@
ctx.getSystemService(DeviceStateManager.class).registerCallback(
new HandlerExecutor(mDeviceStateHandler), mFoldStateListener);
} catch (IllegalStateException e) {
+ mFoldStateListener = null;
Log.v(TAG, "Failed to register device state listener!");
Log.v(TAG, "Device state dependent characteristics updates will not be" +
"functional!");
diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java
index 01e577f..cfbeeff 100644
--- a/core/java/android/window/WindowInfosListenerForTest.java
+++ b/core/java/android/window/WindowInfosListenerForTest.java
@@ -68,12 +68,18 @@
*/
public final boolean isTrustedOverlay;
+ /**
+ * True if the window is visible.
+ */
+ public final boolean isVisible;
+
WindowInfo(@NonNull IBinder windowToken, @NonNull String name, @NonNull Rect bounds,
int inputConfig) {
this.windowToken = windowToken;
this.name = name;
this.bounds = bounds;
this.isTrustedOverlay = (inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
+ this.isVisible = (inputConfig & InputConfig.NOT_VISIBLE) == 0;
}
}
@@ -131,9 +137,6 @@
private static List<WindowInfo> buildWindowInfos(InputWindowHandle[] windowHandles) {
var windowInfos = new ArrayList<WindowInfo>(windowHandles.length);
for (var handle : windowHandles) {
- if ((handle.inputConfig & InputConfig.NOT_VISIBLE) != 0) {
- continue;
- }
var bounds = new Rect(handle.frameLeft, handle.frameTop, handle.frameRight,
handle.frameBottom);
windowInfos.add(new WindowInfo(handle.getWindowToken(), handle.name, bounds,
diff --git a/core/java/com/android/internal/app/AppLocaleCollector.java b/core/java/com/android/internal/app/AppLocaleCollector.java
index 7cf428a..56f633f 100644
--- a/core/java/com/android/internal/app/AppLocaleCollector.java
+++ b/core/java/com/android/internal/app/AppLocaleCollector.java
@@ -157,13 +157,13 @@
* Get a list of system locale that removes all extensions except for the numbering system.
*/
@VisibleForTesting
- public List<LocaleStore.LocaleInfo> getSystemCurrentLocales() {
- List<LocaleStore.LocaleInfo> sysLocales = LocaleStore.getSystemCurrentLocales();
+ public Set<LocaleStore.LocaleInfo> getSystemCurrentLocales() {
+ Set<LocaleStore.LocaleInfo> sysLocales = LocaleStore.getSystemCurrentLocales();
return sysLocales.stream().filter(
// For the locale to be added into the suggestion area, its country could not be
// empty.
info -> info.getLocale().getCountry().length() > 0).collect(
- Collectors.toList());
+ Collectors.toSet());
}
@Override
@@ -225,7 +225,10 @@
// Add current system language into suggestion list
if (!isForCountryMode) {
boolean isCurrentLocale, existsInApp, existsInIme;
- for (LocaleStore.LocaleInfo localeInfo : getSystemCurrentLocales()) {
+ // filter out the system locases that are supported by the application.
+ Set<LocaleStore.LocaleInfo> localeInfoSet =
+ filterSupportedLocales(getSystemCurrentLocales(), result.mAppSupportedLocales);
+ for (LocaleStore.LocaleInfo localeInfo : localeInfoSet) {
isCurrentLocale = mAppCurrentLocale != null
&& localeInfo.getLocale().equals(mAppCurrentLocale.getLocale());
// Add the system suggestion flag if the localeInfo exists in mAllAppActiveLocales
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index f4b858f..43d263b 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -32,7 +32,6 @@
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -404,8 +403,8 @@
/**
* Returns a list of system locale that removes all extensions except for the numbering system.
*/
- public static List<LocaleInfo> getSystemCurrentLocales() {
- List<LocaleInfo> localeList = new ArrayList<>();
+ public static Set<LocaleInfo> getSystemCurrentLocales() {
+ Set<LocaleInfo> localeList = new HashSet<>();
LocaleList systemLangList = LocaleList.getDefault();
for(int i = 0; i < systemLangList.size(); i++) {
Locale sysLocale = getLocaleWithOnlyNumberingSystem(systemLangList.get(i));
diff --git a/core/res/res/xml/irq_device_map.xml b/core/res/res/xml/irq_device_map.xml
index 8b3667e..2f894b9 100644
--- a/core/res/res/xml/irq_device_map.xml
+++ b/core/res/res/xml/irq_device_map.xml
@@ -28,6 +28,8 @@
- Wifi: Use this to denote network traffic that uses the wifi transport.
- Sound_trigger: Use this to denote sound phrase detection, like the ones supported by
SoundTriggerManager.
+ - Sensor: Use this to denote wakeups due to sensor events.
+ - Cellular_data: Use this to denote network traffic on the cellular transport.
The overlay should use tags <device> and <subsystem> to describe this mapping in the
following way:
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
index c6bb07b..6d99e94 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java
@@ -45,7 +45,6 @@
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -67,22 +66,9 @@
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
- private float mOriginalFontScale = Float.MIN_VALUE;
-
- @Before
- public void setup() {
- mOriginalFontScale = Settings.System.getFloat(
- InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(),
- Settings.System.FONT_SCALE,
- Float.MIN_VALUE
- );
- }
-
@After
public void teardown() {
- if (mOriginalFontScale != Float.MIN_VALUE) {
- setSystemFontScale(mOriginalFontScale);
- }
+ restoreSystemFontScaleToDefault();
}
@IwTest(focusArea = "accessibility")
@@ -160,6 +146,28 @@
);
}
+ private static void restoreSystemFontScaleToDefault() {
+ ShellIdentityUtils.invokeWithShellPermissions(() -> {
+ // TODO(b/279083734): would use Settings.System.resetToDefaults() if it existed
+ Settings.System.putString(
+ InstrumentationRegistry.getInstrumentation()
+ .getContext()
+ .getContentResolver(),
+ Settings.System.FONT_SCALE,
+ null,
+ /* overrideableByRestore= */ true);
+ });
+
+ PollingCheck.waitFor(
+ /* timeout= */ 5000,
+ () -> InstrumentationRegistry.getInstrumentation()
+ .getContext()
+ .getResources()
+ .getConfiguration()
+ .fontScale == 1
+ );
+ }
+
private Matcher<View> withTextSizeInRange(float sizeStartPx, float sizeEndPx) {
return new BoundedMatcher<>(TextView.class) {
private static final float TOLERANCE = 0.05f;
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 92c0dab..2a0e476 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2059,6 +2059,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-233530384": {
+ "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+ },
"-230587670": {
"message": "SyncGroup %d: Unfinished container: %s",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 59f120d..4d87c95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -61,6 +61,9 @@
@VisibleForTesting
final ActivityEmbeddingAnimationSpec mAnimationSpec;
+ @Nullable
+ private Animator mActiveAnimator;
+
ActivityEmbeddingAnimationRunner(@NonNull Context context,
@NonNull ActivityEmbeddingController controller) {
mController = controller;
@@ -75,8 +78,10 @@
// applied to make sure the surface is ready.
final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks =
new ArrayList<>();
- final Animator animator = createAnimator(info, startTransaction, finishTransaction,
+ final Animator animator = createAnimator(info, startTransaction,
+ finishTransaction,
() -> mController.onAnimationFinished(transition), postStartTransactionCallbacks);
+ mActiveAnimator = animator;
// Start the animation.
if (!postStartTransactionCallbacks.isEmpty()) {
@@ -98,6 +103,17 @@
}
}
+ void cancelAnimationFromMerge() {
+ if (mActiveAnimator == null) {
+ Log.e(TAG,
+ "No active ActivityEmbedding animator running but mergeAnimation is "
+ + "trying to cancel one."
+ );
+ return;
+ }
+ mActiveAnimator.end();
+ }
+
/**
* Sets transition animation scale settings value.
* @param scale The setting value of transition animation scale.
@@ -153,6 +169,7 @@
adapter.onAnimationEnd(t);
}
t.apply();
+ mActiveAnimator = null;
animationFinishCallback.run();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index bfbddbb..fbdbd3e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -118,6 +118,13 @@
return true;
}
+ @Override
+ public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ mAnimationRunner.cancelAnimationFromMerge();
+ }
+
private boolean handleNonEmbeddedChanges(List<TransitionInfo.Change> changes) {
final Rect nonClosingEmbeddedArea = new Rect();
for (int i = changes.size() - 1; i >= 0; i--) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 53a438e..c980906 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -54,10 +54,42 @@
void setTriggerBack(boolean triggerBack);
/**
- * Sets the threshold values that defining edge swipe behavior.
- * @param progressThreshold the max threshold to keep linear progressing back animation.
+ * Sets the threshold values that define edge swipe behavior.<br>
+ * <br>
+ * <h1>How does {@code nonLinearFactor} work?</h1>
+ * <pre>
+ * screen screen screen
+ * width width width
+ * |——————| |————————————| |————————————————————|
+ * A B A B C A
+ * 1 +——————+—————+ 1 +————————————+ 1 +————————————+———————+
+ * | / | | —/| | | —————/|
+ * | / | | —/ | | ——/ |
+ * | / | | —/ | | ——/ | |
+ * | / | | —/ | | ——/ | |
+ * | / | | —/ | | ——/ | |
+ * |/ | |—/ | |—/ | |
+ * 0 +————————————+ 0 +————————————+ 0 +————————————+———————+
+ * B B B
+ * </pre>
+ * Three devices with different widths (smaller, equal, and wider) relative to the progress
+ * threshold are shown in the graphs.<br>
+ * - A is the width of the screen<br>
+ * - B is the progress threshold (horizontal swipe distance where progress is linear)<br>
+ * - C equals B + (A - B) * nonLinearFactor<br>
+ * <br>
+ * If A is less than or equal to B, {@code progress} for the swipe distance between:<br>
+ * - [0, A] will scale linearly between [0, 1].<br>
+ * If A is greater than B, {@code progress} for swipe distance between:<br>
+ * - [0, B] will scale linearly between [0, B / C]<br>
+ * - (B, A] will scale non-linearly and reach 1.
+ *
+ * @param linearDistance up to this distance progress continues linearly. B in the graph above.
+ * @param maxDistance distance at which the progress will be 1f. A in the graph above.
+ * @param nonLinearFactor This value is used to calculate the target if the screen is wider
+ * than the progress threshold.
*/
- void setSwipeThresholds(float progressThreshold);
+ void setSwipeThresholds(float linearDistance, float maxDistance, float nonLinearFactor);
/**
* Sets the system bar listener to control the system bar color.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 6d879b8..bb543f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -301,9 +301,12 @@
}
@Override
- public void setSwipeThresholds(float progressThreshold) {
+ public void setSwipeThresholds(
+ float linearDistance,
+ float maxDistance,
+ float nonLinearFactor) {
mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds(
- progressThreshold));
+ linearDistance, maxDistance, nonLinearFactor));
}
@Override
@@ -509,7 +512,7 @@
// Constraints - absolute values
float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
- float maxX = mTouchTracker.getMaxX(); // px
+ float maxX = mTouchTracker.getMaxDistance(); // px
float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
// Current state
@@ -605,8 +608,11 @@
mTouchTracker.setTriggerBack(triggerBack);
}
- private void setSwipeThresholds(float progressThreshold) {
- mTouchTracker.setProgressThreshold(progressThreshold);
+ private void setSwipeThresholds(
+ float linearDistance,
+ float maxDistance,
+ float nonLinearFactor) {
+ mTouchTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor);
}
private void invokeOrCancelBack() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 7a00f5b..a0ada39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -28,11 +28,13 @@
* Helper class to record the touch location for gesture and generate back events.
*/
class TouchTracker {
- private static final String PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP =
- "persist.wm.debug.predictive_back_progress_threshold";
- private static final int PROGRESS_THRESHOLD = SystemProperties
- .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
- private float mProgressThreshold;
+ private static final String PREDICTIVE_BACK_LINEAR_DISTANCE_PROP =
+ "persist.wm.debug.predictive_back_linear_distance";
+ private static final int LINEAR_DISTANCE = SystemProperties
+ .getInt(PREDICTIVE_BACK_LINEAR_DISTANCE_PROP, -1);
+ private float mLinearDistance = LINEAR_DISTANCE;
+ private float mMaxDistance;
+ private float mNonLinearFactor;
/**
* Location of the latest touch event
*/
@@ -125,17 +127,42 @@
// the location everytime back is restarted after being cancelled.
float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
float deltaX = Math.abs(startX - touchX);
- float maxX = getMaxX();
- maxX = maxX == 0 ? 1 : maxX;
- return MathUtils.constrain(deltaX / maxX, 0, 1);
+ float linearDistance = mLinearDistance;
+ float maxDistance = getMaxDistance();
+ maxDistance = maxDistance == 0 ? 1 : maxDistance;
+ float progress;
+ if (linearDistance < maxDistance) {
+ // Up to linearDistance it behaves linearly, then slowly reaches 1f.
+
+ // maxDistance is composed of linearDistance + nonLinearDistance
+ float nonLinearDistance = maxDistance - linearDistance;
+ float initialTarget = linearDistance + nonLinearDistance * mNonLinearFactor;
+
+ boolean isLinear = deltaX <= linearDistance;
+ if (isLinear) {
+ progress = deltaX / initialTarget;
+ } else {
+ float nonLinearDeltaX = deltaX - linearDistance;
+ float nonLinearProgress = nonLinearDeltaX / nonLinearDistance;
+ float currentTarget = MathUtils.lerp(
+ /* start = */ initialTarget,
+ /* stop = */ maxDistance,
+ /* amount = */ nonLinearProgress);
+ progress = deltaX / currentTarget;
+ }
+ } else {
+ // Always linear behavior.
+ progress = deltaX / maxDistance;
+ }
+ return MathUtils.constrain(progress, 0, 1);
}
/**
- * Maximum X value (in pixels).
+ * Maximum distance in pixels.
* Progress is considered to be completed (1f) when this limit is exceeded.
*/
- float getMaxX() {
- return PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+ float getMaxDistance() {
+ return mMaxDistance;
}
BackMotionEvent createProgressEvent(float progress) {
@@ -149,7 +176,14 @@
/* departingAnimationTarget = */ null);
}
- public void setProgressThreshold(float progressThreshold) {
- mProgressThreshold = progressThreshold;
+ public void setProgressThresholds(float linearDistance, float maxDistance,
+ float nonLinearFactor) {
+ if (LINEAR_DISTANCE >= 0) {
+ mLinearDistance = LINEAR_DISTANCE;
+ } else {
+ mLinearDistance = linearDistance;
+ }
+ mMaxDistance = maxDistance;
+ mNonLinearFactor = nonLinearFactor;
}
}
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 9677728..fa21db5 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
@@ -1015,6 +1015,16 @@
mPipOrganizer.onExitPipFinished(prevPipTaskChange.getTaskInfo());
}
+ @Override
+ public boolean syncPipSurfaceState(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ final TransitionInfo.Change pipChange = findCurrentPipTaskChange(info);
+ if (pipChange == null) return false;
+ updatePipForUnhandledTransition(pipChange, startTransaction, finishTransaction);
+ return true;
+ }
+
private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction) {
@@ -1025,10 +1035,12 @@
final boolean isInPip = mPipTransitionState.isInPip();
mSurfaceTransactionHelper
.crop(startTransaction, leash, destBounds)
- .round(startTransaction, leash, isInPip);
+ .round(startTransaction, leash, isInPip)
+ .shadow(startTransaction, leash, isInPip);
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destBounds)
- .round(finishTransaction, leash, isInPip);
+ .round(finishTransaction, leash, isInPip)
+ .shadow(finishTransaction, leash, isInPip);
}
/** Hides and shows the existing PIP during fixed rotation transition of other activities. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 949d6f5..2fff0e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -240,6 +240,18 @@
@NonNull final Transitions.TransitionFinishCallback finishCallback) {
}
+ /**
+ * Applies the proper surface states (rounded corners/shadows) to pip surfaces in `info`.
+ * This is intended to be used when PiP is part of another animation but isn't, itself,
+ * animating (eg. unlocking).
+ * @return `true` if there was a pip in `info`.
+ */
+ public boolean syncPipSurfaceState(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ return false;
+ }
+
/** End the currently-playing PiP animation. */
public void end() {
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 087e3a2..a95d038 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -582,7 +582,6 @@
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -604,7 +603,6 @@
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -625,7 +623,6 @@
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -691,7 +688,6 @@
mMainStage.activate(wct, false /* reparent */);
}
- prepareEvictChildTasksIfSplitActive(wct);
mSplitLayout.setDivideRatio(splitRatio);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
@@ -1075,24 +1071,11 @@
}
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+ mMainStage.evictNonOpeningChildren(apps, evictWct);
+ mSideStage.evictNonOpeningChildren(apps, evictWct);
mSyncQueue.queue(evictWct);
}
-
- /**
- * Collects all the current child tasks of a specific split and prepares transaction to evict
- * them to display.
- */
- void prepareEvictChildTasks(@SplitPosition int position, WindowContainerTransaction wct) {
- if (position == mSideStagePosition) {
- mSideStage.evictAllChildren(wct);
- } else {
- mMainStage.evictAllChildren(wct);
- }
- }
-
void prepareEvictNonOpeningChildTasks(@SplitPosition int position, RemoteAnimationTarget[] apps,
WindowContainerTransaction wct) {
if (position == mSideStagePosition) {
@@ -1107,13 +1090,6 @@
mSideStage.evictInvisibleChildren(wct);
}
- void prepareEvictChildTasksIfSplitActive(WindowContainerTransaction wct) {
- if (mMainStage.isActive()) {
- mMainStage.evictAllChildren(wct);
- mSideStage.evictAllChildren(wct);
- }
- }
-
Bundle resolveStartStage(@StageType int stage, @SplitPosition int position,
@Nullable Bundle options, @Nullable WindowContainerTransaction wct) {
switch (stage) {
@@ -1500,10 +1476,8 @@
wct.startTask(taskInfo.taskId,
resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
}
- // If running background, we need to reparent current top visible task to another stage
- // and evict all tasks current under its.
+ // If running background, we need to reparent current top visible task to main stage.
if (!isSplitScreenVisible()) {
- // Recreate so we need to reset position rather than keep position of background split.
mMainStage.reparentTopTask(wct);
prepareSplitLayout(wct);
}
@@ -2337,7 +2311,7 @@
prepareEnterSplitScreen(out);
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
null /* consumedCallback */, null /* finishedCallback */,
- 0 /* extraTransitType */, !mIsDropEntering);
+ TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, !mIsDropEntering);
}
}
return out;
@@ -2604,7 +2578,8 @@
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
if (mainChild == null && sideChild == null) {
Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
- mSplitTransitions.mPendingEnter.cancel(null /* finishedCb */);
+ mSplitTransitions.mPendingEnter.cancel((cancelWct, cancelT)
+ -> prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, cancelWct));
return true;
}
} else {
@@ -2614,10 +2589,7 @@
final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
(sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
mSplitTransitions.mPendingEnter.cancel(
- (cancelWct, cancelT) -> {
- mSideStage.removeAllTasks(cancelWct, dismissTop == STAGE_TYPE_SIDE);
- mMainStage.deactivate(cancelWct, dismissTop == STAGE_TYPE_MAIN);
- });
+ (cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
return true;
}
}
@@ -2626,14 +2598,19 @@
// transitions locally, but remotes (like Launcher) may get confused if they were
// depending on listener callbacks. This can happen because task-organizer callbacks
// aren't serialized with transition callbacks.
+ // This usually occurred on app use trampoline launch new task and finish itself.
// TODO(b/184679596): Find a way to either include task-org information in
// the transition, or synchronize task-org callbacks.
- if (mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
+ final boolean mainNotContainOpenTask =
+ mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId);
+ final boolean sideNotContainOpenTask =
+ sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId);
+ if (mainNotContainOpenTask) {
Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
+ " to have been called with " + mainChild.getTaskInfo().taskId
+ " before startAnimation().");
}
- if (sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
+ if (sideNotContainOpenTask) {
Log.w(TAG, "Expected onTaskAppeared on " + mSideStage
+ " to have been called with " + sideChild.getTaskInfo().taskId
+ " before startAnimation().");
@@ -2642,10 +2619,18 @@
final TransitionInfo.Change finalSideChild = sideChild;
enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
if (finalMainChild != null) {
- mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+ if (!mainNotContainOpenTask) {
+ mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+ } else {
+ mMainStage.evictInvisibleChildren(callbackWct);
+ }
}
if (finalSideChild != null) {
- mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+ if (!sideNotContainOpenTask) {
+ mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+ } else {
+ mSideStage.evictInvisibleChildren(callbackWct);
+ }
}
if (enterTransition.mResizeAnim) {
mShowDecorImmediately = true;
@@ -2904,9 +2889,10 @@
if (!isSplitScreenVisible()) {
mIsDropEntering = true;
}
- if (!isSplitScreenVisible()) {
+ if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
- // TODO(b/280392203) : skip doing this on shell transition once this bug is fixed.
+ // Skip this on shell transition due to we could evict existing tasks on transition
+ // finished.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
}
mLogger.enterRequestedByDrag(position, dragSessionId);
@@ -2916,9 +2902,10 @@
* Sets info to be logged when splitscreen is next entered.
*/
public void onRequestToSplit(InstanceId sessionId, int enterReason) {
- if (!isSplitScreenVisible()) {
+ if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
- // TODO(b/280392203) : skip doing this on shell transition once this bug is fixed.
+ // Skip this on shell transition due to we could evict existing tasks on transition
+ // finished.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
}
mLogger.enterRequested(sessionId, enterReason);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 42633b7..863b5ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -304,8 +304,8 @@
return animateRecentsDuringSplit(mixed, info, startTransaction, finishTransaction,
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
- return mKeyguardHandler.startAnimation(
- transition, info, startTransaction, finishTransaction, finishCallback);
+ return animateKeyguard(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -557,6 +557,27 @@
return handled;
}
+ private boolean animateKeyguard(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ boolean consumed = mKeyguardHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+ if (!consumed) {
+ return false;
+ }
+ // Sync pip state.
+ if (mPipHandler != null) {
+ // We don't know when to apply `startTransaction` so use a separate transaction here.
+ // This should be fine because these surface properties are independent.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mPipHandler.syncPipSurfaceState(info, t, finishTransaction);
+ t.apply();
+ }
+ return true;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index a625346..4fca8b4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -65,12 +65,14 @@
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(createChange(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY))
.build();
- doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
+ doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(),
+ any());
mAnimRunner.startAnimation(mTransition, info, mStartTransaction, mFinishTransaction);
final ArgumentCaptor<Runnable> finishCallback = ArgumentCaptor.forClass(Runnable.class);
- verify(mAnimRunner).createAnimator(eq(info), eq(mStartTransaction), eq(mFinishTransaction),
+ verify(mAnimRunner).createAnimator(eq(info), eq(mStartTransaction),
+ eq(mFinishTransaction),
finishCallback.capture(), any());
verify(mStartTransaction).apply();
verify(mAnimator).start();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
index 4f4f356..ab1ccd4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
@@ -47,6 +47,7 @@
@Mock
ShellInit mShellInit;
+
@Mock
Transitions mTransitions;
@Mock
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
index b8f615a..ba34f1f7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
@@ -29,9 +29,13 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.animation.Animator;
+import android.animation.ValueAnimator;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.TransitionInfo;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -58,7 +62,8 @@
@Before
public void setup() {
super.setUp();
- doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
+ doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(),
+ any());
}
@Test
@@ -182,6 +187,44 @@
verifyNoMoreInteractions(mFinishTransaction);
}
+ @UiThreadTest
+ @Test
+ public void testMergeAnimation() {
+ final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
+ .addChange(createEmbeddedChange(
+ EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS))
+ .build();
+
+ final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mController.onAnimationFinished(mTransition);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ });
+ doReturn(animator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
+ mController.startAnimation(mTransition, info, mStartTransaction,
+ mFinishTransaction, mFinishCallback);
+ verify(mFinishCallback, never()).onTransitionFinished(any(), any());
+ mController.mergeAnimation(mTransition, info, new SurfaceControl.Transaction(),
+ mTransition,
+ (wct, cb) -> {
+ });
+ verify(mFinishCallback).onTransitionFinished(any(), any());
+ }
+
@Test
public void testOnAnimationFinished() {
// Should not call finish when there is no transition.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
deleted file mode 100644
index d62e660..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
+++ /dev/null
@@ -1,141 +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.wm.shell.back;
-
-import static org.junit.Assert.assertEquals;
-
-import android.window.BackEvent;
-import android.window.BackMotionEvent;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class TouchTrackerTest {
- private static final float FAKE_THRESHOLD = 400;
- private static final float INITIAL_X_LEFT_EDGE = 5;
- private static final float INITIAL_X_RIGHT_EDGE = FAKE_THRESHOLD - INITIAL_X_LEFT_EDGE;
- private TouchTracker mTouchTracker;
-
- @Before
- public void setUp() throws Exception {
- mTouchTracker = new TouchTracker();
- mTouchTracker.setProgressThreshold(FAKE_THRESHOLD);
- }
-
- @Test
- public void generatesProgress_onStart() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
- BackMotionEvent event = mTouchTracker.createStartEvent(null);
- assertEquals(event.getProgress(), 0f, 0f);
- }
-
- @Test
- public void generatesProgress_leftEdge() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
- float touchX = 10;
- float velocityX = 0;
- float velocityY = 0;
-
- // Pre-commit
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
-
- // Post-commit
- touchX += 100;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
-
- // Cancel
- touchX -= 10;
- mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Cancel more
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restart
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restarted, but pre-commit
- float restartX = touchX;
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - restartX) / FAKE_THRESHOLD, 0f);
-
- // Restarted, post-commit
- touchX += 10;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
- }
-
- @Test
- public void generatesProgress_rightEdge() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0, BackEvent.EDGE_RIGHT);
- float touchX = INITIAL_X_RIGHT_EDGE - 10; // Fake right edge
- float velocityX = 0f;
- float velocityY = 0f;
-
- // Pre-commit
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
-
- // Post-commit
- touchX -= 100;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
-
- // Cancel
- touchX += 10;
- mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Cancel more
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restart
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restarted, but pre-commit
- float restartX = touchX;
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (restartX - touchX) / FAKE_THRESHOLD, 0f);
-
- // Restarted, post-commit
- touchX -= 10;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
- }
-
- private float getProgress() {
- return mTouchTracker.createProgressEvent().getProgress();
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
new file mode 100644
index 0000000..9088e89
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
@@ -0,0 +1,181 @@
+/*
+ * 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.wm.shell.back
+
+import android.util.MathUtils
+import android.window.BackEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class TouchTrackerTest {
+ private fun linearTouchTracker(): TouchTracker = TouchTracker().apply {
+ setProgressThresholds(MAX_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
+ }
+
+ private fun nonLinearTouchTracker(): TouchTracker = TouchTracker().apply {
+ setProgressThresholds(LINEAR_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
+ }
+
+ private fun TouchTracker.assertProgress(expected: Float) {
+ val actualProgress = createProgressEvent().progress
+ assertEquals(expected, actualProgress, /* delta = */ 0f)
+ }
+
+ @Test
+ fun generatesProgress_onStart() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ val event = linearTracker.createStartEvent(null)
+ assertEquals(0f, event.progress, 0f)
+ }
+
+ @Test
+ fun generatesProgress_leftEdge() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ var touchX = 10f
+ val velocityX = 0f
+ val velocityY = 0f
+
+ // Pre-commit
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+
+ // Post-commit
+ touchX += 100f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+
+ // Cancel
+ touchX -= 10f
+ linearTracker.setTriggerBack(false)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Cancel more
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restart
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restarted, but pre-commit
+ val restartX = touchX
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
+
+ // Restarted, post-commit
+ touchX += 10f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+ }
+
+ @Test
+ fun generatesProgress_rightEdge() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
+ var touchX = INITIAL_X_RIGHT_EDGE - 10 // Fake right edge
+ val velocityX = 0f
+ val velocityY = 0f
+ val target = MAX_DISTANCE
+
+ // Pre-commit
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+
+ // Post-commit
+ touchX -= 100f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+
+ // Cancel
+ touchX += 10f
+ linearTracker.setTriggerBack(false)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Cancel more
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restart
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restarted, but pre-commit
+ val restartX = touchX
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((restartX - touchX) / target)
+
+ // Restarted, post-commit
+ touchX -= 10f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+ }
+
+ @Test
+ fun generatesNonLinearProgress_leftEdge() {
+ val nonLinearTracker = nonLinearTouchTracker()
+ nonLinearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ var touchX = 10f
+ val velocityX = 0f
+ val velocityY = 0f
+ val linearTarget = LINEAR_DISTANCE + (MAX_DISTANCE - LINEAR_DISTANCE) * NON_LINEAR_FACTOR
+
+ // Pre-commit: linear progress
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // Post-commit: still linear progress
+ touchX += 100f
+ nonLinearTracker.setTriggerBack(true)
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // still linear progress
+ touchX = INITIAL_X_LEFT_EDGE + LINEAR_DISTANCE
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // non linear progress
+ touchX += 10
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ val nonLinearTouch = (touchX - INITIAL_X_LEFT_EDGE) - LINEAR_DISTANCE
+ val nonLinearProgress = nonLinearTouch / NON_LINEAR_DISTANCE
+ val nonLinearTarget = MathUtils.lerp(linearTarget, MAX_DISTANCE, nonLinearProgress)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / nonLinearTarget)
+ }
+
+ companion object {
+ private const val MAX_DISTANCE = 500f
+ private const val LINEAR_DISTANCE = 400f
+ private const val NON_LINEAR_DISTANCE = MAX_DISTANCE - LINEAR_DISTANCE
+ private const val NON_LINEAR_FACTOR = 0.2f
+ private const val INITIAL_X_LEFT_EDGE = 5f
+ private const val INITIAL_X_RIGHT_EDGE = MAX_DISTANCE - INITIAL_X_LEFT_EDGE
+ }
+}
\ No newline at end of file
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b1d2e33..4759689 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3730,7 +3730,12 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setA2dpSuspended(boolean enable) {
- AudioSystem.setParameters("A2dpSuspended=" + enable);
+ final IAudioService service = getService();
+ try {
+ service.setA2dpSuspended(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -3743,7 +3748,12 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setLeAudioSuspended(boolean enable) {
- AudioSystem.setParameters("LeAudioSuspended=" + enable);
+ final IAudioService service = getService();
+ try {
+ service.setLeAudioSuspended(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe5afc5..7ce189b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -231,6 +231,12 @@
void setBluetoothScoOn(boolean on);
+ @EnforcePermission("BLUETOOTH_STACK")
+ void setA2dpSuspended(boolean on);
+
+ @EnforcePermission("BLUETOOTH_STACK")
+ void setLeAudioSuspended(boolean enable);
+
boolean isBluetoothScoOn();
void setBluetoothA2dpOn(boolean on);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 6f67d68..1b04f18 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -372,13 +372,12 @@
void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) {
ALOGV("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject lnb(env->NewLocalRef(mLnbObj));
- if (!env->IsSameObject(lnb, nullptr)) {
+ ScopedLocalRef lnb(env, env->NewLocalRef(mLnbObj));
+ if (!env->IsSameObject(lnb.get(), nullptr)) {
env->CallVoidMethod(
- lnb,
+ lnb.get(),
gFields.onLnbEventID,
(jint)lnbEventType);
- env->DeleteLocalRef(lnb);
} else {
ALOGE("LnbClientCallbackImpl::onEvent:"
"Lnb object has been freed. Ignoring callback.");
@@ -388,17 +387,15 @@
void LnbClientCallbackImpl::onDiseqcMessage(const vector<uint8_t> &diseqcMessage) {
ALOGV("LnbClientCallbackImpl::onDiseqcMessage");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject lnb(env->NewLocalRef(mLnbObj));
- if (!env->IsSameObject(lnb, nullptr)) {
- jbyteArray array = env->NewByteArray(diseqcMessage.size());
- env->SetByteArrayRegion(array, 0, diseqcMessage.size(),
+ ScopedLocalRef lnb(env, env->NewLocalRef(mLnbObj));
+ if (!env->IsSameObject(lnb.get(), nullptr)) {
+ ScopedLocalRef array(env, env->NewByteArray(diseqcMessage.size()));
+ env->SetByteArrayRegion(array.get(), 0, diseqcMessage.size(),
reinterpret_cast<const jbyte *>(&diseqcMessage[0]));
env->CallVoidMethod(
- lnb,
+ lnb.get(),
gFields.onLnbDiseqcMessageID,
- array);
- env->DeleteLocalRef(lnb);
- env->DeleteLocalRef(array);
+ array.get());
} else {
ALOGE("LnbClientCallbackImpl::onDiseqcMessage:"
"Lnb object has been freed. Ignoring callback.");
@@ -422,10 +419,9 @@
void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) {
ALOGV("DvrClientCallbackImpl::onRecordStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject dvr(env->NewLocalRef(mDvrObj));
- if (!env->IsSameObject(dvr, nullptr)) {
- env->CallVoidMethod(dvr, gFields.onDvrRecordStatusID, (jint)status);
- env->DeleteLocalRef(dvr);
+ ScopedLocalRef dvr(env, env->NewLocalRef(mDvrObj));
+ if (!env->IsSameObject(dvr.get(), nullptr)) {
+ env->CallVoidMethod(dvr.get(), gFields.onDvrRecordStatusID, (jint)status);
} else {
ALOGE("DvrClientCallbackImpl::onRecordStatus:"
"Dvr object has been freed. Ignoring callback.");
@@ -435,10 +431,9 @@
void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) {
ALOGV("DvrClientCallbackImpl::onPlaybackStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject dvr(env->NewLocalRef(mDvrObj));
- if (!env->IsSameObject(dvr, nullptr)) {
- env->CallVoidMethod(dvr, gFields.onDvrPlaybackStatusID, (jint)status);
- env->DeleteLocalRef(dvr);
+ ScopedLocalRef dvr(env, env->NewLocalRef(mDvrObj));
+ if (!env->IsSameObject(dvr.get(), nullptr)) {
+ env->CallVoidMethod(dvr.get(), gFields.onDvrPlaybackStatusID, (jint)status);
} else {
ALOGE("DvrClientCallbackImpl::onPlaybackStatus:"
"Dvr object has been freed. Ignoring callback.");
@@ -614,7 +609,7 @@
}
/////////////// FilterClientCallbackImpl ///////////////////////
-void FilterClientCallbackImpl::getSectionEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getSectionEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -624,20 +619,20 @@
jint sectionNum = sectionEvent.sectionNum;
jlong dataLength = sectionEvent.dataLength;
- jobject obj = env->NewObject(mSectionEventClass, mSectionEventInitID, tableId, version,
- sectionNum, dataLength);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mSectionEventClass, mSectionEventInitID, tableId,
+ version, sectionNum, dataLength));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getMediaEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
const DemuxFilterMediaEvent &mediaEvent = event.get<DemuxFilterEvent::Tag::media>();
- jobject audioDescriptor = nullptr;
+ ScopedLocalRef<jobject> audioDescriptor(env);
gAudioPresentationFields.init(env);
- jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields);
+ ScopedLocalRef presentationsJObj(env, JAudioPresentationInfo::asJobject(
+ env, gAudioPresentationFields));
switch (mediaEvent.extraMetaData.getTag()) {
case DemuxFilterMediaEventExtraMetaData::Tag::audio: {
@@ -650,9 +645,9 @@
jbyte adGainFront = ad.adGainFront;
jbyte adGainSurround = ad.adGainSurround;
- audioDescriptor = env->NewObject(mAudioDescriptorClass, mAudioDescriptorInitID, adFade,
- adPan, versionTextTag, adGainCenter, adGainFront,
- adGainSurround);
+ audioDescriptor.reset(env->NewObject(mAudioDescriptorClass, mAudioDescriptorInitID,
+ adFade, adPan, versionTextTag, adGainCenter,
+ adGainFront, adGainSurround));
break;
}
case DemuxFilterMediaEventExtraMetaData::Tag::audioPresentations: {
@@ -660,7 +655,7 @@
env, gAudioPresentationFields,
mediaEvent.extraMetaData
.get<DemuxFilterMediaEventExtraMetaData::Tag::audioPresentations>(),
- presentationsJObj);
+ presentationsJObj.get());
break;
}
default: {
@@ -693,31 +688,27 @@
sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scVvc>();
}
- jobject obj = env->NewObject(mMediaEventClass, mMediaEventInitID, streamId, isPtsPresent, pts,
- isDtsPresent, dts, dataLength, offset, nullptr, isSecureMemory,
- avDataId, mpuSequenceNumber, isPesPrivateData, sc,
- audioDescriptor, presentationsJObj);
+ ScopedLocalRef obj(env, env->NewObject(mMediaEventClass, mMediaEventInitID, streamId,
+ isPtsPresent, pts, isDtsPresent, dts, dataLength,
+ offset, nullptr, isSecureMemory, avDataId,
+ mpuSequenceNumber, isPesPrivateData, sc,
+ audioDescriptor.get(), presentationsJObj.get()));
uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
(dataLength > 0 && (dataLength + offset) < avSharedMemSize)) {
sp<MediaEvent> mediaEventSp =
new MediaEvent(mFilterClient, dupFromAidl(mediaEvent.avMemory),
- mediaEvent.avDataId, dataLength + offset, obj);
+ mediaEvent.avDataId, dataLength + offset, obj.get());
mediaEventSp->mAvHandleRefCnt++;
- env->SetLongField(obj, mMediaEventFieldContextID, (jlong)mediaEventSp.get());
- mediaEventSp->incStrong(obj);
+ env->SetLongField(obj.get(), mMediaEventFieldContextID, (jlong)mediaEventSp.get());
+ mediaEventSp->incStrong(obj.get());
}
- env->SetObjectArrayElement(arr, size, obj);
- if(audioDescriptor != nullptr) {
- env->DeleteLocalRef(audioDescriptor);
- }
- env->DeleteLocalRef(obj);
- env->DeleteLocalRef(presentationsJObj);
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getPesEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getPesEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -726,13 +717,12 @@
jint dataLength = pesEvent.dataLength;
jint mpuSequenceNumber = pesEvent.mpuSequenceNumber;
- jobject obj = env->NewObject(mPesEventClass, mPesEventInitID, streamId, dataLength,
- mpuSequenceNumber);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mPesEventClass, mPesEventInitID, streamId, dataLength,
+ mpuSequenceNumber));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getTsRecordEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getTsRecordEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -764,13 +754,12 @@
jlong pts = tsRecordEvent.pts;
jint firstMbInSlice = tsRecordEvent.firstMbInSlice;
- jobject obj = env->NewObject(mTsRecordEventClass, mTsRecordEventInitID, jpid, ts, sc,
- byteNumber, pts, firstMbInSlice);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mTsRecordEventClass, mTsRecordEventInitID, jpid, ts, sc,
+ byteNumber, pts, firstMbInSlice));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getMmtpRecordEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getMmtpRecordEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -783,13 +772,13 @@
jint firstMbInSlice = mmtpRecordEvent.firstMbInSlice;
jlong tsIndexMask = mmtpRecordEvent.tsIndexMask;
- jobject obj = env->NewObject(mMmtpRecordEventClass, mMmtpRecordEventInitID, scHevcIndexMask,
- byteNumber, mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mMmtpRecordEventClass, mMmtpRecordEventInitID,
+ scHevcIndexMask, byteNumber, mpuSequenceNumber, pts,
+ firstMbInSlice, tsIndexMask));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getDownloadEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getDownloadEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -801,25 +790,25 @@
jint lastItemFragmentIndex = downloadEvent.lastItemFragmentIndex;
jint dataLength = downloadEvent.dataLength;
- jobject obj = env->NewObject(mDownloadEventClass, mDownloadEventInitID, itemId, downloadId,
- mpuSequenceNumber, itemFragmentIndex, lastItemFragmentIndex,
- dataLength);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mDownloadEventClass, mDownloadEventInitID, itemId,
+ downloadId, mpuSequenceNumber, itemFragmentIndex,
+ lastItemFragmentIndex, dataLength));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getIpPayloadEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getIpPayloadEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- const DemuxFilterIpPayloadEvent &ipPayloadEvent = event.get<DemuxFilterEvent::Tag::ipPayload>();
+ const DemuxFilterIpPayloadEvent &ipPayloadEvent =
+ event.get<DemuxFilterEvent::Tag::ipPayload>();
jint dataLength = ipPayloadEvent.dataLength;
- jobject obj = env->NewObject(mIpPayloadEventClass, mIpPayloadEventInitID, dataLength);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mIpPayloadEventClass, mIpPayloadEventInitID,
+ dataLength));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getTemiEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getTemiEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -828,110 +817,108 @@
jbyte descrTag = temiEvent.descrTag;
std::vector<uint8_t> descrData = temiEvent.descrData;
- jbyteArray array = env->NewByteArray(descrData.size());
- env->SetByteArrayRegion(array, 0, descrData.size(), reinterpret_cast<jbyte *>(&descrData[0]));
+ ScopedLocalRef array(env, env->NewByteArray(descrData.size()));
+ env->SetByteArrayRegion(array.get(), 0, descrData.size(),
+ reinterpret_cast<jbyte *>(&descrData[0]));
- jobject obj = env->NewObject(mTemiEventClass, mTemiEventInitID, pts, descrTag, array);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(array);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mTemiEventClass, mTemiEventInitID, pts, descrTag,
+ array.get()));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getScramblingStatusEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getScramblingStatusEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
const DemuxFilterMonitorEvent &scramblingStatus =
event.get<DemuxFilterEvent::Tag::monitorEvent>()
.get<DemuxFilterMonitorEvent::Tag::scramblingStatus>();
- jobject obj = env->NewObject(mScramblingStatusEventClass, mScramblingStatusEventInitID,
- scramblingStatus);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mScramblingStatusEventClass,
+ mScramblingStatusEventInitID,
+ scramblingStatus));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getIpCidChangeEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getIpCidChangeEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
const DemuxFilterMonitorEvent &cid = event.get<DemuxFilterEvent::Tag::monitorEvent>()
.get<DemuxFilterMonitorEvent::Tag::cid>();
- jobject obj = env->NewObject(mIpCidChangeEventClass, mIpCidChangeEventInitID, cid);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mIpCidChangeEventClass, mIpCidChangeEventInitID, cid));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
-void FilterClientCallbackImpl::getRestartEvent(jobjectArray &arr, const int size,
+void FilterClientCallbackImpl::getRestartEvent(const jobjectArray& arr, const int size,
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
const int32_t &startId = event.get<DemuxFilterEvent::Tag::startId>();
- jobject obj = env->NewObject(mRestartEventClass, mRestartEventInitID, startId);
- env->SetObjectArrayElement(arr, size, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(mRestartEventClass, mRestartEventInitID, startId));
+ env->SetObjectArrayElement(arr, size, obj.get());
}
void FilterClientCallbackImpl::onFilterEvent(const vector<DemuxFilterEvent> &events) {
ALOGV("FilterClientCallbackImpl::onFilterEvent");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobjectArray array;
+ ScopedLocalRef<jobjectArray> array(env);
if (!events.empty()) {
- array = env->NewObjectArray(events.size(), mEventClass, nullptr);
+ array.reset(env->NewObjectArray(events.size(), mEventClass, nullptr));
}
for (int i = 0, arraySize = 0; i < events.size(); i++) {
const DemuxFilterEvent &event = events[i];
switch (event.getTag()) {
case DemuxFilterEvent::Tag::media: {
- getMediaEvent(array, arraySize, event);
+ getMediaEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::section: {
- getSectionEvent(array, arraySize, event);
+ getSectionEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::pes: {
- getPesEvent(array, arraySize, event);
+ getPesEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::tsRecord: {
- getTsRecordEvent(array, arraySize, event);
+ getTsRecordEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::mmtpRecord: {
- getMmtpRecordEvent(array, arraySize, event);
+ getMmtpRecordEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::download: {
- getDownloadEvent(array, arraySize, event);
+ getDownloadEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::ipPayload: {
- getIpPayloadEvent(array, arraySize, event);
+ getIpPayloadEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::temi: {
- getTemiEvent(array, arraySize, event);
+ getTemiEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterEvent::Tag::monitorEvent: {
switch (event.get<DemuxFilterEvent::Tag::monitorEvent>().getTag()) {
case DemuxFilterMonitorEvent::Tag::scramblingStatus: {
- getScramblingStatusEvent(array, arraySize, event);
+ getScramblingStatusEvent(array.get(), arraySize, event);
arraySize++;
break;
}
case DemuxFilterMonitorEvent::Tag::cid: {
- getIpCidChangeEvent(array, arraySize, event);
+ getIpCidChangeEvent(array.get(), arraySize, event);
arraySize++;
break;
}
@@ -943,7 +930,7 @@
break;
}
case DemuxFilterEvent::Tag::startId: {
- getRestartEvent(array, arraySize, event);
+ getRestartEvent(array.get(), arraySize, event);
arraySize++;
break;
}
@@ -953,32 +940,29 @@
}
}
}
- jobject filter(env->NewLocalRef(mFilterObj));
- if (!env->IsSameObject(filter, nullptr)) {
+ ScopedLocalRef filter(env, env->NewLocalRef(mFilterObj));
+ if (!env->IsSameObject(filter.get(), nullptr)) {
jmethodID methodID = gFields.onFilterEventID;
if (mSharedFilter) {
methodID = gFields.onSharedFilterEventID;
}
- env->CallVoidMethod(filter, methodID, array);
- env->DeleteLocalRef(filter);
+ env->CallVoidMethod(filter.get(), methodID, array.get());
} else {
ALOGE("FilterClientCallbackImpl::onFilterEvent:"
"Filter object has been freed. Ignoring callback.");
}
- env->DeleteLocalRef(array);
}
void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
ALOGV("FilterClientCallbackImpl::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject filter(env->NewLocalRef(mFilterObj));
- if (!env->IsSameObject(filter, nullptr)) {
+ ScopedLocalRef filter(env, env->NewLocalRef(mFilterObj));
+ if (!env->IsSameObject(filter.get(), nullptr)) {
jmethodID methodID = gFields.onFilterStatusID;
if (mSharedFilter) {
methodID = gFields.onSharedFilterStatusID;
}
- env->CallVoidMethod(filter, methodID, (jint)static_cast<uint8_t>(status));
- env->DeleteLocalRef(filter);
+ env->CallVoidMethod(filter.get(), methodID, (jint)static_cast<uint8_t>(status));
} else {
ALOGE("FilterClientCallbackImpl::onFilterStatus:"
"Filter object has been freed. Ignoring callback.");
@@ -1115,13 +1099,12 @@
std::scoped_lock<std::mutex> lock(mMutex);
for (const auto& mapEntry : mListenersMap) {
ALOGV("JTuner:%p, jweak:%p", mapEntry.first, mapEntry.second);
- jobject frontend(env->NewLocalRef(mapEntry.second));
- if (!env->IsSameObject(frontend, nullptr)) {
+ ScopedLocalRef frontend(env, env->NewLocalRef(mapEntry.second));
+ if (!env->IsSameObject(frontend.get(), nullptr)) {
env->CallVoidMethod(
- frontend,
+ frontend.get(),
gFields.onFrontendEventID,
(jint)frontendEventType);
- env->DeleteLocalRef(frontend);
} else {
ALOGW("FrontendClientCallbackImpl::onEvent:"
"Frontend object has been freed. Ignoring callback.");
@@ -1133,20 +1116,18 @@
FrontendScanMessageType type, const FrontendScanMessage& message) {
ALOGV("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
+ ScopedLocalRef clazz(env, env->FindClass("android/media/tv/tuner/Tuner"));
std::scoped_lock<std::mutex> lock(mMutex);
for (const auto& mapEntry : mListenersMap) {
- jobject frontend(env->NewLocalRef(mapEntry.second));
- if (env->IsSameObject(frontend, nullptr)) {
+ ScopedLocalRef frontend(env, env->NewLocalRef(mapEntry.second));
+ if (env->IsSameObject(frontend.get(), nullptr)) {
ALOGE("FrontendClientCallbackImpl::onScanMessage:"
"Tuner object has been freed. Ignoring callback.");
continue;
}
- executeOnScanMessage(env, clazz, frontend, type, message);
- env->DeleteLocalRef(frontend);
+ executeOnScanMessage(env, clazz.get(), frontend.get(), type, message);
}
- env->DeleteLocalRef(clazz);
}
void FrontendClientCallbackImpl::executeOnScanMessage(
@@ -1183,20 +1164,19 @@
}
case FrontendScanMessageType::FREQUENCY: {
std::vector<int64_t> v = message.get<FrontendScanMessage::Tag::frequencies>();
- jlongArray freqs = env->NewLongArray(v.size());
- env->SetLongArrayRegion(freqs, 0, v.size(), reinterpret_cast<jlong *>(&v[0]));
+ ScopedLocalRef freqs(env, env->NewLongArray(v.size()));
+ env->SetLongArrayRegion(freqs.get(), 0, v.size(), reinterpret_cast<jlong *>(&v[0]));
env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onFrequenciesReport", "([J)V"),
- freqs);
- env->DeleteLocalRef(freqs);
+ freqs.get());
break;
}
case FrontendScanMessageType::SYMBOL_RATE: {
std::vector<int32_t> v = message.get<FrontendScanMessage::Tag::symbolRates>();
- jintArray symbolRates = env->NewIntArray(v.size());
- env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
+ ScopedLocalRef symbolRates(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(symbolRates.get(), 0, v.size(),
+ reinterpret_cast<jint *>(&v[0]));
env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onSymbolRates", "([I)V"),
- symbolRates);
- env->DeleteLocalRef(symbolRates);
+ symbolRates.get());
break;
}
case FrontendScanMessageType::HIERARCHY: {
@@ -1211,27 +1191,29 @@
}
case FrontendScanMessageType::PLP_IDS: {
std::vector<int32_t> jintV = message.get<FrontendScanMessage::Tag::plpIds>();
- jintArray plpIds = env->NewIntArray(jintV.size());
- env->SetIntArrayRegion(plpIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
- env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onPlpIds", "([I)V"), plpIds);
- env->DeleteLocalRef(plpIds);
+ ScopedLocalRef plpIds(env, env->NewIntArray(jintV.size()));
+ env->SetIntArrayRegion(plpIds.get(), 0, jintV.size(),
+ reinterpret_cast<jint *>(&jintV[0]));
+ env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onPlpIds", "([I)V"),
+ plpIds.get());
break;
}
case FrontendScanMessageType::GROUP_IDS: {
std::vector<int32_t> jintV = message.get<FrontendScanMessage::groupIds>();
- jintArray groupIds = env->NewIntArray(jintV.size());
- env->SetIntArrayRegion(groupIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
- env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onGroupIds", "([I)V"), groupIds);
- env->DeleteLocalRef(groupIds);
+ ScopedLocalRef groupIds(env, env->NewIntArray(jintV.size()));
+ env->SetIntArrayRegion(groupIds.get(), 0, jintV.size(),
+ reinterpret_cast<jint *>(&jintV[0]));
+ env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onGroupIds", "([I)V"),
+ groupIds.get());
break;
}
case FrontendScanMessageType::INPUT_STREAM_IDS: {
std::vector<int32_t> jintV = message.get<FrontendScanMessage::inputStreamIds>();
- jintArray streamIds = env->NewIntArray(jintV.size());
- env->SetIntArrayRegion(streamIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+ ScopedLocalRef streamIds(env, env->NewIntArray(jintV.size()));
+ env->SetIntArrayRegion(streamIds.get(), 0, jintV.size(),
+ reinterpret_cast<jint *>(&jintV[0]));
env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onInputStreamIds", "([I)V"),
- streamIds);
- env->DeleteLocalRef(streamIds);
+ streamIds.get());
break;
}
case FrontendScanMessageType::STANDARD: {
@@ -1254,26 +1236,25 @@
break;
}
case FrontendScanMessageType::ATSC3_PLP_INFO: {
- jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo");
- jmethodID init = env->GetMethodID(plpClazz, "<init>", "(IZ)V");
+ ScopedLocalRef plpClazz(env,
+ env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo"));
+ jmethodID init = env->GetMethodID(plpClazz.get(), "<init>", "(IZ)V");
std::vector<FrontendScanAtsc3PlpInfo> plpInfos =
message.get<FrontendScanMessage::atsc3PlpInfos>();
- jobjectArray array = env->NewObjectArray(plpInfos.size(), plpClazz, nullptr);
+ ScopedLocalRef array(env,
+ env->NewObjectArray(plpInfos.size(), plpClazz.get(), nullptr));
for (int i = 0; i < plpInfos.size(); i++) {
const FrontendScanAtsc3PlpInfo &info = plpInfos[i];
jint plpId = info.plpId;
jboolean lls = info.bLlsFlag;
- jobject obj = env->NewObject(plpClazz, init, plpId, lls);
- env->SetObjectArrayElement(array, i, obj);
- env->DeleteLocalRef(obj);
+ ScopedLocalRef obj(env, env->NewObject(plpClazz.get(), init, plpId, lls));
+ env->SetObjectArrayElement(array.get(), i, obj.get());
}
env->CallVoidMethod(frontend,
env->GetMethodID(clazz, "onAtsc3PlpInfos",
"([Landroid/media/tv/tuner/frontend/"
"Atsc3PlpInfo;)V"),
- array);
- env->DeleteLocalRef(array);
- env->DeleteLocalRef(plpClazz);
+ array.get());
break;
}
case FrontendScanMessageType::MODULATION: {
@@ -1341,11 +1322,12 @@
}
case FrontendScanMessageType::DVBT_CELL_IDS: {
std::vector<int32_t> jintV = message.get<FrontendScanMessage::dvbtCellIds>();
- jintArray cellIds = env->NewIntArray(jintV.size());
- env->SetIntArrayRegion(cellIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
- env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onDvbtCellIdsReported", "([I)V"),
- cellIds);
- env->DeleteLocalRef(cellIds);
+ ScopedLocalRef cellIds(env, env->NewIntArray(jintV.size()));
+ env->SetIntArrayRegion(cellIds.get(), 0, jintV.size(),
+ reinterpret_cast<jint *>(&jintV[0]));
+ env->CallVoidMethod(frontend,
+ env->GetMethodID(clazz, "onDvbtCellIdsReported", "([I)V"),
+ cellIds.get());
break;
}
default:
@@ -1434,7 +1416,8 @@
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass arrayListClazz = env->FindClass("java/util/ArrayList");
jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
- jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
+ jobject obj = env->NewObject(arrayListClazz,
+ env->GetMethodID(arrayListClazz, "<init>", "()V"));
jclass integerClazz = env->FindClass("java/lang/Integer");
jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
@@ -1672,7 +1655,7 @@
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendInfo");
jmethodID infoInit =
env->GetMethodID(clazz, "<init>",
- "(IIJJIIJI[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
+ "(IIJJIIJI[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V");
jint type = (jint)feInfo->type;
jlong minFrequency = feInfo->minFrequency;
@@ -1812,9 +1795,8 @@
jmethodID init = env->GetMethodID(clazz, "<init>", "(II)V");
jobjectArray valObj = env->NewObjectArray(size, clazz, nullptr);
for (int i = 0; i < size; i++) {
- jobject readinessObj = env->NewObject(clazz, init, intTypes[i], readiness[i]);
- env->SetObjectArrayElement(valObj, i, readinessObj);
- env->DeleteLocalRef(readinessObj);
+ ScopedLocalRef readinessObj(env, env->NewObject(clazz, init, intTypes[i], readiness[i]));
+ env->SetObjectArrayElement(valObj, i, readinessObj.get());
}
return valObj;
}
@@ -2260,79 +2242,72 @@
switch (s.getTag()) {
case FrontendStatus::Tag::isDemodLocked: {
jfieldID field = env->GetFieldID(clazz, "mIsDemodLocked", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isDemodLocked>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env,
+ env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isDemodLocked>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::snr: {
jfieldID field = env->GetFieldID(clazz, "mSnr", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::snr>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::snr>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::ber: {
jfieldID field = env->GetFieldID(clazz, "mBer", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::ber>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::ber>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::per: {
jfieldID field = env->GetFieldID(clazz, "mPer", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::per>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::per>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::preBer: {
jfieldID field = env->GetFieldID(clazz, "mPerBer", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::preBer>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::preBer>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::signalQuality: {
jfieldID field = env->GetFieldID(clazz, "mSignalQuality", "Ljava/lang/Integer;");
- jobject newIntegerObj = env->NewObject(intClazz, initInt,
- s.get<FrontendStatus::Tag::signalQuality>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt,
+ s.get<FrontendStatus::Tag::signalQuality>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::signalStrength: {
jfieldID field = env->GetFieldID(clazz, "mSignalStrength", "Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- s.get<FrontendStatus::Tag::signalStrength>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ s.get<FrontendStatus::Tag::signalStrength>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::symbolRate: {
jfieldID field = env->GetFieldID(clazz, "mSymbolRate", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::symbolRate>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt,
+ s.get<FrontendStatus::Tag::symbolRate>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::innerFec: {
jfieldID field = env->GetFieldID(clazz, "mInnerFec", "Ljava/lang/Long;");
- jclass longClazz = env->FindClass("java/lang/Long");
- jmethodID initLong = env->GetMethodID(longClazz, "<init>", "(J)V");
- jobject newLongObj =
- env->NewObject(longClazz, initLong,
- static_cast<long>(s.get<FrontendStatus::Tag::innerFec>()));
- env->SetObjectField(statusObj, field, newLongObj);
- env->DeleteLocalRef(newLongObj);
- env->DeleteLocalRef(longClazz);
+ ScopedLocalRef longClazz(env, env->FindClass("java/lang/Long"));
+ jmethodID initLong = env->GetMethodID(longClazz.get(), "<init>", "(J)V");
+ ScopedLocalRef newLongObj(env,
+ env->NewObject(longClazz.get(), initLong,
+ static_cast<long>(s.get<FrontendStatus::Tag::innerFec>())));
+ env->SetObjectField(statusObj, field, newLongObj.get());
break;
}
case FrontendStatus::Tag::modulationStatus: {
@@ -2373,139 +2348,128 @@
}
}
if (valid) {
- jobject newIntegerObj = env->NewObject(intClazz, initInt, intModulation);
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, intModulation));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
}
break;
}
case FrontendStatus::Tag::inversion: {
jfieldID field = env->GetFieldID(clazz, "mInversion", "Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- static_cast<jint>(s.get<FrontendStatus::Tag::inversion>()));
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ static_cast<jint>(s.get<FrontendStatus::Tag::inversion>())));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::lnbVoltage: {
jfieldID field = env->GetFieldID(clazz, "mLnbVoltage", "Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- static_cast<jint>(s.get<FrontendStatus::Tag::lnbVoltage>()));
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ static_cast<jint>(s.get<FrontendStatus::Tag::lnbVoltage>())));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::plpId: {
jfieldID field = env->GetFieldID(clazz, "mPlpId", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::plpId>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::plpId>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::isEWBS: {
jfieldID field = env->GetFieldID(clazz, "mIsEwbs", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isEWBS>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env, env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isEWBS>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::agc: {
jfieldID field = env->GetFieldID(clazz, "mAgc", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::agc>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::agc>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::isLnaOn: {
jfieldID field = env->GetFieldID(clazz, "mIsLnaOn", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isLnaOn>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env, env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isLnaOn>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::isLayerError: {
jfieldID field = env->GetFieldID(clazz, "mIsLayerErrors", "[Z");
vector<bool> layerErr = s.get<FrontendStatus::Tag::isLayerError>();
- jbooleanArray valObj = env->NewBooleanArray(layerErr.size());
+ ScopedLocalRef valObj(env, env->NewBooleanArray(layerErr.size()));
for (size_t i = 0; i < layerErr.size(); i++) {
jboolean x = layerErr[i];
- env->SetBooleanArrayRegion(valObj, i, 1, &x);
+ env->SetBooleanArrayRegion(valObj.get(), i, 1, &x);
}
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::mer: {
jfieldID field = env->GetFieldID(clazz, "mMer", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::mer>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::mer>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::freqOffset: {
jfieldID field = env->GetFieldID(clazz, "mFreqOffset", "Ljava/lang/Long;");
- jobject newLongObj = env->NewObject(longClazz, initLong,
- s.get<FrontendStatus::Tag::freqOffset>());
- env->SetObjectField(statusObj, field, newLongObj);
- env->DeleteLocalRef(newLongObj);
+ ScopedLocalRef newLongObj(env, env->NewObject(longClazz, initLong,
+ s.get<FrontendStatus::Tag::freqOffset>()));
+ env->SetObjectField(statusObj, field, newLongObj.get());
break;
}
case FrontendStatus::Tag::hierarchy: {
jfieldID field = env->GetFieldID(clazz, "mHierarchy", "Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- static_cast<jint>(s.get<FrontendStatus::Tag::hierarchy>()));
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ static_cast<jint>(s.get<FrontendStatus::Tag::hierarchy>())));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::isRfLocked: {
jfieldID field = env->GetFieldID(clazz, "mIsRfLocked", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isRfLocked>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env, env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isRfLocked>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::plpInfo: {
jfieldID field = env->GetFieldID(clazz, "mPlpInfo",
"[Landroid/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo;");
- jclass plpClazz = env->FindClass(
- "android/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo");
- jmethodID initPlp = env->GetMethodID(plpClazz, "<init>", "(IZI)V");
+ ScopedLocalRef plpClazz(env, env->FindClass(
+ "android/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo"));
+ jmethodID initPlp = env->GetMethodID(plpClazz.get(), "<init>", "(IZI)V");
- vector<FrontendStatusAtsc3PlpInfo> plpInfos = s.get<FrontendStatus::Tag::plpInfo>();
- jobjectArray valObj = env->NewObjectArray(plpInfos.size(), plpClazz, nullptr);
+ vector<FrontendStatusAtsc3PlpInfo> plpInfos =
+ s.get<FrontendStatus::Tag::plpInfo>();
+ ScopedLocalRef valObj(env, env->NewObjectArray(plpInfos.size(), plpClazz.get(),
+ nullptr));
for (int i = 0; i < plpInfos.size(); i++) {
const FrontendStatusAtsc3PlpInfo &info = plpInfos[i];
jint plpId = info.plpId;
jboolean isLocked = info.isLocked;
jint uec = info.uec;
- jobject plpObj = env->NewObject(plpClazz, initPlp, plpId, isLocked, uec);
- env->SetObjectArrayElement(valObj, i, plpObj);
- env->DeleteLocalRef(plpObj);
+ ScopedLocalRef plpObj(env, env->NewObject(plpClazz.get(), initPlp, plpId,
+ isLocked, uec));
+ env->SetObjectArrayElement(valObj.get(), i, plpObj.get());
}
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
- env->DeleteLocalRef(plpClazz);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::modulations: {
jfieldID field = env->GetFieldID(clazz, "mModulationsExt", "[I");
std::vector<FrontendModulation> v = s.get<FrontendStatus::Tag::modulations>();
- jintArray valObj = env->NewIntArray(v.size());
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
bool valid = false;
jint m[1];
for (int i = 0; i < v.size(); i++) {
@@ -2514,63 +2478,63 @@
case FrontendModulation::Tag::dvbc: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::dvbc>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::dvbs: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::dvbs>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::dvbt: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::dvbt>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::isdbs: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::isdbs>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::isdbs3: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::isdbs3>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::isdbt: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::isdbt>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::atsc: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::atsc>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::atsc3: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::atsc3>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
case FrontendModulation::Tag::dtmb: {
m[0] = static_cast<jint>(
modulation.get<FrontendModulation::Tag::dtmb>());
- env->SetIntArrayRegion(valObj, i, 1, m);
+ env->SetIntArrayRegion(valObj.get(), i, 1, m);
valid = true;
break;
}
@@ -2579,31 +2543,28 @@
}
}
if (valid) {
- env->SetObjectField(statusObj, field, valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
}
- env->DeleteLocalRef(valObj);
break;
}
case FrontendStatus::Tag::bers: {
jfieldID field = env->GetFieldID(clazz, "mBers", "[I");
std::vector<int32_t> v = s.get<FrontendStatus::Tag::bers>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(), reinterpret_cast<jint *>(&v[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::codeRates: {
jfieldID field = env->GetFieldID(clazz, "mCodeRates", "[I");
std::vector<FrontendInnerFec> v = s.get<FrontendStatus::Tag::codeRates>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(), reinterpret_cast<jint *>(&v[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::bandwidth: {
@@ -2642,9 +2603,9 @@
break;
}
if (valid) {
- jobject newIntegerObj = env->NewObject(intClazz, initInt, intBandwidth);
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env, env->NewObject(intClazz, initInt,
+ intBandwidth));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
}
break;
}
@@ -2655,8 +2616,8 @@
bool valid = true;
switch (interval.getTag()) {
case FrontendGuardInterval::Tag::dvbt: {
- intInterval =
- static_cast<jint>(interval.get<FrontendGuardInterval::Tag::dvbt>());
+ intInterval = static_cast<jint>(
+ interval.get<FrontendGuardInterval::Tag::dvbt>());
break;
}
case FrontendGuardInterval::Tag::isdbt: {
@@ -2665,8 +2626,8 @@
break;
}
case FrontendGuardInterval::Tag::dtmb: {
- intInterval =
- static_cast<jint>(interval.get<FrontendGuardInterval::Tag::dtmb>());
+ intInterval = static_cast<jint>(
+ interval.get<FrontendGuardInterval::Tag::dtmb>());
break;
}
default:
@@ -2674,14 +2635,15 @@
break;
}
if (valid) {
- jobject newIntegerObj = env->NewObject(intClazz, initInt, intInterval);
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env, env->NewObject(intClazz, initInt,
+ intInterval));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
}
break;
}
case FrontendStatus::Tag::transmissionMode: {
- jfieldID field = env->GetFieldID(clazz, "mTransmissionMode", "Ljava/lang/Integer;");
+ jfieldID field = env->GetFieldID(clazz, "mTransmissionMode",
+ "Ljava/lang/Integer;");
const FrontendTransmissionMode &transmissionMode =
s.get<FrontendStatus::Tag::transmissionMode>();
jint intTransmissionMode;
@@ -2707,32 +2669,30 @@
break;
}
if (valid) {
- jobject newIntegerObj = env->NewObject(intClazz, initInt, intTransmissionMode);
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env, env->NewObject(intClazz, initInt,
+ intTransmissionMode));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
}
break;
}
case FrontendStatus::Tag::uec: {
jfieldID field = env->GetFieldID(clazz, "mUec", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::uec>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::uec>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::systemId: {
jfieldID field = env->GetFieldID(clazz, "mSystemId", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::systemId>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::systemId>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::interleaving: {
jfieldID field = env->GetFieldID(clazz, "mInterleaving", "[I");
std::vector<FrontendInterleaveMode> v = s.get<FrontendStatus::Tag::interleaving>();
- jintArray valObj = env->NewIntArray(v.size());
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
bool valid = false;
jint in[1];
for (int i = 0; i < v.size(); i++) {
@@ -2741,28 +2701,28 @@
case FrontendInterleaveMode::Tag::atsc3: {
in[0] = static_cast<jint>(
interleaving.get<FrontendInterleaveMode::Tag::atsc3>());
- env->SetIntArrayRegion(valObj, i, 1, in);
+ env->SetIntArrayRegion(valObj.get(), i, 1, in);
valid = true;
break;
}
case FrontendInterleaveMode::Tag::dvbc: {
in[0] = static_cast<jint>(
interleaving.get<FrontendInterleaveMode::Tag::dvbc>());
- env->SetIntArrayRegion(valObj, i, 1, in);
+ env->SetIntArrayRegion(valObj.get(), i, 1, in);
valid = true;
break;
}
case FrontendInterleaveMode::Tag::dtmb: {
in[0] = static_cast<jint>(
interleaving.get<FrontendInterleaveMode::Tag::dtmb>());
- env->SetIntArrayRegion(valObj, i, 1, in);
+ env->SetIntArrayRegion(valObj.get(), i, 1, in);
valid = true;
break;
}
case FrontendInterleaveMode::Tag::isdbt: {
in[0] = static_cast<jint>(
interleaving.get<FrontendInterleaveMode::Tag::isdbt>());
- env->SetIntArrayRegion(valObj, i, 1, in);
+ env->SetIntArrayRegion(valObj.get(), i, 1, in);
valid = true;
break;
}
@@ -2771,31 +2731,28 @@
}
}
if (valid) {
- env->SetObjectField(statusObj, field, valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
}
- env->DeleteLocalRef(valObj);
break;
}
case FrontendStatus::Tag::isdbtSegment: {
jfieldID field = env->GetFieldID(clazz, "mIsdbtSegment", "[I");
std::vector<int32_t> v = s.get<FrontendStatus::Tag::isdbtSegment>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(), reinterpret_cast<jint*>(&v[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::tsDataRate: {
jfieldID field = env->GetFieldID(clazz, "mTsDataRate", "[I");
std::vector<int32_t> v = s.get<FrontendStatus::Tag::tsDataRate>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&v[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(), reinterpret_cast<jint *>(&v[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::rollOff: {
@@ -2813,7 +2770,8 @@
break;
}
case FrontendRollOff::Tag::isdbs3: {
- intRollOff = static_cast<jint>(rollOff.get<FrontendRollOff::Tag::isdbs3>());
+ intRollOff = static_cast<jint>(
+ rollOff.get<FrontendRollOff::Tag::isdbs3>());
break;
}
default:
@@ -2821,141 +2779,135 @@
break;
}
if (valid) {
- jobject newIntegerObj = env->NewObject(intClazz, initInt, intRollOff);
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env, env->NewObject(intClazz, initInt,
+ intRollOff));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
}
break;
}
case FrontendStatus::Tag::isMiso: {
jfieldID field = env->GetFieldID(clazz, "mIsMisoEnabled", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isMiso>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env, env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isMiso>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::isLinear: {
jfieldID field = env->GetFieldID(clazz, "mIsLinear", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isLinear>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env, env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isLinear>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::isShortFrames: {
jfieldID field = env->GetFieldID(clazz, "mIsShortFrames", "Ljava/lang/Boolean;");
- jobject newBooleanObj = env->NewObject(booleanClazz, initBoolean,
- s.get<FrontendStatus::Tag::isShortFrames>());
- env->SetObjectField(statusObj, field, newBooleanObj);
- env->DeleteLocalRef(newBooleanObj);
+ ScopedLocalRef newBooleanObj(env,
+ env->NewObject(booleanClazz, initBoolean,
+ s.get<FrontendStatus::Tag::isShortFrames>()));
+ env->SetObjectField(statusObj, field, newBooleanObj.get());
break;
}
case FrontendStatus::Tag::isdbtMode: {
jfieldID field = env->GetFieldID(clazz, "mIsdbtMode", "Ljava/lang/Integer;");
- jobject newIntegerObj =
- env->NewObject(intClazz, initInt, s.get<FrontendStatus::Tag::isdbtMode>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ ScopedLocalRef newIntegerObj(env,
+ env->NewObject(intClazz, initInt,
+ s.get<FrontendStatus::Tag::isdbtMode>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::partialReceptionFlag: {
jfieldID field =
- env->GetFieldID(clazz, "mIsdbtPartialReceptionFlag", "Ljava/lang/Integer;");
- jobject newIntegerObj =
+ env->GetFieldID(clazz, "mIsdbtPartialReceptionFlag",
+ "Ljava/lang/Integer;");
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- s.get<FrontendStatus::Tag::partialReceptionFlag>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ s.get<FrontendStatus::Tag::partialReceptionFlag>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::streamIdList: {
jfieldID field = env->GetFieldID(clazz, "mStreamIds", "[I");
std::vector<int32_t> ids = s.get<FrontendStatus::Tag::streamIdList>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&ids[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(),
+ reinterpret_cast<jint *>(&ids[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::dvbtCellIds: {
jfieldID field = env->GetFieldID(clazz, "mDvbtCellIds", "[I");
std::vector<int32_t> ids = s.get<FrontendStatus::Tag::dvbtCellIds>();
- jintArray valObj = env->NewIntArray(v.size());
- env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&ids[0]));
+ ScopedLocalRef valObj(env, env->NewIntArray(v.size()));
+ env->SetIntArrayRegion(valObj.get(), 0, v.size(),
+ reinterpret_cast<jint *>(&ids[0]));
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::allPlpInfo: {
jfieldID field = env->GetFieldID(clazz, "mAllPlpInfo",
- "[Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;");
- jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo");
- jmethodID initPlp = env->GetMethodID(plpClazz, "<init>", "(IZ)V");
+ "[Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;");
+ ScopedLocalRef plpClazz(env,
+ env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo"));
+ jmethodID initPlp = env->GetMethodID(plpClazz.get(), "<init>", "(IZ)V");
vector<FrontendScanAtsc3PlpInfo> plpInfos =
s.get<FrontendStatus::Tag::allPlpInfo>();
- jobjectArray valObj = env->NewObjectArray(plpInfos.size(), plpClazz, nullptr);
+ ScopedLocalRef valObj(env, env->NewObjectArray(plpInfos.size(), plpClazz.get(),
+ nullptr));
for (int i = 0; i < plpInfos.size(); i++) {
- jobject plpObj = env->NewObject(plpClazz, initPlp, plpInfos[i].plpId,
- plpInfos[i].bLlsFlag);
- env->SetObjectArrayElement(valObj, i, plpObj);
- env->DeleteLocalRef(plpObj);
+ ScopedLocalRef plpObj(env, env->NewObject(plpClazz.get(), initPlp,
+ plpInfos[i].plpId,
+ plpInfos[i].bLlsFlag));
+ env->SetObjectArrayElement(valObj.get(), i, plpObj.get());
}
- env->SetObjectField(statusObj, field, valObj);
- env->DeleteLocalRef(valObj);
- env->DeleteLocalRef(plpClazz);
+ env->SetObjectField(statusObj, field, valObj.get());
break;
}
case FrontendStatus::Tag::iptvContentUrl: {
jfieldID field = env->GetFieldID(clazz, "mIptvContentUrl", "Ljava/lang/String;");
std::string iptvContentUrl = s.get<FrontendStatus::Tag::iptvContentUrl>();
- jstring iptvContentUrlUtf8 = env->NewStringUTF(iptvContentUrl.c_str());
- env->SetObjectField(statusObj, field, iptvContentUrlUtf8);
- env->DeleteLocalRef(iptvContentUrlUtf8);
+ ScopedLocalRef iptvContentUrlUtf8(env, env->NewStringUTF(iptvContentUrl.c_str()));
+ env->SetObjectField(statusObj, field, iptvContentUrlUtf8.get());
break;
}
case FrontendStatus::Tag::iptvPacketsLost: {
jfieldID field = env->GetFieldID(clazz, "mIptvPacketsLost", "Ljava/lang/Long;");
- jobject newLongObj =
+ ScopedLocalRef newLongObj(env,
env->NewObject(longClazz, initLong,
- s.get<FrontendStatus::Tag::iptvPacketsLost>());
- env->SetObjectField(statusObj, field, newLongObj);
- env->DeleteLocalRef(newLongObj);
+ s.get<FrontendStatus::Tag::iptvPacketsLost>()));
+ env->SetObjectField(statusObj, field, newLongObj.get());
break;
}
case FrontendStatus::Tag::iptvPacketsReceived: {
- jfieldID field = env->GetFieldID(clazz, "mIptvPacketsReceived", "Ljava/lang/Long;");
- jobject newLongObj =
+ jfieldID field = env->GetFieldID(clazz, "mIptvPacketsReceived",
+ "Ljava/lang/Long;");
+ ScopedLocalRef newLongObj(env,
env->NewObject(longClazz, initLong,
- s.get<FrontendStatus::Tag::iptvPacketsReceived>());
- env->SetObjectField(statusObj, field, newLongObj);
- env->DeleteLocalRef(newLongObj);
+ s.get<FrontendStatus::Tag::iptvPacketsReceived>()));
+ env->SetObjectField(statusObj, field, newLongObj.get());
break;
}
case FrontendStatus::Tag::iptvWorstJitterMs: {
jfieldID field = env->GetFieldID(clazz, "mIptvWorstJitterMs",
"Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- s.get<FrontendStatus::Tag::iptvWorstJitterMs>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ s.get<FrontendStatus::Tag::iptvWorstJitterMs>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
case FrontendStatus::Tag::iptvAverageJitterMs: {
jfieldID field = env->GetFieldID(clazz, "mIptvAverageJitterMs",
"Ljava/lang/Integer;");
- jobject newIntegerObj =
+ ScopedLocalRef newIntegerObj(env,
env->NewObject(intClazz, initInt,
- s.get<FrontendStatus::Tag::iptvAverageJitterMs>());
- env->SetObjectField(statusObj, field, newIntegerObj);
- env->DeleteLocalRef(newIntegerObj);
+ s.get<FrontendStatus::Tag::iptvAverageJitterMs>()));
+ env->SetObjectField(statusObj, field, newIntegerObj.get());
break;
}
}
@@ -3089,21 +3041,22 @@
vector<FrontendAtsc3PlpSettings> plps = vector<FrontendAtsc3PlpSettings>(len);
// parse PLP settings
for (int i = 0; i < len; i++) {
- jobject plp = env->GetObjectArrayElement(plpSettings, i);
- int32_t plpId = env->GetIntField(plp, env->GetFieldID(plpClazz, "mPlpId", "I"));
+ ScopedLocalRef plp(env, env->GetObjectArrayElement(plpSettings, i));
+ int32_t plpId = env->GetIntField(plp.get(), env->GetFieldID(plpClazz, "mPlpId", "I"));
FrontendAtsc3Modulation modulation =
static_cast<FrontendAtsc3Modulation>(
- env->GetIntField(plp, env->GetFieldID(plpClazz, "mModulation", "I")));
+ env->GetIntField(plp.get(), env->GetFieldID(plpClazz, "mModulation",
+ "I")));
FrontendAtsc3TimeInterleaveMode interleaveMode =
static_cast<FrontendAtsc3TimeInterleaveMode>(
env->GetIntField(
- plp, env->GetFieldID(plpClazz, "mInterleaveMode", "I")));
+ plp.get(), env->GetFieldID(plpClazz, "mInterleaveMode", "I")));
FrontendAtsc3CodeRate codeRate =
static_cast<FrontendAtsc3CodeRate>(
- env->GetIntField(plp, env->GetFieldID(plpClazz, "mCodeRate", "I")));
+ env->GetIntField(plp.get(), env->GetFieldID(plpClazz, "mCodeRate", "I")));
FrontendAtsc3Fec fec =
static_cast<FrontendAtsc3Fec>(
- env->GetIntField(plp, env->GetFieldID(plpClazz, "mFec", "I")));
+ env->GetIntField(plp.get(), env->GetFieldID(plpClazz, "mFec", "I")));
FrontendAtsc3PlpSettings frontendAtsc3PlpSettings {
.plpId = plpId,
.modulation = modulation,
@@ -3112,7 +3065,6 @@
.fec = fec,
};
plps[i] = frontendAtsc3PlpSettings;
- env->DeleteLocalRef(plp);
}
return plps;
}
@@ -3457,18 +3409,17 @@
"android/media/tv/tuner/frontend/IsdbtFrontendSettings$IsdbtLayerSettings");
frontendIsdbtSettings.layerSettings.resize(len);
for (int i = 0; i < len; i++) {
- jobject layer = env->GetObjectArrayElement(layerSettings, i);
+ ScopedLocalRef layer(env, env->GetObjectArrayElement(layerSettings, i));
frontendIsdbtSettings.layerSettings[i].modulation = static_cast<FrontendIsdbtModulation>(
- env->GetIntField(layer, env->GetFieldID(layerClazz, "mModulation", "I")));
+ env->GetIntField(layer.get(), env->GetFieldID(layerClazz, "mModulation", "I")));
frontendIsdbtSettings.layerSettings[i].timeInterleave =
static_cast<FrontendIsdbtTimeInterleaveMode>(
- env->GetIntField(layer,
+ env->GetIntField(layer.get(),
env->GetFieldID(layerClazz, "mTimeInterleaveMode", "I")));
frontendIsdbtSettings.layerSettings[i].coderate = static_cast<FrontendIsdbtCoderate>(
- env->GetIntField(layer, env->GetFieldID(layerClazz, "mCodeRate", "I")));
+ env->GetIntField(layer.get(), env->GetFieldID(layerClazz, "mCodeRate", "I")));
frontendIsdbtSettings.layerSettings[i].numOfSegment =
- env->GetIntField(layer, env->GetFieldID(layerClazz, "mNumOfSegments", "I"));
- env->DeleteLocalRef(layer);
+ env->GetIntField(layer.get(), env->GetFieldID(layerClazz, "mNumOfSegments", "I"));
}
frontendSettings.set<FrontendSettings::Tag::isdbt>(frontendIsdbtSettings);
@@ -3498,7 +3449,8 @@
env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I")));
FrontendDtmbTimeInterleaveMode interleaveMode =
static_cast<FrontendDtmbTimeInterleaveMode>(
- env->GetIntField(settings, env->GetFieldID(clazz, "mTimeInterleaveMode", "I")));
+ env->GetIntField(settings, env->GetFieldID(clazz, "mTimeInterleaveMode",
+ "I")));
FrontendDtmbSettings frontendDtmbSettings{
.frequency = freq,
@@ -3515,7 +3467,8 @@
return frontendSettings;
}
-static DemuxIpAddress getDemuxIpAddress(JNIEnv *env, const jobject& config, const char* className) {
+static DemuxIpAddress getDemuxIpAddress(JNIEnv *env, const jobject& config,
+ const char* className) {
jclass clazz = env->FindClass(className);
jbyteArray jsrcIpAddress = static_cast<jbyteArray>(
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 6b1b6b1..01c998d 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -163,17 +163,19 @@
jmethodID mRestartEventInitID;
jfieldID mMediaEventFieldContextID;
bool mSharedFilter;
- void getSectionEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getMediaEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getPesEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getTsRecordEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getMmtpRecordEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getDownloadEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getIpPayloadEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getTemiEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getScramblingStatusEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getIpCidChangeEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
- void getRestartEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getSectionEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getMediaEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getPesEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getTsRecordEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getMmtpRecordEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getDownloadEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getIpPayloadEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getTemiEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+ void getScramblingStatusEvent(const jobjectArray& arr, const int size,
+ const DemuxFilterEvent& event);
+ void getIpCidChangeEvent(const jobjectArray& arr, const int size,
+ const DemuxFilterEvent& event);
+ void getRestartEvent(const jobjectArray& arr, const int size, const DemuxFilterEvent& event);
};
struct JTuner;
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index aa5ce30..79635a0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -21,14 +21,13 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
+import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.TabRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
@@ -50,7 +49,7 @@
Column {
val coroutineScope = rememberCoroutineScope()
- val pagerState by rememberPageStateFixed()
+ val pagerState = rememberPageStateFixed()
TabRow(
selectedTabIndex = pagerState.currentPage,
@@ -89,17 +88,30 @@
*/
@Composable
@OptIn(ExperimentalFoundationApi::class)
-private fun rememberPageStateFixed(): State<PagerState> {
+private fun rememberPageStateFixed(): PagerState {
var currentPage by rememberSaveable { mutableStateOf(0) }
- val pagerStateHolder = remember { mutableStateOf(PagerState(currentPage)) }
- LaunchedEffect(LocalConfiguration.current.orientation) {
+ var targetPage by rememberSaveable { mutableStateOf(-1) }
+ val pagerState = rememberPagerState()
+ val configuration = LocalConfiguration.current
+ var lastScreenWidthDp by rememberSaveable { mutableStateOf(-1) }
+ val screenWidthDp = configuration.screenWidthDp
+ LaunchedEffect(screenWidthDp) {
// Reset pager state to fix an issue after configuration change.
- // When we declare android:configChanges="orientation" in the manifest, the pager state is
- // in a weird state after configuration change.
- pagerStateHolder.value = PagerState(currentPage)
+ // When we declare android:configChanges in the manifest, the pager state is in a weird
+ // state after configuration change.
+ targetPage = currentPage
+ lastScreenWidthDp = screenWidthDp
+ }
+ LaunchedEffect(targetPage) {
+ if (targetPage != -1) {
+ pagerState.scrollToPage(targetPage)
+ targetPage = -1
+ }
}
SideEffect {
- currentPage = pagerStateHolder.value.currentPage
+ if (lastScreenWidthDp == screenWidthDp) {
+ currentPage = pagerState.currentPage
+ }
}
- return pagerStateHolder
+ return pagerState
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4d6dd4b..f5bacb6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -250,6 +250,7 @@
}
}
cachedDevice.onActiveDeviceChanged(isActive, bluetoothProfile);
+ mDeviceManager.onActiveDeviceChanged(cachedDevice);
}
for (BluetoothCallback callback : mCallbacks) {
callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 67e3e03..d55144e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -328,6 +328,13 @@
return false;
}
+ /** Handles when the device been set as active/inactive. */
+ public synchronized void onActiveDeviceChanged(CachedBluetoothDevice cachedBluetoothDevice) {
+ if (cachedBluetoothDevice.isHearingAidDevice()) {
+ mHearingAidDeviceManager.onActiveDeviceChanged(cachedBluetoothDevice);
+ }
+ }
+
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
device.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 4354e0c..e5e5782 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -224,15 +224,9 @@
// It is necessary to do remove and add for updating the mapping on
// preference and device
mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
- // Only need to set first device of a set. AudioDeviceInfo for
- // GET_DEVICES_OUTPUTS will not change device.
- setAudioRoutingConfig(cachedDevice);
}
return true;
}
- // Only need to set first device of a set. AudioDeviceInfo for GET_DEVICES_OUTPUTS
- // will not change device.
- setAudioRoutingConfig(cachedDevice);
break;
case BluetoothProfile.STATE_DISCONNECTED:
mainDevice = findMainDevice(cachedDevice);
@@ -258,13 +252,20 @@
return true;
}
- // Only need to clear when last device of a set get disconnected
- clearAudioRoutingConfig();
break;
}
return false;
}
+ void onActiveDeviceChanged(CachedBluetoothDevice device) {
+ if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
+ BluetoothProfile.LE_AUDIO)) {
+ setAudioRoutingConfig(device);
+ } else {
+ clearAudioRoutingConfig();
+ }
+ }
+
private void setAudioRoutingConfig(CachedBluetoothDevice device) {
AudioDeviceAttributes hearingDeviceAttributes =
mRoutingHelper.getMatchedHearingDeviceAttributes(device);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 3361a66..8c316d1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -46,6 +46,7 @@
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@@ -396,6 +397,21 @@
}
@Test
+ public void dispatchActiveDeviceChanged_callExpectedOnActiveDeviceChanged() {
+ mBluetoothEventManager.registerCallback(mBluetoothCallback);
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
+ Collections.singletonList(mCachedDevice1));
+
+ mBluetoothEventManager.dispatchActiveDeviceChanged(mCachedDevice1,
+ BluetoothProfile.HEARING_AID);
+
+ verify(mCachedDeviceManager).onActiveDeviceChanged(mCachedDevice1);
+ verify(mBluetoothCallback).onActiveDeviceChanged(mCachedDevice1,
+ BluetoothProfile.HEARING_AID);
+ }
+
+ @Test
public void showUnbondMessage_reasonAuthTimeout_showCorrectedErrorCode() {
mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 4b3820e..7e7c76e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -17,7 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -604,4 +606,20 @@
verify(mDevice2).setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
verify(mDevice2).createBond(BluetoothDevice.TRANSPORT_LE);
}
+
+ @Test
+ public void onActiveDeviceChanged_validHiSyncId_callExpectedFunction() {
+ mHearingAidDeviceManager = spy(new HearingAidDeviceManager(mContext, mLocalBluetoothManager,
+ mCachedDeviceManager.mCachedDevices));
+ doNothing().when(mHearingAidDeviceManager).onActiveDeviceChanged(any());
+ mCachedDeviceManager.mHearingAidDeviceManager = mHearingAidDeviceManager;
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
+ cachedDevice1.setHearingAidInfo(
+ new HearingAidInfo.Builder().setHiSyncId(HISYNCID1).build());
+
+ mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1);
+
+ verify(mHearingAidDeviceManager).onActiveDeviceChanged(cachedDevice1);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index a839136..0d5de88 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -478,37 +478,24 @@
}
@Test
- public void onProfileConnectionStateChanged_connected_callSetStrategies() {
+ public void onActiveDeviceChanged_connected_callSetStrategies() {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
mHearingDeviceAttribute);
+ when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
- mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(mCachedDevice1,
- BluetoothProfile.STATE_CONNECTED);
+ mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1);
verify(mHelper, atLeastOnce()).setPreferredDeviceRoutingStrategies(
eq(List.of(mAudioStrategy)), any(AudioDeviceAttributes.class), anyInt());
}
@Test
- public void onProfileConnectionStateChanged_disconnected_callSetStrategiesWithAutoValue() {
+ public void onActiveDeviceChanged_disconnected_callSetStrategiesWithAutoValue() {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
mHearingDeviceAttribute);
+ when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(false);
- mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(mCachedDevice1,
- BluetoothProfile.STATE_DISCONNECTED);
-
- verify(mHelper, atLeastOnce()).setPreferredDeviceRoutingStrategies(
- eq(List.of(mAudioStrategy)), /* hearingDevice= */ isNull(),
- eq(HearingAidAudioRoutingConstants.RoutingValue.AUTO));
- }
- @Test
- public void onProfileConnectionStateChanged_unpairing_callSetStrategiesWithAutoValue() {
- when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
- mHearingDeviceAttribute);
-
- when(mCachedDevice1.getUnpairing()).thenReturn(true);
- mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(mCachedDevice1,
- BluetoothProfile.STATE_DISCONNECTED);
+ mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1);
verify(mHelper, atLeastOnce()).setPreferredDeviceRoutingStrategies(
eq(List.of(mAudioStrategy)), /* hearingDevice= */ isNull(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index c6c3019..6f6d0f9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -62,7 +62,7 @@
override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
- UserAction.Back to SceneModel(SceneKey.LockScreen),
+ UserAction.Back to SceneModel(SceneKey.Lockscreen),
)
)
.asStateFlow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockScreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
similarity index 91%
rename from packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockScreenScene.kt
rename to packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index ad33eb5..ab7bc26 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockScreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -33,7 +33,7 @@
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.ui.viewmodel.LockScreenSceneViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -48,13 +48,13 @@
/** The lock screen scene shows when the device is locked. */
@SysUISingleton
-class LockScreenScene
+class LockscreenScene
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val viewModel: LockScreenSceneViewModel,
+ private val viewModel: LockscreenSceneViewModel,
) : ComposableScene {
- override val key = SceneKey.LockScreen
+ override val key = SceneKey.Lockscreen
override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
viewModel.upDestinationSceneKey
@@ -69,7 +69,7 @@
override fun Content(
modifier: Modifier,
) {
- LockScreenScene(
+ LockscreenScene(
viewModel = viewModel,
modifier = modifier,
)
@@ -86,8 +86,8 @@
}
@Composable
-private fun LockScreenScene(
- viewModel: LockScreenSceneViewModel,
+private fun LockscreenScene(
+ viewModel: LockscreenSceneViewModel,
modifier: Modifier = Modifier,
) {
// TODO(b/280879610): implement the real UI.
@@ -99,7 +99,7 @@
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.align(Alignment.Center)
) {
- Text("Lock screen", style = MaterialTheme.typography.headlineMedium)
+ Text("Lockscreen", style = MaterialTheme.typography.headlineMedium)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
diff --git a/packages/SystemUI/docs/device-entry/keyguard.md b/packages/SystemUI/docs/device-entry/keyguard.md
index 8634c95..1898b97 100644
--- a/packages/SystemUI/docs/device-entry/keyguard.md
+++ b/packages/SystemUI/docs/device-entry/keyguard.md
@@ -20,6 +20,10 @@
An indication to power off the device most likely comes from one of two signals: the user presses the power button or the screen timeout has passed. This may [lock the device](#How-the-device-locks)
+#### Long-pressing on keyguard
+
+OEMs may choose to enable a long-press action that displays a button at the bottom of lockscreen. This button links to lockscreen customization. This can be achieved by overriding the `long_press_keyguard_customize_lockscreen_enabled` resource in `packages/SystemUI/res/values/config.xml`.
+
#### On Lockscreen
#### On Lockscreen, occluded by an activity
diff --git a/packages/SystemUI/docs/device-entry/quickaffordance.md b/packages/SystemUI/docs/device-entry/quickaffordance.md
index d662649..afcf846 100644
--- a/packages/SystemUI/docs/device-entry/quickaffordance.md
+++ b/packages/SystemUI/docs/device-entry/quickaffordance.md
@@ -17,7 +17,9 @@
By default, AOSP ships with a "bottom right" and a "bottom left" slot, each with a slot capacity of `1`, allowing only one Quick Affordance on each side of the lock screen.
### Customizing Slots
-OEMs may choose to override the IDs and number of slots and/or override the default capacities. This can be achieved by overridding the `config_keyguardQuickAffordanceSlots` resource in `packages/SystemUI/res/values/config.xml`.
+OEMs may choose to enable customization of slots. An entry point in settings will appear when overriding the `custom_lockscreen_shortcuts_enabled` resource in `packages/SystemUI/res/values/config.xml`.
+
+OEMs may also choose to override the IDs and number of slots and/or override the default capacities. This can be achieved by overridding the `config_keyguardQuickAffordanceSlots` resource in `packages/SystemUI/res/values/config.xml`.
### Default Quick Affordances
OEMs may also choose to predefine default Quick Affordances for each slot. To achieve this, a developer may override the `config_keyguardQuickAffordanceDefaults` resource in `packages/SystemUI/res/values/config.xml`. Note that defaults only work until the user of the device selects a different quick affordance for that slot, even if they select the "None" option.
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
index 8bb7877..371670c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
@@ -39,7 +39,8 @@
android:ellipsize="marquee"
android:visibility="gone"
android:gravity="center"
- androidprv:allCaps="@bool/kg_use_all_caps" />
+ androidprv:allCaps="@bool/kg_use_all_caps"
+ androidprv:debugLocation="Emergency" />
<com.android.keyguard.EmergencyButton
android:id="@+id/emergency_call_button"
diff --git a/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml
index 3b67ddd..bab604d 100644
--- a/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/dream_overlay_bottom_affordance_bg.xml
@@ -18,9 +18,7 @@
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
<size
android:width="@dimen/dream_overlay_bottom_affordance_height"
android:height="@dimen/dream_overlay_bottom_affordance_width"/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index 0cd0623..e8a48c7 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -21,8 +21,6 @@
android:layout_width="@dimen/dream_overlay_bottom_affordance_width"
android:layout_gravity="bottom|start"
android:padding="@dimen/dream_overlay_bottom_affordance_padding"
- android:background="@drawable/dream_overlay_bottom_affordance_bg"
android:scaleType="fitCenter"
android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/controls_icon"
android:contentDescription="@string/quick_controls_title" />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index e9acf3f..a3a7135 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -59,55 +59,44 @@
</LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="bottom"
- android:layout_marginHorizontal="@dimen/keyguard_affordance_horizontal_offset"
+ <com.android.systemui.animation.view.LaunchableImageView
+ android:id="@+id/start_button"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
+ android:layout_gravity="start|bottom"
+ android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:gravity="bottom"
- >
+ android:scaleType="fitCenter"
+ android:padding="@dimen/keyguard_affordance_fixed_padding"
+ android:tint="?android:attr/textColorPrimary"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
+ android:visibility="invisible" />
- <com.android.systemui.animation.view.LaunchableImageView
- android:id="@+id/start_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:scaleType="fitCenter"
- android:padding="@dimen/keyguard_affordance_fixed_padding"
- android:tint="?android:attr/textColorPrimary"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
- android:visibility="invisible" />
+ <com.android.systemui.animation.view.LaunchableImageView
+ android:id="@+id/end_button"
+ android:layout_height="@dimen/keyguard_affordance_fixed_height"
+ android:layout_width="@dimen/keyguard_affordance_fixed_width"
+ android:layout_gravity="end|bottom"
+ android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
+ android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+ android:scaleType="fitCenter"
+ android:padding="@dimen/keyguard_affordance_fixed_padding"
+ android:tint="?android:attr/textColorPrimary"
+ android:background="@drawable/keyguard_bottom_affordance_bg"
+ android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
+ android:visibility="invisible" />
- <FrameLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:paddingHorizontal="24dp"
- >
- <include
- android:id="@+id/keyguard_settings_button"
- layout="@layout/keyguard_settings_popup_menu"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:visibility="gone"
- />
- </FrameLayout>
-
- <com.android.systemui.animation.view.LaunchableImageView
- android:id="@+id/end_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:scaleType="fitCenter"
- android:padding="@dimen/keyguard_affordance_fixed_padding"
- android:tint="?android:attr/textColorPrimary"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:foreground="@drawable/keyguard_bottom_affordance_selected_border"
- android:visibility="invisible" />
-
- </LinearLayout>
+ <include
+ android:id="@+id/keyguard_settings_button"
+ layout="@layout/keyguard_settings_popup_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center"
+ android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+ android:layout_marginHorizontal="@dimen/keyguard_affordance_horizontal_offset"
+ android:visibility="gone"
+ />
<FrameLayout
android:id="@+id/overlay_container"
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 8b85940..64c4eff 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -78,6 +78,7 @@
android:textColor="?attr/wallpaperTextColorSecondary"
android:singleLine="true"
systemui:showMissingSim="true"
- systemui:showAirplaneMode="true" />
+ systemui:showAirplaneMode="true"
+ systemui:debugLocation="Keyguard" />
</com.android.systemui.statusbar.phone.KeyguardStatusBarView>
diff --git a/packages/SystemUI/res/raw/sfps_pulse.json b/packages/SystemUI/res/raw/sfps_pulse.json
index 9fe4eb6..2a72dfb 100644
--- a/packages/SystemUI/res/raw/sfps_pulse.json
+++ b/packages/SystemUI/res/raw/sfps_pulse.json
@@ -1 +1 @@
-{"v":"5.7.13","fr":60,"ip":0,"op":300,"w":42,"h":80,"nm":"sfps_pulse_motion_04","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.617,"y":0.539},"o":{"x":0.477,"y":0},"t":0,"s":[28,40,0],"to":[0.365,0,0],"ti":[-1.009,0,0]},{"i":{"x":0.436,"y":1},"o":{"x":0.17,"y":0.547},"t":10,"s":[30.576,40,0],"to":[1.064,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":30,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":60,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":90,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":120,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":150,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":180,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":210,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":240,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":270,"s":[32.503,40,0],"to":[0,0,0],"ti":[0.751,0,0]},{"t":300,"s":[28,40,0]}],"ix":2,"l":2},"a":{"a":0,"k":[28.253,40,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1.566,0],[-3.929,-5.503],[-2.751,-6.68],[3.929,0],[-2.751,6.68],[-3.929,5.503]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.218,40],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue600","cl":"blue600","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[41.878,40,0],"ix":2,"l":2},"a":{"a":0,"k":[28.253,40,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[55,55],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 2","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28.253,40],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[75]},{"t":30,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[55,55]},{"t":30,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-30,"op":30,"st":-30,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[75]},{"t":60,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[55,55]},{"t":60,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[75]},{"t":90,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[55,55]},{"t":90,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":90,"st":30,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[75]},{"t":120,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[55,55]},{"t":120,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":120,"st":60,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[75]},{"t":150,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":90,"s":[55,55]},{"t":150,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":90,"op":150,"st":90,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":160,"s":[75]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":120,"s":[55,55]},{"t":180,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":120,"op":180,"st":120,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":190,"s":[75]},{"t":210,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":150,"s":[55,55]},{"t":210,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":210,"st":150,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":220,"s":[75]},{"t":240,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":180,"s":[55,55]},{"t":240,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":180,"op":240,"st":180,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[75]},{"t":270,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":210,"s":[55,55]},{"t":270,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":210,"op":270,"st":210,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":280,"s":[75]},{"t":300,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":240,"s":[55,55]},{"t":300,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":240,"op":300,"st":240,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":310,"s":[75]},{"t":330,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":270,"s":[55,55]},{"t":330,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.858823537827,0.803921580315,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":270,"op":330,"st":270,"bm":0}],"markers":[]}
\ No newline at end of file
+{"v":"5.7.14","fr":60,"ip":0,"op":300,"w":42,"h":80,"nm":"sfps_pulse_motion_04","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.617,"y":0.539},"o":{"x":0.477,"y":0},"t":0,"s":[28,40,0],"to":[0.365,0,0],"ti":[-1.009,0,0]},{"i":{"x":0.436,"y":1},"o":{"x":0.17,"y":0.547},"t":10,"s":[30.576,40,0],"to":[1.064,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":30,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":60,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":90,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":120,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":150,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":180,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":210,"s":[32.503,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":240,"s":[28,40,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":270,"s":[32.503,40,0],"to":[0,0,0],"ti":[0.751,0,0]},{"t":300,"s":[28,40,0]}],"ix":2,"l":2},"a":{"a":0,"k":[28.253,40,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1.566,0],[-3.929,-5.503],[-2.751,-6.68],[3.929,0],[-2.751,6.68],[-3.929,5.503]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30.218,40],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue600","cl":"blue600","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[41.878,40,0],"ix":2,"l":2},"a":{"a":0,"k":[28.253,40,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[55,55],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 2","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28.253,40],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[75]},{"t":30,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[55,55]},{"t":30,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-30,"op":30,"st":-30,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[75]},{"t":60,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[55,55]},{"t":60,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":70,"s":[75]},{"t":90,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[55,55]},{"t":90,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":90,"st":30,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[75]},{"t":120,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[55,55]},{"t":120,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":60,"op":120,"st":60,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[75]},{"t":150,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":90,"s":[55,55]},{"t":150,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":90,"op":150,"st":90,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":160,"s":[75]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":120,"s":[55,55]},{"t":180,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":120,"op":180,"st":120,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":190,"s":[75]},{"t":210,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":150,"s":[55,55]},{"t":210,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":150,"op":210,"st":150,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":220,"s":[75]},{"t":240,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":180,"s":[55,55]},{"t":240,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":180,"op":240,"st":180,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[75]},{"t":270,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":210,"s":[55,55]},{"t":270,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":210,"op":270,"st":210,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":280,"s":[75]},{"t":300,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":240,"s":[55,55]},{"t":300,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":240,"op":300,"st":240,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":310,"s":[75]},{"t":330,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.587,40,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.25,0.25],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":270,"s":[55,55]},{"t":330,"s":[80,80]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960785687,0.450980395079,0.909803926945,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[16.338,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":270,"op":330,"st":270,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 8d8fdf0..bd86e51 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -146,6 +146,7 @@
<attr name="allCaps" format="boolean" />
<attr name="showMissingSim" format="boolean" />
<attr name="showAirplaneMode" format="boolean" />
+ <attr name="debugLocation" format="string" />
</declare-styleable>
<declare-styleable name="IlluminationDrawable">
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b4e1b66..c3651cf 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -44,6 +44,12 @@
<!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
<integer name="navigation_bar_deadzone_orientation">0</integer>
+ <!-- Whether or not lockscreen shortcuts can be customized -->
+ <bool name="custom_lockscreen_shortcuts_enabled">false</bool>
+
+ <!-- Whether or not long-pressing on keyguard will display to customize lockscreen -->
+ <bool name="long_press_keyguard_customize_lockscreen_enabled">false</bool>
+
<bool name="config_dead_zone_flash">false</bool>
<!-- Whether to enable dimming navigation buttons when wallpaper is not visible, should be
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7187de8..d5806ec 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -45,6 +45,9 @@
<dimen name="navigation_edge_action_drag_threshold">16dp</dimen>
<!-- The threshold to progress back animation for edge swipe -->
<dimen name="navigation_edge_action_progress_threshold">412dp</dimen>
+ <!-- This value is used to calculate the target if the screen is wider than the
+ navigation_edge_action_progress_threshold. See BackAnimation#setSwipeThresholds -->
+ <item name="back_progress_non_linear_factor" format="float" type="dimen">0.2</item>
<!-- The minimum display position of the arrow on the screen -->
<dimen name="navigation_edge_arrow_min_y">64dp</dimen>
<!-- The amount by which the arrow is shifted to avoid the finger-->
@@ -1643,6 +1646,19 @@
<dimen name="dream_overlay_bottom_affordance_height">64dp</dimen>
<dimen name="dream_overlay_bottom_affordance_width">64dp</dimen>
<dimen name="dream_overlay_bottom_affordance_radius">32dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_key_text_shadow_dx">0.5dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_key_text_shadow_dy">0.5dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_key_text_shadow_radius">1dp</dimen>
+ <item name="dream_overlay_bottom_affordance_key_shadow_alpha" format="float" type="dimen">
+ 0.35
+ </item>
+ <dimen name="dream_overlay_bottom_affordance_ambient_text_shadow_dx">0.5dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_ambient_text_shadow_dy">0.5dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_ambient_text_shadow_radius">2dp</dimen>
+ <item name="dream_overlay_bottom_affordance_ambient_shadow_alpha" format="float" type="dimen">
+ 0.4
+ </item>
+ <dimen name="dream_overlay_bottom_affordance_inset">1dp</dimen>
<dimen name="dream_overlay_bottom_affordance_padding">14dp</dimen>
<dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen>
<dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
index 19d0a3d..6b9274c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shared.shadow
+import android.content.res.ColorStateList
import android.graphics.BlendMode
import android.graphics.Canvas
import android.graphics.Color
@@ -106,6 +107,14 @@
mIconDrawable.draw(canvas)
}
+ override fun getIntrinsicHeight(): Int {
+ return mCanvasSize
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return mCanvasSize
+ }
+
override fun getOpacity(): Int {
return PixelFormat.TRANSPARENT
}
@@ -121,4 +130,8 @@
override fun setTint(color: Int) {
mIconDrawable.setTint(color)
}
+
+ override fun setTintList(tint: ColorStateList?) {
+ mIconDrawable.setTintList(tint)
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
index e4f6e131..87a9b0f 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java
@@ -33,6 +33,8 @@
private final boolean mShowAirplaneMode;
+ private final String mDebugLocation;
+
public CarrierText(Context context) {
this(context, null);
}
@@ -46,6 +48,7 @@
useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false);
mShowAirplaneMode = a.getBoolean(R.styleable.CarrierText_showAirplaneMode, false);
mShowMissingSim = a.getBoolean(R.styleable.CarrierText_showMissingSim, false);
+ mDebugLocation = a.getString(R.styleable.CarrierText_debugLocation);
} finally {
a.recycle();
}
@@ -70,6 +73,10 @@
return mShowMissingSim;
}
+ public String getDebugLocation() {
+ return mDebugLocation;
+ }
+
private static class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
private final Locale mLocale;
private final boolean mAllCaps;
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 997c527..33f9ecd 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -53,6 +53,7 @@
mCarrierTextManager = carrierTextManagerBuilder
.setShowAirplaneMode(mView.getShowAirplaneMode())
.setShowMissingSim(mView.getShowMissingSim())
+ .setDebugLocationString(mView.getDebugLocation())
.build();
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index 1f75e81..a724514 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -651,6 +651,7 @@
private final CarrierTextManagerLogger mLogger;
private boolean mShowAirplaneMode;
private boolean mShowMissingSim;
+ private String mDebugLocation;
@Inject
public Builder(
@@ -689,14 +690,25 @@
return this;
}
+ /**
+ * To help disambiguate logs, set a location to be used in the LogBuffer calls, e.g.:
+ * "keyguard" or "keyguard emergency status bar"
+ */
+ public Builder setDebugLocationString(String debugLocationString) {
+ mDebugLocation = debugLocationString;
+ return this;
+ }
+
/** Create a CarrierTextManager. */
public CarrierTextManager build() {
+ mLogger.setLocation(mDebugLocation);
return new CarrierTextManager(
mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiRepository,
mTelephonyManager, mTelephonyListenerManager, mWakefulnessLifecycle,
mMainExecutor, mBgExecutor, mKeyguardUpdateMonitor, mLogger);
}
}
+
/**
* Data structure for passing information to CarrierTextController subscribers
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 4bf7be6..c5b14e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -108,6 +108,7 @@
}
updateFontSizes()
updateTimeListeners()
+ cachedWeatherData?.let { value.events.onWeatherDataChanged(it) }
value.smallClock.view.addOnAttachStateChangeListener(
object : OnAttachStateChangeListener {
override fun onViewAttachedToWindow(p0: View?) {
@@ -239,6 +240,7 @@
var largeTimeListener: TimeListener? = null
val shouldTimeListenerRun: Boolean
get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD
+ private var cachedWeatherData: WeatherData? = null
private var smallClockIsDark = true
private var largeClockIsDark = true
@@ -305,6 +307,7 @@
}
override fun onWeatherDataChanged(data: WeatherData) {
+ cachedWeatherData = data
clock?.run { events.onWeatherDataChanged(data) }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5cc0547..4b02171 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -599,7 +599,6 @@
*/
public void startAppearAnimation(SecurityMode securityMode) {
setTranslationY(0f);
- setAlpha(1f);
updateChildren(0 /* translationY */, 1f /* alpha */);
mViewMode.startAppearAnimation(securityMode);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 5b1edc7..b5e5420 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -674,7 +674,6 @@
public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) {
- setAlpha(1f);
mView.startAppearAnimation(mCurrentSecurityMode);
getCurrentSecurityController(controller -> controller.startAppearAnimation());
}
@@ -1112,7 +1111,7 @@
*/
public void setExpansion(float fraction) {
float scaledFraction = BouncerPanelExpansionCalculator.showBouncerProgress(fraction);
- mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+ setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
mView.setTranslationY(scaledFraction * mTranslationY);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
index 4001a4e..1978715 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
@@ -18,16 +18,20 @@
import androidx.annotation.IntDef
import com.android.keyguard.CarrierTextManager.CarrierTextCallbackInfo
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.CarrierTextManagerLog
import javax.inject.Inject
/** Logger adapter for [CarrierTextManager] to add detailed messages in a [LogBuffer] */
-@SysUISingleton
class CarrierTextManagerLogger @Inject constructor(@CarrierTextManagerLog val buffer: LogBuffer) {
/**
+ * To help disambiguate carrier text manager instances, set a location string here which will
+ * propagate to [logUpdate] and [logUpdateCarrierTextForReason]
+ */
+ var location: String? = null
+
+ /**
* This method and the methods below trace the execution of CarrierTextManager.updateCarrierText
*/
fun logUpdate(numSubs: Int) {
@@ -35,7 +39,7 @@
TAG,
LogLevel.VERBOSE,
{ int1 = numSubs },
- { "updateCarrierText: numSubs=$int1" },
+ { "updateCarrierText: location=${location ?: "(unknown)"} numSubs=$int1" },
)
}
@@ -99,7 +103,10 @@
TAG,
LogLevel.DEBUG,
{ int1 = reason },
- { "refreshing carrier info for reason: ${reason.reasonMessage()}" }
+ {
+ "refreshing carrier info for reason: ${reason.reasonMessage()}" +
+ " location=${location ?: "(unknown)"}"
+ }
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index cd195f6..9d9a87d 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -33,7 +33,7 @@
* A device that is not yet unlocked requires unlocking by completing an authentication
* challenge according to the current authentication method.
*
- * Note that this state has no real bearing on whether the lock screen is showing or dismissed.
+ * Note that this state has no real bearing on whether the lockscreen is showing or dismissed.
*/
val isUnlocked: StateFlow<Boolean>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 9007279..0782537 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -20,6 +20,7 @@
import android.app.ActivityTaskManager
import android.content.Context
import android.content.res.Configuration
+import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
@@ -459,7 +460,12 @@
addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
PorterDuffColorFilter(chevronFill, PorterDuff.Mode.SRC_ATOP)
}
- } else if (isDarkMode(context)) {
+ } else {
+ if (!isDarkMode(context)) {
+ addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP)
+ }
+ }
for (key in listOf(".blue600", ".blue400")) {
addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
PorterDuffColorFilter(
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 57ce580..8264fed 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -73,7 +73,7 @@
is AuthenticationMethodModel.Swipe ->
sceneInteractor.setCurrentScene(
containerName,
- SceneModel(SceneKey.LockScreen),
+ SceneModel(SceneKey.Lockscreen),
)
else -> Unit
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index f973aee..4d99282 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -39,6 +40,7 @@
import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.controls.ui.ControlsActivity;
import com.android.systemui.controls.ui.ControlsUiController;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
@@ -56,17 +58,20 @@
* devices at home like lights and thermostats).
*/
public class DreamHomeControlsComplication implements Complication {
+ private final Resources mResources;
private final DreamHomeControlsComplicationComponent.Factory mComponentFactory;
@Inject
public DreamHomeControlsComplication(
+ @Main Resources resources,
DreamHomeControlsComplicationComponent.Factory componentFactory) {
+ mResources = resources;
mComponentFactory = componentFactory;
}
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mComponentFactory.create().getViewHolder();
+ return mComponentFactory.create(mResources).getViewHolder();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
index ef18d66..2b5aa7c 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -18,12 +18,19 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.widget.ImageView;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.complication.DreamHomeControlsComplication;
+import com.android.systemui.shared.shadow.DoubleShadowIconDrawable;
+import com.android.systemui.shared.shadow.DoubleShadowTextHelper;
+import dagger.BindsInstance;
import dagger.Module;
import dagger.Provides;
import dagger.Subcomponent;
@@ -59,7 +66,7 @@
*/
@Subcomponent.Factory
interface Factory {
- DreamHomeControlsComplicationComponent create();
+ DreamHomeControlsComplicationComponent create(@BindsInstance Resources resources);
}
/**
@@ -68,6 +75,7 @@
@Module
interface DreamHomeControlsModule {
String DREAM_HOME_CONTROLS_CHIP_VIEW = "dream_home_controls_chip_view";
+ String DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE = "dream_home_controls_background_drawable";
/**
* Provides the dream home controls chip view.
@@ -75,9 +83,56 @@
@Provides
@DreamHomeControlsComplicationScope
@Named(DREAM_HOME_CONTROLS_CHIP_VIEW)
- static ImageView provideHomeControlsChipView(LayoutInflater layoutInflater) {
- return (ImageView) layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
- null, false);
+ static ImageView provideHomeControlsChipView(
+ LayoutInflater layoutInflater,
+ @Named(DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE) Drawable backgroundDrawable) {
+ final ImageView chip =
+ (ImageView) layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
+ null, false);
+ chip.setBackground(backgroundDrawable);
+
+ return chip;
+ }
+
+ @Provides
+ @DreamHomeControlsComplicationScope
+ @Named(DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE)
+ static Drawable providesHomeControlsBackground(Context context, Resources resources) {
+ final Drawable background = new DoubleShadowIconDrawable(createShadowInfo(
+ resources,
+ R.dimen.dream_overlay_bottom_affordance_key_text_shadow_radius,
+ R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dx,
+ R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dy,
+ R.dimen.dream_overlay_bottom_affordance_key_shadow_alpha
+ ),
+ createShadowInfo(
+ resources,
+ R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_radius,
+ R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_dx,
+ R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_dy,
+ R.dimen.dream_overlay_bottom_affordance_ambient_shadow_alpha
+ ),
+ resources.getDrawable(R.drawable.dream_overlay_bottom_affordance_bg),
+ resources.getDimensionPixelOffset(
+ R.dimen.dream_overlay_bottom_affordance_width),
+ resources.getDimensionPixelSize(R.dimen.dream_overlay_bottom_affordance_inset)
+ );
+
+ background.setTintList(
+ Utils.getColorAttr(context, com.android.internal.R.attr.colorSurface));
+
+ return background;
+ }
+
+ private static DoubleShadowTextHelper.ShadowInfo createShadowInfo(Resources resources,
+ int blurId, int offsetXId, int offsetYId, int alphaId) {
+
+ return new DoubleShadowTextHelper.ShadowInfo(
+ resources.getDimension(blurId),
+ resources.getDimension(offsetXId),
+ resources.getDimension(offsetYId),
+ resources.getFloat(alphaId)
+ );
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 340ed2e..05df31b 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -338,8 +338,7 @@
// TODO(b/280426085): Tracking Bug
@JvmField
- val NEW_BLUETOOTH_REPOSITORY =
- unreleasedFlag(612, "new_bluetooth_repository", teamfood = true)
+ val NEW_BLUETOOTH_REPOSITORY = unreleasedFlag(612, "new_bluetooth_repository")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
@@ -562,7 +561,7 @@
// TODO(b/270987164): Tracking Bug
@JvmField
- val TRACKPAD_GESTURE_FEATURES = releasedFlag(1205, "trackpad_gesture_features")
+ val TRACKPAD_GESTURE_FEATURES = unreleasedFlag(1205, "trackpad_gesture_features", teamfood = true)
// TODO(b/263826204): Tracking Bug
@JvmField
@@ -613,7 +612,8 @@
// 1700 - clipboard
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
// TODO(b/278714186) Tracking Bug
- @JvmField val CLIPBOARD_IMAGE_TIMEOUT = unreleasedFlag(1702, "clipboard_image_timeout")
+ @JvmField val CLIPBOARD_IMAGE_TIMEOUT =
+ unreleasedFlag(1702, "clipboard_image_timeout", teamfood = true)
// TODO(b/279405451): Tracking Bug
@JvmField
val CLIPBOARD_SHARED_TRANSITIONS = unreleasedFlag(1703, "clipboard_shared_transitions")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index bd6dfe3..f96f337 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -258,12 +258,10 @@
*/
private var surfaceBehindAlpha = 1f
- private var wallpaperAlpha = 1f
-
@VisibleForTesting
var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
- var wallpaperAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
+ var wallpaperCannedUnlockAnimator = ValueAnimator.ofFloat(0f, 1f)
/**
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
@@ -330,6 +328,7 @@
if (surfaceBehindAlpha == 0f) {
Log.d(TAG, "surfaceBehindAlphaAnimator#onAnimationEnd")
surfaceBehindRemoteAnimationTargets = null
+ wallpaperTargets = null
keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation(
false /* cancelled */)
} else {
@@ -340,23 +339,17 @@
})
}
- with(wallpaperAlphaAnimator) {
+ with(wallpaperCannedUnlockAnimator) {
duration = LAUNCHER_ICONS_ANIMATION_DURATION_MS
interpolator = Interpolators.ALPHA_OUT
addUpdateListener { valueAnimator: ValueAnimator ->
- wallpaperAlpha = valueAnimator.animatedValue as Float
- setWallpaperAppearAmount(wallpaperAlpha)
+ setWallpaperAppearAmount(valueAnimator.animatedValue as Float)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
- Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, animation ended ")
- if (wallpaperAlpha == 1f) {
- wallpaperTargets = null
- keyguardViewMediator.get().finishExitRemoteAnimation()
- } else {
- Log.d(TAG, "wallpaperAlphaAnimator#onAnimationEnd, " +
- "animation was cancelled: skipping finishAnimation()")
- }
+ Log.d(TAG, "wallpaperCannedUnlockAnimator#onAnimationEnd")
+ keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
+ false /* cancelled */)
}
})
}
@@ -387,11 +380,6 @@
context.resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
}
- fun isAnyKeyguyardAnimatorPlaying(): Boolean {
- return surfaceBehindAlphaAnimator.isStarted ||
- wallpaperAlphaAnimator.isStarted || surfaceBehindEntryAnimator.isStarted
- }
-
/**
* Add a listener to be notified of various stages of the unlock animation.
*/
@@ -536,8 +524,6 @@
wallpaperTargets = wallpapers
surfaceBehindRemoteAnimationStartTime = startTime
- fadeInWallpaper()
-
// If we specifically requested that the surface behind be made visible (vs. it being made
// visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch
// gesture and the surface behind the keyguard should be made visible so that we can animate
@@ -599,7 +585,9 @@
// Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
// Check it here in case there is no more change to the dismiss amount after the last change
// that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached()
- finishKeyguardExitRemoteAnimationIfReachThreshold()
+ if (!playingCannedUnlockAnimation) {
+ finishKeyguardExitRemoteAnimationIfReachThreshold()
+ }
}
/**
@@ -650,7 +638,7 @@
* transition if possible.
*/
private fun unlockToLauncherWithInWindowAnimations() {
- setSurfaceBehindAppearAmount(1f)
+ setSurfaceBehindAppearAmount(1f, wallpapers = false)
try {
// Begin the animation, waiting for the shade to animate out.
@@ -676,19 +664,8 @@
// visible, hide our smartspace.
lockscreenSmartspace?.visibility = View.INVISIBLE
- // As soon as the shade has animated out of the way, finish the keyguard exit animation. The
- // in-window animations in the Launcher window will end on their own.
- handler.postDelayed({
- if (keyguardViewMediator.get().isShowingAndNotOccluded &&
- !keyguardStateController.isKeyguardGoingAway) {
- Log.e(TAG, "Finish keyguard exit animation delayed Runnable ran, but we are " +
- "showing and not going away.")
- return@postDelayed
- }
-
- keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
- false /* cancelled */)
- }, CANNED_UNLOCK_START_DELAY)
+ // Start an animation for the wallpaper, which will finish keyguard exit when it completes.
+ fadeInWallpaper()
}
/**
@@ -809,7 +786,16 @@
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
* cancelled).
*/
- fun setSurfaceBehindAppearAmount(amount: Float) {
+ fun setSurfaceBehindAppearAmount(amount: Float, wallpapers: Boolean = true) {
+ val animationAlpha = when {
+ // If we're snapping the keyguard back, immediately begin fading it out.
+ keyguardStateController.isSnappingKeyguardBackAfterSwipe -> amount
+ // If the screen has turned back off, the unlock animation is going to be cancelled,
+ // so set the surface alpha to 0f so it's no longer visible.
+ !powerManager.isInteractive -> 0f
+ else -> surfaceBehindAlpha
+ }
+
surfaceBehindRemoteAnimationTargets?.forEach { surfaceBehindRemoteAnimationTarget ->
val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget.screenSpaceBounds.height()
@@ -839,16 +825,6 @@
surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
)
-
- val animationAlpha = when {
- // If we're snapping the keyguard back, immediately begin fading it out.
- keyguardStateController.isSnappingKeyguardBackAfterSwipe -> amount
- // If the screen has turned back off, the unlock animation is going to be cancelled,
- // so set the surface alpha to 0f so it's no longer visible.
- !powerManager.isInteractive -> 0f
- else -> surfaceBehindAlpha
- }
-
// SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
// unable to draw
val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget.leash
@@ -863,28 +839,27 @@
} else {
applyParamsToSurface(
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
- surfaceBehindRemoteAnimationTarget.leash)
- .withMatrix(surfaceBehindMatrix)
- .withCornerRadius(roundedCornerRadius)
- .withAlpha(animationAlpha)
- .build()
+ surfaceBehindRemoteAnimationTarget.leash)
+ .withMatrix(surfaceBehindMatrix)
+ .withCornerRadius(roundedCornerRadius)
+ .withAlpha(animationAlpha)
+ .build()
)
}
}
+
+ if (wallpapers) {
+ setWallpaperAppearAmount(amount)
+ }
}
- /**
- * Modify the opacity of a wallpaper window.
- */
fun setWallpaperAppearAmount(amount: Float) {
- wallpaperTargets?.forEach { wallpaper ->
- val animationAlpha = when {
- // If the screen has turned back off, the unlock animation is going to be cancelled,
- // so set the surface alpha to 0f so it's no longer visible.
- !powerManager.isInteractive -> 0f
- else -> amount
- }
+ val animationAlpha = when {
+ !powerManager.isInteractive -> 0f
+ else -> amount
+ }
+ wallpaperTargets?.forEach { wallpaper ->
// SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
// unable to draw
val sc: SurfaceControl? = wallpaper.leash
@@ -923,6 +898,7 @@
setSurfaceBehindAppearAmount(1f)
surfaceBehindAlphaAnimator.cancel()
surfaceBehindEntryAnimator.cancel()
+ wallpaperCannedUnlockAnimator.cancel()
try {
launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
} catch (e: RemoteException) {
@@ -931,6 +907,7 @@
// That target is no longer valid since the animation finished, null it out.
surfaceBehindRemoteAnimationTargets = null
+ wallpaperTargets = null
playingCannedUnlockAnimation = false
willUnlockWithInWindowLauncherAnimations = false
@@ -972,8 +949,8 @@
private fun fadeInWallpaper() {
Log.d(TAG, "fadeInWallpaper")
- wallpaperAlphaAnimator.cancel()
- wallpaperAlphaAnimator.start()
+ wallpaperCannedUnlockAnimator.cancel()
+ wallpaperCannedUnlockAnimator.start()
}
private fun fadeOutSurfaceBehind() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 51af8fb..45e4623 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3009,19 +3009,6 @@
mSurfaceBehindRemoteAnimationRequested = false;
mSurfaceBehindRemoteAnimationRunning = false;
mKeyguardStateController.notifyKeyguardGoingAway(false);
- finishExitRemoteAnimation();
- }
-
- void finishExitRemoteAnimation() {
- if (mKeyguardUnlockAnimationControllerLazy.get().isAnyKeyguyardAnimatorPlaying()
- || mKeyguardStateController.isDismissingFromSwipe()) {
- // If the animation is ongoing, or we are not done with the swipe gesture,
- // it's too early to terminate the animation
- Log.d(TAG, "finishAnimation not executing now because "
- + "not all animations have finished");
- return;
- }
- Log.d(TAG, "finishAnimation executing");
if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt
index ea6700e..ca430da 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt
@@ -17,12 +17,14 @@
package com.android.systemui.keyguard.domain.interactor
+import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.view.accessibility.AccessibilityManager
import androidx.annotation.VisibleForTesting
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -55,6 +57,7 @@
class KeyguardLongPressInteractor
@Inject
constructor(
+ @Application private val appContext: Context,
@Application private val scope: CoroutineScope,
transitionInteractor: KeyguardTransitionInteractor,
repository: KeyguardRepository,
@@ -169,7 +172,8 @@
private fun isFeatureEnabled(): Boolean {
return featureFlags.isEnabled(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED) &&
- featureFlags.isEnabled(Flags.REVAMPED_WALLPAPER_UI)
+ featureFlags.isEnabled(Flags.REVAMPED_WALLPAPER_UI) &&
+ appContext.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled)
}
/** Updates application state to ask to show the menu. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 8e65c4d..2275337 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -19,12 +19,15 @@
import android.app.AlertDialog
import android.app.admin.DevicePolicyManager
+import android.content.Context
import android.content.Intent
import android.util.Log
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.dock.DockManager
@@ -75,6 +78,7 @@
private val devicePolicyManager: DevicePolicyManager,
private val dockManager: DockManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Application private val appContext: Context,
) {
private val isUsingRepository: Boolean
get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
@@ -408,7 +412,8 @@
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED,
value =
!isFeatureDisabledByDevicePolicy() &&
- featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES),
+ featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) &&
+ appContext.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled),
),
KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
index 6170180..d0bc25f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
@@ -36,8 +36,8 @@
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
-/** Hosts business and application state accessing logic for the lock screen scene. */
-class LockScreenSceneInteractor
+/** Hosts business and application state accessing logic for the lockscreen scene. */
+class LockscreenSceneInteractor
@AssistedInject
constructor(
@Application applicationScope: CoroutineScope,
@@ -59,7 +59,7 @@
initialValue = !authenticationInteractor.isUnlocked.value,
)
- /** Whether it's currently possible to swipe up to dismiss the lock screen. */
+ /** Whether it's currently possible to swipe up to dismiss the lockscreen. */
val isSwipeToDismissEnabled: StateFlow<Boolean> =
combine(
authenticationInteractor.isUnlocked,
@@ -81,9 +81,9 @@
)
init {
- // LOCKING SHOWS LOCK SCREEN.
+ // LOCKING SHOWS Lockscreen.
//
- // Move to the lock screen scene if the device becomes locked while in any scene.
+ // Move to the lockscreen scene if the device becomes locked while in any scene.
applicationScope.launch {
authenticationInteractor.isUnlocked
.map { !it }
@@ -92,7 +92,7 @@
if (isLocked) {
sceneInteractor.setCurrentScene(
containerName = containerName,
- scene = SceneModel(SceneKey.LockScreen),
+ scene = SceneModel(SceneKey.Lockscreen),
)
}
}
@@ -101,7 +101,7 @@
// BYPASS UNLOCK.
//
// Moves to the gone scene if bypass is enabled and the device becomes unlocked while in the
- // lock screen scene.
+ // lockscreen scene.
applicationScope.launch {
combine(
authenticationInteractor.isBypassEnabled,
@@ -110,7 +110,7 @@
::Triple,
)
.collect { (isBypassEnabled, isUnlocked, currentScene) ->
- if (isBypassEnabled && isUnlocked && currentScene.key == SceneKey.LockScreen) {
+ if (isBypassEnabled && isUnlocked && currentScene.key == SceneKey.Lockscreen) {
sceneInteractor.setCurrentScene(
containerName = containerName,
scene = SceneModel(SceneKey.Gone),
@@ -119,9 +119,9 @@
}
}
- // SWIPE TO DISMISS LOCK SCREEN.
+ // SWIPE TO DISMISS Lockscreen.
//
- // If switched from the lock screen to the gone scene and the auth method was a swipe,
+ // If switched from the lockscreen to the gone scene and the auth method was a swipe,
// unlocks the device.
applicationScope.launch {
combine(
@@ -133,7 +133,7 @@
val (previousScene, currentScene) = scenes
if (
authMethod is AuthenticationMethodModel.Swipe &&
- previousScene.key == SceneKey.LockScreen &&
+ previousScene.key == SceneKey.Lockscreen &&
currentScene.key == SceneKey.Gone
) {
authenticationInteractor.unlockDevice()
@@ -141,9 +141,9 @@
}
}
- // DISMISS LOCK SCREEN IF AUTH METHOD IS REMOVED.
+ // DISMISS Lockscreen IF AUTH METHOD IS REMOVED.
//
- // If the auth method becomes None while on the lock screen scene, dismisses the lock
+ // If the auth method becomes None while on the lockscreen scene, dismisses the lock
// screen.
applicationScope.launch {
combine(
@@ -153,7 +153,7 @@
)
.collect { (authMethod, scene) ->
if (
- scene.key == SceneKey.LockScreen &&
+ scene.key == SceneKey.Lockscreen &&
authMethod == AuthenticationMethodModel.None
) {
sceneInteractor.setCurrentScene(
@@ -165,8 +165,8 @@
}
}
- /** Attempts to dismiss the lock screen. This will cause the bouncer to show, if needed. */
- fun dismissLockScreen() {
+ /** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
+ fun dismissLockscreen() {
bouncerInteractor.showOrUnlockDevice(containerName = containerName)
}
@@ -181,6 +181,6 @@
interface Factory {
fun create(
containerName: String,
- ): LockScreenSceneInteractor
+ ): LockscreenSceneInteractor
}
}
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 233146a5..54bc349 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
@@ -40,6 +40,7 @@
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.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shared.system.SysUiStatsLog
@@ -196,6 +197,7 @@
cancelShowRunnable()
repository.setPrimaryShowingSoon(false)
repository.setPrimaryShow(false)
+ repository.setPanelExpansion(EXPANSION_HIDDEN)
primaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.INVISIBLE)
Trace.endSection()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 0db4ab1..555a09b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -124,7 +124,9 @@
setUpUdfps(rootView)
- setUpClock(rootView)
+ if (!shouldHideClock) {
+ setUpClock(rootView)
+ }
rootView.measure(
View.MeasureSpec.makeMeasureSpec(
@@ -352,28 +354,23 @@
clockController.clock = clock
colorOverride?.let { clock.events.onSeedColorChanged(it) }
- if (!shouldHideClock) {
- clock.largeClock.events.onTargetRegionChanged(
- KeyguardClockSwitch.getLargeClockRegion(parentView)
- )
- clockView?.let { parentView.removeView(it) }
- clockView =
- clock.largeClock.view.apply {
- if (shouldHighlightSelectedAffordance) {
- alpha = DIM_ALPHA
- }
- parentView.addView(this)
- visibility = View.VISIBLE
+ clock.largeClock.events.onTargetRegionChanged(
+ KeyguardClockSwitch.getLargeClockRegion(parentView)
+ )
+
+ clockView?.let { parentView.removeView(it) }
+ clockView =
+ clock.largeClock.view.apply {
+ if (shouldHighlightSelectedAffordance) {
+ alpha = DIM_ALPHA
}
- } else {
- clockView?.visibility = View.GONE
- }
+ parentView.addView(this)
+ visibility = View.VISIBLE
+ }
// Hide smart space if the clock has weather display; otherwise show it
- val hasCustomWeatherDataDisplay =
- clock.largeClock.config.hasCustomWeatherDataDisplay == true
- hideSmartspace(hasCustomWeatherDataDisplay)
+ hideSmartspace(clock.largeClock.config.hasCustomWeatherDataDisplay)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModel.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 08b9613..f212a55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -20,7 +20,7 @@
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -31,17 +31,17 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-/** Models UI state and handles user input for the lock screen scene. */
-class LockScreenSceneViewModel
+/** Models UI state and handles user input for the lockscreen scene. */
+class LockscreenSceneViewModel
@AssistedInject
constructor(
@Application applicationScope: CoroutineScope,
- interactorFactory: LockScreenSceneInteractor.Factory,
+ interactorFactory: LockscreenSceneInteractor.Factory,
@Assisted containerName: String,
) {
- private val interactor: LockScreenSceneInteractor = interactorFactory.create(containerName)
+ private val interactor: LockscreenSceneInteractor = interactorFactory.create(containerName)
- /** The icon for the "lock" button on the lock screen. */
+ /** The icon for the "lock" button on the lockscreen. */
val lockButtonIcon: StateFlow<Icon> =
interactor.isDeviceLocked
.map { isLocked -> lockIcon(isLocked = isLocked) }
@@ -63,12 +63,12 @@
/** Notifies that the lock button on the lock screen was clicked. */
fun onLockButtonClicked() {
- interactor.dismissLockScreen()
+ interactor.dismissLockscreen()
}
/** Notifies that some content on the lock screen was clicked. */
fun onContentClicked() {
- interactor.dismissLockScreen()
+ interactor.dismissLockscreen()
}
private fun upDestinationSceneKey(
@@ -103,6 +103,6 @@
interface Factory {
fun create(
containerName: String,
- ): LockScreenSceneViewModel
+ ): LockscreenSceneViewModel
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index edab56e..1fd11bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -323,7 +323,6 @@
if (isFlungAwayFromEdge(endX = event.x) ||
previousXTranslation > params.staticTriggerThreshold
) {
- updateArrowState(GestureState.ACTIVE)
updateArrowState(GestureState.FLUNG)
} else {
updateArrowState(GestureState.CANCELLED)
@@ -331,8 +330,11 @@
}
GestureState.INACTIVE -> {
if (isFlungAwayFromEdge(endX = event.x)) {
+ // This is called outside of updateArrowState so that
+ // BackAnimationController can immediately evaluate state
+ // instead of after the flung delay
+ backCallback.setTriggerBack(true)
mainHandler.postDelayed(MIN_DURATION_INACTIVE_BEFORE_FLUNG_ANIMATION) {
- updateArrowState(GestureState.ACTIVE)
updateArrowState(GestureState.FLUNG)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 42de7f0..5818fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -63,6 +63,8 @@
import android.view.WindowManager;
import android.window.BackEvent;
+import androidx.annotation.DimenRes;
+
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.systemui.R;
@@ -225,7 +227,8 @@
// The slop to distinguish between horizontal and vertical motion
private float mTouchSlop;
// The threshold for back swipe full progress.
- private float mBackSwipeProgressThreshold;
+ private float mBackSwipeLinearThreshold;
+ private float mNonLinearFactor;
// Duration after which we consider the event as longpress.
private final int mLongPressTimeout;
private int mStartingQuickstepRotation = -1;
@@ -471,11 +474,19 @@
final float backGestureSlop = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.BACK_GESTURE_SLOP_MULTIPLIER, 0.75f);
mTouchSlop = mViewConfiguration.getScaledTouchSlop() * backGestureSlop;
- mBackSwipeProgressThreshold = res.getDimension(
+ mBackSwipeLinearThreshold = res.getDimension(
R.dimen.navigation_edge_action_progress_threshold);
+ mNonLinearFactor = getDimenFloat(res,
+ R.dimen.back_progress_non_linear_factor);
updateBackAnimationThresholds();
}
+ private float getDimenFloat(Resources res, @DimenRes int resId) {
+ TypedValue typedValue = new TypedValue();
+ res.getValue(resId, typedValue, true);
+ return typedValue.getFloat();
+ }
+
public void updateNavigationBarOverlayExcludeRegion(Rect exclude) {
mNavBarOverlayExcludedBounds.set(exclude);
}
@@ -1116,8 +1127,9 @@
if (mBackAnimation == null) {
return;
}
- mBackAnimation.setSwipeThresholds(
- Math.min(mDisplaySize.x, mBackSwipeProgressThreshold));
+ int maxDistance = mDisplaySize.x;
+ float linearDistance = Math.min(maxDistance, mBackSwipeLinearThreshold);
+ mBackAnimation.setSwipeThresholds(linearDistance, maxDistance, mNonLinearFactor);
}
private boolean sendEvent(int action, int code) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
index 182ece7..6d881d5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
@@ -132,7 +132,7 @@
entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f)
entryWidthTowardsEdgeInterpolator = PathInterpolator(1f, -3f, 1f, 1.2f)
- activeWidthInterpolator = PathInterpolator(.56f, -0.39f, .18f, 1.46f)
+ activeWidthInterpolator = PathInterpolator(.7f, -0.24f, .48f, 1.21f)
arrowAngleInterpolator = entryWidthInterpolator
horizontalTranslationInterpolator = PathInterpolator(0.2f, 1.0f, 1.0f, 1.0f)
verticalTranslationInterpolator = PathInterpolator(.5f, 1.15f, .41f, .94f)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 6525a98..36dec1d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.qs.ui.viewmodel
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -25,15 +25,15 @@
class QuickSettingsSceneViewModel
@AssistedInject
constructor(
- lockScreenSceneInteractorFactory: LockScreenSceneInteractor.Factory,
+ lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory,
@Assisted containerName: String,
) {
- private val lockScreenSceneInteractor: LockScreenSceneInteractor =
- lockScreenSceneInteractorFactory.create(containerName)
+ private val lockscreenSceneInteractor: LockscreenSceneInteractor =
+ lockscreenSceneInteractorFactory.create(containerName)
/** Notifies that some content in quick settings was clicked. */
fun onContentClicked() {
- lockScreenSceneInteractor.dismissLockScreen()
+ lockscreenSceneInteractor.dismissLockscreen()
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt
index 9ef439d..e7811e3 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneKey.kt
@@ -32,8 +32,8 @@
*/
object Gone : SceneKey("gone")
- /** The lock screen is the scene that shows when the device is locked. */
- object LockScreen : SceneKey("lockscreen")
+ /** The lockscreen is the scene that shows when the device is locked. */
+ object Lockscreen : SceneKey("lockscreen")
/**
* The shade is the scene whose primary purpose is to show a scrollable list of notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
index 2336673..9235fcc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java
@@ -84,7 +84,7 @@
Color.YELLOW, "calculatePanelHeightShade()");
drawDebugInfo(canvas,
(int) mQsController.calculateNotificationsTopPadding(
- mNotificationPanelViewController.isExpanding(),
+ mNotificationPanelViewController.isExpandingOrCollapsing(),
mNotificationPanelViewController.getKeyguardNotificationStaticPadding(),
mNotificationPanelViewController.getExpandedFraction()),
Color.MAGENTA, "calculateNotificationsTopPadding()");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index af12bc2..0fdd7ca 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -233,7 +233,6 @@
import javax.inject.Provider;
import kotlin.Unit;
-
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -415,7 +414,11 @@
private final KeyguardClockPositionAlgorithm.Result
mClockPositionResult =
new KeyguardClockPositionAlgorithm.Result();
- private boolean mIsExpanding;
+ /**
+ * Indicates shade (or just QS) is expanding or collapsing but doesn't fully cover KEYGUARD
+ * state when shade can be expanded with swipe down or swipe down from the top to full QS.
+ */
+ private boolean mIsExpandingOrCollapsing;
/**
* Indicates drag starting height when swiping down or up on heads-up notifications.
@@ -1862,7 +1865,7 @@
@Override
public void expandToNotifications() {
- if (mSplitShadeEnabled && (isShadeFullyExpanded() || isExpanding())) {
+ if (mSplitShadeEnabled && (isShadeFullyExpanded() || isExpandingOrCollapsing())) {
return;
}
if (mQsController.getExpanded()) {
@@ -2109,6 +2112,9 @@
? QUICK_SETTINGS : (
mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
if (!isFalseTouch(x, y, interactionType)) {
+ mShadeLog.logFlingExpands(vel, vectorVel, interactionType,
+ this.mFlingAnimationUtils.getMinVelocityPxPerSecond(),
+ mExpandedFraction > 0.5f, mAllowExpandForSmallExpansion);
if (Math.abs(vectorVel) < this.mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
expands = shouldExpandWhenNotFlinging();
} else {
@@ -2269,7 +2275,7 @@
void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScrollLayoutController.updateTopPadding(
- mQsController.calculateNotificationsTopPadding(mIsExpanding,
+ mQsController.calculateNotificationsTopPadding(mIsExpandingOrCollapsing,
getKeyguardNotificationStaticPadding(), mExpandedFraction), animate);
if (isKeyguardShowing()
&& mKeyguardBypassController.getBypassEnabled()) {
@@ -2322,7 +2328,7 @@
}
int maxHeight;
if (mQsController.isExpandImmediate() || mQsController.getExpanded()
- || mIsExpanding && mQsController.getExpandedWhenExpandingStarted()
+ || mIsExpandingOrCollapsing && mQsController.getExpandedWhenExpandingStarted()
|| mPulsing || mSplitShadeEnabled) {
maxHeight = mQsController.calculatePanelHeightExpanded(
mClockPositionResult.stackScrollerPadding);
@@ -2342,8 +2348,11 @@
return maxHeight;
}
- public boolean isExpanding() {
- return mIsExpanding;
+ @Override
+ public boolean isExpandingOrCollapsing() {
+ float lockscreenExpansionProgress = mQsController.getLockscreenShadeDragProgress();
+ return mIsExpandingOrCollapsing
+ || (0 < lockscreenExpansionProgress && lockscreenExpansionProgress < 1);
}
private void onHeightUpdated(float expandedHeight) {
@@ -2355,7 +2364,7 @@
mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
}
if (!mQsController.getExpanded() || mQsController.isExpandImmediate()
- || mIsExpanding && mQsController.getExpandedWhenExpandingStarted()) {
+ || mIsExpandingOrCollapsing && mQsController.getExpandedWhenExpandingStarted()) {
// Updating the clock position will set the top padding which might
// trigger a new panel height and re-position the clock.
// This is a circular dependency and should be avoided, otherwise we'll have
@@ -2493,7 +2502,7 @@
mNotificationStackScrollLayoutController.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());
- mIsExpanding = false;
+ mIsExpandingOrCollapsing = false;
mMediaHierarchyManager.setCollapsingShadeFromQS(false);
mMediaHierarchyManager.setQsExpanded(mQsController.getExpanded());
if (isFullyCollapsed()) {
@@ -2908,6 +2917,10 @@
&& mBarState == StatusBarState.SHADE;
}
+ private boolean isPanelVisibleBecauseScrimIsAnimatingOff() {
+ return mUnlockedScreenOffAnimationController.isAnimationPlaying();
+ }
+
@Override
public boolean shouldHideStatusBarIconsWhenExpanded() {
if (mIsLaunchAnimationRunning) {
@@ -3199,7 +3212,7 @@
ipw.print("mDisplayTopInset="); ipw.println(mDisplayTopInset);
ipw.print("mDisplayRightInset="); ipw.println(mDisplayRightInset);
ipw.print("mDisplayLeftInset="); ipw.println(mDisplayLeftInset);
- ipw.print("mIsExpanding="); ipw.println(mIsExpanding);
+ ipw.print("mIsExpandingOrCollapsing="); ipw.println(mIsExpandingOrCollapsing);
ipw.print("mHeadsUpStartHeight="); ipw.println(mHeadsUpStartHeight);
ipw.print("mListenForHeadsUp="); ipw.println(mListenForHeadsUp);
ipw.print("mNavigationBarBottomHeight="); ipw.println(mNavigationBarBottomHeight);
@@ -3431,7 +3444,7 @@
void notifyExpandingStarted() {
if (!mExpanding) {
mExpanding = true;
- mIsExpanding = true;
+ mIsExpandingOrCollapsing = true;
mQsController.onExpandingStarted(mQsController.getFullyExpanded());
}
}
@@ -3492,7 +3505,7 @@
* gesture), we always play haptic.
*/
private void maybeVibrateOnOpening(boolean openingWithTouch) {
- if (mVibrateOnOpening) {
+ if (mVibrateOnOpening && mBarState != KEYGUARD && mBarState != SHADE_LOCKED) {
if (!openingWithTouch || !mHasVibratedOnOpen) {
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
mHasVibratedOnOpen = true;
@@ -3792,7 +3805,7 @@
} else if (mBarState == SHADE_LOCKED) {
return true;
} else {
- // case of two finger swipe from the top of keyguard
+ // case of swipe from the top of keyguard to expanded QS
return mQsController.computeExpansionFraction() == 1;
}
}
@@ -3967,6 +3980,7 @@
|| isPanelVisibleBecauseOfHeadsUp()
|| mTracking
|| mHeightAnimator != null
+ || isPanelVisibleBecauseScrimIsAnimatingOff()
&& !mIsSpringBackAnimation;
}
@@ -4044,7 +4058,7 @@
* shade QS are always expanded
*/
private void closeQsIfPossible() {
- boolean openOrOpening = isShadeFullyExpanded() || isExpanding();
+ boolean openOrOpening = isShadeFullyExpanded() || isExpandingOrCollapsing();
if (!(mSplitShadeEnabled && openOrOpening)) {
mQsController.closeQs();
}
@@ -4767,7 +4781,7 @@
// If pulse is expanding already, let's give it the touch. There are situations
// where the panel starts expanding even though we're also pulsing
- boolean pulseShouldGetTouch = (!mIsExpanding
+ boolean pulseShouldGetTouch = (!mIsExpandingOrCollapsing
&& !mQsController.shouldQuickSettingsIntercept(mDownX, mDownY, 0))
|| mPulseExpansionHandler.isExpanding();
if (pulseShouldGetTouch && mPulseExpansionHandler.onTouchEvent(event)) {
@@ -4933,7 +4947,7 @@
mShadeLog.logHasVibrated(mHasVibratedOnOpen, mExpandedFraction);
}
addMovement(event);
- if (!isFullyCollapsed() && !isOnKeyguard()) {
+ if (!isFullyCollapsed()) {
maybeVibrateOnOpening(true /* openingWithTouch */);
}
float h = y - mInitialExpandY;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index e08bc33..d0a3cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -78,6 +78,11 @@
boolean isShadeFullyOpen();
/**
+ * Returns whether shade or QS are currently opening or collapsing.
+ */
+ boolean isExpandingOrCollapsing();
+
+ /**
* Add a runnable for NotificationPanelView to post when the panel is expanded.
*
* @param action the action to post
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index c71467b..d00dab6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -164,6 +164,11 @@
}
@Override
+ public boolean isExpandingOrCollapsing() {
+ return mNotificationPanelViewController.isExpandingOrCollapsing();
+ }
+
+ @Override
public void postOnShadeExpanded(Runnable executable) {
mNotificationPanelViewController.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 25073c1b..2b772e3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -253,6 +253,31 @@
)
}
+ fun logFlingExpands(
+ vel: Float,
+ vectorVel: Float,
+ interactionType: Int,
+ minVelocityPxPerSecond: Float,
+ expansionOverHalf: Boolean,
+ allowExpandForSmallExpansion: Boolean
+ ) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ int1 = interactionType
+ long1 = vel.toLong()
+ long2 = vectorVel.toLong()
+ double1 = minVelocityPxPerSecond.toDouble()
+ bool1 = expansionOverHalf
+ bool2 = allowExpandForSmallExpansion
+ },
+ { "NPVC flingExpands called with vel: $long1, vectorVel: $long2, " +
+ "interactionType: $int1, minVelocityPxPerSecond: $double1 " +
+ "expansionOverHalf: $bool1, allowExpandForSmallExpansion: $bool2" }
+ )
+ }
+
fun flingQs(flingType: Int, isClick: Boolean) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index d5a9e95..f75047c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -48,7 +48,7 @@
fun expandToNotifications()
/** Returns whether the shade is expanding or collapsing itself or quick settings. */
- val isExpanding: Boolean
+ val isExpandingOrCollapsing: Boolean
/**
* Returns whether the shade height is greater than zero (i.e. partially or fully expanded),
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index 0ebcfa2..fc1e87a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -141,6 +141,7 @@
mCarrierTextManager = carrierTextManagerBuilder
.setShowAirplaneMode(false)
.setShowMissingSim(false)
+ .setDebugLocationString("Shade")
.build();
mCarrierConfigTracker = carrierConfigTracker;
mSlotIndexResolver = slotIndexResolver;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index dcae258..8a96a47 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.shade.ui.viewmodel
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -33,11 +33,11 @@
@AssistedInject
constructor(
@Application private val applicationScope: CoroutineScope,
- lockScreenSceneInteractorFactory: LockScreenSceneInteractor.Factory,
+ lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory,
@Assisted private val containerName: String,
) {
- private val lockScreenInteractor: LockScreenSceneInteractor =
- lockScreenSceneInteractorFactory.create(containerName)
+ private val lockScreenInteractor: LockscreenSceneInteractor =
+ lockscreenSceneInteractorFactory.create(containerName)
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
@@ -54,13 +54,13 @@
/** Notifies that some content in the shade was clicked. */
fun onContentClicked() {
- lockScreenInteractor.dismissLockScreen()
+ lockScreenInteractor.dismissLockscreen()
}
private fun upDestinationSceneKey(
isLocked: Boolean,
): SceneKey {
- return if (isLocked) SceneKey.LockScreen else SceneKey.Gone
+ return if (isLocked) SceneKey.Lockscreen else SceneKey.Gone
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ae7c216..b0f3f59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -93,6 +93,12 @@
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
+ /**
+ * The ExpandableNotificationRow that is pulsing, or the one that was pulsing
+ * when the device started to transition from AOD to LockScreen.
+ */
+ private ExpandableNotificationRow mPulsingRow;
+
/** Fraction of lockscreen to shade animation (on lockscreen swipe down). */
private float mFractionToShade;
@@ -564,6 +570,19 @@
return mPulsing && entry.isAlerting();
}
+ public void setPulsingRow(ExpandableNotificationRow row) {
+ mPulsingRow = row;
+ }
+
+ /**
+ * @param row The row to check
+ * @return true if row is the pulsing row when the device started to transition from AOD to lock
+ * screen
+ */
+ public boolean isPulsingRow(ExpandableView row) {
+ return mPulsingRow == row;
+ }
+
public boolean isPanelTracking() {
return mPanelTracking;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 92d767a..6f1c378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -548,7 +548,7 @@
ExpandableViewState viewState = view.getViewState();
viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
- final float expansionFraction = getExpansionFractionWithoutShelf(
+ float expansionFraction = getExpansionFractionWithoutShelf(
algorithmState, ambientState);
// Add gap between sections.
@@ -619,6 +619,11 @@
updateViewWithShelf(view, viewState, shelfStart);
}
}
+ // Avoid pulsing notification flicker during AOD to LS
+ // A pulsing notification is already expanded, no need to expand it again with animation
+ if (ambientState.isPulsingRow(view)) {
+ expansionFraction = 1.0f;
+ }
// Clip height of view right before shelf.
viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction);
}
@@ -700,9 +705,11 @@
&& !(child instanceof FooterView);
}
- private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
+ @VisibleForTesting
+ void updatePulsingStates(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
int childCount = algorithmState.visibleChildren.size();
+ ExpandableNotificationRow pulsingRow = null;
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
if (!(child instanceof ExpandableNotificationRow)) {
@@ -714,6 +721,19 @@
}
ExpandableViewState viewState = row.getViewState();
viewState.hidden = false;
+ pulsingRow = row;
+ }
+
+ // Set AmbientState#pulsingRow to the current pulsing row when on AOD.
+ // Set AmbientState#pulsingRow=null when on lockscreen, since AmbientState#pulsingRow
+ // is only used for skipping the unfurl animation for (the notification that was already
+ // showing at full height on AOD) during the AOD=>lockscreen transition, where
+ // dozeAmount=[1f, 0f). We also need to reset the pulsingRow once it is no longer used
+ // because it will interfere with future unfurling animations - for example, during the
+ // LS=>AOD animation, the pulsingRow may stay at full height when it should squish with the
+ // rest of the stack.
+ if (ambientState.getDozeAmount() == 0.0f || ambientState.getDozeAmount() == 1.0f) {
+ ambientState.setPulsingRow(pulsingRow);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 37e77766..0ccc819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -339,7 +339,7 @@
mHeadsUpManager.unpinAll(true /* userUnpinned */);
mMetricsLogger.count("panel_open", 1);
} else if (!mQsController.getExpanded()
- && !mShadeViewController.isExpanding()) {
+ && !mShadeViewController.isExpandingOrCollapsing()) {
mQsController.flingQs(0 /* velocity */,
ShadeViewController.FLING_EXPAND);
mMetricsLogger.count("panel_open_qs", 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 263566e..5c99f34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1224,6 +1224,7 @@
// By default turning off the screen also closes the shade.
// We want to make sure that the shade status is kept after folding/unfolding.
boolean isShadeOpen = mShadeController.isShadeFullyOpen();
+ boolean isShadeExpandingOrCollapsing = mShadeController.isExpandingOrCollapsing();
boolean leaveOpen = isShadeOpen && !willGoToSleep && mState == SHADE;
if (DEBUG) {
Log.d(TAG, String.format(
@@ -1231,14 +1232,15 @@
+ "isFolded=%s, "
+ "willGoToSleep=%s, "
+ "isShadeOpen=%s, "
+ + "isShadeExpandingOrCollapsing=%s, "
+ "leaveOpen=%s",
- isFolded, willGoToSleep, isShadeOpen, leaveOpen));
+ isFolded, willGoToSleep, isShadeOpen, isShadeExpandingOrCollapsing, leaveOpen));
}
if (leaveOpen) {
// below makes shade stay open when going from folded to unfolded
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
}
- if (mState != SHADE && isShadeOpen) {
+ if (mState != SHADE && (isShadeOpen || isShadeExpandingOrCollapsing)) {
// When device state changes on KEYGUARD/SHADE_LOCKED we don't want to keep the state of
// the shade and instead we open clean state of keyguard with shade closed.
// Normally some parts of QS state (like expanded/collapsed) are persisted and
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f2fbd7d..414a2ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -488,7 +488,7 @@
final boolean hideBouncerOverDream =
mDreamOverlayStateController.isOverlayActive()
&& (mShadeViewController.isExpanded()
- || mShadeViewController.isExpanding());
+ || mShadeViewController.isExpandingOrCollapsing());
final boolean isUserTrackingStarted =
event.getFraction() != EXPANSION_HIDDEN && event.getTracking();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 1559c64..d2e5a45 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -18,6 +18,7 @@
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
+import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
import static com.google.common.truth.Truth.assertThat;
@@ -691,6 +692,14 @@
verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
}
+ @Test
+ public void setExpansion_setsAlpha() {
+ mKeyguardSecurityContainerController.setExpansion(EXPANSION_VISIBLE);
+
+ verify(mView).setAlpha(1f);
+ verify(mView).setTranslationY(0f);
+ }
+
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
mKeyguardSecurityContainerController.onViewAttached();
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 3cbb249..63b0b25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -29,6 +29,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -73,6 +74,9 @@
private Context mContext;
@Mock
+ private Resources mResources;
+
+ @Mock
private ControlsComponent mControlsComponent;
@Mock
@@ -118,7 +122,7 @@
@Test
public void complicationType() {
final DreamHomeControlsComplication complication =
- new DreamHomeControlsComplication(mComponentFactory);
+ new DreamHomeControlsComplication(mResources, mComponentFactory);
assertThat(complication.getRequiredTypeAvailability()).isEqualTo(
COMPLICATION_TYPE_HOME_CONTROLS);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 9cf988e..8ee7d3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -30,6 +30,7 @@
import android.view.SurfaceControlViewHost
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.R
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
@@ -67,6 +68,7 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -103,6 +105,7 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, true)
whenever(previewRenderer.surfacePackage).thenReturn(previewSurfacePackage)
whenever(previewRendererFactory.create(any())).thenReturn(previewRenderer)
whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper)
@@ -195,6 +198,7 @@
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
backgroundDispatcher = testDispatcher,
+ appContext = mContext,
)
underTest.previewManager =
KeyguardRemotePreviewManager(
@@ -216,6 +220,13 @@
)
}
+ @After
+ fun tearDown() {
+ mContext
+ .getOrCreateTestableResources()
+ .removeOverride(R.bool.custom_lockscreen_shortcuts_enabled)
+ }
+
@Test
fun onAttachInfo_reportsContext() {
val callback: SystemUIAppComponentFactoryBase.ContextAvailableCallback = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index 0a9618c..688c2db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -114,7 +114,6 @@
@After
fun tearDown() {
keyguardUnlockAnimationController.notifyFinishedKeyguardExitAnimation(true)
- keyguardUnlockAnimationController.wallpaperAlphaAnimator.cancel()
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index dfef947..5de24e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -21,6 +21,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -39,6 +40,7 @@
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,6 +67,7 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ overrideResource(R.bool.long_press_keyguard_customize_lockscreen_enabled, true)
whenever(accessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenAnswer {
it.arguments[0]
}
@@ -76,6 +79,13 @@
runBlocking { createUnderTest() }
}
+ @After
+ fun tearDown() {
+ mContext
+ .getOrCreateTestableResources()
+ .removeOverride(R.bool.long_press_keyguard_customize_lockscreen_enabled)
+ }
+
@Test
fun isEnabled() =
testScope.runTest {
@@ -108,6 +118,17 @@
}
@Test
+ fun isEnabled_alwaysFalseWhenConfigEnabledBooleanIsFalse() =
+ testScope.runTest {
+ overrideResource(R.bool.long_press_keyguard_customize_lockscreen_enabled, false)
+ createUnderTest()
+ val isEnabled by collectLastValue(underTest.isLongPressHandlingEnabled)
+ runCurrent()
+
+ assertThat(isEnabled).isFalse()
+ }
+
+ @Test
fun longPressed_menuClicked_showsSettings() =
testScope.runTest {
val isMenuVisible by collectLastValue(underTest.isMenuVisible)
@@ -267,6 +288,7 @@
) {
underTest =
KeyguardLongPressInteractor(
+ appContext = mContext,
scope = testScope.backgroundScope,
transitionInteractor =
KeyguardTransitionInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index a75e11a..fb21847 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -340,6 +340,7 @@
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
backgroundDispatcher = testDispatcher,
+ appContext = mContext,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 3336e3b..5d2c3ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -200,6 +200,7 @@
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
backgroundDispatcher = testDispatcher,
+ appContext = mContext,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index c2c528a..d622f1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockScreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -36,7 +36,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
-class LockScreenSceneInteractorTest : SysuiTestCase() {
+class LockscreenSceneInteractorTest : SysuiTestCase() {
private val testScope = TestScope()
private val utils = SceneTestUtils(this, testScope)
@@ -96,9 +96,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.dismissLockScreen()
+ underTest.dismissLockscreen()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -109,9 +109,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.unlockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.dismissLockScreen()
+ underTest.dismissLockscreen()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -122,9 +122,9 @@
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.dismissLockScreen()
+ underTest.dismissLockscreen()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -142,7 +142,7 @@
authenticationInteractor.lockDevice()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
}
@Test
@@ -150,11 +150,11 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.LockScreen))
+ sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
if (!authenticationInteractor.isBypassEnabled.value) {
authenticationInteractor.toggleBypassEnabled()
}
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
authenticationInteractor.biometricUnlock()
@@ -166,22 +166,22 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
authenticationInteractor.lockDevice()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.LockScreen))
+ sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
if (authenticationInteractor.isBypassEnabled.value) {
authenticationInteractor.toggleBypassEnabled()
}
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
authenticationInteractor.biometricUnlock()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
}
@Test
fun switchFromLockScreenToGone_authMethodSwipe_unlocksDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.LockScreen))
+ sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isUnlocked).isFalse()
@@ -194,7 +194,7 @@
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.LockScreen))
+ sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
assertThat(isUnlocked).isFalse()
@@ -223,9 +223,9 @@
fun authMethodChangedToNone_onLockScreenScene_dismissesLockScreen() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.LockScreen))
+ sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
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 5d39794..b5cb44a 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
@@ -159,6 +159,7 @@
verify(repository).setPrimaryShow(false)
verify(mPrimaryBouncerCallbackInteractor).dispatchVisibilityChanged(View.INVISIBLE)
verify(repository).setPrimaryStartDisappearAnimation(null)
+ verify(repository).setPanelExpansion(EXPANSION_HIDDEN)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 69d43af..8a36dbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -211,6 +211,7 @@
)
val keyguardLongPressInteractor =
KeyguardLongPressInteractor(
+ appContext = mContext,
scope = testScope.backgroundScope,
transitionInteractor =
KeyguardTransitionInteractor(
@@ -240,6 +241,7 @@
devicePolicyManager = devicePolicyManager,
dockManager = dockManager,
backgroundDispatcher = testDispatcher,
+ appContext = mContext,
),
bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
burnInHelperWrapper = burnInHelperWrapper,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 9e8be3e..8ba3f0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockScreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -22,7 +22,7 @@
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
@@ -39,7 +39,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
-class LockScreenSceneViewModelTest : SysuiTestCase() {
+class LockscreenSceneViewModelTest : SysuiTestCase() {
private val testScope = TestScope()
private val utils = SceneTestUtils(this, testScope)
@@ -50,11 +50,11 @@
)
private val underTest =
- LockScreenSceneViewModel(
+ LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
interactorFactory =
- object : LockScreenSceneInteractor.Factory {
- override fun create(containerName: String): LockScreenSceneInteractor {
+ object : LockscreenSceneInteractor.Factory {
+ override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 3f838e6..105387d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -20,7 +20,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
@@ -49,9 +49,9 @@
private val underTest =
QuickSettingsSceneViewModel(
- lockScreenSceneInteractorFactory =
- object : LockScreenSceneInteractor.Factory {
- override fun create(containerName: String): LockScreenSceneInteractor {
+ lockscreenSceneInteractorFactory =
+ object : LockscreenSceneInteractor.Factory {
+ override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 6c7017bac..de15c77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -45,7 +45,7 @@
listOf(
SceneKey.QuickSettings,
SceneKey.Shade,
- SceneKey.LockScreen,
+ SceneKey.Lockscreen,
SceneKey.Bouncer,
SceneKey.Gone,
)
@@ -62,7 +62,7 @@
fun currentScene() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val currentScene by collectLastValue(underTest.currentScene("container1"))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene("container1", SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
@@ -88,7 +88,7 @@
utils.fakeSceneContainerConfig("container1"),
utils.fakeSceneContainerConfig(
"container2",
- listOf(SceneKey.QuickSettings, SceneKey.LockScreen)
+ listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
),
)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index cf99e3b..ee4f6c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -46,7 +46,7 @@
@Test
fun sceneTransitions() = runTest {
val currentScene by collectLastValue(underTest.currentScene("container1"))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene("container1", SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 6105c87..cd2f5af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -63,7 +63,7 @@
@Test
fun sceneTransition() = runTest {
val currentScene by collectLastValue(underTest.currentScene)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.LockScreen))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.setCurrentScene(SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 48e0b53..a5a9de5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -902,6 +902,13 @@
}
@Test
+ public void isExpandingOrCollapsing_returnsTrue_whenQsLockscreenDragInProgress() {
+ when(mQsController.getLockscreenShadeDragProgress()).thenReturn(0.5f);
+ assertThat(mNotificationPanelViewController.isExpandingOrCollapsing()).isTrue();
+ }
+
+
+ @Test
public void getMaxPanelTransitionDistance_inSplitShade_withHeadsUp_returnsBiggerValue() {
enableSplitShade(true);
mNotificationPanelViewController.expandToQs();
@@ -1099,7 +1106,7 @@
}
@Test
- public void shadeExpanded_inShadeState() {
+ public void shadeFullyExpanded_inShadeState() {
mStatusBarStateController.setState(SHADE);
mNotificationPanelViewController.setExpandedHeight(0);
@@ -1111,7 +1118,7 @@
}
@Test
- public void shadeExpanded_onKeyguard() {
+ public void shadeFullyExpanded_onKeyguard() {
mStatusBarStateController.setState(KEYGUARD);
int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
@@ -1120,8 +1127,39 @@
}
@Test
- public void shadeExpanded_onShadeLocked() {
+ public void shadeFullyExpanded_onShadeLocked() {
mStatusBarStateController.setState(SHADE_LOCKED);
assertThat(mNotificationPanelViewController.isShadeFullyExpanded()).isTrue();
}
+
+ @Test
+ public void shadeExpanded_whenHasHeight() {
+ int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
+ mNotificationPanelViewController.setExpandedHeight(transitionDistance);
+ assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void shadeExpanded_whenInstantExpanding() {
+ mNotificationPanelViewController.expand(true);
+ assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void shadeExpanded_whenHunIsPresent() {
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void shadeExpanded_whenWaitingForExpandGesture() {
+ mNotificationPanelViewController.startWaitingForExpandGesture();
+ assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void shadeExpanded_whenUnlockedOffscreenAnimationRunning() {
+ when(mUnlockedScreenOffAnimationController.isAnimationPlaying()).thenReturn(true);
+ assertThat(mNotificationPanelViewController.isExpanded()).isTrue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 2ef3d60..57ae621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -109,6 +110,8 @@
.thenReturn(mCarrierTextControllerBuilder);
when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean()))
.thenReturn(mCarrierTextControllerBuilder);
+ when(mCarrierTextControllerBuilder.setDebugLocationString(anyString()))
+ .thenReturn(mCarrierTextControllerBuilder);
when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextManager);
doAnswer(invocation -> mCallback = invocation.getArgument(0))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 2e7f83d..69d03d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -20,7 +20,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
@@ -50,9 +50,9 @@
private val underTest =
ShadeSceneViewModel(
applicationScope = testScope.backgroundScope,
- lockScreenSceneInteractorFactory =
- object : LockScreenSceneInteractor.Factory {
- override fun create(containerName: String): LockScreenSceneInteractor {
+ lockscreenSceneInteractorFactory =
+ object : LockscreenSceneInteractor.Factory {
+ override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
@@ -74,7 +74,7 @@
authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.PIN(1234))
authenticationInteractor.lockDevice()
- assertThat(upTransitionSceneKey).isEqualTo(SceneKey.LockScreen)
+ assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 7f20f1e..e12d179 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -716,6 +716,94 @@
.isLessThan(px(R.dimen.heads_up_pinned_elevation))
}
+ @Test
+ fun aodToLockScreen_hasPulsingNotification_pulsingNotificationRowDoesNotChange() {
+ // Given: Before AOD to LockScreen, there was a pulsing notification
+ val pulsingNotificationView = createPulsingViewMock()
+ val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
+ algorithmState.visibleChildren.add(pulsingNotificationView)
+ ambientState.setPulsingRow(pulsingNotificationView)
+
+ // When: during AOD to LockScreen, any dozeAmount between (0, 1.0) is equivalent as a middle
+ // stage; here we use 0.5 for testing.
+ // stackScrollAlgorithm.updatePulsingStates is called
+ ambientState.dozeAmount = 0.5f
+ stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
+
+ // Then: ambientState.pulsingRow should still be pulsingNotificationView
+ assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+ }
+
+ @Test
+ fun deviceOnAod_hasPulsingNotification_recordPulsingNotificationRow() {
+ // Given: Device is on AOD, there is a pulsing notification
+ // ambientState.pulsingRow is null before stackScrollAlgorithm.updatePulsingStates
+ ambientState.dozeAmount = 1.0f
+ val pulsingNotificationView = createPulsingViewMock()
+ val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
+ algorithmState.visibleChildren.add(pulsingNotificationView)
+ ambientState.setPulsingRow(null)
+
+ // When: stackScrollAlgorithm.updatePulsingStates is called
+ stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
+
+ // Then: ambientState.pulsingRow should record the pulsingNotificationView
+ assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+ }
+
+ @Test
+ fun deviceOnLockScreen_hasPulsingNotificationBefore_clearPulsingNotificationRowRecord() {
+ // Given: Device finished AOD to LockScreen, there was a pulsing notification, and
+ // ambientState.pulsingRow was not null before AOD to LockScreen
+ // pulsingNotificationView.showingPulsing() returns false since the device is on LockScreen
+ ambientState.dozeAmount = 0.0f
+ val pulsingNotificationView = createPulsingViewMock()
+ whenever(pulsingNotificationView.showingPulsing()).thenReturn(false)
+ val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
+ algorithmState.visibleChildren.add(pulsingNotificationView)
+ ambientState.setPulsingRow(pulsingNotificationView)
+
+ // When: stackScrollAlgorithm.updatePulsingStates is called
+ stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
+
+ // Then: ambientState.pulsingRow should be null
+ assertTrue(ambientState.isPulsingRow(null))
+ }
+
+ @Test
+ fun aodToLockScreen_hasPulsingNotification_pulsingNotificationRowShowAtFullHeight() {
+ // Given: Before AOD to LockScreen, there was a pulsing notification
+ val pulsingNotificationView = createPulsingViewMock()
+ val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
+ algorithmState.visibleChildren.add(pulsingNotificationView)
+ ambientState.setPulsingRow(pulsingNotificationView)
+
+ // When: during AOD to LockScreen, any dozeAmount between (0, 1.0) is equivalent as a middle
+ // stage; here we use 0.5 for testing. The expansionFraction is also 0.5.
+ // stackScrollAlgorithm.resetViewStates is called.
+ ambientState.dozeAmount = 0.5f
+ setExpansionFractionWithoutShelfDuringAodToLockScreen(
+ ambientState,
+ algorithmState,
+ fraction = 0.5f
+ )
+ stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+ // Then: pulsingNotificationView should show at full height
+ assertEquals(
+ stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView),
+ pulsingNotificationView.viewState.height
+ )
+
+ // After: reset dozeAmount and expansionFraction
+ ambientState.dozeAmount = 0f
+ setExpansionFractionWithoutShelfDuringAodToLockScreen(
+ ambientState,
+ algorithmState,
+ fraction = 1f
+ )
+ }
+
private fun createHunViewMock(
isShadeOpen: Boolean,
fullyVisible: Boolean,
@@ -744,6 +832,29 @@
headsUpIsVisible = fullyVisible
}
+ private fun createPulsingViewMock(
+ ) =
+ mock<ExpandableNotificationRow>().apply {
+ whenever(this.viewState).thenReturn(ExpandableViewState())
+ whenever(this.showingPulsing()).thenReturn(true)
+ }
+
+ private fun setExpansionFractionWithoutShelfDuringAodToLockScreen(
+ ambientState: AmbientState,
+ algorithmState: StackScrollAlgorithm.StackScrollAlgorithmState,
+ fraction: Float
+ ) {
+ // showingShelf: false
+ algorithmState.firstViewInShelf = null
+ // scrimPadding: 0, because device is on lock screen
+ ambientState.setStatusBarState(StatusBarState.KEYGUARD)
+ ambientState.dozeAmount = 0.0f
+ // set stackEndHeight and stackHeight
+ // ExpansionFractionWithoutShelf == stackHeight / stackEndHeight
+ ambientState.stackEndHeight = 100f
+ ambientState.stackHeight = ambientState.stackEndHeight * fraction
+ }
+
private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
expansionFraction: Float,
expectedAlpha: Float,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c83769d..cf6d5b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -335,6 +335,7 @@
private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
private final InitController mInitController = new InitController();
private final DumpManager mDumpManager = new DumpManager();
+ private final ScreenLifecycle mScreenLifecycle = new ScreenLifecycle(mDumpManager);
@Before
public void setup() throws Exception {
@@ -487,7 +488,7 @@
mUserSwitcherController,
mBatteryController,
mColorExtractor,
- new ScreenLifecycle(mDumpManager),
+ mScreenLifecycle,
mWakefulnessLifecycle,
mStatusBarStateController,
Optional.of(mBubbles),
@@ -554,6 +555,7 @@
return mViewRootImpl;
}
};
+ mScreenLifecycle.addObserver(mCentralSurfaces.mScreenObserver);
mCentralSurfaces.initShadeVisibilityListener();
when(mViewRootImpl.getOnBackInvokedDispatcher())
.thenReturn(mOnBackInvokedDispatcher);
@@ -1253,6 +1255,32 @@
}
@Test
+ public void deviceStateChange_unfolded_shadeExpanding_onKeyguard_closesQS() {
+ setFoldedStates(FOLD_STATE_FOLDED);
+ setGoToSleepStates(FOLD_STATE_FOLDED);
+ mCentralSurfaces.setBarStateForTest(KEYGUARD);
+ when(mNotificationPanelViewController.isExpandingOrCollapsing()).thenReturn(true);
+
+ setDeviceState(FOLD_STATE_UNFOLDED);
+ mScreenLifecycle.dispatchScreenTurnedOff();
+
+ verify(mQuickSettingsController).closeQs();
+ }
+
+ @Test
+ public void deviceStateChange_unfolded_shadeExpanded_onKeyguard_closesQS() {
+ setFoldedStates(FOLD_STATE_FOLDED);
+ setGoToSleepStates(FOLD_STATE_FOLDED);
+ mCentralSurfaces.setBarStateForTest(KEYGUARD);
+ when(mNotificationPanelViewController.isShadeFullyExpanded()).thenReturn(true);
+
+ setDeviceState(FOLD_STATE_UNFOLDED);
+ mScreenLifecycle.dispatchScreenTurnedOff();
+
+ verify(mQuickSettingsController).closeQs();
+ }
+
+ @Test
public void startActivityDismissingKeyguard_isShowingAndIsOccluded() {
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(true);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 5a350bb..be3d54a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -23,7 +23,7 @@
import com.android.systemui.bouncer.data.repo.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.keyguard.domain.interactor.LockScreenSceneInteractor
+import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.data.model.SceneContainerConfig
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -58,7 +58,7 @@
return listOf(
SceneKey.QuickSettings,
SceneKey.Shade,
- SceneKey.LockScreen,
+ SceneKey.Lockscreen,
SceneKey.Bouncer,
SceneKey.Gone,
)
@@ -71,7 +71,7 @@
return SceneContainerConfig(
name = name,
sceneKeys = sceneKeys,
- initialSceneKey = SceneKey.LockScreen,
+ initialSceneKey = SceneKey.Lockscreen,
)
}
@@ -139,8 +139,8 @@
authenticationInteractor: AuthenticationInteractor,
sceneInteractor: SceneInteractor,
bouncerInteractor: BouncerInteractor,
- ): LockScreenSceneInteractor {
- return LockScreenSceneInteractor(
+ ): LockscreenSceneInteractor {
+ return LockscreenSceneInteractor(
applicationScope = applicationScope(),
authenticationInteractor = authenticationInteractor,
bouncerInteractorFactory =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 544828a..bfa397f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18894,12 +18894,14 @@
@Override
public void waitForBroadcastIdle() {
- waitForBroadcastIdle(LOG_WRITER_INFO);
+ waitForBroadcastIdle(LOG_WRITER_INFO, false);
}
- public void waitForBroadcastIdle(@NonNull PrintWriter pw) {
+ void waitForBroadcastIdle(@NonNull PrintWriter pw, boolean flushBroadcastLoopers) {
enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
- BroadcastLoopers.waitForIdle(pw);
+ if (flushBroadcastLoopers) {
+ BroadcastLoopers.waitForIdle(pw);
+ }
for (BroadcastQueue queue : mBroadcastQueues) {
queue.waitForIdle(pw);
}
@@ -18912,7 +18914,7 @@
waitForBroadcastBarrier(LOG_WRITER_INFO, false, false);
}
- public void waitForBroadcastBarrier(@NonNull PrintWriter pw,
+ void waitForBroadcastBarrier(@NonNull PrintWriter pw,
boolean flushBroadcastLoopers, boolean flushApplicationThreads) {
enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
if (flushBroadcastLoopers) {
@@ -18930,7 +18932,7 @@
* Wait for all pending {@link IApplicationThread} events to be processed in
* all currently running apps.
*/
- public void waitForApplicationBarrier(@NonNull PrintWriter pw) {
+ void waitForApplicationBarrier(@NonNull PrintWriter pw) {
final CountDownLatch finishedLatch = new CountDownLatch(1);
final AtomicInteger pingCount = new AtomicInteger(0);
final AtomicInteger pongCount = new AtomicInteger(0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 979874e..add22bd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -3447,7 +3447,17 @@
int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException {
pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw));
- mInternal.waitForBroadcastIdle(pw);
+ boolean flushBroadcastLoopers = false;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--flush-broadcast-loopers")) {
+ flushBroadcastLoopers = true;
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ mInternal.waitForBroadcastIdle(pw, flushBroadcastLoopers);
return 0;
}
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 87214de..030d596 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -247,6 +247,26 @@
private static final long DEFAULT_DELAY_URGENT_MILLIS = -120_000;
/**
+ * For {@link BroadcastQueueModernImpl}: Delay to apply to broadcasts to
+ * foreground processes, typically a negative value to indicate they should be
+ * executed before most other pending broadcasts.
+ */
+ public long DELAY_FOREGROUND_PROC_MILLIS = DEFAULT_DELAY_FOREGROUND_PROC_MILLIS;
+ private static final String KEY_DELAY_FOREGROUND_PROC_MILLIS =
+ "bcast_delay_foreground_proc_millis";
+ private static final long DEFAULT_DELAY_FOREGROUND_PROC_MILLIS = -120_000;
+
+ /**
+ * For {@link BroadcastQueueModernImpl}: Delay to apply to broadcasts to
+ * persistent processes, typically a negative value to indicate they should be
+ * executed before most other pending broadcasts.
+ */
+ public long DELAY_PERSISTENT_PROC_MILLIS = DEFAULT_DELAY_FOREGROUND_PROC_MILLIS;
+ private static final String KEY_DELAY_PERSISTENT_PROC_MILLIS =
+ "bcast_delay_persistent_proc_millis";
+ private static final long DEFAULT_DELAY_PERSISTENT_PROC_MILLIS = -120_000;
+
+ /**
* For {@link BroadcastQueueModernImpl}: Maximum number of complete
* historical broadcasts to retain for debugging purposes.
*/
@@ -411,6 +431,10 @@
DEFAULT_DELAY_CACHED_MILLIS);
DELAY_URGENT_MILLIS = getDeviceConfigLong(KEY_DELAY_URGENT_MILLIS,
DEFAULT_DELAY_URGENT_MILLIS);
+ DELAY_FOREGROUND_PROC_MILLIS = getDeviceConfigLong(KEY_DELAY_FOREGROUND_PROC_MILLIS,
+ DEFAULT_DELAY_FOREGROUND_PROC_MILLIS);
+ DELAY_PERSISTENT_PROC_MILLIS = getDeviceConfigLong(KEY_DELAY_PERSISTENT_PROC_MILLIS,
+ DEFAULT_DELAY_PERSISTENT_PROC_MILLIS);
MAX_HISTORY_COMPLETE_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_COMPLETE_SIZE,
DEFAULT_MAX_HISTORY_COMPLETE_SIZE);
MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE,
@@ -463,6 +487,10 @@
TimeUtils.formatDuration(DELAY_CACHED_MILLIS)).println();
pw.print(KEY_DELAY_URGENT_MILLIS,
TimeUtils.formatDuration(DELAY_URGENT_MILLIS)).println();
+ pw.print(KEY_DELAY_FOREGROUND_PROC_MILLIS,
+ TimeUtils.formatDuration(DELAY_FOREGROUND_PROC_MILLIS)).println();
+ pw.print(KEY_DELAY_PERSISTENT_PROC_MILLIS,
+ TimeUtils.formatDuration(DELAY_PERSISTENT_PROC_MILLIS)).println();
pw.print(KEY_MAX_HISTORY_COMPLETE_SIZE, MAX_HISTORY_COMPLETE_SIZE).println();
pw.print(KEY_MAX_HISTORY_SUMMARY_SIZE, MAX_HISTORY_SUMMARY_SIZE).println();
pw.print(KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES,
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 2803b4b..3ac2b2b 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -1098,8 +1098,11 @@
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
mRunnableAtReason = REASON_INSTRUMENTED;
} else if (mUidForeground) {
- mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
+ mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS;
mRunnableAtReason = REASON_FOREGROUND;
+ } else if (mProcessPersistent) {
+ mRunnableAt = runnableAt + constants.DELAY_PERSISTENT_PROC_MILLIS;
+ mRunnableAtReason = REASON_PERSISTENT;
} else if (mCountOrdered > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_ORDERED;
@@ -1112,9 +1115,6 @@
} else if (mCountManifest > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_MANIFEST;
- } else if (mProcessPersistent) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_PERSISTENT;
} else if (mUidCached) {
if (r.deferUntilActive) {
// All enqueued broadcasts are deferrable, defer
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index b22ece3..9e66bfe 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -175,7 +175,7 @@
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@PowerExemptionManager.ReasonCode
- int mAllowWhileInUsePermissionInFgsReason;
+ int mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
// Integer version of mAllowWhileInUsePermissionInFgs that we keep track to compare
// the old and new logics.
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 71401f4..f4c9d05 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -209,6 +209,7 @@
private void init() {
setupMessaging(mContext);
+ initAudioHalBluetoothState();
initRoutingStrategyIds();
mPreferredCommunicationDevice = null;
updateActiveCommunicationDevice();
@@ -864,21 +865,174 @@
}
}
- /**
- * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
- */
+ // Lock protecting state variable related to Bluetooth audio state
+ private final Object mBluetoothAudioStateLock = new Object();
+
+ // Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
+ @GuardedBy("mBluetoothAudioStateLock")
private boolean mBluetoothScoOn;
+ // value of BT_SCO parameter currently applied to audio HAL.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothScoOnApplied;
+
+ // A2DP suspend state requested by AudioManager.setA2dpSuspended() API.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothA2dpSuspendedExt;
+ // A2DP suspend state requested by AudioDeviceInventory.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothA2dpSuspendedInt;
+ // value of BT_A2dpSuspendedSCO parameter currently applied to audio HAL.
+
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothA2dpSuspendedApplied;
+
+ // LE Audio suspend state requested by AudioManager.setLeAudioSuspended() API.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothLeSuspendedExt;
+ // LE Audio suspend state requested by AudioDeviceInventory.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothLeSuspendedInt;
+ // value of LeAudioSuspended parameter currently applied to audio HAL.
+ @GuardedBy("mBluetoothAudioStateLock")
+ private boolean mBluetoothLeSuspendedApplied;
+
+ private void initAudioHalBluetoothState() {
+ synchronized (mBluetoothAudioStateLock) {
+ mBluetoothScoOnApplied = false;
+ AudioSystem.setParameters("BT_SCO=off");
+ mBluetoothA2dpSuspendedApplied = false;
+ AudioSystem.setParameters("A2dpSuspended=false");
+ mBluetoothLeSuspendedApplied = false;
+ AudioSystem.setParameters("LeAudioSuspended=false");
+ }
+ }
+
+ @GuardedBy("mBluetoothAudioStateLock")
+ private void updateAudioHalBluetoothState() {
+ if (mBluetoothScoOn != mBluetoothScoOnApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothScoOn: "
+ + mBluetoothScoOn + ", mBluetoothScoOnApplied: " + mBluetoothScoOnApplied);
+ }
+ if (mBluetoothScoOn) {
+ if (!mBluetoothA2dpSuspendedApplied) {
+ AudioSystem.setParameters("A2dpSuspended=true");
+ mBluetoothA2dpSuspendedApplied = true;
+ }
+ if (!mBluetoothLeSuspendedApplied) {
+ AudioSystem.setParameters("LeAudioSuspended=true");
+ mBluetoothLeSuspendedApplied = true;
+ }
+ AudioSystem.setParameters("BT_SCO=on");
+ } else {
+ AudioSystem.setParameters("BT_SCO=off");
+ }
+ mBluetoothScoOnApplied = mBluetoothScoOn;
+ }
+ if (!mBluetoothScoOnApplied) {
+ if ((mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt)
+ != mBluetoothA2dpSuspendedApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothA2dpSuspendedExt: "
+ + mBluetoothA2dpSuspendedExt
+ + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothA2dpSuspendedApplied: "
+ + mBluetoothA2dpSuspendedApplied);
+ }
+ mBluetoothA2dpSuspendedApplied =
+ mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt;
+ if (mBluetoothA2dpSuspendedApplied) {
+ AudioSystem.setParameters("A2dpSuspended=true");
+ } else {
+ AudioSystem.setParameters("A2dpSuspended=false");
+ }
+ }
+ if ((mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt)
+ != mBluetoothLeSuspendedApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothLeSuspendedExt: "
+ + mBluetoothLeSuspendedExt
+ + ", mBluetoothLeSuspendedInt: " + mBluetoothLeSuspendedInt
+ + ", mBluetoothLeSuspendedApplied: " + mBluetoothLeSuspendedApplied);
+ }
+ mBluetoothLeSuspendedApplied =
+ mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt;
+ if (mBluetoothLeSuspendedApplied) {
+ AudioSystem.setParameters("LeAudioSuspended=true");
+ } else {
+ AudioSystem.setParameters("LeAudioSuspended=false");
+ }
+ }
+ }
+ }
/*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setBluetoothScoOn: " + on + " " + eventSource);
}
- synchronized (mDeviceStateLock) {
+ synchronized (mBluetoothAudioStateLock) {
mBluetoothScoOn = on;
+ updateAudioHalBluetoothState();
postUpdateCommunicationRouteClient(eventSource);
}
}
+ /*package*/ void setA2dpSuspended(boolean enable, boolean internal, String eventSource) {
+ synchronized (mBluetoothAudioStateLock) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "setA2dpSuspended source: " + eventSource + ", enable: "
+ + enable + ", internal: " + internal
+ + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothA2dpSuspendedExt: " + mBluetoothA2dpSuspendedExt);
+ }
+ if (internal) {
+ mBluetoothA2dpSuspendedInt = enable;
+ } else {
+ mBluetoothA2dpSuspendedExt = enable;
+ }
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void clearA2dpSuspended() {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "clearA2dpSuspended");
+ }
+ synchronized (mBluetoothAudioStateLock) {
+ mBluetoothA2dpSuspendedInt = false;
+ mBluetoothA2dpSuspendedExt = false;
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void setLeAudioSuspended(boolean enable, boolean internal, String eventSource) {
+ synchronized (mBluetoothAudioStateLock) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "setLeAudioSuspended source: " + eventSource + ", enable: "
+ + enable + ", internal: " + internal
+ + ", mBluetoothLeSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothLeSuspendedExt: " + mBluetoothA2dpSuspendedExt);
+ }
+ if (internal) {
+ mBluetoothLeSuspendedInt = enable;
+ } else {
+ mBluetoothLeSuspendedExt = enable;
+ }
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void clearLeAudioSuspended() {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "clearLeAudioSuspended");
+ }
+ synchronized (mBluetoothAudioStateLock) {
+ mBluetoothLeSuspendedInt = false;
+ mBluetoothLeSuspendedExt = false;
+ updateAudioHalBluetoothState();
+ }
+ }
+
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.startWatchingRoutes(observer);
@@ -1985,7 +2139,11 @@
*/
@GuardedBy("mDeviceStateLock")
@Nullable private AudioDeviceAttributes preferredCommunicationDevice() {
- boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
+ boolean btSCoOn = mBtHelper.isBluetoothScoOn();
+ synchronized (mBluetoothAudioStateLock) {
+ btSCoOn = btSCoOn && mBluetoothScoOn;
+ }
+
if (btSCoOn) {
// Use the SCO device known to BtHelper so that it matches exactly
// what has been communicated to audio policy manager. The device
@@ -2020,12 +2178,6 @@
"updateCommunicationRoute, preferredCommunicationDevice: "
+ preferredCommunicationDevice + " eventSource: " + eventSource)));
- if (preferredCommunicationDevice == null
- || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
- AudioSystem.setParameters("BT_SCO=off");
- } else {
- AudioSystem.setParameters("BT_SCO=on");
- }
if (preferredCommunicationDevice == null) {
AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
if (defaultDevice != null) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 58c7326..a561612 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1479,7 +1479,7 @@
}
// Reset A2DP suspend state each time a new sink is connected
- mAudioSystem.setParameters("A2dpSuspended=false");
+ mDeviceBroker.clearA2dpSuspended();
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
@@ -1752,7 +1752,8 @@
private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
// prevent any activity on the A2DP audio output to avoid unwanted
// reconnection of the sink.
- mAudioSystem.setParameters("A2dpSuspended=true");
+ mDeviceBroker.setA2dpSuspended(
+ true /*enable*/, true /*internal*/, "makeA2dpDeviceUnavailableLater");
// retrieve DeviceInfo before removing device
final String deviceKey =
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
@@ -1899,7 +1900,7 @@
"LE Audio device addr=" + address + " now available").printLog(TAG));
}
// Reset LEA suspend state each time a new sink is connected
- mAudioSystem.setParameters("LeAudioSuspended=false");
+ mDeviceBroker.clearLeAudioSuspended();
UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
@@ -1954,7 +1955,8 @@
private void makeLeAudioDeviceUnavailableLater(String address, int device, int delayMs) {
// prevent any activity on the LEA output to avoid unwanted
// reconnection of the sink.
- mAudioSystem.setParameters("LeAudioSuspended=true");
+ mDeviceBroker.setLeAudioSuspended(
+ true /*enable*/, true /*internal*/, "makeLeAudioDeviceUnavailableLater");
// the device will be made unavailable later, so consider it disconnected right away
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
// send the delayed message to make the device unavailable later
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b3fffbf..355981a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6424,6 +6424,26 @@
mDeviceBroker.setBluetoothScoOn(on, eventSource);
}
+ /** @see AudioManager#setA2dpSuspended(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setA2dpSuspended(boolean enable) {
+ super.setA2dpSuspended_enforcePermission();
+ final String eventSource = new StringBuilder("setA2dpSuspended(").append(enable)
+ .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
+ .append(Binder.getCallingPid()).toString();
+ mDeviceBroker.setA2dpSuspended(enable, false /*internal*/, eventSource);
+ }
+
+ /** @see AudioManager#setA2dpSuspended(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setLeAudioSuspended(boolean enable) {
+ super.setLeAudioSuspended_enforcePermission();
+ final String eventSource = new StringBuilder("setLeAudioSuspended(").append(enable)
+ .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
+ .append(Binder.getCallingPid()).toString();
+ mDeviceBroker.setLeAudioSuspended(enable, false /*internal*/, eventSource);
+ }
+
/** @see AudioManager#isBluetoothScoOn()
* Note that it doesn't report internal state, but state seen by apps (which may have
* called setBluetoothScoOn() */
@@ -11033,6 +11053,11 @@
dumpAccessibilityServiceUids(pw);
dumpAssistantServicesUids(pw);
+ pw.print(" supportsBluetoothVariableLatency=");
+ pw.println(AudioSystem.supportsBluetoothVariableLatency());
+ pw.print(" isBluetoothVariableLatencyEnabled=");
+ pw.println(AudioSystem.isBluetoothVariableLatencyEnabled());
+
dumpAudioPolicies(pw);
mDynPolicyLogger.dump(pw);
mPlaybackMonitor.dump(pw);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index bfa6c36e..e46c3cc 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -445,8 +445,8 @@
/*package*/ synchronized void resetBluetoothSco() {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- AudioSystem.setParameters("A2dpSuspended=false");
- AudioSystem.setParameters("LeAudioSuspended=false");
+ mDeviceBroker.clearA2dpSuspended();
+ mDeviceBroker.clearLeAudioSuspended();
mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e5c50e6..4edc8bc 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -23,7 +23,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.SparseArray;
import android.view.Display;
@@ -333,6 +332,10 @@
return mPrimaryDisplayDevice != null;
}
+ boolean isDirtyLocked() {
+ return mDirty;
+ }
+
/**
* Updates the {@link DisplayGroup} to which the logical display belongs.
*
@@ -341,8 +344,7 @@
public void updateDisplayGroupIdLocked(int groupId) {
if (groupId != mDisplayGroupId) {
mDisplayGroupId = groupId;
- mBaseDisplayInfo.displayGroupId = groupId;
- mInfo.set(null);
+ mDirty = true;
}
}
@@ -932,18 +934,6 @@
return mDisplayGroupName;
}
- /**
- * Returns whether a display group other than the default display group needs to be assigned.
- *
- * <p>If display group name is empty or {@code Display.FLAG_OWN_DISPLAY_GROUP} is set, the
- * display is assigned to the default display group.
- */
- public boolean needsOwnDisplayGroupLocked() {
- DisplayInfo info = getDisplayInfoLocked();
- return (info.flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0
- || !TextUtils.isEmpty(mDisplayGroupName);
- }
-
public void dumpLocked(PrintWriter pw) {
pw.println("mDisplayId=" + mDisplayId);
pw.println("mIsEnabled=" + mIsEnabled);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 254441c2..d01b03f 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -679,7 +679,9 @@
for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) {
final int displayId = mLogicalDisplays.keyAt(i);
LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ assignDisplayGroupLocked(display);
+ boolean wasDirty = display.isDirtyLocked();
mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
@@ -713,19 +715,14 @@
// The display is new.
} else if (!wasPreviouslyUpdated) {
Slog.i(TAG, "Adding new display: " + displayId + ": " + newDisplayInfo);
- assignDisplayGroupLocked(display);
mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);
// Underlying displays device has changed to a different one.
} else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) {
- // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
- assignDisplayGroupLocked(display);
mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED);
// Something about the display device has changed.
- } else if (!mTempDisplayInfo.equals(newDisplayInfo)) {
- // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
- assignDisplayGroupLocked(display);
+ } else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) {
// If only the hdr/sdr ratio changed, then send just the event for that case
if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) {
mLogicalDisplaysToUpdate.put(displayId,
@@ -851,9 +848,18 @@
}
}
+ /** This method should be called before LogicalDisplay.updateLocked,
+ * DisplayInfo in LogicalDisplay (display.getDisplayInfoLocked()) is not updated yet,
+ * and should not be used directly or indirectly in this method */
private void assignDisplayGroupLocked(LogicalDisplay display) {
+ if (!display.isValidLocked()) { // null check for display.mPrimaryDisplayDevice
+ return;
+ }
+ // updated primary device directly from LogicalDisplay (not from DisplayInfo)
+ final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
+ // final in LogicalDisplay
final int displayId = display.getDisplayIdLocked();
- final String primaryDisplayUniqueId = display.getPrimaryDisplayDeviceLocked().getUniqueId();
+ final String primaryDisplayUniqueId = displayDevice.getUniqueId();
final Integer linkedDeviceUniqueId =
mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId);
@@ -866,8 +872,17 @@
}
final DisplayGroup oldGroup = getDisplayGroupLocked(groupId);
- // Get the new display group if a change is needed
- final boolean needsOwnDisplayGroup = display.needsOwnDisplayGroupLocked();
+ // groupName directly from LogicalDisplay (not from DisplayInfo)
+ final String groupName = display.getDisplayGroupNameLocked();
+ // DisplayDeviceInfo is safe to use, it is updated earlier
+ final DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+ // Get the new display group if a change is needed, if display group name is empty and
+ // {@code DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP} is not set, the display is assigned
+ // to the default display group.
+ final boolean needsOwnDisplayGroup =
+ (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0
+ || !TextUtils.isEmpty(groupName);
+
final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP;
final boolean needsDeviceDisplayGroup =
!needsOwnDisplayGroup && linkedDeviceUniqueId != null;
diff --git a/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
index 73ab782..712a696 100644
--- a/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
+++ b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
@@ -23,6 +23,7 @@
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
@@ -48,6 +49,7 @@
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -62,15 +64,14 @@
private static final String SUBSYSTEM_SENSOR_STRING = "Sensor";
private static final String SUBSYSTEM_CELLULAR_DATA_STRING = "Cellular_data";
private static final String TRACE_TRACK_WAKEUP_ATTRIBUTION = "wakeup_attribution";
- @VisibleForTesting
- static final long WAKEUP_REASON_HALF_WINDOW_MS = 500;
+
private static final long WAKEUP_WRITE_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
private final Handler mHandler;
private final IrqDeviceMap mIrqDeviceMap;
@VisibleForTesting
final Config mConfig = new Config();
- private final WakingActivityHistory mRecentWakingActivity = new WakingActivityHistory();
+ private final WakingActivityHistory mRecentWakingActivity;
@VisibleForTesting
final TimeSparseArray<Wakeup> mWakeupEvents = new TimeSparseArray<>();
@@ -85,6 +86,8 @@
public CpuWakeupStats(Context context, int mapRes, Handler handler) {
mIrqDeviceMap = IrqDeviceMap.getInstance(context, mapRes);
+ mRecentWakingActivity = new WakingActivityHistory(
+ () -> mConfig.WAKING_ACTIVITY_RETENTION_MS);
mHandler = handler;
}
@@ -202,15 +205,14 @@
/** Notes a wakeup reason as reported by SuspendControlService to battery stats. */
public synchronized void noteWakeupTimeAndReason(long elapsedRealtime, long uptime,
String rawReason) {
- final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime);
+ final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime,
+ mIrqDeviceMap);
if (parsedWakeup == null) {
+ // This wakeup is unsupported for attribution. Exit.
return;
}
mWakeupEvents.put(elapsedRealtime, parsedWakeup);
attemptAttributionFor(parsedWakeup);
- // Assuming that wakeups always arrive in monotonically increasing elapsedRealtime order,
- // we can delete all history that will not be useful in attributing future wakeups.
- mRecentWakingActivity.clearAllBefore(elapsedRealtime - WAKEUP_REASON_HALF_WINDOW_MS);
// Limit history of wakeups and their attribution to the last retentionDuration. Note that
// the last wakeup and its attribution (if computed) is always stored, even if that wakeup
@@ -244,25 +246,22 @@
}
private synchronized void attemptAttributionFor(Wakeup wakeup) {
- final SparseBooleanArray subsystems = getResponsibleSubsystemsForWakeup(wakeup);
- if (subsystems == null) {
- // We don't support attribution for this kind of wakeup yet.
- return;
- }
+ final SparseBooleanArray subsystems = wakeup.mResponsibleSubsystems;
SparseArray<SparseIntArray> attribution = mWakeupAttribution.get(wakeup.mElapsedMillis);
if (attribution == null) {
attribution = new SparseArray<>();
mWakeupAttribution.put(wakeup.mElapsedMillis, attribution);
}
+ final long matchingWindowMillis = mConfig.WAKEUP_MATCHING_WINDOW_MS;
for (int subsystemIdx = 0; subsystemIdx < subsystems.size(); subsystemIdx++) {
final int subsystem = subsystems.keyAt(subsystemIdx);
- // Blame all activity that happened WAKEUP_REASON_HALF_WINDOW_MS before or after
+ // Blame all activity that happened matchingWindowMillis before or after
// the wakeup from each responsible subsystem.
- final long startTime = wakeup.mElapsedMillis - WAKEUP_REASON_HALF_WINDOW_MS;
- final long endTime = wakeup.mElapsedMillis + WAKEUP_REASON_HALF_WINDOW_MS;
+ final long startTime = wakeup.mElapsedMillis - matchingWindowMillis;
+ final long endTime = wakeup.mElapsedMillis + matchingWindowMillis;
final SparseIntArray uidsToBlame = mRecentWakingActivity.removeBetween(subsystem,
startTime, endTime);
@@ -272,18 +271,16 @@
private synchronized boolean attemptAttributionWith(int subsystem, long activityElapsed,
SparseIntArray uidProcStates) {
+ final long matchingWindowMillis = mConfig.WAKEUP_MATCHING_WINDOW_MS;
+
final int startIdx = mWakeupEvents.closestIndexOnOrAfter(
- activityElapsed - WAKEUP_REASON_HALF_WINDOW_MS);
+ activityElapsed - matchingWindowMillis);
final int endIdx = mWakeupEvents.closestIndexOnOrBefore(
- activityElapsed + WAKEUP_REASON_HALF_WINDOW_MS);
+ activityElapsed + matchingWindowMillis);
for (int wakeupIdx = startIdx; wakeupIdx <= endIdx; wakeupIdx++) {
final Wakeup wakeup = mWakeupEvents.valueAt(wakeupIdx);
- final SparseBooleanArray subsystems = getResponsibleSubsystemsForWakeup(wakeup);
- if (subsystems == null) {
- // Unsupported for attribution
- continue;
- }
+ final SparseBooleanArray subsystems = wakeup.mResponsibleSubsystems;
if (subsystems.get(subsystem)) {
// We don't expect more than one wakeup to be found within such a short window, so
// just attribute this one and exit
@@ -405,11 +402,13 @@
*/
@VisibleForTesting
static final class WakingActivityHistory {
- private static final long WAKING_ACTIVITY_RETENTION_MS = TimeUnit.MINUTES.toMillis(10);
-
+ private LongSupplier mRetentionSupplier;
@VisibleForTesting
- final SparseArray<TimeSparseArray<SparseIntArray>> mWakingActivity =
- new SparseArray<>();
+ final SparseArray<TimeSparseArray<SparseIntArray>> mWakingActivity = new SparseArray<>();
+
+ WakingActivityHistory(LongSupplier retentionSupplier) {
+ mRetentionSupplier = retentionSupplier;
+ }
void recordActivity(int subsystem, long elapsedRealtime, SparseIntArray uidProcStates) {
if (uidProcStates == null) {
@@ -433,27 +432,13 @@
}
}
}
- // Limit activity history per subsystem to the last WAKING_ACTIVITY_RETENTION_MS.
- // Note that the last activity is always present, even if it occurred before
- // WAKING_ACTIVITY_RETENTION_MS.
+ // Limit activity history per subsystem to the last retention period as supplied by
+ // mRetentionSupplier. Note that the last activity is always present, even if it
+ // occurred before the retention period.
final int endIdx = wakingActivity.closestIndexOnOrBefore(
- elapsedRealtime - WAKING_ACTIVITY_RETENTION_MS);
+ elapsedRealtime - mRetentionSupplier.getAsLong());
for (int i = endIdx; i >= 0; i--) {
- wakingActivity.removeAt(endIdx);
- }
- }
-
- void clearAllBefore(long elapsedRealtime) {
- for (int subsystemIdx = mWakingActivity.size() - 1; subsystemIdx >= 0; subsystemIdx--) {
- final TimeSparseArray<SparseIntArray> activityPerSubsystem =
- mWakingActivity.valueAt(subsystemIdx);
- final int endIdx = activityPerSubsystem.closestIndexOnOrBefore(elapsedRealtime);
- for (int removeIdx = endIdx; removeIdx >= 0; removeIdx--) {
- activityPerSubsystem.removeAt(removeIdx);
- }
- // Generally waking activity is a high frequency occurrence for any subsystem, so we
- // don't delete the TimeSparseArray even if it is now empty, to avoid object churn.
- // This will leave one TimeSparseArray per subsystem, which are few right now.
+ wakingActivity.removeAt(i);
}
}
@@ -515,33 +500,6 @@
}
}
- private SparseBooleanArray getResponsibleSubsystemsForWakeup(Wakeup wakeup) {
- if (ArrayUtils.isEmpty(wakeup.mDevices)) {
- return null;
- }
- final SparseBooleanArray result = new SparseBooleanArray();
- for (final Wakeup.IrqDevice device : wakeup.mDevices) {
- final List<String> rawSubsystems = mIrqDeviceMap.getSubsystemsForDevice(device.mDevice);
-
- boolean anyKnownSubsystem = false;
- if (rawSubsystems != null) {
- for (int i = 0; i < rawSubsystems.size(); i++) {
- final int subsystem = stringToKnownSubsystem(rawSubsystems.get(i));
- if (subsystem != CPU_WAKEUP_SUBSYSTEM_UNKNOWN) {
- // Just in case the xml had arbitrary subsystem names, we want to make sure
- // that we only put the known ones into our attribution map.
- result.put(subsystem, true);
- anyKnownSubsystem = true;
- }
- }
- }
- if (!anyKnownSubsystem) {
- result.put(CPU_WAKEUP_SUBSYSTEM_UNKNOWN, true);
- }
- }
- return result;
- }
-
static int stringToKnownSubsystem(String rawSubsystem) {
switch (rawSubsystem) {
case SUBSYSTEM_ALARM_STRING:
@@ -598,15 +556,19 @@
long mElapsedMillis;
long mUptimeMillis;
IrqDevice[] mDevices;
+ SparseBooleanArray mResponsibleSubsystems;
- private Wakeup(int type, IrqDevice[] devices, long elapsedMillis, long uptimeMillis) {
+ private Wakeup(int type, IrqDevice[] devices, long elapsedMillis, long uptimeMillis,
+ SparseBooleanArray responsibleSubsystems) {
mType = type;
mDevices = devices;
mElapsedMillis = elapsedMillis;
mUptimeMillis = uptimeMillis;
+ mResponsibleSubsystems = responsibleSubsystems;
}
- static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis) {
+ static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis,
+ IrqDeviceMap deviceMap) {
final String[] components = rawReason.split(":");
if (ArrayUtils.isEmpty(components) || components[0].startsWith(ABORT_REASON_PREFIX)) {
// Accounting of aborts is not supported yet.
@@ -616,6 +578,7 @@
int type = TYPE_IRQ;
int parsedDeviceCount = 0;
final IrqDevice[] parsedDevices = new IrqDevice[components.length];
+ final SparseBooleanArray responsibleSubsystems = new SparseBooleanArray();
for (String component : components) {
final Matcher matcher = sIrqPattern.matcher(component.trim());
@@ -635,13 +598,35 @@
continue;
}
parsedDevices[parsedDeviceCount++] = new IrqDevice(line, device);
+
+ final List<String> rawSubsystems = deviceMap.getSubsystemsForDevice(device);
+ boolean anyKnownSubsystem = false;
+ if (rawSubsystems != null) {
+ for (int i = 0; i < rawSubsystems.size(); i++) {
+ final int subsystem = stringToKnownSubsystem(rawSubsystems.get(i));
+ if (subsystem != CPU_WAKEUP_SUBSYSTEM_UNKNOWN) {
+ // Just in case the xml had arbitrary subsystem names, we want to
+ // make sure that we only put the known ones into our map.
+ responsibleSubsystems.put(subsystem, true);
+ anyKnownSubsystem = true;
+ }
+ }
+ }
+ if (!anyKnownSubsystem) {
+ responsibleSubsystems.put(CPU_WAKEUP_SUBSYSTEM_UNKNOWN, true);
+ }
}
}
if (parsedDeviceCount == 0) {
return null;
}
+ if (responsibleSubsystems.size() == 1 && responsibleSubsystems.get(
+ CPU_WAKEUP_SUBSYSTEM_UNKNOWN, false)) {
+ // There is no attributable subsystem here, so we do not support it.
+ return null;
+ }
return new Wakeup(type, Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis,
- uptimeMillis);
+ uptimeMillis, responsibleSubsystems);
}
@Override
@@ -651,6 +636,7 @@
+ ", mElapsedMillis=" + mElapsedMillis
+ ", mUptimeMillis=" + mUptimeMillis
+ ", mDevices=" + Arrays.toString(mDevices)
+ + ", mResponsibleSubsystems=" + mResponsibleSubsystems
+ '}';
}
@@ -672,18 +658,28 @@
static final class Config implements DeviceConfig.OnPropertiesChangedListener {
static final String KEY_WAKEUP_STATS_RETENTION_MS = "wakeup_stats_retention_ms";
+ static final String KEY_WAKEUP_MATCHING_WINDOW_MS = "wakeup_matching_window_ms";
+ static final String KEY_WAKING_ACTIVITY_RETENTION_MS = "waking_activity_retention_ms";
private static final String[] PROPERTY_NAMES = {
KEY_WAKEUP_STATS_RETENTION_MS,
+ KEY_WAKEUP_MATCHING_WINDOW_MS,
+ KEY_WAKING_ACTIVITY_RETENTION_MS,
};
static final long DEFAULT_WAKEUP_STATS_RETENTION_MS = TimeUnit.DAYS.toMillis(3);
+ private static final long DEFAULT_WAKEUP_MATCHING_WINDOW_MS = TimeUnit.SECONDS.toMillis(1);
+ private static final long DEFAULT_WAKING_ACTIVITY_RETENTION_MS =
+ TimeUnit.MINUTES.toMillis(5);
/**
* Wakeup stats are retained only for this duration.
*/
public volatile long WAKEUP_STATS_RETENTION_MS = DEFAULT_WAKEUP_STATS_RETENTION_MS;
+ public volatile long WAKEUP_MATCHING_WINDOW_MS = DEFAULT_WAKEUP_MATCHING_WINDOW_MS;
+ public volatile long WAKING_ACTIVITY_RETENTION_MS = DEFAULT_WAKING_ACTIVITY_RETENTION_MS;
+ @SuppressLint("MissingPermission")
void register(Executor executor) {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_STATS,
executor, this);
@@ -702,6 +698,15 @@
WAKEUP_STATS_RETENTION_MS = properties.getLong(
KEY_WAKEUP_STATS_RETENTION_MS, DEFAULT_WAKEUP_STATS_RETENTION_MS);
break;
+ case KEY_WAKEUP_MATCHING_WINDOW_MS:
+ WAKEUP_MATCHING_WINDOW_MS = properties.getLong(
+ KEY_WAKEUP_MATCHING_WINDOW_MS, DEFAULT_WAKEUP_MATCHING_WINDOW_MS);
+ break;
+ case KEY_WAKING_ACTIVITY_RETENTION_MS:
+ WAKING_ACTIVITY_RETENTION_MS = properties.getLong(
+ KEY_WAKING_ACTIVITY_RETENTION_MS,
+ DEFAULT_WAKING_ACTIVITY_RETENTION_MS);
+ break;
}
}
}
@@ -711,7 +716,19 @@
pw.increaseIndent();
- pw.print(KEY_WAKEUP_STATS_RETENTION_MS, WAKEUP_STATS_RETENTION_MS);
+ pw.print(KEY_WAKEUP_STATS_RETENTION_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKEUP_STATS_RETENTION_MS, pw);
+ pw.println();
+
+ pw.print(KEY_WAKEUP_MATCHING_WINDOW_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKEUP_MATCHING_WINDOW_MS, pw);
+ pw.println();
+
+ pw.print(KEY_WAKING_ACTIVITY_RETENTION_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKING_ACTIVITY_RETENTION_MS, pw);
pw.println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index c05d148..87ebdbf 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -234,6 +234,7 @@
int type = msg.arg2;
Bundle data = (Bundle) msg.obj;
mCallback.onTvMessage(deviceId, type, data);
+ break;
}
default:
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7a43728..9add537 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3987,6 +3987,8 @@
if (mFallbackWallpaper != null) {
dumpWallpaper(mFallbackWallpaper, pw);
}
+ pw.print("mIsLockscreenLiveWallpaperEnabled=");
+ pw.println(mIsLockscreenLiveWallpaperEnabled);
}
}
}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 778951a..98ee98b 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -248,7 +248,10 @@
Slog.e(TAG, "WM sent Transaction to organized, but never received" +
" commit callback. Application ANR likely to follow.");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- onCommitted(merged);
+ synchronized (mWm.mGlobalLock) {
+ onCommitted(merged.mNativeObject != 0
+ ? merged : mWm.mTransactionFactory.get());
+ }
}
};
CommitCallback callback = new CommitCallback();
diff --git a/services/core/java/com/android/server/wm/ContentRecordingController.java b/services/core/java/com/android/server/wm/ContentRecordingController.java
index 040da88..4da55e2 100644
--- a/services/core/java/com/android/server/wm/ContentRecordingController.java
+++ b/services/core/java/com/android/server/wm/ContentRecordingController.java
@@ -98,6 +98,13 @@
mSession == null ? null : mSession.getVirtualDisplayId());
incomingDisplayContent = wmService.mRoot.getDisplayContentOrCreate(
incomingSession.getVirtualDisplayId());
+ if (incomingDisplayContent == null) {
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Incoming session on display %d can't be set since it "
+ + "is already null; the corresponding VirtualDisplay must have "
+ + "already been removed.", incomingSession.getVirtualDisplayId());
+ return;
+ }
incomingDisplayContent.setContentRecordingSession(incomingSession);
// TODO(b/270118861): When user grants consent to re-use, explicitly ask ContentRecorder
// to update, since no config/display change arrives. Mark recording as black.
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index 72829c0..5f95c28 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -99,7 +99,10 @@
// Extract unique HDR output types.
std::set<int> hdrOutputTypes;
for (const auto& hdrConversionCapability : hdrConversionCapabilities) {
- hdrOutputTypes.insert(hdrConversionCapability.outputType);
+ // Filter out the value for SDR which is 0.
+ if (hdrConversionCapability.outputType > 0) {
+ hdrOutputTypes.insert(hdrConversionCapability.outputType);
+ }
}
jintArray array = env->NewIntArray(hdrOutputTypes.size());
if (array == nullptr) {
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
index a3eb390..6782b5c 100644
--- a/services/core/jni/tvinput/JTvInputHal.cpp
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -16,6 +16,8 @@
#include "JTvInputHal.h"
+#include <nativehelper/ScopedLocalRef.h>
+
namespace android {
JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, std::shared_ptr<ITvInputWrapper> tvInput,
@@ -278,21 +280,27 @@
void JTvInputHal::onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type,
AidlTvMessage& message, signed char data[], int dataLength) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject bundle = env->NewObject(gBundleClassInfo.clazz, gBundleClassInfo.constructor);
- const jsize len = static_cast<jsize>(dataLength);
- jbyteArray convertedData = env->NewByteArray(len);
- env->SetByteArrayRegion(convertedData, 0, len, reinterpret_cast<const jbyte*>(data));
- env->CallObjectMethod(bundle, gBundleClassInfo.putString,
- "android.media.tv.TvInputManager.subtype", message.subType.c_str());
- env->CallObjectMethod(bundle, gBundleClassInfo.putByteArray,
- "android.media.tv.TvInputManager.raw_data", convertedData);
- env->CallObjectMethod(bundle, gBundleClassInfo.putInt,
- "android.media.tv.TvInputManager.group_id", message.groupId);
- env->CallObjectMethod(bundle, gBundleClassInfo.putInt,
- "android.media.tv.TvInputManager.stream_id", streamId);
+ ScopedLocalRef<jobject> bundle(env,
+ env->NewObject(gBundleClassInfo.clazz,
+ gBundleClassInfo.constructor));
+ ScopedLocalRef<jbyteArray> convertedData(env, env->NewByteArray(dataLength));
+ env->SetByteArrayRegion(convertedData.get(), 0, dataLength, reinterpret_cast<jbyte*>(data));
+ std::string key = "android.media.tv.TvInputManager.raw_data";
+ ScopedLocalRef<jstring> jkey(env, env->NewStringUTF(key.c_str()));
+ env->CallVoidMethod(bundle.get(), gBundleClassInfo.putByteArray, jkey.get(),
+ convertedData.get());
+ ScopedLocalRef<jstring> subtype(env, env->NewStringUTF(message.subType.c_str()));
+ key = "android.media.tv.TvInputManager.subtype";
+ jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
+ env->CallVoidMethod(bundle.get(), gBundleClassInfo.putString, jkey.get(), subtype.get());
+ key = "android.media.tv.TvInputManager.group_id";
+ jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
+ env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), message.groupId);
+ key = "android.media.tv.TvInputManager.stream_id";
+ jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
+ env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), streamId);
env->CallVoidMethod(mThiz, gTvInputHalClassInfo.tvMessageReceived, deviceId,
- static_cast<int>(type), bundle);
- env->DeleteLocalRef(convertedData);
+ static_cast<jint>(type), bundle.get());
}
void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index d9467a5..c7a71ee 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -39,7 +39,7 @@
"PackageManagerServiceHostTestsIntentVerifyUtils",
"block_device_writer_jar",
],
- test_suites: ["general-tests"],
+ test_suites: ["device-tests"],
data: [
":PackageManagerTestApex",
":PackageManagerTestApexApp",
diff --git a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
index 2382548..f594f6f 100644
--- a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
+++ b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
@@ -30,6 +30,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
+ <option name="install-arg" value="-g" />
<option name="test-file-name" value="PackageManagerServiceServerTests.apk" />
</target_preparer>
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 581fe4a..f47954b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -537,6 +537,30 @@
assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
}
+ @Test
+ public void testRunnableAt_persistentProc() {
+ final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+
+ final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+ final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
+ List.of(makeMockRegisteredReceiver()));
+ enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
+
+ assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
+
+ doReturn(true).when(mProcess).isPersistent();
+ queue.setProcessAndUidState(mProcess, false, false);
+ assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_PERSISTENT, queue.getRunnableAtReason());
+
+ doReturn(false).when(mProcess).isPersistent();
+ queue.setProcessAndUidState(mProcess, false, false);
+ assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
+ }
+
/**
* Verify that a cached process that would normally be delayed becomes
* immediately runnable when the given broadcast is enqueued.
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index f6cf571..30ff8ba 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
@@ -191,6 +192,19 @@
}
@Test
+ public void testUpdateLayoutLimitedRefreshRate_setsDirtyFlag() {
+ SurfaceControl.RefreshRateRange layoutLimitedRefreshRate =
+ new SurfaceControl.RefreshRateRange(0, 120);
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate);
+ assertTrue(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+ }
+
+ @Test
public void testUpdateRefreshRateThermalThrottling() {
SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>();
refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120));
@@ -207,6 +221,45 @@
}
@Test
+ public void testUpdateRefreshRateThermalThrottling_setsDirtyFlag() {
+ SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>();
+ refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120));
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges);
+ assertTrue(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+ }
+
+ @Test
+ public void testUpdateDisplayGroupIdLocked() {
+ int newId = 999;
+ DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
+ mLogicalDisplay.updateDisplayGroupIdLocked(newId);
+ DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked();
+ // Display info should only be updated when updateLocked is called
+ assertEquals(info2, info1);
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked();
+ assertNotEquals(info3, info2);
+ assertEquals(newId, info3.displayGroupId);
+ }
+
+ @Test
+ public void testUpdateDisplayGroupIdLocked_setsDirtyFlag() {
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateDisplayGroupIdLocked(99);
+ assertTrue(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+ }
+
+ @Test
public void testSetThermalBrightnessThrottlingDataId() {
String brightnessThrottlingDataId = "throttling_data_id";
DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked();
@@ -220,4 +273,15 @@
assertNotEquals(info3, info2);
assertEquals(brightnessThrottlingDataId, info3.thermalBrightnessThrottlingDataId);
}
+
+ @Test
+ public void testSetThermalBrightnessThrottlingDataId_setsDirtyFlag() {
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.setThermalBrightnessThrottlingDataIdLocked("99");
+ assertTrue(mLogicalDisplay.isDirtyLocked());
+
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ assertFalse(mLogicalDisplay.isDirtyLocked());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
index 76b6a82..d181419 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
@@ -23,8 +23,6 @@
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI;
-import static com.android.server.power.stats.wakeups.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS;
-
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -55,7 +53,7 @@
private static final String KERNEL_REASON_SENSOR_IRQ = "15 test.sensor.device";
private static final String KERNEL_REASON_CELLULAR_DATA_IRQ = "18 test.cellular_data.device";
private static final String KERNEL_REASON_UNKNOWN_IRQ = "140 test.unknown.device";
- private static final String KERNEL_REASON_UNKNOWN = "free-form-reason test.alarm.device";
+ private static final String KERNEL_REASON_UNKNOWN_FORMAT = "free-form-reason test.alarm.device";
private static final String KERNEL_REASON_ALARM_ABNORMAL = "-1 test.alarm.device";
private static final String KERNEL_REASON_ABORT = "Abort: due to test.alarm.device";
@@ -85,30 +83,29 @@
@Test
public void removesOldWakeups() {
- // The xml resource doesn't matter for this test.
- final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_1, mHandler);
+ final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long retention = obj.mConfig.WAKEUP_STATS_RETENTION_MS;
final Set<Long> timestamps = new HashSet<>();
final long firstWakeup = 453192;
- obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_UNKNOWN_IRQ);
+ // Reasons do not matter for this test, as long as they map to known subsystems
+ obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_ALARM_IRQ);
timestamps.add(firstWakeup);
for (int i = 1; i < 1000; i++) {
final long delta = mRandom.nextLong(retention);
if (timestamps.add(firstWakeup + delta)) {
- obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_SENSOR_IRQ);
}
}
assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());
- obj.noteWakeupTimeAndReason(firstWakeup + retention + 1242, 231,
- KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(firstWakeup + retention, 231, KERNEL_REASON_WIFI_IRQ);
assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());
for (int i = 0; i < 100; i++) {
final long now = mRandom.nextLong(retention + 1, 100 * retention);
- obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_SOUND_TRIGGER_IRQ);
assertThat(obj.mWakeupEvents.closestIndexOnOrBefore(now - retention)).isLessThan(0);
}
}
@@ -201,9 +198,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3, TEST_UID_5);
@@ -234,9 +231,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, wakeupTime + 5, TEST_UID_3,
TEST_UID_5);
@@ -268,9 +265,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 3, TEST_UID_4, TEST_UID_5);
@@ -300,9 +297,9 @@
// Alarm activity
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4,
@@ -311,9 +308,9 @@
// Wifi activity
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_4);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_4);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_3);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_3);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 1, TEST_UID_2,
@@ -347,33 +344,67 @@
}
@Test
- public void unknownIrqAttribution() {
+ public void unknownIrqSoloIgnored() {
final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long wakeupTime = 92123410;
obj.noteWakeupTimeAndReason(wakeupTime, 24, KERNEL_REASON_UNKNOWN_IRQ);
- assertThat(obj.mWakeupEvents.size()).isEqualTo(1);
+ assertThat(obj.mWakeupEvents.size()).isEqualTo(0);
- // Unrelated subsystems, should not be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 3, TEST_UID_4,
TEST_UID_5);
- final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
- assertThat(attribution).isNotNull();
- assertThat(attribution.size()).isEqualTo(1);
- assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue();
- final SparseIntArray uidProcStates = attribution.get(CPU_WAKEUP_SUBSYSTEM_UNKNOWN);
- assertThat(uidProcStates == null || uidProcStates.size() == 0).isTrue();
+ // Any nearby activity should not end up in the attribution map.
+ assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
}
@Test
- public void unknownWakeupIgnored() {
+ public void unknownAndWifiAttribution() {
+ final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
+ final long wakeupTime = 92123410;
+
+ populateDefaultProcStates(obj);
+
+ obj.noteWakeupTimeAndReason(wakeupTime, 24,
+ KERNEL_REASON_UNKNOWN_IRQ + ":" + KERNEL_REASON_WIFI_IRQ);
+
+ // Wifi activity
+ // Outside the window, so should be ignored.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_4);
+ // Should be attributed
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1);
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 1, TEST_UID_3,
+ TEST_UID_5);
+
+ // Unrelated, should be ignored.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
+
+ final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
+ assertThat(attribution).isNotNull();
+ assertThat(attribution.size()).isEqualTo(2);
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue();
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(
+ TEST_PROC_STATE_1);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).indexOfKey(TEST_UID_2)).isLessThan(0);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(
+ TEST_PROC_STATE_3);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).indexOfKey(TEST_UID_4)).isLessThan(0);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(
+ TEST_PROC_STATE_5);
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue();
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isNull();
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_ALARM)).isFalse();
+ }
+
+ @Test
+ public void unknownFormatWakeupIgnored() {
final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long wakeupTime = 72123210;
- obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN);
+ obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN_FORMAT);
// Should be ignored as this type of wakeup is not known.
assertThat(obj.mWakeupEvents.size()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
index cba7dbe..b02618e 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
@@ -28,8 +28,11 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.ThreadLocalRandom;
+
@RunWith(AndroidJUnit4.class)
public class WakingActivityHistoryTest {
+ private volatile long mTestRetention = 54;
private static boolean areSame(SparseIntArray a, SparseIntArray b) {
if (a == b) {
@@ -55,7 +58,7 @@
@Test
public void recordActivityAppendsUids() {
- final WakingActivityHistory history = new WakingActivityHistory();
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
final int subsystem = 42;
final long timestamp = 54;
@@ -100,7 +103,7 @@
@Test
public void recordActivityDoesNotDeleteExistingUids() {
- final WakingActivityHistory history = new WakingActivityHistory();
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
final int subsystem = 42;
long timestamp = 101;
@@ -151,4 +154,120 @@
assertThat(recordedUids.get(62, -1)).isEqualTo(31);
assertThat(recordedUids.get(85, -1)).isEqualTo(39);
}
+
+ @Test
+ public void removeBetween() {
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
+
+ final int subsystem = 43;
+
+ final SparseIntArray uids = new SparseIntArray();
+ uids.put(1, 17);
+ uids.put(15, 2);
+ uids.put(62, 31);
+ history.recordActivity(subsystem, 123, uids);
+
+ uids.put(54, 91);
+ history.recordActivity(subsystem, 150, uids);
+
+ uids.put(101, 32);
+ uids.delete(1);
+ history.recordActivity(subsystem, 191, uids);
+
+ SparseIntArray removedUids = history.removeBetween(subsystem, 100, 122);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 124, 149);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 151, 190);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 192, 240);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+
+ // Removing from a different subsystem should do nothing.
+ removedUids = history.removeBetween(subsystem + 1, 0, 300);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 0, 300);
+ assertThat(removedUids.size()).isEqualTo(5);
+ assertThat(removedUids.get(1, -1)).isEqualTo(17);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(0);
+
+ history.recordActivity(subsystem, 23, uids);
+ uids.put(31, 123);
+ history.recordActivity(subsystem, 49, uids);
+ uids.put(177, 432);
+ history.recordActivity(subsystem, 89, uids);
+
+ removedUids = history.removeBetween(subsystem, 23, 23);
+ assertThat(removedUids.size()).isEqualTo(4);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(2);
+
+ removedUids = history.removeBetween(subsystem, 49, 54);
+ assertThat(removedUids.size()).isEqualTo(5);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+ assertThat(removedUids.get(31, -1)).isEqualTo(123);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(1);
+
+ removedUids = history.removeBetween(subsystem, 23, 89);
+ assertThat(removedUids.size()).isEqualTo(6);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+ assertThat(removedUids.get(31, -1)).isEqualTo(123);
+ assertThat(removedUids.get(177, -1)).isEqualTo(432);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void deletesActivityPastRetention() {
+ final WakingActivityHistory history = new WakingActivityHistory(() -> mTestRetention);
+ final int subsystem = 49;
+
+ mTestRetention = 454;
+
+ final long firstTime = 342;
+ for (int i = 0; i < mTestRetention; i++) {
+ history.recordActivity(subsystem, firstTime + i, new SparseIntArray());
+ }
+ assertThat(history.mWakingActivity.get(subsystem)).isNotNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(mTestRetention);
+
+ history.recordActivity(subsystem, firstTime + mTestRetention + 7, new SparseIntArray());
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(mTestRetention - 7);
+
+ final ThreadLocalRandom random = ThreadLocalRandom.current();
+
+ for (int i = 0; i < 100; i++) {
+ final long time = random.nextLong(firstTime + mTestRetention + 100,
+ 456 * mTestRetention);
+ history.recordActivity(subsystem, time, new SparseIntArray());
+ assertThat(history.mWakingActivity.get(subsystem).closestIndexOnOrBefore(
+ time - mTestRetention)).isLessThan(0);
+ }
+ }
}
diff --git a/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java b/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java
index 7d9a6a5..d16e90e 100644
--- a/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java
+++ b/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java
@@ -37,9 +37,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -54,7 +54,7 @@
private LocaleStore.LocaleInfo mAppCurrentLocale;
private Set<LocaleInfo> mAllAppActiveLocales;
private Set<LocaleInfo> mImeLocales;
- private List<LocaleInfo> mSystemCurrentLocales;
+ private Set<LocaleInfo> mSystemCurrentLocales;
private Set<LocaleInfo> mSystemSupportedLocales;
private AppLocaleStore.AppLocaleResult mResult;
private static final String PKG1 = "pkg1";
@@ -73,14 +73,6 @@
public void setUp() throws Exception {
mAppLocaleCollector = spy(
new AppLocaleCollector(InstrumentationRegistry.getContext(), PKG1));
-
- mAppCurrentLocale = createLocaleInfo("en-US", CURRENT);
- mAllAppActiveLocales = initAllAppActivatedLocales();
- mImeLocales = initImeLocales();
- mSystemSupportedLocales = initSystemSupportedLocales();
- mSystemCurrentLocales = initSystemCurrentLocales();
- mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG,
- initAppSupportedLocale());
}
@Test
@@ -88,7 +80,7 @@
LocaleList.setDefault(
LocaleList.forLanguageTags("en-US-u-mu-fahrenhe,ar-JO-u-mu-fahrenhe-nu-latn"));
- List<LocaleStore.LocaleInfo> list =
+ Set<LocaleStore.LocaleInfo> list =
mAppLocaleCollector.getSystemCurrentLocales();
LocaleList expected = LocaleList.forLanguageTags("en-US,ar-JO-u-nu-latn");
@@ -99,7 +91,69 @@
}
@Test
- public void testGetSupportedLocaleList() {
+ public void testGetSupportedLocaleList_filterNonAppsupportedSystemLanguage() {
+ mAppCurrentLocale = createLocaleInfo("en-US", CURRENT);
+
+ // App supports five locales
+ HashSet<Locale> appSupported =
+ getAppSupportedLocales(new String[] {
+ "en-US",
+ "fr",
+ "ar",
+ "es",
+ "bn"
+ });
+ // There are six locales in system current locales.
+ mSystemCurrentLocales = getSystemCurrentLocales(new String[] {
+ "en-US",
+ "fr-FR",
+ "ar-JO",
+ "ca-AD",
+ "da-DK",
+ "es-US"
+ });
+ mAllAppActiveLocales = Collections.emptySet();
+ mImeLocales = Collections.emptySet();
+ mSystemSupportedLocales = Collections.emptySet();
+ mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG,
+ appSupported);
+
+ doReturn(mAppCurrentLocale).when(mAppLocaleCollector).getAppCurrentLocale();
+ doReturn(mResult).when(mAppLocaleCollector).getAppSupportedLocales();
+ doReturn(mAllAppActiveLocales).when(mAppLocaleCollector).getAllAppActiveLocales();
+ doReturn(mImeLocales).when(mAppLocaleCollector).getActiveImeLocales();
+ doReturn(mSystemSupportedLocales).when(mAppLocaleCollector).getSystemSupportedLocale(
+ anyObject(), eq(null), eq(true));
+ doReturn(mSystemCurrentLocales).when(
+ mAppLocaleCollector).getSystemCurrentLocales();
+
+ Set<LocaleInfo> result = mAppLocaleCollector.getSupportedLocaleList(null, true, false);
+
+ // The result would show four rather than six locales in the suggested region.
+ HashMap<String, Integer> expectedResult = new HashMap<>();
+ expectedResult.put("en-US", CURRENT); // The locale current App activates.
+ expectedResult.put("ar-JO", SYSTEM_AVAILABLE);
+ expectedResult.put("fr-FR", SYSTEM_AVAILABLE);
+ expectedResult.put("es-US", SYSTEM_AVAILABLE);
+ expectedResult.put(createLocaleInfo("", SYSTEM).getId(), SYSTEM); // System language title
+
+ assertEquals(result.size(), expectedResult.size());
+ for (LocaleStore.LocaleInfo info: result) {
+ int suggestionFlags = expectedResult.getOrDefault(info.getId(), -1);
+ assertEquals(info.mSuggestionFlags, suggestionFlags);
+ }
+ }
+
+ @Test
+ public void testGetSupportedLocaleList_withActiveLocalesFromOtherAppAndIme() {
+ mAppCurrentLocale = createLocaleInfo("en-US", CURRENT);
+ mAllAppActiveLocales = initAllAppActivatedLocales();
+ mImeLocales = initImeLocales();
+ mSystemSupportedLocales = initSystemSupportedLocales();
+ mSystemCurrentLocales = initSystemCurrentLocales();
+ mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG,
+ initAppSupportedLocale());
+
doReturn(mAppCurrentLocale).when(mAppLocaleCollector).getAppCurrentLocale();
doReturn(mResult).when(mAppLocaleCollector).getAppSupportedLocales();
doReturn(mAllAppActiveLocales).when(mAppLocaleCollector).getAllAppActiveLocales();
@@ -147,8 +201,8 @@
);
}
- private List<LocaleInfo> initSystemCurrentLocales() {
- return List.of(createLocaleInfo("zh-Hant-TW", SYSTEM_AVAILABLE),
+ private Set<LocaleInfo> initSystemCurrentLocales() {
+ return Set.of(createLocaleInfo("zh-Hant-TW", SYSTEM_AVAILABLE),
createLocaleInfo("ja-JP", SYSTEM_AVAILABLE),
// will be filtered because current App activates this locale.
createLocaleInfo("en-US", SYSTEM_AVAILABLE));
@@ -188,6 +242,22 @@
return hs;
}
+ private Set<LocaleStore.LocaleInfo> getSystemCurrentLocales(String []languageTags) {
+ HashSet<LocaleStore.LocaleInfo> hs = new HashSet<>(languageTags.length);
+ for (String tag:languageTags) {
+ hs.add(createLocaleInfo(tag, SYSTEM_AVAILABLE));
+ }
+ return hs;
+ }
+
+ private HashSet<Locale> getAppSupportedLocales(String []languageTags) {
+ HashSet<Locale> hs = new HashSet<>(languageTags.length);
+ for (String language:languageTags) {
+ hs.add(Locale.forLanguageTag(language));
+ }
+ return hs;
+ }
+
private LocaleInfo createLocaleInfo(String languageTag, int suggestionFlag) {
LocaleInfo localeInfo = LocaleStore.fromLocale(Locale.forLanguageTag(languageTag));
localeInfo.mSuggestionFlags = suggestionFlag;