Merge "Allow System ChooserActivity to start home activity" into qt-r1-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index a3ef9c4..87295fa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -54,6 +54,7 @@
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method public long getTotalRam();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+ method public static boolean isHighEndGfx();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 17368b7..91b98c7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -925,7 +925,7 @@
* (which tends to consume a lot more RAM).
* @hide
*/
- @UnsupportedAppUsage
+ @TestApi
static public boolean isHighEndGfx() {
return !isLowRamDeviceStatic()
&& !RoSystemProperties.CONFIG_AVOID_GFX_ACCEL
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index caab00c..775ec99 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -300,5 +300,5 @@
/**
* Called when the system gesture exclusion has changed.
*/
- void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
+ oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e44c5f7..4eee1db 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1115,6 +1115,22 @@
regularly selected color mode will be used if this value is negative. -->
<integer name="config_accessibilityColorMode">-1</integer>
+ <!-- The following two arrays specify which color space to use for display composition when a
+ certain color mode is active.
+ Composition color spaces are defined in android.view.Display.COLOR_MODE_xxx, and color
+ modes are defined in ColorDisplayManager.COLOR_MODE_xxx and
+ ColorDisplayManager.VENDOR_COLOR_MODE_xxx.
+ The color space COLOR_MODE_DEFAULT (0) lets the system select the most appropriate
+ composition color space for currently displayed content. Other values (e.g.,
+ COLOR_MODE_SRGB) override system selection; these other color spaces must be supported by
+ the device for for display composition.
+ If a color mode does not have a corresponding color space specified in this array, the
+ currently set composition color space will not be modified.-->
+ <integer-array name="config_displayCompositionColorModes">
+ </integer-array>
+ <integer-array name="config_displayCompositionColorSpaces">
+ </integer-array>
+
<!-- Indicate whether to allow the device to suspend when the screen is off
due to the proximity sensor. This resource should only be set to true
if the sensor HAL correctly handles the proximity sensor as a wake-up source.
@@ -4129,8 +4145,27 @@
for higher refresh rates to be automatically used out of the box -->
<integer name="config_defaultPeakRefreshRate">60</integer>
- <!-- The default brightness threshold that allows to switch to higher refresh rate -->
- <integer name="config_brightnessThresholdOfPeakRefreshRate">-1</integer>
+ <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+ vendor to tune the curves to have exact same brightness for different refresh rate. So
+ flicker could be observed at switch time. The issue is worse at the gamma lower end.
+ In addition, human eyes are more sensitive to the flicker at darker environment.
+ To prevent flicker, we only support higher refresh rates if the display brightness is above
+ a threshold. And the darker environment could have higher threshold.
+ For example, no higher refresh rate if
+ display brightness <= disp0 && ambient brightness <= amb0
+ || display brightness <= disp1 && ambient brightness <= amb1 -->
+ <integer-array translatable="false" name="config_brightnessThresholdsOfPeakRefreshRate">
+ <!--
+ <item>disp0</item>
+ <item>disp1</item>
+ -->
+ </integer-array>
+ <integer-array translatable="false" name="config_ambientThresholdsOfPeakRefreshRate">
+ <!--
+ <item>amb0</item>
+ <item>amb1</item>
+ -->
+ </integer-array>
<!-- The type of the light sensor to be used by the display framework for things like
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e19d1697..d13c715 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3192,6 +3192,8 @@
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
<java-symbol type="array" name="config_availableColorModes" />
<java-symbol type="integer" name="config_accessibilityColorMode" />
+ <java-symbol type="array" name="config_displayCompositionColorModes" />
+ <java-symbol type="array" name="config_displayCompositionColorSpaces" />
<java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
<java-symbol type="bool" name="config_displayWhiteBalanceEnabledDefault" />
<java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
@@ -3788,7 +3790,8 @@
<!-- For high refresh rate displays -->
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
- <java-symbol type="integer" name="config_brightnessThresholdOfPeakRefreshRate" />
+ <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
+ <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
<!-- For Auto-Brightness -->
<java-symbol type="string" name="config_displayLightSensorType" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 28d5402..52ec1f0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -30,7 +30,7 @@
*/
@ProvidesInterface(version = FalsingManager.VERSION)
public interface FalsingManager {
- int VERSION = 1;
+ int VERSION = 2;
void onSucccessfulUnlock();
@@ -103,4 +103,6 @@
void onTouchEvent(MotionEvent ev, int width, int height);
void dump(PrintWriter pw);
+
+ void cleanup();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 69630c4..c7c648c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -237,6 +237,7 @@
MIN_DRAG_SIZE, getResources().getDisplayMetrics())
&& !mUpdateMonitor.isFaceDetectionRunning()) {
mUpdateMonitor.requestFaceAuth();
+ mCallback.userActivity();
showMessage(null, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 67dfdca..fba0d50 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -168,6 +168,7 @@
.append("enabled=").append(isEnabled() ? 1 : 0)
.append(" mScreenOn=").append(mScreenOn ? 1 : 0)
.append(" mState=").append(StatusBarState.toShortString(mState))
+ .append(" mShowingAod=").append(mShowingAod ? 1 : 0)
.toString()
);
}
@@ -550,6 +551,14 @@
pw.println();
}
+ @Override
+ public void cleanup() {
+ mSensorManager.unregisterListener(mSensorEventListener);
+ mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+ Dependency.get(StatusBarStateController.class).removeCallback(mStatusBarStateListener);
+ KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mKeyguardUpdateCallback);
+ }
+
public Uri reportRejectedTouch() {
if (mDataCollector.isEnabled()) {
return mDataCollector.reportRejectedTouch();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 3cc8ec9a..8210951 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -65,6 +65,7 @@
public void onPluginConnected(FalsingPlugin plugin, Context context) {
FalsingManager pluginFalsingManager = plugin.getFalsingManager(context);
if (pluginFalsingManager != null) {
+ mInternalFalsingManager.cleanup();
mInternalFalsingManager = pluginFalsingManager;
}
}
@@ -290,4 +291,9 @@
public void dump(PrintWriter pw) {
mInternalFalsingManager.dump(pw);
}
+
+ @Override
+ public void cleanup() {
+ mInternalFalsingManager.cleanup();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 00f35aa..cee01a4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -324,6 +324,11 @@
public void dump(PrintWriter printWriter) {
}
+ @Override
+ public void cleanup() {
+ unregisterSensors();
+ }
+
static void logDebug(String msg) {
logDebug(msg, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3c9d4a9..ae6dac5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -50,9 +50,23 @@
*/
void onSlpiTap(float x, float y);
+ /**
+ * Artificially dim down the the display by changing scrim opacities.
+ * @param scrimOpacity opacity from 0 to 1.
+ */
default void setAodDimmingScrim(float scrimOpacity) {}
+
+ /**
+ * Sets the actual display brightness.
+ * @param value from 0 to 255.
+ */
void setDozeScreenBrightness(int value);
+ /**
+ * Makes scrims black and changes animation durations.
+ */
+ default void prepareForGentleWakeUp() {}
+
void onIgnoreTouchWhilePulsing(boolean ignore);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 5be097c..38ee2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -82,7 +82,10 @@
boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
boolean pulseEnding = oldState == DozeMachine.State.DOZE_PULSE_DONE
&& newState == DozeMachine.State.DOZE_AOD;
- if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) {
+ boolean turningOn = (oldState == DozeMachine.State.DOZE_AOD_PAUSED
+ || oldState == DozeMachine.State.DOZE) && newState == DozeMachine.State.DOZE_AOD;
+ boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
+ if (messagePending || justInitialized || pulseEnding || turningOn) {
// During initialization, we hide the navigation bar. That is however only applied after
// a traversal; setting the screen state here is immediate however, so it can happen
// that the screen turns on again before the navigation bar is hidden. To work around
@@ -91,7 +94,7 @@
// Delay screen state transitions even longer while animations are running.
boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD
- && mParameters.shouldControlScreenOff();
+ && mParameters.shouldControlScreenOff() && !turningOn;
if (shouldDelayTransition) {
mWakeLock.setAcquired(true);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index cf04b7f..6918501 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -198,7 +198,10 @@
updateListening();
}
- private void updateListening() {
+ /**
+ * Registers/unregisters sensors based on internal state.
+ */
+ public void updateListening() {
boolean anyListening = false;
for (TriggerSensor s : mSensors) {
// We don't want to be listening while we're PAUSED (prox sensor is covered)
@@ -231,7 +234,7 @@
public void onUserSwitched() {
for (TriggerSensor s : mSensors) {
- s.updateListener();
+ s.updateListening();
}
}
@@ -246,7 +249,7 @@
return;
}
for (TriggerSensor s : mSensors) {
- s.updateListener();
+ s.updateListening();
}
}
};
@@ -409,22 +412,22 @@
public void setListening(boolean listen) {
if (mRequested == listen) return;
mRequested = listen;
- updateListener();
+ updateListening();
}
public void setDisabled(boolean disabled) {
if (mDisabled == disabled) return;
mDisabled = disabled;
- updateListener();
+ updateListening();
}
public void ignoreSetting(boolean ignored) {
if (mIgnoresSetting == ignored) return;
mIgnoresSetting = ignored;
- updateListener();
+ updateListening();
}
- public void updateListener() {
+ public void updateListening() {
if (!mConfigured || mSensor == null) return;
if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
&& !mRegistered) {
@@ -480,7 +483,7 @@
mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
event.values);
if (!mRegistered) {
- updateListener(); // reregister, this sensor only fires once
+ updateListening(); // reregister, this sensor only fires once
}
}));
}
@@ -541,7 +544,7 @@
}
@Override
- public void updateListener() {
+ public void updateListening() {
if (!mConfigured) return;
AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 97b08d5..8ef01e8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -201,7 +201,7 @@
// Let's prepare the display to wake-up by drawing black.
// This will cover the hardware wake-up sequence, where the display
// becomes black for a few frames.
- mDozeHost.setAodDimmingScrim(255f);
+ mDozeHost.setAodDimmingScrim(1f);
}
mMachine.wakeUp();
}
@@ -314,6 +314,9 @@
break;
case DOZE_PULSE_DONE:
mDozeSensors.requestTemporaryDisable();
+ // A pulse will temporarily disable sensors that require a touch screen.
+ // Let's make sure that they are re-enabled when the pulse is over.
+ mDozeSensors.updateListening();
break;
case FINISH:
mBroadcastReceiver.unregister(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 51e96d2..e877d44 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -130,6 +130,7 @@
break;
case DOZE:
case DOZE_AOD_PAUSED:
+ mHost.prepareForGentleWakeUp();
unscheduleTimeTick();
break;
case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index bc7174d..930f57e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -260,6 +260,7 @@
boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
biometricSourceType);
if (unlockAllowed) {
+ mKeyguardViewMediator.userActivity();
startWakeAndUnlock(biometricSourceType);
} else {
Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
@@ -466,8 +467,11 @@
}
if (mStatusBarKeyguardViewManager.isShowing()) {
if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
- return bypass && !mKeyguardBypassController.canPlaySubtleWindowAnimations()
- ? MODE_UNLOCK_COLLAPSING : MODE_UNLOCK_FADING;
+ if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
+ return MODE_UNLOCK_FADING;
+ } else {
+ return MODE_DISMISS_BOUNCER;
+ }
} else if (unlockingAllowed) {
return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
} else {
@@ -567,6 +571,13 @@
}
/**
+ * Successful authentication with fingerprint, face, or iris when the lockscreen fades away
+ */
+ public boolean isUnlockFading() {
+ return mMode == MODE_UNLOCK_FADING;
+ }
+
+ /**
* Translates biometric source type for logging purpose.
*/
private int toSubtype(BiometricSourceType biometricSourceType) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index c88b22b..0aec2b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -167,4 +167,8 @@
pw.print(" qSExpanded: "); pw.println(qSExpanded)
pw.print(" bouncerShowing: "); pw.println(bouncerShowing)
}
+
+ companion object {
+ const val BYPASS_PANEL_FADE_DURATION = 67
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f38c04..1aec5e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -487,6 +487,20 @@
}
/**
+ * Set front scrim to black, cancelling animations, in order to prepare to fade them
+ * away once the display turns on.
+ */
+ public void prepareForGentleWakeUp() {
+ if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) {
+ mCurrentInFrontAlpha = 1f;
+ mAnimateChange = false;
+ updateScrims();
+ mAnimateChange = true;
+ mAnimationDuration = ANIMATION_DURATION_LONG;
+ }
+ }
+
+ /**
* If the lock screen sensor is active.
*/
public void setWakeLockScreenSensorActive(boolean active) {
@@ -932,6 +946,12 @@
}
}
+ public void setUnlockIsFading(boolean unlockFading) {
+ for (ScrimState state : ScrimState.values()) {
+ state.setUnlockIsFading(unlockFading);
+ }
+ }
+
public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
for (ScrimState state : ScrimState.values()) {
state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index d152ecd..763e0d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -147,7 +147,9 @@
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
mCurrentInFrontAlpha = 0;
- mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+ mAnimationDuration = mUnlockIsFading
+ ? KeyguardBypassController.BYPASS_PANEL_FADE_DURATION
+ : StatusBar.FADE_KEYGUARD_DURATION;
mAnimateChange = !mLaunchingAffordanceWithPreview;
if (previousState == ScrimState.AOD) {
@@ -198,6 +200,7 @@
boolean mHasBackdrop;
boolean mLaunchingAffordanceWithPreview;
boolean mWakeLockScreenSensorActive;
+ boolean mUnlockIsFading;
ScrimState(int index) {
mIndex = index;
@@ -285,4 +288,8 @@
public void setWakeLockScreenSensorActive(boolean active) {
mWakeLockScreenSensorActive = active;
}
+
+ public void setUnlockIsFading(boolean unlockIsFading) {
+ mUnlockIsFading = unlockIsFading;
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index fb8eca1..9e6454e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3840,6 +3840,7 @@
public void notifyBiometricAuthModeChanged() {
updateDozing();
+ mScrimController.setUnlockIsFading(mBiometricUnlockController.isUnlockFading());
updateScrimController();
mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock(),
mBiometricUnlockController.isBiometricUnlock());
@@ -3851,7 +3852,8 @@
// We don't want to end up in KEYGUARD state when we're unlocking with
// fingerprint from doze. We should cross fade directly from black.
- boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
+ boolean unlocking = mBiometricUnlockController.isWakeAndUnlock()
+ || mKeyguardMonitor.isKeyguardFadingAway();
// Do not animate the scrim expansion when triggered by the fingerprint sensor.
mScrimController.setExpansionAffectsAlpha(
@@ -3876,9 +3878,9 @@
} else if (isPulsing()) {
mScrimController.transitionTo(ScrimState.PULSING,
mDozeScrimController.getScrimCallback());
- } else if (mDozing && !wakeAndUnlocking) {
+ } else if (mDozing && !unlocking) {
mScrimController.transitionTo(ScrimState.AOD);
- } else if (mIsKeyguard && !wakeAndUnlocking) {
+ } else if (mIsKeyguard && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else if (mBubbleController.isStackExpanded()) {
mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
@@ -4119,6 +4121,11 @@
mScrimController.setAodFrontScrimAlpha(scrimOpacity);
}
+ @Override
+ public void prepareForGentleWakeUp() {
+ mScrimController.prepareForGentleWakeUp();
+ }
+
private void dispatchTap(View view, float x, float y) {
long now = SystemClock.elapsedRealtime();
dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
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 da85039..1321784 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,7 +84,6 @@
// make everything a bit slower to bridge a gap until the user is unlocked and home screen has
// dranw its first frame.
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
- private static final long BYPASS_PANEL_FADE_DURATION = 67;
private static String TAG = "StatusBarKeyguardViewManager";
@@ -269,7 +268,7 @@
boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& !mNotificationPanelView.isQsExpanded();
boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
- && !mBouncer.isAnimatingAway();
+ && !mBouncer.isAnimatingAway() && !mKeyguardMonitor.isKeyguardFadingAway();
if (mLastLockVisible != lockVisible) {
mLastLockVisible = lockVisible;
@@ -278,8 +277,14 @@
AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
0 /* delay */);
} else {
+ final long duration;
+ if (needsBypassFading()) {
+ duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+ } else {
+ duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2;
+ }
CrossFadeHelper.fadeOut(mLockIconContainer,
- AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2 /* duration */,
+ duration /* duration */,
0 /* delay */, null /* runnable */);
}
}
@@ -566,7 +571,7 @@
if (needsBypassFading()) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
- BYPASS_PANEL_FADE_DURATION,
+ KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
() -> {
mStatusBar.hideKeyguard();
onKeyguardFadedAway();
@@ -582,7 +587,7 @@
if (needsBypassFading()) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
- BYPASS_PANEL_FADE_DURATION,
+ KeyguardBypassController.BYPASS_PANEL_FADE_DURATION,
() -> {
mStatusBar.hideKeyguard();
});
@@ -601,6 +606,7 @@
mBiometricUnlockController.finishKeyguardFadingAway();
}
}
+ updateLockIcon();
updateStates();
mStatusBarWindowController.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 2d6ae26..2ed0970 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.withSettings;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.utils.hardware.FakeSensorManager;
import org.mockito.Answers;
import org.mockito.MockSettings;
@@ -39,6 +40,7 @@
when(params.getPickupPerformsProxCheck()).thenReturn(true);
when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
+ when(params.getDisplayNeedsBlanking()).thenReturn(false);
doneHolder[0] = true;
return params;
@@ -52,11 +54,17 @@
when(config.pickupGestureEnabled(anyInt())).thenReturn(false);
when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
when(config.alwaysOnEnabled(anyInt())).thenReturn(false);
+ when(config.enabled(anyInt())).thenReturn(true);
+ when(config.getWakeLockScreenDebounce()).thenReturn(0L);
when(config.doubleTapSensorType()).thenReturn(null);
when(config.tapSensorType()).thenReturn(null);
when(config.longPressSensorType()).thenReturn(null);
+ when(config.tapGestureEnabled(anyInt())).thenReturn(true);
+ when(config.tapSensorAvailable()).thenReturn(true);
+ when(config.tapSensorType()).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE);
+
when(config.dozePickupSensorAvailable()).thenReturn(false);
when(config.wakeScreenGestureAvailable()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 6979fd8..eb8ef09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -19,6 +19,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -27,18 +28,17 @@
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
-import android.app.Instrumentation;
+import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -46,14 +46,12 @@
import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@Ignore("failing")
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
public class DozeTriggersTest extends SysuiTestCase {
private DozeTriggers mTriggers;
private DozeMachine mMachine;
@@ -61,10 +59,10 @@
private AmbientDisplayConfiguration mConfig;
private DozeParameters mParameters;
private FakeSensorManager mSensors;
+ private Sensor mTapSensor;
private WakeLock mWakeLock;
- private Instrumentation mInstrumentation;
private AlarmManager mAlarmManager;
- private DockManagerFake mDockManagerFake;
+ private DockManager mDockManagerFake;
@BeforeClass
public static void setupSuite() {
@@ -74,15 +72,15 @@
@Before
public void setUp() throws Exception {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
mMachine = mock(DozeMachine.class);
mAlarmManager = mock(AlarmManager.class);
- mHost = new DozeHostFake();
+ mHost = spy(new DozeHostFake());
mConfig = DozeConfigurationUtil.createMockConfig();
mParameters = DozeConfigurationUtil.createMockParameters();
- mSensors = new FakeSensorManager(mContext);
+ mSensors = spy(new FakeSensorManager(mContext));
+ mTapSensor = mSensors.getFakeTapSensor().getSensor();
mWakeLock = new WakeLockFake();
- mDockManagerFake = spy(new DockManagerFake());
+ mDockManagerFake = mock(DockManager.class);
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, mConfig, mParameters,
mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true,
@@ -95,29 +93,45 @@
mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+ clearInvocations(mMachine);
mHost.callback.onNotificationAlerted();
-
mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
mHost.callback.onNotificationAlerted();
-
mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
verify(mMachine).requestPulse(anyInt());
}
@Test
+ public void testTransitionTo_disablesAndEnablesTouchSensors() {
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+ mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+ verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+
+ clearInvocations(mSensors);
+ mTriggers.transitionTo(DozeMachine.State.DOZE,
+ DozeMachine.State.DOZE_REQUEST_PULSE);
+ mTriggers.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
+ DozeMachine.State.DOZE_PULSING);
+ verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor));
+
+ clearInvocations(mSensors);
+ mTriggers.transitionTo(DozeMachine.State.DOZE_PULSING, DozeMachine.State.DOZE_PULSE_DONE);
+ verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+ }
+
+ @Test
public void testDockEventListener_registerAndUnregister() {
mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-
verify(mDockManagerFake).addListener(any());
mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
-
verify(mDockManagerFake).removeListener(any());
}
@@ -128,7 +142,6 @@
mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
null /* rawValues */);
-
verify(mMachine, never()).wakeUp();
}
@@ -142,7 +155,7 @@
false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
null /* rawValues */);
- verify(mHost).setAodDimmingScrim(eq(255));
+ verify(mHost).setAodDimmingScrim(eq(1f));
verify(mMachine).wakeUp();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a99dc7f..7d9920d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -192,6 +194,34 @@
}
@Test
+ public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
+ reset(mKeyguardBypassController);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FACE);
+
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+ }
+
+ @Test
+ public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FACE);
+
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ assertThat(mBiometricUnlockController.getMode())
+ .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+ }
+
+ @Test
public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
reset(mUpdateMonitor);
reset(mStatusBarKeyguardViewManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
index a4ae166..29b8ab60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
@@ -40,18 +40,23 @@
import java.util.List;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
/**
* Rudimentary fake for SensorManager
*
- * Currently only supports the proximity sensor.
+ * Currently only supports proximity, light and tap sensors.
*
* Note that this class ignores the "Handler" argument, so the test is responsible for calling the
* listener on the right thread.
*/
public class FakeSensorManager extends SensorManager {
+ public static final String TAP_SENSOR_TYPE = "tapSensorType";
+
private final MockProximitySensor mMockProximitySensor;
private final FakeGenericSensor mFakeLightSensor;
+ private final FakeGenericSensor mFakeTapSensor;
private final FakeGenericSensor[] mSensors;
public FakeSensorManager(Context context) throws Exception {
@@ -59,12 +64,13 @@
.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (proxSensor == null) {
// No prox? Let's create a fake one!
- proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
+ proxSensor = createSensor(Sensor.TYPE_PROXIMITY, null);
}
mSensors = new FakeGenericSensor[]{
mMockProximitySensor = new MockProximitySensor(proxSensor),
- mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT)),
+ mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)),
+ mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE))
};
}
@@ -76,6 +82,10 @@
return mFakeLightSensor;
}
+ public FakeGenericSensor getFakeTapSensor() {
+ return mFakeTapSensor;
+ }
+
@Override
public Sensor getDefaultSensor(int type) {
Sensor s = super.getDefaultSensor(type);
@@ -160,13 +170,13 @@
@Override
protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
- return false;
+ return true;
}
@Override
protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
boolean disable) {
- return false;
+ return true;
}
@Override
@@ -185,12 +195,15 @@
return false;
}
- private Sensor createSensor(int type) throws Exception {
+ private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
constr.setAccessible(true);
Sensor sensor = constr.newInstance();
setSensorType(sensor, type);
+ if (stringType != null) {
+ setSensorField(sensor, "mStringType", stringType);
+ }
setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
setSensorField(sensor, "mVendor", "Mock Vendor");
setSensorField(sensor, "mVersion", 1);
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 9bbc315..8e5c73bf 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -16,33 +16,33 @@
package com.android.server;
+import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
+import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT;
+import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
+import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT;
+import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
+import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT;
+
import android.content.Context;
+import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.UEventObserver;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
-import android.media.AudioManager;
-import android.util.Log;
import android.view.InputDevice;
import com.android.internal.R;
import com.android.server.input.InputManagerService;
import com.android.server.input.InputManagerService.WiredAccessoryCallbacks;
-import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
-import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
-import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
-import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT;
-import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT;
-import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT;
-
import java.io.File;
-import java.io.FileReader;
import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -538,7 +538,7 @@
synchronized (mLock) {
int mask = maskAndState.first;
int state = maskAndState.second;
- updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state));
+ updateLocked(name, mHeadsetState & ~(mask & ~state) | (mask & state));
return;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 884ecba..350df11 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -123,6 +123,8 @@
/*package*/ void onAudioServerDied() {
// Restore forced usage for communications and record
synchronized (mDeviceStateLock) {
+ AudioSystem.setParameters(
+ "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off"));
onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4b08db6..7e2dcae 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5577,6 +5577,7 @@
/**
* @return true if there is currently a registered dynamic mixing policy that affects media
+ * and is not a render + loopback policy
*/
/*package*/ boolean hasMediaDynamicPolicy() {
synchronized (mAudioPolicies) {
@@ -5585,7 +5586,8 @@
}
final Collection<AudioPolicyProxy> appColl = mAudioPolicies.values();
for (AudioPolicyProxy app : appColl) {
- if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA)) {
+ if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA,
+ AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER)) {
return true;
}
}
@@ -7348,9 +7350,10 @@
Binder.restoreCallingIdentity(identity);
}
- boolean hasMixAffectingUsage(int usage) {
+ boolean hasMixAffectingUsage(int usage, int excludedFlags) {
for (AudioMix mix : mMixes) {
- if (mix.isAffectingUsage(usage)) {
+ if (mix.isAffectingUsage(usage)
+ && ((mix.getRouteFlags() & excludedFlags) != excludedFlags)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 99341d1..4f33ebb0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -303,6 +303,8 @@
private final Spline mMinimumBrightnessSpline;
private final ColorSpace mWideColorSpace;
+ private SensorManager mSensorManager;
+
public DisplayManagerService(Context context) {
this(context, new Injector());
}
@@ -430,7 +432,7 @@
}
mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
- mDisplayModeDirector.start();
+ mDisplayModeDirector.start(mSensorManager);
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
@@ -2358,6 +2360,7 @@
};
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
+ mSensorManager = sensorManager;
}
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 14bd2d8..78a48da 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,41 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
+import android.os.PowerManager;
+import android.os.SystemClock;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.R;
+import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
+import com.android.server.display.whitebalance.AmbientFilter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -74,7 +89,7 @@
private final AppRequestObserver mAppRequestObserver;
private final SettingsObserver mSettingsObserver;
private final DisplayObserver mDisplayObserver;
-
+ private final BrightnessObserver mBrightnessObserver;
private Listener mListener;
@@ -87,6 +102,8 @@
mAppRequestObserver = new AppRequestObserver();
mSettingsObserver = new SettingsObserver(context, handler);
mDisplayObserver = new DisplayObserver(context, handler);
+ mBrightnessObserver = new BrightnessObserver(context, handler);
+
}
/**
@@ -96,15 +113,17 @@
* This has to be deferred because the object may be constructed before the rest of the system
* is ready.
*/
- public void start() {
+ public void start(SensorManager sensorManager) {
mSettingsObserver.observe();
mDisplayObserver.observe();
mSettingsObserver.observe();
+ mBrightnessObserver.observe(sensorManager);
synchronized (mLock) {
// We may have a listener already registered before the call to start, so go ahead and
// notify them to pick up our newly initialized state.
notifyAllowedModesChangedLocked();
}
+
}
/**
@@ -315,6 +334,7 @@
}
mSettingsObserver.dumpLocked(pw);
mAppRequestObserver.dumpLocked(pw);
+ mBrightnessObserver.dumpLocked(pw);
}
}
@@ -486,20 +506,15 @@
Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
private final Uri mLowPowerModeSetting =
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
- private final Uri mBrightnessSetting =
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
private final Context mContext;
private final float mDefaultPeakRefreshRate;
- private final int mBrightnessThreshold;
SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
super(handler);
mContext = context;
mDefaultPeakRefreshRate = (float) context.getResources().getInteger(
R.integer.config_defaultPeakRefreshRate);
- mBrightnessThreshold = context.getResources().getInteger(
- R.integer.config_brightnessThresholdOfPeakRefreshRate);
}
public void observe() {
@@ -508,14 +523,9 @@
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
- if (mBrightnessThreshold >= 0) {
- cr.registerContentObserver(mBrightnessSetting, false /*notifyDescendants*/, this,
- UserHandle.USER_SYSTEM);
- }
synchronized (mLock) {
updateRefreshRateSettingLocked();
updateLowPowerModeSettingLocked();
- updateBrightnessSettingLocked();
}
}
@@ -526,8 +536,6 @@
updateRefreshRateSettingLocked();
} else if (mLowPowerModeSetting.equals(uri)) {
updateLowPowerModeSettingLocked();
- } else if (mBrightnessThreshold >=0 && mBrightnessSetting.equals(uri)) {
- updateBrightnessSettingLocked();
}
}
}
@@ -542,6 +550,7 @@
vote = null;
}
updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote);
+ mBrightnessObserver.onLowPowerModeEnabled(inLowPowerMode);
}
private void updateRefreshRateSettingLocked() {
@@ -549,23 +558,7 @@
Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
Vote vote = Vote.forRefreshRates(0f, peakRefreshRate);
updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote);
- }
-
- private void updateBrightnessSettingLocked() {
- int brightness = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, -1);
-
- if (brightness < 0) {
- return;
- }
-
- final Vote vote;
- if (brightness <= mBrightnessThreshold) {
- vote = Vote.forRefreshRates(0f, 60f);
- } else {
- vote = null;
- }
- updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+ mBrightnessObserver.onPeakRefreshRateEnabled(peakRefreshRate > 60f);
}
public void dumpLocked(PrintWriter pw) {
@@ -715,4 +708,240 @@
}
}
}
+
+ /**
+ * This class manages brightness threshold for switching between 60 hz and higher refresh rate.
+ * See more information at the definition of
+ * {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and
+ * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
+ */
+ private class BrightnessObserver extends ContentObserver {
+ private final Uri mDisplayBrightnessSetting =
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+
+ private final static int LIGHT_SENSOR_RATE_MS = 250;
+ private final int[] mDisplayBrightnessThresholds;
+ private final int[] mAmbientBrightnessThresholds;
+ // valid threshold if any item from the array >= 0
+ private boolean mShouldObserveDisplayChange;
+ private boolean mShouldObserveAmbientChange;
+
+ private SensorManager mSensorManager;
+ private Sensor mLightSensor;
+ // Take it as low brightness before valid sensor data comes
+ private float mAmbientLux = -1.0f;
+ private AmbientFilter mAmbientFilter;
+
+ private final Context mContext;
+ private ScreenStateReceiver mScreenStateReceiver;
+
+ // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
+ // off. After initialization, these states will be updated from the same handler thread.
+ private boolean mScreenOn = false;
+ private boolean mPeakRefreshRateEnabled = false;
+ private boolean mLowPowerModeEnabled = false;
+
+ BrightnessObserver(Context context, Handler handler) {
+ super(handler);
+ mContext = context;
+ mDisplayBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_brightnessThresholdsOfPeakRefreshRate);
+ mAmbientBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_ambientThresholdsOfPeakRefreshRate);
+ if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display brightness threshold array and ambient "
+ + "brightness threshold array have different length");
+ }
+
+ mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
+ mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
+ }
+
+ public void observe(SensorManager sensorManager) {
+ if (mShouldObserveDisplayChange) {
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(mDisplayBrightnessSetting,
+ false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+ }
+
+ if (mShouldObserveAmbientChange) {
+ Resources resources = mContext.getResources();
+ String lightSensorType = resources.getString(
+ com.android.internal.R.string.config_displayLightSensorType);
+
+ Sensor lightSensor = null;
+ if (!TextUtils.isEmpty(lightSensorType)) {
+ List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+ for (int i = 0; i < sensors.size(); i++) {
+ Sensor sensor = sensors.get(i);
+ if (lightSensorType.equals(sensor.getStringType())) {
+ lightSensor = sensor;
+ break;
+ }
+ }
+ }
+
+ if (lightSensor == null) {
+ lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+
+ if (lightSensor != null) {
+ final Resources res = mContext.getResources();
+
+ mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
+ mSensorManager = sensorManager;
+ mLightSensor = lightSensor;
+
+ // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
+ if (mContext.getSystemService(PowerManager.class).isInteractive()) {
+ onScreenOn(true);
+ }
+ mScreenStateReceiver = new ScreenStateReceiver(mContext);
+ }
+ }
+
+ if (mShouldObserveDisplayChange || mShouldObserveAmbientChange) {
+ synchronized (mLock) {
+ onBrightnessChangedLocked();
+ }
+ }
+ }
+
+ public void onPeakRefreshRateEnabled(boolean b) {
+ if (mShouldObserveAmbientChange && mPeakRefreshRateEnabled != b) {
+ mPeakRefreshRateEnabled = b;
+ updateSensorStatus();
+ }
+ }
+
+ public void onLowPowerModeEnabled(boolean b) {
+ if (mShouldObserveAmbientChange && mLowPowerModeEnabled != b) {
+ mLowPowerModeEnabled = b;
+ updateSensorStatus();
+ }
+ }
+
+ public void dumpLocked(PrintWriter pw) {
+ pw.println(" BrightnessObserver");
+
+ for (int d: mDisplayBrightnessThresholds) {
+ pw.println(" mDisplayBrightnessThreshold: " + d);
+ }
+
+ for (int d: mAmbientBrightnessThresholds) {
+ pw.println(" mAmbientBrightnessThreshold: " + d);
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ synchronized (mLock) {
+ onBrightnessChangedLocked();
+ }
+ }
+
+ /**
+ * Checks to see if at least one value is positive, in which case it is necessary to listen
+ * to value changes.
+ */
+ private boolean checkShouldObserve(int[] a) {
+ for (int d: a) {
+ if (d >= 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void onBrightnessChangedLocked() {
+ int brightness = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, -1);
+
+ Vote vote = null;
+ for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
+ int disp = mDisplayBrightnessThresholds[i];
+ int ambi = mAmbientBrightnessThresholds[i];
+
+ if (disp >= 0 && ambi >= 0) {
+ if (brightness <= disp && mAmbientLux <= ambi) {
+ vote = Vote.forRefreshRates(0f, 60f);
+ }
+ } else if (disp >= 0) {
+ if (brightness <= disp) {
+ vote = Vote.forRefreshRates(0f, 60f);
+ }
+ } else if (ambi >= 0) {
+ if (mAmbientLux <= ambi) {
+ vote = Vote.forRefreshRates(0f, 60f);
+ }
+ }
+
+ if (vote != null) {
+ break;
+ }
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux +
+ (vote != null ? " 60hz only" : " no refresh rate limit"));
+ }
+ updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+ }
+
+ private void onScreenOn(boolean on) {
+ // Not check mShouldObserveAmbientChange because Screen status receiver is registered
+ // only when it is true.
+ if (mScreenOn != on) {
+ mScreenOn = on;
+ updateSensorStatus();
+ }
+ }
+
+ private void updateSensorStatus() {
+ if (mSensorManager == null || mLightSensorListener == null) {
+ return;
+ }
+
+ if (mScreenOn && !mLowPowerModeEnabled && mPeakRefreshRateEnabled) {
+ mSensorManager.registerListener(mLightSensorListener,
+ mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
+ } else {
+ mSensorManager.unregisterListener(mLightSensorListener);
+ }
+ }
+
+ private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ long now = SystemClock.uptimeMillis();
+ mAmbientFilter.addValue(now, event.values[0]);
+ mAmbientLux = mAmbientFilter.getEstimate(now);
+
+ synchronized (mLock) {
+ onBrightnessChangedLocked();
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Not used.
+ }
+ };
+
+ private final class ScreenStateReceiver extends BroadcastReceiver {
+ public ScreenStateReceiver(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ context.registerReceiver(this, filter, null, mHandler);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 2e5aafe..7fb5b19 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -63,6 +63,8 @@
import android.provider.Settings.System;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
@@ -171,6 +173,11 @@
private NightDisplayAutoMode mNightDisplayAutoMode;
+ /**
+ * Map of color modes -> display composition colorspace
+ */
+ private SparseIntArray mColorModeCompositionColorSpaces = null;
+
public ColorDisplayService(Context context) {
super(context);
mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -267,6 +274,30 @@
return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
}
+ private void setUpDisplayCompositionColorSpaces(Resources res) {
+ mColorModeCompositionColorSpaces = null;
+
+ final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes);
+ if (colorModes == null) {
+ return;
+ }
+
+ final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces);
+ if (compSpaces == null) {
+ return;
+ }
+
+ if (colorModes.length != compSpaces.length) {
+ Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes");
+ return;
+ }
+
+ mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length);
+ for (int i = 0; i < colorModes.length; i++) {
+ mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]);
+ }
+ }
+
private void setUp() {
Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
@@ -359,6 +390,8 @@
onAccessibilityInversionChanged();
onAccessibilityDaltonizerChanged();
+ setUpDisplayCompositionColorSpaces(getContext().getResources());
+
// Set the color mode, if valid, and immediately apply the updated tint matrix based on the
// existing activated state. This ensures consistency of tint across the color mode change.
onDisplayColorModeChanged(getColorModeInternal());
@@ -450,6 +483,14 @@
}
}
+ private int getCompositionColorSpace(int mode) {
+ if (mColorModeCompositionColorSpaces == null) {
+ return Display.COLOR_MODE_INVALID;
+ }
+
+ return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
+ }
+
private void onDisplayColorModeChanged(int mode) {
if (mode == NOT_SET) {
return;
@@ -470,7 +511,8 @@
// DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
// on the state of DisplayTransformManager.
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
- dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
+ dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
+ getCompositionColorSpace(mode));
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
updateDisplayWhiteBalanceStatus();
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 5ff45a9..d5706a5 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -26,6 +26,7 @@
import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +78,8 @@
@VisibleForTesting
static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
@VisibleForTesting
+ static final String PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE = "persist.sys.sf.color_mode";
+ @VisibleForTesting
static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
private static final float COLOR_SATURATION_NATURAL = 1.0f;
@@ -251,23 +254,24 @@
/**
* Sets color mode and updates night display transform values.
*/
- public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
+ public boolean setColorMode(int colorMode, float[] nightDisplayMatrix,
+ int compositionColorMode) {
if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
applySaturation(COLOR_SATURATION_NATURAL);
- setDisplayColor(DISPLAY_COLOR_MANAGED);
+ setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
} else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
applySaturation(COLOR_SATURATION_BOOSTED);
- setDisplayColor(DISPLAY_COLOR_MANAGED);
+ setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
} else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
applySaturation(COLOR_SATURATION_NATURAL);
- setDisplayColor(DISPLAY_COLOR_UNMANAGED);
+ setDisplayColor(DISPLAY_COLOR_UNMANAGED, compositionColorMode);
} else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
applySaturation(COLOR_SATURATION_NATURAL);
- setDisplayColor(DISPLAY_COLOR_ENHANCED);
+ setDisplayColor(DISPLAY_COLOR_ENHANCED, compositionColorMode);
} else if (colorMode >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
&& colorMode <= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX) {
applySaturation(COLOR_SATURATION_NATURAL);
- setDisplayColor(colorMode);
+ setDisplayColor(colorMode, compositionColorMode);
}
setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
@@ -323,13 +327,21 @@
/**
* Toggles native mode on/off in SurfaceFlinger.
*/
- private void setDisplayColor(int color) {
+ private void setDisplayColor(int color, int compositionColorMode) {
SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, Integer.toString(color));
+ if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+ SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE,
+ Integer.toString(compositionColorMode));
+ }
+
final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
if (flinger != null) {
final Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
data.writeInt(color);
+ if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+ data.writeInt(compositionColorMode);
+ }
try {
flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
index 123cd73..3580897 100644
--- a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
+++ b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
@@ -36,7 +36,7 @@
* - {@link WeightedMovingAverageAmbientFilter}
* A weighted average prioritising recent changes.
*/
-abstract class AmbientFilter {
+abstract public class AmbientFilter {
protected static final boolean DEBUG = false; // Enable for verbose logs.
@@ -156,8 +156,7 @@
/**
* A weighted average prioritising recent changes.
*/
- @VisibleForTesting
- public static class WeightedMovingAverageAmbientFilter extends AmbientFilter {
+ static class WeightedMovingAverageAmbientFilter extends AmbientFilter {
// How long the latest ambient value change is predicted to last.
private static final int PREDICTION_TIME = 100; // Milliseconds
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index 4df7d6b..bf0a1d1 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -115,8 +115,7 @@
* Creates a BrightnessFilter which functions as a weighted moving average buffer for recent
* brightness values.
*/
- @VisibleForTesting
- static AmbientFilter createBrightnessFilter(Resources resources) {
+ public static AmbientFilter createBrightnessFilter(Resources resources) {
final int horizon = resources.getInteger(
com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon);
final float intercept = getFloat(resources,
@@ -129,7 +128,6 @@
+ "expected config_displayWhiteBalanceBrightnessFilterIntercept");
}
-
/**
* Creates an ambient color sensor instance to redirect sensor data to callbacks.
*/
diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
index 5cbd237..4ef63c0 100644
--- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
+++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
@@ -122,7 +122,7 @@
*/
public void markSlotDeleted(int slot) throws RuntimeException {
ensureSlotMapLoaded();
- if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) {
+ if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
throw new RuntimeException("password slot " + slot + " cannot be deleted");
}
mSlotMap.remove(slot);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bd198dd..d358f9a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -397,7 +397,7 @@
// for enabling and disabling notification pulse behavior
boolean mScreenOn = true;
- protected boolean mInCall = false;
+ protected boolean mInCallStateOffHook = false;
boolean mNotificationPulseEnabled;
private Uri mInCallNotificationUri;
@@ -1292,7 +1292,7 @@
mScreenOn = false;
updateNotificationPulse();
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
- mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
+ mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
updateNotificationPulse();
} else if (action.equals(Intent.ACTION_USER_STOPPED)) {
@@ -5710,7 +5710,7 @@
}
if (DBG) Slog.v(TAG, "Interrupting!");
if (hasValidSound) {
- if (mInCall) {
+ if (isInCall()) {
playInCallNotification();
beep = true;
} else {
@@ -5724,7 +5724,7 @@
final boolean ringerModeSilent =
mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT;
- if (!mInCall && hasValidVibrate && !ringerModeSilent) {
+ if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
buzz = playVibration(record, vibration, hasValidSound);
if(buzz) {
mVibrateNotificationKey = key;
@@ -5812,7 +5812,7 @@
return false;
}
// not if in call or the screen's on
- if (mInCall || mScreenOn) {
+ if (isInCall() || mScreenOn) {
return false;
}
@@ -6913,7 +6913,7 @@
}
// Don't flash while we are in a call or screen is on
- if (ledNotification == null || mInCall || mScreenOn) {
+ if (ledNotification == null || isInCall() || mScreenOn) {
mNotificationLight.turnOff();
} else {
NotificationRecord.Light light = ledNotification.getLight();
@@ -7381,6 +7381,18 @@
}
}
+ private boolean isInCall() {
+ if (mInCallStateOffHook) {
+ return true;
+ }
+ int audioMode = mAudioManager.getMode();
+ if (audioMode == AudioManager.MODE_IN_CALL
+ || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+ return true;
+ }
+ return false;
+ }
+
public class NotificationAssistants extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0f96f99..8a9dfc7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4998,6 +4998,9 @@
* - the cmd arg isn't the flattened component name of an existing activity:
* dump all activity whose component contains the cmd as a substring
* - A hex number of the ActivityRecord object instance.
+ * <p>
+ * The caller should not hold lock when calling this method because it will wait for the
+ * activities to complete the dump.
*
* @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
* @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
@@ -5050,29 +5053,28 @@
private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
final ActivityRecord r, String[] args, boolean dumpAll) {
String innerPrefix = prefix + " ";
+ IApplicationThread appThread = null;
synchronized (mGlobalLock) {
pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
pw.print(" pid=");
- if (r.hasProcess()) pw.println(r.app.getPid());
- else pw.println("(not running)");
+ if (r.hasProcess()) {
+ pw.println(r.app.getPid());
+ appThread = r.app.getThread();
+ } else {
+ pw.println("(not running)");
+ }
if (dumpAll) {
r.dump(pw, innerPrefix);
}
}
- if (r.attachedToProcess()) {
+ if (appThread != null) {
// flush anything that is already in the PrintWriter since the thread is going
// to write to the file descriptor directly
pw.flush();
- try {
- TransferPipe tp = new TransferPipe();
- try {
- r.app.getThread().dumpActivity(tp.getWriteFd(),
- r.appToken, innerPrefix, args);
- tp.go(fd);
- } finally {
- tp.kill();
- }
+ try (TransferPipe tp = new TransferPipe()) {
+ appThread.dumpActivity(tp.getWriteFd(), r.appToken, innerPrefix, args);
+ tp.go(fd);
} catch (IOException e) {
pw.println(innerPrefix + "Failure while dumping the activity: " + e);
} catch (RemoteException e) {
@@ -7181,10 +7183,8 @@
public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
boolean dumpFocusedStackOnly) {
- synchronized (mGlobalLock) {
- return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti,
- dumpAll, dumpVisibleStacksOnly, dumpFocusedStackOnly);
- }
+ return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti, dumpAll,
+ dumpVisibleStacksOnly, dumpFocusedStackOnly);
}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
index 73b3b8b..a785300 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE;
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
@@ -28,6 +29,7 @@
import android.hardware.display.ColorDisplayManager;
import android.os.SystemProperties;
+import android.view.Display;
import androidx.test.runner.AndroidJUnit4;
@@ -79,7 +81,7 @@
@Test
public void setColorMode_natural() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("0" /* managed */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -88,7 +90,7 @@
@Test
public void setColorMode_boosted() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("0" /* managed */);
@@ -98,7 +100,7 @@
@Test
public void setColorMode_saturated() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("1" /* unmanaged */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -107,7 +109,7 @@
@Test
public void setColorMode_automatic() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("2" /* enhanced */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -116,7 +118,7 @@
@Test
public void setColorMode_vendor() {
- mDtm.setColorMode(0x100, mNightDisplayMatrix);
+ mDtm.setColorMode(0x100, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo(Integer.toString(0x100) /* pass-through */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -125,10 +127,38 @@
@Test
public void setColorMode_outOfBounds() {
- mDtm.setColorMode(0x50, mNightDisplayMatrix);
+ mDtm.setColorMode(0x50, mNightDisplayMatrix, -1);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo(null);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
.isEqualTo(null);
}
+
+ @Test
+ public void setColorMode_withoutColorSpace() {
+ String magicPropertyValue = "magic";
+
+ // Start with a known state, which we expect to remain unmodified
+ SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+ Display.COLOR_MODE_INVALID);
+ assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+ .isEqualTo(magicPropertyValue);
+ }
+
+ @Test
+ public void setColorMode_withColorSpace() {
+ String magicPropertyValue = "magic";
+ int testPropertyValue = Display.COLOR_MODE_SRGB;
+
+ // Start with a known state, which we expect to get modified
+ SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+ testPropertyValue);
+ assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+ .isEqualTo(Integer.toString(testPropertyValue));
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index fb2913b..a19b387 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -18,13 +18,19 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.res.Resources;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.Time;
import android.os.Handler;
@@ -33,6 +39,7 @@
import android.provider.Settings.Secure;
import android.provider.Settings.System;
import android.test.mock.MockContentResolver;
+import android.view.Display;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -73,6 +80,8 @@
private ColorDisplayService mCds;
private ColorDisplayService.BinderService mBinderService;
+ private Resources mResourcesSpy;
+
@BeforeClass
public static void setDtm() {
final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
@@ -84,6 +93,9 @@
mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
doReturn(mContext).when(mContext).getApplicationContext();
+ mResourcesSpy = Mockito.spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(mResourcesSpy);
+
mUserId = ActivityManager.getCurrentUser();
final MockContentResolver cr = new MockContentResolver(mContext);
@@ -1050,6 +1062,80 @@
assertDwbActive(true);
}
+ @Test
+ public void compositionColorSpaces_noResources() {
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+ reset(dtm);
+
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+ .thenReturn(new int[] {});
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+ .thenReturn(new int[] {});
+ setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+ startService();
+ verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+ eq(Display.COLOR_MODE_INVALID));
+ }
+
+ @Test
+ public void compositionColorSpaces_invalidResources() {
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+ reset(dtm);
+
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL,
+ // Missing second color mode
+ });
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ Display.COLOR_MODE_DISPLAY_P3
+ });
+ setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+ startService();
+ verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+ eq(Display.COLOR_MODE_INVALID));
+ }
+
+ @Test
+ public void compositionColorSpaces_validResources_validColorMode() {
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+ reset(dtm);
+
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL
+ });
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ });
+ setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+ startService();
+ verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+ eq(Display.COLOR_MODE_SRGB));
+ }
+
+ @Test
+ public void compositionColorSpaces_validResources_invalidColorMode() {
+ final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+ reset(dtm);
+
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL
+ });
+ when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ });
+ setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
+ startService();
+ verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(),
+ eq(Display.COLOR_MODE_INVALID));
+ }
+
/**
* Configures Night display to use a custom schedule.
*
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 6061d51..8c3373f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -156,7 +156,7 @@
mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager);
mService.mScreenOn = false;
- mService.mInCall = false;
+ mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true;
}
@@ -681,7 +681,7 @@
mService.buzzBeepBlinkLocked(r);
Mockito.reset(mRingtonePlayer);
- mService.mInCall = true;
+ mService.mInCallStateOffHook = true;
mService.buzzBeepBlinkLocked(r);
verify(mService, times(1)).playInCallNotification();
@@ -1137,7 +1137,7 @@
@Test
public void testLightsInCall() {
- mService.mInCall = true;
+ mService.mInCallStateOffHook = true;
NotificationRecord r = getLightsNotification();
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();