summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java40
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt121
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt102
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java119
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java303
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java19
52 files changed, 1109 insertions, 456 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 099dd5d82a10..87e853cf64d7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -18,6 +18,7 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
@@ -30,6 +31,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.internal.policy.SystemBarUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -57,8 +60,14 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
private boolean mBouncerVisible;
private boolean mAltBouncerShowing;
+ /**
+ * Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
+ * contain {@link R.id.keyguard_message_area_container}.
+ */
+ @Nullable
private ViewGroup mContainer;
- private int mTopMargin;
+ private int mContainerTopMargin;
+ private int mLastOrientation = -1;
public KeyguardMessageArea(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -74,16 +83,31 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
mContainer = getRootView().findViewById(R.id.keyguard_message_area_container);
}
- void onConfigChanged() {
- final int newTopMargin = SystemBarUtils.getStatusBarHeight(getContext());
- if (mTopMargin == newTopMargin) {
+ void onConfigChanged(Configuration newConfig) {
+ if (mContainer == null) {
return;
}
- mTopMargin = newTopMargin;
- ViewGroup.MarginLayoutParams lp =
+ final int newTopMargin = SystemBarUtils.getStatusBarHeight(getContext());
+ if (mContainerTopMargin != newTopMargin) {
+ mContainerTopMargin = newTopMargin;
+ ViewGroup.MarginLayoutParams lp =
(ViewGroup.MarginLayoutParams) mContainer.getLayoutParams();
- lp.topMargin = mTopMargin;
- mContainer.setLayoutParams(lp);
+ lp.topMargin = mContainerTopMargin;
+ mContainer.setLayoutParams(lp);
+ }
+
+ if (mLastOrientation != newConfig.orientation) {
+ mLastOrientation = newConfig.orientation;
+ int messageAreaTopMargin = 0;
+ if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ messageAreaTopMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_lock_padding);
+ }
+
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
+ lp.topMargin = messageAreaTopMargin;
+ setLayoutParams(lp);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 05318bb0df78..659aadd69614 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -50,7 +50,7 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@Override
public void onConfigChanged(Configuration newConfig) {
- mView.onConfigChanged();
+ mView.onConfigChanged(newConfig);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 1efda7edee2f..5b4f7a21f8d0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -21,10 +21,13 @@ import static com.android.systemui.statusbar.policy.DevicePostureController.DEVI
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
+import androidx.constraintlayout.helper.widget.Flow;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
@@ -87,48 +90,45 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
}
private void updateMargins() {
+ Resources res = mContext.getResources();
+
// Re-apply everything to the keys...
- int bottomMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.num_pad_entry_row_margin_bottom);
- int rightMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.num_pad_key_margin_end);
- String ratio = mContext.getResources().getString(R.string.num_pad_key_ratio);
-
- // mView contains all Views that make up the PIN pad; row0 = the entry test field, then
- // rows 1-4 contain the buttons. Iterate over all views that make up the buttons in the pad,
- // and re-set all the margins.
- for (int row = 1; row < 5; row++) {
- for (int column = 0; column < 3; column++) {
- View key = mViews[row][column];
-
- ConstraintLayout.LayoutParams lp =
- (ConstraintLayout.LayoutParams) key.getLayoutParams();
-
- lp.dimensionRatio = ratio;
-
- // Don't set any margins on the last row of buttons.
- if (row != 4) {
- lp.bottomMargin = bottomMargin;
- }
-
- // Don't set margins on the rightmost buttons.
- if (column != 2) {
- lp.rightMargin = rightMargin;
- }
-
- key.setLayoutParams(lp);
- }
- }
+ int verticalMargin = res.getDimensionPixelSize(R.dimen.num_pad_entry_row_margin_bottom);
+ int horizontalMargin = res.getDimensionPixelSize(R.dimen.num_pad_key_margin_end);
+ String ratio = res.getString(R.string.num_pad_key_ratio);
+
+ Flow flow = (Flow) mContainer.findViewById(R.id.flow1);
+ flow.setHorizontalGap(horizontalMargin);
+ flow.setVerticalGap(verticalMargin);
// Update the guideline based on the device posture...
- float halfOpenPercentage =
- mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
+ float halfOpenPercentage = res.getFloat(R.dimen.half_opened_bouncer_height_ratio);
ConstraintSet cs = new ConstraintSet();
cs.clone(mContainer);
cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
cs.applyTo(mContainer);
+
+ // Password entry area
+ int passwordHeight = res.getDimensionPixelSize(R.dimen.keyguard_password_height);
+ View pinEntry = findViewById(getPasswordTextViewId());
+ ViewGroup.LayoutParams lp = pinEntry.getLayoutParams();
+ lp.height = passwordHeight;
+ pinEntry.setLayoutParams(lp);
+
+ // Below row0
+ View row0 = findViewById(R.id.row0);
+ row0.setPadding(0, 0, 0, verticalMargin);
+
+ // Above the emergency contact area
+ int marginTop = res.getDimensionPixelSize(R.dimen.keyguard_eca_top_margin);
+ View eca = findViewById(R.id.keyguard_selector_fade_container);
+ if (eca != null) {
+ ViewGroup.MarginLayoutParams mLp = (ViewGroup.MarginLayoutParams) eca.getLayoutParams();
+ mLp.topMargin = marginTop;
+ eca.setLayoutParams(mLp);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2789e27178cc..42f0fccd61b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1186,6 +1186,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return fingerprintAllowed || faceAllowed;
}
+ /**
+ * Returns whether the user is unlocked with a biometric that is currently bypassing
+ * the lock screen.
+ */
+ public boolean getUserUnlockedWithBiometricAndIsBypassing(int userId) {
+ BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
+ BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
+ // fingerprint always bypasses
+ boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
+ && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
+ boolean faceAllowed = face != null && face.mAuthenticated
+ && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
+ return fingerprintAllowed || faceAllowed && mKeyguardBypassController.canBypass();
+ }
+
public boolean getUserTrustIsManaged(int userId) {
return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
index b7404dfeb1cc..dfbe348c6ede 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
@@ -37,7 +37,7 @@ class BiometricDisplayListener(
private val onChanged: () -> Unit
) : DisplayManager.DisplayListener {
- private var lastRotation = context.display?.rotation ?: Surface.ROTATION_0
+ private var lastRotation = Surface.ROTATION_0
override fun onDisplayAdded(displayId: Int) {}
override fun onDisplayRemoved(displayId: Int) {}
@@ -63,6 +63,7 @@ class BiometricDisplayListener(
/** Listen for changes. */
fun enable() {
+ lastRotation = context.display?.rotation ?: Surface.ROTATION_0
displayManager.registerDisplayListener(this, handler)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3e9d6b0fa362..250c16c81eac 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -480,8 +480,33 @@ public class UdfpsController implements DozeReceiver {
final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
if (!isIlluminationRequested && !mGoodCaptureReceived &&
!exceedsVelocityThreshold) {
- onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor,
- major);
+ final int rawX = (int) event.getRawX();
+ final int rawY = (int) event.getRawY();
+ // Default coordinates assume portrait mode.
+ int x = rawX;
+ int y = rawY;
+
+ // Gets the size based on the current rotation of the display.
+ Point p = new Point();
+ mContext.getDisplay().getRealSize(p);
+
+ // Transform x, y to portrait mode if the device is in landscape mode.
+ switch (mContext.getDisplay().getRotation()) {
+ case Surface.ROTATION_90:
+ x = p.y - rawY;
+ y = rawX;
+ break;
+
+ case Surface.ROTATION_270:
+ x = rawY;
+ y = p.x - rawX;
+ break;
+
+ default:
+ // Do nothing to stay in portrait mode.
+ }
+
+ onFingerDown(x, y, minor, major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ac38b13cc4dd..9137dca6cc71 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -97,6 +97,8 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
@NonNull private final ValueAnimator.AnimatorUpdateListener mEdgeHintWidthUpdateListener;
@NonNull private final Animator.AnimatorListener mEdgeHintPulseListener;
+ private boolean mShowingNewUdfpsEnroll = false;
+
UdfpsEnrollDrawable(@NonNull Context context) {
super(context);
@@ -211,6 +213,8 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
@Override
public void onAnimationRepeat(Animator animation) {}
};
+ mShowingNewUdfpsEnroll = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_udfpsSupportsNewUi);
}
void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
@@ -292,6 +296,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
mShouldShowTipHint = shouldShow;
+ if (mShowingNewUdfpsEnroll) {
+ return;
+ }
+
if (mTipHintWidthAnimator != null && mTipHintWidthAnimator.isRunning()) {
mTipHintWidthAnimator.cancel();
}
@@ -306,6 +314,7 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
} else {
mTipHintWidthAnimator.start();
}
+
}
private void updateEdgeHintVisibility() {
@@ -315,6 +324,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
mShouldShowEdgeHint = shouldShow;
+ if (mShowingNewUdfpsEnroll) {
+ return;
+ }
+
if (mEdgeHintWidthAnimator != null && mEdgeHintWidthAnimator.isRunning()) {
mEdgeHintWidthAnimator.cancel();
}
@@ -333,6 +346,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
private void startTipHintPulseAnimation() {
+ if (mShowingNewUdfpsEnroll) {
+ return;
+ }
+
mHandler.removeCallbacksAndMessages(null);
if (mTipHintAnimatorSet != null && mTipHintAnimatorSet.isRunning()) {
mTipHintAnimatorSet.cancel();
@@ -353,6 +370,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
private void startEdgeHintPulseAnimation() {
+ if (mShowingNewUdfpsEnroll) {
+ return;
+ }
+
mHandler.removeCallbacksAndMessages(null);
if (mEdgeHintAnimatorSet != null && mEdgeHintAnimatorSet.isRunning()) {
mEdgeHintAnimatorSet.cancel();
@@ -409,6 +430,10 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mSensorOutlinePaint.setAlpha(mAlpha);
}
+ if (mShowingNewUdfpsEnroll) {
+ return;
+ }
+
// Draw the finger tip or edges hint.
if (isTipHintVisible() || isEdgeHintVisible()) {
canvas.save();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index befb648152d4..789ad6223e79 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -118,9 +118,11 @@ public class DozeMachine {
switch (this) {
case UNINITIALIZED:
case INITIALIZED:
- case DOZE_REQUEST_PULSE:
return parameters.shouldControlScreenOff() ? Display.STATE_ON
: Display.STATE_OFF;
+ case DOZE_REQUEST_PULSE:
+ return parameters.getDisplayNeedsBlanking() ? Display.STATE_OFF
+ : Display.STATE_ON;
case DOZE_AOD_PAUSED:
case DOZE:
return Display.STATE_OFF;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 36319380ad50..52db1bd00c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -105,17 +105,7 @@ public class DozeScreenState implements DozeMachine.Part {
updateUdfpsController();
if (mUdfpsController == null) {
- mAuthController.addCallback(new AuthController.Callback() {
- @Override
- public void onAllAuthenticatorsRegistered() {
- updateUdfpsController();
- }
-
- @Override
- public void onEnrollmentsChanged() {
- updateUdfpsController();
- }
- });
+ mAuthController.addCallback(mAuthControllerCallback);
}
}
@@ -128,6 +118,11 @@ public class DozeScreenState implements DozeMachine.Part {
}
@Override
+ public void destroy() {
+ mAuthController.removeCallback(mAuthControllerCallback);
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState(mParameters);
mDozeHost.cancelGentleSleep();
@@ -222,4 +217,16 @@ public class DozeScreenState implements DozeMachine.Part {
mWakeLock.setAcquired(false);
}
}
+
+ private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+ @Override
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsController();
+ }
+
+ @Override
+ public void onEnrollmentsChanged() {
+ updateUdfpsController();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index fabe92d2532d..94d5ee2b923c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Matrix
+import android.util.Log
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
@@ -38,6 +39,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
+const val TAG = "KeyguardUnlock"
+
/**
* Starting scale factor for the app/launcher surface behind the keyguard, when it's animating
* in during keyguard exit.
@@ -254,7 +257,12 @@ class KeyguardUnlockAnimationController @Inject constructor(
}
fun hideKeyguardViewAfterRemoteAnimation() {
- keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
+ if (keyguardViewController.isShowing) {
+ keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
+ } else {
+ Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
+ "showing. Ignoring...")
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 112bfafbdc20..b7916f9f09e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -112,6 +112,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -209,7 +210,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 13;
private static final int NOTIFY_STARTED_WAKING_UP = 14;
private static final int NOTIFY_SCREEN_TURNED_ON = 15;
- private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
@@ -324,6 +324,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
// the properties of the keyguard
private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
/**
* Last SIM state reported by the telephony system.
@@ -439,7 +440,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private boolean mInGestureNavigationMode;
private boolean mWakeAndUnlocking;
- private IKeyguardDrawnCallback mDrawnCallback;
private CharSequence mCustomMessage;
/**
@@ -846,7 +846,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+ Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+ Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy) {
super(context);
mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
@@ -862,6 +863,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mKeyguardDisplayManager = keyguardDisplayManager;
dumpManager.registerDumpable(getClass().getName(), this);
mDeviceConfig = deviceConfig;
+ mNotificationShadeWindowControllerLazy = notificationShadeWindowControllerLazy;
mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
@@ -1260,7 +1262,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
}
public void onScreenTurnedOff() {
- notifyScreenTurnedOff();
mUpdateMonitor.dispatchScreenTurnedOff();
}
@@ -1664,12 +1665,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mHandler.sendMessage(msg);
}
- private void notifyScreenTurnedOff() {
- if (DEBUG) Log.d(TAG, "notifyScreenTurnedOff");
- Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_OFF);
- mHandler.sendMessage(msg);
- }
-
/**
* Send message to keyguard telling it to show itself
* @see #handleShow
@@ -1857,9 +1852,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
handleNotifyScreenTurnedOn();
Trace.endSection();
break;
- case NOTIFY_SCREEN_TURNED_OFF:
- handleNotifyScreenTurnedOff();
- break;
case NOTIFY_STARTED_WAKING_UP:
Trace.beginSection(
"KeyguardViewMediator#handleMessage NOTIFY_STARTED_WAKING_UP");
@@ -1895,10 +1887,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
Trace.beginSection(
"KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
- handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration,
- params.mApps, params.mWallpapers, params.mNonApps,
- params.mFinishedCallback);
- mFalsingCollector.onSuccessfulUnlock();
+ mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(
+ () -> {
+ handleStartKeyguardExitAnimation(params.startTime,
+ params.fadeoutDuration, params.mApps, params.mWallpapers,
+ params.mNonApps, params.mFinishedCallback);
+ mFalsingCollector.onSuccessfulUnlock();
+ });
Trace.endSection();
break;
case CANCEL_KEYGUARD_EXIT_ANIM:
@@ -2196,10 +2191,12 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mKeyguardGoingAwayRunnable.run();
} else {
// TODO(bc-unlock): Fill parameters
- handleStartKeyguardExitAnimation(
- SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
- mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */,
- null /* nonApps */, null /* finishedCallback */);
+ mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(() -> {
+ handleStartKeyguardExitAnimation(
+ SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
+ mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */,
+ null /* nonApps */, null /* finishedCallback */);
+ });
}
}
Trace.endSection();
@@ -2236,16 +2233,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
IRemoteAnimationRunner runner = mKeyguardExitAnimationRunner;
mKeyguardExitAnimationRunner = null;
- if (mWakeAndUnlocking && mDrawnCallback != null) {
-
- // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
- // the next draw from here so we don't have to wait for window manager to signal
- // this to our ViewRootImpl.
- mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
- notifyDrawn(mDrawnCallback);
- mDrawnCallback = null;
- }
-
LatencyTracker.getInstance(mContext)
.onActionEnd(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
@@ -2601,11 +2588,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mKeyguardViewControllerLazy.get().onScreenTurningOn();
if (callback != null) {
- if (mWakeAndUnlocking) {
- mDrawnCallback = callback;
- } else {
- notifyDrawn(callback);
- }
+ notifyDrawn(callback);
}
}
Trace.endSection();
@@ -2620,13 +2603,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
Trace.endSection();
}
- private void handleNotifyScreenTurnedOff() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
- mDrawnCallback = null;
- }
- }
-
private void notifyDrawn(final IKeyguardDrawnCallback callback) {
Trace.beginSection("KeyguardViewMediator#notifyDrawn");
if (mPendingDrawnTasks.decrementAndGet() == 0) {
@@ -2795,7 +2771,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
pw.print(" mPendingLock: "); pw.println(mPendingLock);
pw.print(" mPendingDrawnTasks: "); pw.println(mPendingDrawnTasks.get());
pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
- pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index cae9feeb62eb..88dcf6d35075 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -42,6 +42,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -97,7 +98,8 @@ public class KeyguardModule {
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+ Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+ Lazy<NotificationShadeWindowController> notificationShadeWindowController) {
return new KeyguardViewMediator(
context,
falsingCollector,
@@ -120,7 +122,8 @@ public class KeyguardModule {
keyguardStateController,
keyguardUnlockAnimationController,
unlockedScreenOffAnimationController,
- notificationShadeDepthController
+ notificationShadeDepthController,
+ notificationShadeWindowController
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index b85f10726040..70f89e499ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -209,17 +209,17 @@ class MediaCarouselController @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
- if (addOrUpdatePlayer(key, oldKey, data)) {
+ if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
// Log card received if a new resumable media card is added
MediaPlayerData.getMediaPlayer(key)?.let {
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
- /* isRecommendationCard */ false,
- intArrayOf(
+ surfaces = intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = MediaPlayerData.getMediaPlayerIndex(key))
@@ -242,8 +242,7 @@ class MediaCarouselController @Inject constructor(
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
- /* isRecommendationCard */ false,
- intArrayOf(
+ surfaces = intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = index,
@@ -277,12 +276,17 @@ class MediaCarouselController @Inject constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean,
- isSsReactivated: Boolean
+ shouldPrioritize: Boolean
) {
if (DEBUG) Log.d(TAG, "Loading Smartspace media update")
+ // Log the case where the hidden media carousel with the existed inactive resume
+ // media is shown by the Smartspace signal.
if (data.isActive) {
- if (isSsReactivated && shouldPrioritize) {
+ val hasActivatedExistedResumeMedia =
+ !mediaManager.hasActiveMedia() &&
+ mediaManager.hasAnyMedia() &&
+ shouldPrioritize
+ if (hasActivatedExistedResumeMedia) {
// Log resume card received if resumable media card is reactivated and
// recommendation card is valid and ranked first
MediaPlayerData.players().forEachIndexed { index, it ->
@@ -294,8 +298,7 @@ class MediaCarouselController @Inject constructor(
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
- /* isRecommendationCard */ false,
- intArrayOf(
+ surfaces = intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = index,
@@ -310,8 +313,7 @@ class MediaCarouselController @Inject constructor(
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
- /* isRecommendationCard */ true,
- intArrayOf(
+ surfaces = intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = MediaPlayerData.getMediaPlayerIndex(key),
@@ -408,7 +410,12 @@ class MediaCarouselController @Inject constructor(
}
// Returns true if new player is added
- private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData): Boolean {
+ private fun addOrUpdatePlayer(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ isSsReactivated: Boolean
+ ): Boolean {
val dataCopy = data.copy(backgroundColor = bgColor)
MediaPlayerData.moveIfExists(oldKey, key)
val existingPlayer = MediaPlayerData.getMediaPlayer(key)
@@ -424,12 +431,13 @@ class MediaCarouselController @Inject constructor(
newPlayer.playerViewHolder?.player?.setLayoutParams(lp)
newPlayer.bindPlayer(dataCopy, key)
newPlayer.setListening(currentlyExpanded)
- MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer, systemClock)
+ MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer, systemClock, isSsReactivated)
updatePlayerToState(newPlayer, noAnimation = true)
reorderAllPlayers(curVisibleMediaKey)
} else {
existingPlayer.bindPlayer(dataCopy, key)
- MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer, systemClock)
+ MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer, systemClock,
+ isSsReactivated)
if (visualStabilityManager.isReorderingAllowed || shouldScrollToActivePlayer) {
reorderAllPlayers(curVisibleMediaKey)
} else {
@@ -523,8 +531,10 @@ class MediaCarouselController @Inject constructor(
it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
}
} else {
+ val isSsReactivated = MediaPlayerData.isSsReactivated(key)
removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
- addOrUpdatePlayer(key = key, oldKey = null, data = data)
+ addOrUpdatePlayer(
+ key = key, oldKey = null, data = data, isSsReactivated = isSsReactivated)
}
}
}
@@ -682,7 +692,8 @@ class MediaCarouselController @Inject constructor(
this.desiredHostState = it
currentlyExpanded = it.expansion > 0
- val shouldCloseGuts = !currentlyExpanded && !mediaManager.hasActiveMedia() &&
+ val shouldCloseGuts = !currentlyExpanded &&
+ !mediaManager.hasActiveMediaOrRecommendation() &&
desiredHostState.showsOnlyActiveMedia
for (mediaPlayer in MediaPlayerData.players()) {
@@ -747,7 +758,6 @@ class MediaCarouselController @Inject constructor(
val mediaControlPanel = MediaPlayerData.players().elementAt(visibleMediaIndex)
val hasActiveMediaOrRecommendationCard =
MediaPlayerData.hasActiveMediaOrRecommendationCard()
- val isRecommendationCard = mediaControlPanel.recommendationViewHolder != null
if (!hasActiveMediaOrRecommendationCard && !qsExpanded) {
// Skip logging if on LS or QQS, and there is no active media card
return
@@ -755,7 +765,6 @@ class MediaCarouselController @Inject constructor(
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
mediaControlPanel.mInstanceId,
mediaControlPanel.mUid,
- isRecommendationCard,
intArrayOf(mediaControlPanel.surfaceForSmartspaceLogging))
mediaControlPanel.mIsImpressed = true
}
@@ -769,7 +778,6 @@ class MediaCarouselController @Inject constructor(
* @param instanceId id to uniquely identify a card, e.g. each headphone generates a new
* instanceId
* @param uid uid for the application that media comes from
- * @param isRecommendationCard whether the card is media recommendation
* @param surfaces list of display surfaces the media card is on (e.g. lockscreen, shade) when
* the event happened
* @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
@@ -779,21 +787,27 @@ class MediaCarouselController @Inject constructor(
* @param rank the rank for media card in the media carousel, starting from 0
* @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency
* between headphone connection to sysUI displays media recommendation card
+ * @param isSwipeToDismiss whether is to log swipe-to-dismiss event
*
*/
fun logSmartspaceCardReported(
eventId: Int,
instanceId: Int,
uid: Int,
- isRecommendationCard: Boolean,
surfaces: IntArray,
interactedSubcardRank: Int = 0,
interactedSubcardCardinality: Int = 0,
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex,
- receivedLatencyMillis: Int = 0
+ receivedLatencyMillis: Int = 0,
+ isSwipeToDismiss: Boolean = false
) {
+ if (MediaPlayerData.players().size <= rank) {
+ return
+ }
+
+ val mediaControlKey = MediaPlayerData.playerKeys().elementAt(rank)
// Only log media resume card when Smartspace data is available
- if (!isRecommendationCard &&
+ if (!mediaControlKey.isSsMediaRec &&
!mediaManager.smartspaceMediaData.isActive &&
MediaPlayerData.smartspaceMediaData == null) {
return
@@ -809,22 +823,28 @@ class MediaCarouselController @Inject constructor(
// card type for each new feature.
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
surface,
- rank,
+ // Use -1 as rank value to indicate user swipe to dismiss the card
+ if (isSwipeToDismiss) -1 else rank,
cardinality,
- if (isRecommendationCard)
+ if (mediaControlKey.isSsMediaRec)
15 // MEDIA_RECOMMENDATION
+ else if (mediaControlKey.isSsReactivated)
+ 43 // MEDIA_RESUME_SS_ACTIVATED
else
31, // MEDIA_RESUME
uid,
interactedSubcardRank,
interactedSubcardCardinality,
- receivedLatencyMillis
+ receivedLatencyMillis,
+ null // Media cards cannot have subcards.
)
/* ktlint-disable max-line-length */
if (DEBUG) {
Log.d(TAG, "Log Smartspace card event id: $eventId instance id: $instanceId" +
" surface: $surface rank: $rank cardinality: $cardinality " +
- "isRecommendationCard: $isRecommendationCard uid: $uid " +
+ "isRecommendationCard: ${mediaControlKey.isSsMediaRec} " +
+ "isSsReactivated: ${mediaControlKey.isSsReactivated}" +
+ "uid: $uid " +
"interactedSubcardRank: $interactedSubcardRank " +
"interactedSubcardCardinality: $interactedSubcardCardinality " +
"received_latency_millis: $receivedLatencyMillis")
@@ -839,10 +859,9 @@ class MediaCarouselController @Inject constructor(
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
it.mInstanceId,
it.mUid,
- it.recommendationViewHolder != null,
intArrayOf(it.surfaceForSmartspaceLogging),
- // Use -1 as rank value to indicate user swipe to dismiss the card
- rank = -1)
+ rank = index,
+ isSwipeToDismiss = true)
// Reset card impressed state when swipe to dismissed
it.mIsImpressed = false
}
@@ -871,29 +890,37 @@ internal object MediaPlayerData {
private set
data class MediaSortKey(
- // Whether the item represents a Smartspace media recommendation.
- val isSsMediaRec: Boolean,
+ val isSsMediaRec: Boolean, // Whether the item represents a Smartspace media recommendation.
val data: MediaData,
- val updateTime: Long = 0
+ val updateTime: Long = 0,
+ val isSsReactivated: Boolean = false
)
private val comparator =
compareByDescending<MediaSortKey> { it.data.isPlaying == true &&
it.data.playbackLocation == MediaData.PLAYBACK_LOCAL }
- .thenByDescending { it.data.isPlaying == true &&
- it.data.playbackLocation == MediaData.PLAYBACK_CAST_LOCAL }
- .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
- .thenByDescending { !it.data.resumption }
- .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
- .thenByDescending { it.updateTime }
- .thenByDescending { it.data.notificationKey }
+ .thenByDescending { it.data.isPlaying == true &&
+ it.data.playbackLocation == MediaData.PLAYBACK_CAST_LOCAL
+ }
+ .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
+ .thenByDescending { !it.data.resumption }
+ .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
+ .thenByDescending { it.updateTime }
+ .thenByDescending { it.data.notificationKey }
private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
- fun addMediaPlayer(key: String, data: MediaData, player: MediaControlPanel, clock: SystemClock) {
+ fun addMediaPlayer(
+ key: String,
+ data: MediaData,
+ player: MediaControlPanel,
+ clock: SystemClock,
+ isSsReactivated: Boolean
+ ) {
removeMediaPlayer(key)
- val sortKey = MediaSortKey(isSsMediaRec = false, data, clock.currentTimeMillis())
+ val sortKey = MediaSortKey(isSsMediaRec = false,
+ data, clock.currentTimeMillis(), isSsReactivated = isSsReactivated)
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
}
@@ -907,8 +934,8 @@ internal object MediaPlayerData {
) {
shouldPrioritizeSs = shouldPrioritize
removeMediaPlayer(key)
- val sortKey = MediaSortKey(/* isSsMediaRec= */ true,
- EMPTY.copy(isPlaying = false), clock.currentTimeMillis())
+ val sortKey = MediaSortKey(isSsMediaRec = true,
+ EMPTY.copy(isPlaying = false), clock.currentTimeMillis(), isSsReactivated = true)
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
smartspaceMediaData = data
@@ -988,4 +1015,8 @@ internal object MediaPlayerData {
}
return false
}
+
+ fun isSsReactivated(key: String): Boolean = mediaData.get(key)?.let {
+ it.isSsReactivated
+ } ?: false
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index f66eb5ba008a..65b06946d3e7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -22,6 +22,7 @@ import android.app.PendingIntent;
import android.app.smartspace.SmartspaceAction;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -35,6 +36,7 @@ import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Process;
import android.text.Layout;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -85,6 +87,7 @@ public class MediaControlPanel {
private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6;
private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
+ private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
@@ -155,8 +158,8 @@ public class MediaControlPanel {
mSeekBarViewModel.setLogSmartspaceClick(() -> {
logSmartspaceCardReported(
- 760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ false);
+ 760 // SMARTSPACE_CARD_CLICK
+ );
return Unit.INSTANCE;
});
}
@@ -323,8 +326,9 @@ public class MediaControlPanel {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
if (mMediaViewController.isGutsVisible()) return;
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ false);
+ logSmartspaceCardReported(
+ 760 // SMARTSPACE_CARD_CLICK
+ );
mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
buildLaunchAnimatorController(mPlayerViewHolder.getPlayer()));
});
@@ -444,8 +448,9 @@ public class MediaControlPanel {
button.setEnabled(true);
button.setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ false);
+ logSmartspaceCardReported(
+ 760 // SMARTSPACE_CARD_CLICK
+ );
action.run();
}
});
@@ -481,8 +486,9 @@ public class MediaControlPanel {
mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
- logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
- /* isRecommendationCard */ false);
+ logSmartspaceCardReported(
+ 761 // SMARTSPACE_CARD_DISMISS
+ );
if (mKey != null) {
closeGuts();
@@ -578,18 +584,33 @@ public class MediaControlPanel {
icon.setColorFilter(getGrayscaleFilter());
ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon();
headerLogoImageView.setImageDrawable(icon);
+
// Set up media source app's label text.
- CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
- if (appLabel.length() != 0) {
+ CharSequence appName = getAppName(data.getCardAction());
+ if (TextUtils.isEmpty(appName)) {
+ Intent launchIntent =
+ packageManager.getLaunchIntentForPackage(data.getPackageName());
+ if (launchIntent != null) {
+ ActivityInfo launchActivity = launchIntent.resolveActivityInfo(packageManager, 0);
+ appName = launchActivity.loadLabel(packageManager);
+ } else {
+ Log.w(TAG, "Package " + data.getPackageName()
+ + " does not have a main launcher activity. Fallback to full app name");
+ appName = packageManager.getApplicationLabel(applicationInfo);
+ }
+ }
+ // Set the app name as card's title.
+ if (!TextUtils.isEmpty(appName)) {
TextView headerTitleText = mRecommendationViewHolder.getCardText();
- headerTitleText.setText(appLabel);
+ headerTitleText.setText(appName);
}
+
// Set up media rec card's tap action if applicable.
setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
/* interactedSubcardRank */ -1);
// Set up media rec card's accessibility label.
recommendationCard.setContentDescription(
- mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel));
+ mContext.getString(R.string.controls_media_smartspace_rec_description, appName));
List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
@@ -634,12 +655,12 @@ public class MediaControlPanel {
mediaCoverImageView.setContentDescription(
mContext.getString(
R.string.controls_media_smartspace_rec_item_no_artist_description,
- recommendation.getTitle(), appLabel));
+ recommendation.getTitle(), appName));
} else {
mediaCoverImageView.setContentDescription(
mContext.getString(
R.string.controls_media_smartspace_rec_item_description,
- recommendation.getTitle(), artistName, appLabel));
+ recommendation.getTitle(), artistName, appName));
}
if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
@@ -665,8 +686,9 @@ public class MediaControlPanel {
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
- logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
- /* isRecommendationCard */ true);
+ logSmartspaceCardReported(
+ 761 // SMARTSPACE_CARD_DISMISS
+ );
closeGuts();
mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
data.getTargetId(), MediaViewController.GUTS_ANIMATION_DURATION + 100L);
@@ -823,7 +845,6 @@ public class MediaControlPanel {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ true,
interactedSubcardRank,
getSmartspaceSubCardCardinality());
@@ -844,6 +865,17 @@ public class MediaControlPanel {
});
}
+ /** Returns the upstream app name if available. */
+ @Nullable
+ private String getAppName(SmartspaceAction action) {
+ if (action == null || action.getIntent() == null
+ || action.getIntent().getExtras() == null) {
+ return null;
+ }
+
+ return action.getIntent().getExtras().getString(KEY_SMARTSPACE_APP_NAME);
+ }
+
/** Returns if the Smartspace action will open the activity in foreground. */
private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) {
if (action == null || action.getIntent() == null
@@ -882,18 +914,17 @@ public class MediaControlPanel {
return SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DEFAULT_SURFACE;
}
- private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard) {
- logSmartspaceCardReported(eventId, isRecommendationCard,
+ private void logSmartspaceCardReported(int eventId) {
+ logSmartspaceCardReported(eventId,
/* interactedSubcardRank */ 0,
/* interactedSubcardCardinality */ 0);
}
- private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard,
+ private void logSmartspaceCardReported(int eventId,
int interactedSubcardRank, int interactedSubcardCardinality) {
mMediaCarouselController.logSmartspaceCardReported(eventId,
mInstanceId,
mUid,
- isRecommendationCard,
new int[]{getSurfaceForSmartspaceLogging()},
interactedSubcardRank,
interactedSubcardCardinality);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index b68f2a7654f0..311973ad5af0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -32,7 +32,8 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
entries[key] = data to entries.remove(oldKey)?.second
@@ -46,8 +47,7 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean,
- isSsReactivated: Boolean
+ shouldPrioritize: Boolean
) {
listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index ae5c1f2b19a9..919bce2cb360 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -87,7 +87,8 @@ class MediaDataFilter @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
if (oldKey != null && oldKey != key) {
allEntries.remove(oldKey)
@@ -112,8 +113,7 @@ class MediaDataFilter @Inject constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean,
- isSsReactivated: Boolean
+ shouldPrioritize: Boolean
) {
if (!data.isActive) {
Log.d(TAG, "Inactive recommendation data. Skip triggering.")
@@ -138,13 +138,12 @@ class MediaDataFilter @Inject constructor(
}
}
- val activeMedia = userEntries.filter { (key, value) -> value.active }
- var isSsReactivatedMutable = activeMedia.isEmpty() && userEntries.isNotEmpty()
+ val shouldReactivate = !hasActiveMedia() && hasAnyMedia()
if (timeSinceActive < smartspaceMaxAgeMillis) {
// It could happen there are existing active media resume cards, then we don't need to
// reactivate.
- if (isSsReactivatedMutable) {
+ if (shouldReactivate) {
val lastActiveKey = sorted.lastKey() // most recently active
// Notify listeners to consider this media active
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
@@ -154,7 +153,7 @@ class MediaDataFilter @Inject constructor(
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
receivedSmartspaceCardLatency =
(systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis)
- .toInt())
+ .toInt(), isSsReactivated = true)
}
}
} else {
@@ -166,8 +165,7 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
return
}
- listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable,
- isSsReactivatedMutable) }
+ listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
}
override fun onMediaDataRemoved(key: String) {
@@ -258,14 +256,27 @@ class MediaDataFilter @Inject constructor(
}
/**
- * Are there any media notifications active?
+ * Are there any media notifications active, including the recommendation?
*/
- fun hasActiveMedia() = userEntries.any { it.value.active } || smartspaceMediaData.isActive
+ fun hasActiveMediaOrRecommendation() =
+ userEntries.any { it.value.active } ||
+ (smartspaceMediaData.isActive && smartspaceMediaData.isValid)
/**
* Are there any media entries we should display?
*/
- fun hasAnyMedia() = userEntries.isNotEmpty() || smartspaceMediaData.isActive
+ fun hasAnyMediaOrRecommendation() = userEntries.isNotEmpty() ||
+ (smartspaceMediaData.isActive && smartspaceMediaData.isValid)
+
+ /**
+ * Are there any media notifications active (excluding the recommendation)?
+ */
+ fun hasActiveMedia() = userEntries.any { it.value.active }
+
+ /**
+ * Are there any media entries we should display (excluding the recommendation)?
+ */
+ fun hasAnyMedia() = userEntries.isNotEmpty()
/**
* Add a listener for filtered [MediaData] changes
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 7c0f7fc2967e..5d2d556a5773 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -828,15 +828,27 @@ class MediaDataManager(
fun onSwipeToDismiss() = mediaDataFilter.onSwipeToDismiss()
/**
- * Are there any media notifications active?
+ * Are there any media notifications active, including the recommendations?
*/
- fun hasActiveMedia() = mediaDataFilter.hasActiveMedia()
+ fun hasActiveMediaOrRecommendation() = mediaDataFilter.hasActiveMediaOrRecommendation()
/**
- * Are there any media entries we should display?
+ * Are there any media entries we should display, including the recommendations?
* If resumption is enabled, this will include inactive players
* If resumption is disabled, we only want to show active players
*/
+ fun hasAnyMediaOrRecommendation() = mediaDataFilter.hasAnyMediaOrRecommendation()
+
+ /**
+ * Are there any resume media notifications active, excluding the recommendations?
+ */
+ fun hasActiveMedia() = mediaDataFilter.hasActiveMedia()
+
+ /**
+ * Are there any resume media notifications active, excluding the recommendations?
+ * If resumption is enabled, this will include inactive players
+ * If resumption is disabled, we only want to show active players
+ */
fun hasAnyMedia() = mediaDataFilter.hasAnyMedia()
interface Listener {
@@ -855,13 +867,17 @@ class MediaDataManager(
* @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI
* displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace
* signal.
+ *
+ * @param isSsReactivated indicates resume media card is reactivated by Smartspace
+ * recommendation signal
*/
fun onMediaDataLoaded(
key: String,
oldKey: String?,
data: MediaData,
immediately: Boolean = true,
- receivedSmartspaceCardLatency: Int = 0
+ receivedSmartspaceCardLatency: Int = 0,
+ isSsReactivated: Boolean = false
) {}
/**
@@ -870,15 +886,11 @@ class MediaDataManager(
* @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true,
* it will be prioritized as the first card. Otherwise, it will show up as the last card as
* default.
- *
- * @param isSsReactivated indicates resume media card is reactivated by Smartspace
- * recommendation signal
*/
fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean = false,
- isSsReactivated: Boolean = false
+ shouldPrioritize: Boolean = false
) {}
/** Called whenever a previously existing Media notification was removed. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index bed254fe8249..085bae8bc25d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -68,7 +68,8 @@ class MediaDeviceManager @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
if (oldKey != null && oldKey != key) {
val oldEntry = entries.remove(oldKey)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index c8cd43287c99..a7640ff951c8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -28,6 +28,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import androidx.annotation.VisibleForTesting
+import com.android.keyguard.KeyguardViewController
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
@@ -39,7 +40,6 @@ import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.Utils
@@ -82,7 +82,7 @@ class MediaHierarchyManager @Inject constructor(
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
configurationController: ConfigurationController,
wakefulnessLifecycle: WakefulnessLifecycle,
- private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ private val keyguardViewController: KeyguardViewController
) {
/**
@@ -998,7 +998,7 @@ class MediaHierarchyManager @Inject constructor(
private fun isLockScreenVisibleToUser(): Boolean {
return !statusBarStateController.isDozing &&
- !statusBarKeyguardViewManager.isBouncerShowing &&
+ !keyguardViewController.isBouncerShowing &&
statusBarStateController.state == StatusBarState.KEYGUARD &&
notifLockscreenUserManager.shouldShowLockscreenNotifications() &&
statusBarStateController.isExpanded &&
@@ -1007,7 +1007,7 @@ class MediaHierarchyManager @Inject constructor(
private fun isLockScreenShadeVisibleToUser(): Boolean {
return !statusBarStateController.isDozing &&
- !statusBarKeyguardViewManager.isBouncerShowing &&
+ !keyguardViewController.isBouncerShowing &&
(statusBarStateController.state == StatusBarState.SHADE_LOCKED ||
(statusBarStateController.state == StatusBarState.KEYGUARD && qsExpanded))
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 0a4b68b501f7..3ed90fd0c58c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -61,7 +61,8 @@ class MediaHost constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
if (immediately) {
updateViewVisibility()
@@ -71,8 +72,7 @@ class MediaHost constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean,
- isSsReactivated: Boolean
+ shouldPrioritize: Boolean
) {
updateViewVisibility()
}
@@ -162,9 +162,9 @@ class MediaHost constructor(
private fun updateViewVisibility() {
state.visible = if (showsOnlyActiveMedia) {
- mediaDataManager.hasActiveMedia()
+ mediaDataManager.hasActiveMediaOrRecommendation()
} else {
- mediaDataManager.hasAnyMedia()
+ mediaDataManager.hasAnyMediaOrRecommendation()
}
val newVisibility = if (visible) View.VISIBLE else View.GONE
if (newVisibility != hostView.visibility) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 35f95dd27c1f..61d0b41e9bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -184,7 +184,8 @@ class MediaResumeListener @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
index 1c448a2ff8c4..31792967899d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
@@ -96,7 +96,8 @@ class MediaSessionBasedFilter @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
backgroundExecutor.execute {
data.token?.let {
@@ -143,8 +144,7 @@ class MediaSessionBasedFilter @Inject constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
- shouldPrioritize: Boolean,
- isSsReactivated: Boolean
+ shouldPrioritize: Boolean
) {
backgroundExecutor.execute {
dispatchSmartspaceMediaDataLoaded(key, data)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 9581a633a8c5..51755065d4b6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -63,7 +63,8 @@ class MediaTimeoutListener @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
- receivedSmartspaceCardLatency: Int
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
) {
var reusedListener: PlaybackStateListener? = null
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 113ba59cd514..e01916f0abe8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -177,13 +177,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mConnectedItem = mContainerLayout;
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
- if (mController.getSelectableMediaDevice().size() > 0) {
- mAddIcon.setVisibility(View.VISIBLE);
- mAddIcon.setTransitionAlpha(1);
- mAddIcon.setOnClickListener(this::onEndItemClick);
- } else {
- mAddIcon.setVisibility(View.GONE);
- }
+ mAddIcon.setVisibility(View.VISIBLE);
+ mAddIcon.setTransitionAlpha(1);
+ mAddIcon.setOnClickListener(this::onEndItemClick);
mTitleIcon.setImageDrawable(getSpeakerDrawable());
final CharSequence sessionName = mController.getSessionName();
final CharSequence title = TextUtils.isEmpty(sessionName)
@@ -198,7 +194,10 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
if (mController.isTransferring()) {
return;
}
-
+ if (isCurrentlyConnected(device)) {
+ Log.d(TAG, "This device is already connected! : " + device.getName());
+ return;
+ }
mCurrentActivePosition = -1;
playSwitchingAnim(mConnectedItem, view);
mController.connectDevice(device);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index f2cb254c3b97..b309c1bb67b9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -150,6 +150,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
void refresh() {
+ refresh(false);
+ }
+
+ void refresh(boolean deviceSetChanged) {
// Update header icon
final int iconRes = getHeaderIconRes();
final IconCompat iconCompat = getHeaderIcon();
@@ -175,7 +179,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
int currentActivePosition = mAdapter.getCurrentActivePosition();
- if (currentActivePosition >= 0 && currentActivePosition < mAdapter.getItemCount()) {
+ if (!deviceSetChanged && currentActivePosition >= 0
+ && currentActivePosition < mAdapter.getItemCount()) {
mAdapter.notifyItemChanged(currentActivePosition);
} else {
mAdapter.notifyDataSetChanged();
@@ -215,6 +220,11 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
@Override
+ public void onDeviceListChanged() {
+ mMainThreadHandler.post(() -> refresh(true));
+ }
+
+ @Override
public void dismissDialog() {
dismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index a1e2c57c5c37..0d368fa5fb7f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -84,7 +84,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final SystemUIDialogManager mDialogManager;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
- private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private final NotificationEntryManager mNotificationEntryManager;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -117,8 +116,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
mDialogLaunchAnimator = dialogLaunchAnimator;
- mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
mDialogManager = dialogManager;
}
@@ -166,7 +163,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
buildMediaDevices(devices);
- mCallback.onRouteChanged();
+ mCallback.onDeviceListChanged();
}
@Override
@@ -496,10 +493,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|| features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
}
+ private boolean isPlayBackInfoLocal() {
+ return mMediaController.getPlaybackInfo() != null
+ && mMediaController.getPlaybackInfo().getPlaybackType()
+ == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+ }
+
boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
- // TODO(b/202500642): Also enable volume control for remote non-group sessions.
- return !isActiveRemoteDevice(device)
- || mVolumeAdjustmentForRemoteGroupSessions;
+ return isPlayBackInfoLocal()
+ || mLocalMediaManager.isMediaSessionAvailableForVolumeControl();
}
private final MediaController.Callback mCb = new MediaController.Callback() {
@@ -529,11 +531,16 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
void onMediaStoppedOrPaused();
/**
- * Override to handle the device updating.
+ * Override to handle the device status or attributes updating.
*/
void onRouteChanged();
/**
+ * Override to handle the devices set updating.
+ */
+ void onDeviceListChanged();
+
+ /**
* Override to dismiss dialog.
*/
void dismissDialog();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index a201c071bbbe..6c95cc661e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -107,6 +107,8 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
initSeekbar(device);
final List<MediaDevice> selectedDevices = mController.getSelectedMediaDevice();
if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+ mSeekBar.setEnabled(false);
+ mSeekBar.setOnTouchListener((v, event) -> true);
mCheckBox.setButtonDrawable(R.drawable.ic_check_box);
mCheckBox.setChecked(false);
mCheckBox.setEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index e82e9d284bdd..e348f2ca7b31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -428,7 +428,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void setBrightnessMirrorController(
BrightnessMirrorController brightnessMirrorController) {
mQSPanelController.setBrightnessMirror(brightnessMirrorController);
- mQuickQSPanelController.setBrightnessMirror(brightnessMirrorController);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 001c740e310a..1837b5bf2044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -182,7 +182,9 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
/** */
public void setListening(boolean listening, boolean expanded) {
- setListening(listening && expanded);
+ // TODO(218268829): checking for split shade is workaround but when proper fix lands
+ // "|| mShouldUseSplitNotificationShade" should be removed
+ setListening(listening && (expanded || mShouldUseSplitNotificationShade));
if (mView.isListening()) {
refreshAllTiles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
deleted file mode 100644
index 65889d792769..000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs
-
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.settings.brightness.BrightnessController
-import com.android.systemui.settings.brightness.BrightnessSliderController
-import com.android.systemui.settings.brightness.MirroredBrightnessController
-import com.android.systemui.statusbar.policy.BrightnessMirrorController
-import javax.inject.Inject
-
-/**
- * Controls brightness slider in QQS, which is visible only in split shade. It's responsible for
- * showing/hiding it when appropriate and (un)registering listeners
- */
-class QuickQSBrightnessController @VisibleForTesting constructor(
- private val brightnessControllerFactory: () -> BrightnessController
-) : MirroredBrightnessController {
-
- @Inject constructor(
- brightnessControllerFactory: BrightnessController.Factory,
- brightnessSliderControllerFactory: BrightnessSliderController.Factory,
- quickQSPanel: QuickQSPanel
- ) : this(brightnessControllerFactory = {
- val slider = brightnessSliderControllerFactory.create(quickQSPanel.context,
- quickQSPanel)
- slider.init()
- quickQSPanel.setBrightnessView(slider.rootView)
- brightnessControllerFactory.create(slider)
- })
-
- private var isListening = false
- private var brightnessController: BrightnessController? = null
- private var mirrorController: BrightnessMirrorController? = null
-
- fun init(shouldUseSplitNotificationShade: Boolean) {
- refreshVisibility(shouldUseSplitNotificationShade)
- }
-
- /**
- * Starts/Stops listening for brightness changing events.
- * It's fine to call this function even if slider is not visible (which would be the case for
- * all small screen devices), it will just do nothing in that case
- */
- fun setListening(listening: Boolean) {
- if (listening) {
- // controller can be null when slider was never shown
- if (!isListening && brightnessController != null) {
- brightnessController?.registerCallbacks()
- isListening = true
- }
- } else {
- brightnessController?.unregisterCallbacks()
- isListening = false
- }
- }
-
- fun checkRestrictionAndSetEnabled() {
- brightnessController?.checkRestrictionAndSetEnabled()
- }
-
- fun refreshVisibility(shouldUseSplitNotificationShade: Boolean) {
- if (shouldUseSplitNotificationShade) {
- showBrightnessSlider()
- } else {
- hideBrightnessSlider()
- }
- }
-
- override fun setMirror(controller: BrightnessMirrorController) {
- mirrorController = controller
- mirrorController?.let { brightnessController?.setMirror(it) }
- }
-
- private fun hideBrightnessSlider() {
- brightnessController?.hideSlider()
- }
-
- private fun showBrightnessSlider() {
- if (brightnessController == null) {
- brightnessController = brightnessControllerFactory()
- mirrorController?.also { brightnessController?.setMirror(it) }
- brightnessController?.registerCallbacks()
- isListening = true
- }
- brightnessController?.showSlider()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 92690c7d1202..fdd764ce7127 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -30,8 +30,6 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
-import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import java.util.ArrayList;
import java.util.List;
@@ -51,9 +49,6 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
}
};
- // brightness is visible only in split shade
- private final QuickQSBrightnessController mBrightnessController;
- private final BrightnessMirrorHandler mBrightnessMirrorHandler;
private final FooterActionsController mFooterActionsController;
@Inject
@@ -63,13 +58,10 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager,
- QuickQSBrightnessController quickQSBrightnessController,
@Named(QQS_FOOTER) FooterActionsController footerActionsController
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
uiEventLogger, qsLogger, dumpManager);
- mBrightnessController = quickQSBrightnessController;
- mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
mFooterActionsController = footerActionsController;
}
@@ -79,7 +71,6 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
mMediaHost.setExpansion(0.0f);
mMediaHost.setShowsOnlyActiveMedia(true);
mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
- mBrightnessController.init(mShouldUseSplitNotificationShade);
mFooterActionsController.init();
mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
}
@@ -88,20 +79,17 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
protected void onViewAttached() {
super.onViewAttached();
mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
- mBrightnessMirrorHandler.onQsPanelAttached();
}
@Override
protected void onViewDetached() {
super.onViewDetached();
mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
- mBrightnessMirrorHandler.onQsPanelDettached();
}
@Override
void setListening(boolean listening) {
super.setListening(listening);
- mBrightnessController.setListening(listening);
mFooterActionsController.setListening(listening);
}
@@ -115,14 +103,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
}
@Override
- public void refreshAllTiles() {
- mBrightnessController.checkRestrictionAndSetEnabled();
- super.refreshAllTiles();
- }
-
- @Override
protected void onConfigurationChanged() {
- mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
}
@@ -146,8 +127,4 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
public int getNumQuickTiles() {
return mView.getNumQuickTiles();
}
-
- public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
- mBrightnessMirrorHandler.setController(brightnessMirrorController);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 0e3b5b5c882b..5b378007d570 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -242,13 +242,12 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onMediaDataLoaded(@NonNull String key,
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
- int receivedSmartspaceCardLatency) {
+ int receivedSmartspaceCardLatency, boolean isSsReactivated) {
}
@Override
public void onSmartspaceMediaDataLoaded(@NonNull String key,
- @NonNull SmartspaceMediaData data, boolean shouldPrioritize,
- boolean isSsReactivated) {
+ @NonNull SmartspaceMediaData data, boolean shouldPrioritize) {
}
@Override
@@ -317,13 +316,12 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onMediaDataLoaded(@NonNull String key,
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
- int receivedSmartspaceCardLatency) {
+ int receivedSmartspaceCardLatency, boolean isSsReactivated) {
}
@Override
public void onSmartspaceMediaDataLoaded(@NonNull String key,
- @NonNull SmartspaceMediaData data, boolean shouldPrioritize,
- boolean isSsReactivated) {
+ @NonNull SmartspaceMediaData data, boolean shouldPrioritize) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 6ea79af8b9ad..65ff5583e7d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
@@ -188,6 +189,14 @@ public interface NotificationShadeWindowController extends RemoteInputController
default void setLightRevealScrimOpaque(boolean opaque) {}
/**
+ * Defer any application of window {@link WindowManager.LayoutParams} until {@code scope} is
+ * fully applied.
+ */
+ default void batchApplyWindowLayoutParams(@NonNull Runnable scope) {
+ scope.run();
+ }
+
+ /**
* Custom listener to pipe data back to plugins about whether or not the status bar would be
* collapsed if not for the plugin.
* TODO: Find cleaner way to do this.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 464b2b69c58e..e0e928073336 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -25,6 +25,7 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -42,6 +43,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.Assert;
import com.android.wm.shell.bubbles.Bubbles;
@@ -92,6 +94,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private final KeyguardBypassController mBypassController;
private final ForegroundServiceSectionController mFgsSectionController;
private AssistantFeedbackController mAssistantFeedbackController;
+ private final KeyguardStateController mKeyguardStateController;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final Context mContext;
private NotificationPresenter mPresenter;
@@ -121,7 +125,9 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
ForegroundServiceSectionController fgsSectionController,
DynamicChildBindController dynamicChildBindController,
LowPriorityInflationHelper lowPriorityInflationHelper,
- AssistantFeedbackController assistantFeedbackController) {
+ AssistantFeedbackController assistantFeedbackController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ KeyguardStateController keyguardStateController) {
mContext = context;
mHandler = mainHandler;
mFeatureFlags = featureFlags;
@@ -140,6 +146,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
mDynamicChildBindController = dynamicChildBindController;
mLowPriorityInflationHelper = lowPriorityInflationHelper;
mAssistantFeedbackController = assistantFeedbackController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardStateController = keyguardStateController;
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -163,6 +171,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
beginUpdate();
+ boolean dynamicallyUnlocked = mDynamicPrivacyController.isDynamicallyUnlocked()
+ && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+ && mKeyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(
+ KeyguardUpdateMonitor.getCurrentUser()))
+ && !mKeyguardStateController.isKeyguardGoingAway();
List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
final int N = activeNotifications.size();
@@ -181,7 +194,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(currentUserId);
boolean userPublic = devicePublic
|| mLockscreenUserManager.isLockscreenPublicMode(userId);
- if (userPublic && mDynamicPrivacyController.isDynamicallyUnlocked()
+ if (userPublic && dynamicallyUnlocked
&& (userId == currentUserId || userId == UserHandle.USER_ALL
|| !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
userPublic = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index da2b85ee0b61..af503a9360ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -28,6 +28,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.SystemProperties;
+import android.os.Trace;
import android.text.format.DateFormat;
import android.util.FloatProperty;
import android.util.Log;
@@ -507,6 +508,7 @@ public class StatusBarStateControllerImpl implements
}
private void recordHistoricalState(int newState, int lastState, boolean upcoming) {
+ Trace.traceCounter(Trace.TRACE_TAG_APP, "statusBarState", newState);
mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
HistoricalState state = mHistoricalRecords[mHistoryIndex];
state.mNewState = newState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index f2d926d97108..4c5522fc66c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -23,6 +23,7 @@ import android.os.Handler;
import android.service.dreams.IDreamManager;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.SysUISingleton;
@@ -69,6 +70,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tracing.ProtoTracer;
@@ -201,7 +203,9 @@ public interface StatusBarDependenciesModule {
ForegroundServiceSectionController fgsSectionController,
DynamicChildBindController dynamicChildBindController,
LowPriorityInflationHelper lowPriorityInflationHelper,
- AssistantFeedbackController assistantFeedbackController) {
+ AssistantFeedbackController assistantFeedbackController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ KeyguardStateController keyguardStateController) {
return new NotificationViewHierarchyManager(
context,
mainHandler,
@@ -217,7 +221,9 @@ public interface StatusBarDependenciesModule {
fgsSectionController,
dynamicChildBindController,
lowPriorityInflationHelper,
- assistantFeedbackController);
+ assistantFeedbackController,
+ keyguardUpdateMonitor,
+ keyguardStateController);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index fe1cd7b98cf9..43710916628a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -157,6 +157,8 @@ public class KeyguardCoordinator implements Coordinator {
}
}
+ // TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
+ // these same updates
private void setupInvalidateNotifListCallbacks() {
// register onKeyguardShowing callback
mKeyguardStateController.addCallback(mKeyguardCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index a115e0400de3..9c82cb64a0d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -17,7 +17,10 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import android.os.UserHandle
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.DynamicPrivacyController
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -26,6 +29,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
+import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Module
import dagger.Provides
@@ -36,9 +40,13 @@ object SensitiveContentCoordinatorModule {
@CoordinatorScope
fun provideCoordinator(
dynamicPrivacyController: DynamicPrivacyController,
- lockscreenUserManager: NotificationLockscreenUserManager
+ lockscreenUserManager: NotificationLockscreenUserManager,
+ keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ statusBarStateController: StatusBarStateController,
+ keyguardStateController: KeyguardStateController
): SensitiveContentCoordinator =
- SensitiveContentCoordinatorImpl(dynamicPrivacyController, lockscreenUserManager)
+ SensitiveContentCoordinatorImpl(dynamicPrivacyController, lockscreenUserManager,
+ keyguardUpdateMonitor, statusBarStateController, keyguardStateController)
}
/** Coordinates re-inflation and post-processing of sensitive notification content. */
@@ -46,7 +54,10 @@ interface SensitiveContentCoordinator : Coordinator
private class SensitiveContentCoordinatorImpl(
private val dynamicPrivacyController: DynamicPrivacyController,
- private val lockscreenUserManager: NotificationLockscreenUserManager
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val statusBarStateController: StatusBarStateController,
+ private val keyguardStateController: KeyguardStateController
) : Invalidator("SensitiveContentInvalidator"),
SensitiveContentCoordinator,
DynamicPrivacyController.Listener,
@@ -61,6 +72,19 @@ private class SensitiveContentCoordinatorImpl(
override fun onDynamicPrivacyChanged(): Unit = invalidateList()
override fun onBeforeRenderList(entries: List<ListEntry>) {
+ if (keyguardStateController.isKeyguardGoingAway() ||
+ statusBarStateController.getState() == StatusBarState.KEYGUARD &&
+ keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ // don't update yet if:
+ // - the keyguard is currently going away
+ // - LS is about to be dismissed by a biometric that bypasses LS (avoid notif flash)
+
+ // TODO(b/206118999): merge this class with KeyguardCoordinator which ensures the
+ // dependent state changes invalidate the pipeline
+ return
+ }
+
val currentUserId = lockscreenUserManager.currentUserId
val devicePublic = lockscreenUserManager.isLockscreenPublicMode(currentUserId)
val deviceSensitive = devicePublic &&
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 98b5dcc25730..2df56bfa3909 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -405,7 +405,6 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
// During wake and unlock, we need to draw black before waking up to avoid abrupt
// brightness changes due to display state transitions.
boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
- boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
Runnable wakeUp = ()-> {
if (!wasDeviceInteractive) {
if (DEBUG_BIO_WAKELOCK) {
@@ -414,15 +413,12 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"android.policy:BIOMETRIC");
}
- if (delayWakeUp) {
- mKeyguardViewMediator.onWakeAndUnlocking();
- }
Trace.beginSection("release wake-and-unlock");
releaseBiometricWakeLock();
Trace.endSection();
};
- if (!delayWakeUp && mMode != MODE_NONE) {
+ if (mMode != MODE_NONE) {
wakeUp.run();
}
switch (mMode) {
@@ -472,11 +468,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mUpdateMonitor.awakenFromDream();
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- if (delayWakeUp) {
- mHandler.postDelayed(wakeUp, mWakeUpDelay);
- } else {
- mKeyguardViewMediator.onWakeAndUnlocking();
- }
+ mKeyguardViewMediator.onWakeAndUnlocking();
Trace.endSection();
break;
case MODE_ONLY_WAKE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 33c4109b3426..7432fa98051d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -145,6 +145,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -664,7 +665,9 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
- StatusBarStateController statusBarStateController, DozeLog dozeLog,
+ StatusBarStateController statusBarStateController,
+ NotificationShadeWindowController notificationShadeWindowController,
+ DozeLog dozeLog,
DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper,
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
@@ -716,6 +719,7 @@ public class NotificationPanelViewController extends PanelViewController {
dozeLog,
keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController,
+ notificationShadeWindowController,
vibratorHelper,
statusBarKeyguardViewManager,
latencyTracker,
@@ -1293,9 +1297,11 @@ public class NotificationPanelViewController extends PanelViewController {
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
- .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
+ .getVisibleNotificationCount() != 0
+ || mMediaDataManager.hasActiveMediaOrRecommendation();
boolean splitShadeWithActiveMedia =
- mShouldUseSplitNotificationShade && mMediaDataManager.hasActiveMedia();
+ mShouldUseSplitNotificationShade
+ && mMediaDataManager.hasActiveMediaOrRecommendation();
if ((hasVisibleNotifications && !mShouldUseSplitNotificationShade)
|| (splitShadeWithActiveMedia && !mDozing)) {
mKeyguardStatusViewController.displayClock(SMALL);
@@ -1361,7 +1367,8 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
- .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
+ .getVisibleNotificationCount() != 0
+ || mMediaDataManager.hasActiveMediaOrRecommendation();
boolean shouldBeCentered =
!mShouldUseSplitNotificationShade || !hasVisibleNotifications || mDozing;
if (mStatusViewCentered != shouldBeCentered) {
@@ -2576,7 +2583,7 @@ public class NotificationPanelViewController extends PanelViewController {
float endPosition = 0;
if (pxAmount > 0.0f) {
if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() == 0
- && !mMediaDataManager.hasActiveMedia()) {
+ && !mMediaDataManager.hasActiveMediaOrRecommendation()) {
// No notifications are visible, let's animate to the height of qs instead
if (mQs != null) {
// Let's interpolate to the header height instead of the top padding,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 030a8951943d..8c76a1bf4f83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -107,6 +107,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
private final SysuiColorExtractor mColorExtractor;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private float mFaceAuthDisplayBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+ /**
+ * Layout params would be aggregated and dispatched all at once if this is > 0.
+ *
+ * @see #batchApplyWindowLayoutParams(Runnable)
+ */
+ private int mDeferWindowLayoutParams;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -433,6 +439,20 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
+ private void applyWindowLayoutParams() {
+ if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
+ mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
+ }
+ }
+
+ @Override
+ public void batchApplyWindowLayoutParams(Runnable scope) {
+ mDeferWindowLayoutParams++;
+ scope.run();
+ mDeferWindowLayoutParams--;
+ applyWindowLayoutParams();
+ }
+
private void apply(State state) {
applyKeyguardFlags(state);
applyFocusableFlag(state);
@@ -447,9 +467,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
applyHasTopUi(state);
applyNotTouchable(state);
applyStatusBarColorSpaceAgnosticFlag(state);
- if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
- mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
- }
+ applyWindowLayoutParams();
+
if (mHasTopUi != mHasTopUiChanged) {
whitelistIpcs(() -> {
try {
@@ -722,6 +741,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
pw.println(TAG + ":");
pw.println(" mKeyguardMaxRefreshRate=" + mKeyguardMaxRefreshRate);
pw.println(" mKeyguardPreferredRefreshRate=" + mKeyguardPreferredRefreshRate);
+ pw.println(" mDeferWindowLayoutParams=" + mDeferWindowLayoutParams);
pw.println(mCurrentState);
if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
mNotificationShadeView.getViewRootImpl().dump(" ", pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 2bf16fc9e52c..040820e90790 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -54,6 +54,7 @@ import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -177,6 +178,7 @@ public abstract class PanelViewController {
private boolean mExpandLatencyTracking;
private final PanelView mView;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
protected final Resources mResources;
protected final KeyguardStateController mKeyguardStateController;
protected final SysuiStatusBarStateController mStatusBarStateController;
@@ -215,6 +217,7 @@ public abstract class PanelViewController {
DozeLog dozeLog,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController,
+ NotificationShadeWindowController notificationShadeWindowController,
VibratorHelper vibratorHelper,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
LatencyTracker latencyTracker,
@@ -247,6 +250,7 @@ public abstract class PanelViewController {
mResources = mView.getResources();
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = statusBarStateController;
+ mNotificationShadeWindowController = notificationShadeWindowController;
mFlingAnimationUtils = flingAnimationUtilsBuilder
.reset()
.setMaxLengthSeconds(0.6f)
@@ -743,34 +747,36 @@ public abstract class PanelViewController {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
- if (mExpandLatencyTracking && h != 0f) {
- DejankUtils.postAfterTraversal(
- () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
- mExpandLatencyTracking = false;
- }
- float maxPanelHeight = getMaxPanelHeight();
- if (mHeightAnimator == null) {
- if (mTracking) {
- float overExpansionPixels = Math.max(0, h - maxPanelHeight);
- setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ if (mExpandLatencyTracking && h != 0f) {
+ DejankUtils.postAfterTraversal(
+ () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
+ mExpandLatencyTracking = false;
+ }
+ float maxPanelHeight = getMaxPanelHeight();
+ if (mHeightAnimator == null) {
+ if (mTracking) {
+ float overExpansionPixels = Math.max(0, h - maxPanelHeight);
+ setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
+ }
+ mExpandedHeight = Math.min(h, maxPanelHeight);
+ } else {
+ mExpandedHeight = h;
}
- mExpandedHeight = Math.min(h, maxPanelHeight);
- } else {
- mExpandedHeight = h;
- }
- // If we are closing the panel and we are almost there due to a slow decelerating
- // interpolator, abort the animation.
- if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
- mExpandedHeight = 0f;
- if (mHeightAnimator != null) {
- mHeightAnimator.end();
+ // If we are closing the panel and we are almost there due to a slow decelerating
+ // interpolator, abort the animation.
+ if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
+ mExpandedHeight = 0f;
+ if (mHeightAnimator != null) {
+ mHeightAnimator.end();
+ }
}
- }
- mExpandedFraction = Math.min(1f,
- maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
- onHeightUpdated(mExpandedHeight);
- updatePanelExpansionAndVisibility();
+ mExpandedFraction = Math.min(1f,
+ maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ onHeightUpdated(mExpandedHeight);
+ updatePanelExpansionAndVisibility();
+ });
}
/**
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 33212182cfcf..a6fb317cdfc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1351,8 +1351,11 @@ public class StatusBar extends SystemUI implements
* keyguard.
*/
private void dispatchPanelExpansionForKeyguardDismiss(float fraction, boolean trackingTouch) {
- // Things that mean we're not dismissing the keyguard, and should ignore this expansion:
+ // Things that mean we're not swiping to dismiss the keyguard, and should ignore this
+ // expansion:
// - Keyguard isn't even visible.
+ // - Keyguard is occluded. Expansion changes here are the shade being expanded over the
+ // occluding activity.
// - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt).
// - The SIM is locked, you can't swipe to unlock. If the SIM is locked but there is no
// device lock set, canDismissLockScreen returns true even though you should not be able
@@ -1360,6 +1363,7 @@ public class StatusBar extends SystemUI implements
// - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
// keyguard.
if (!isKeyguardShowing()
+ || mIsOccluded
|| !mKeyguardStateController.canDismissLockScreen()
|| mKeyguardViewMediator.isAnySimPinSecure()
|| (mNotificationPanelViewController.isQsExpanded() && trackingTouch)) {
@@ -2957,6 +2961,7 @@ public class StatusBar extends SystemUI implements
}
public void showKeyguardImpl() {
+ Trace.beginSection("StatusBar#showKeyguard");
mIsKeyguard = true;
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
mNotificationPanelViewController.cancelAnimation();
@@ -2969,6 +2974,7 @@ public class StatusBar extends SystemUI implements
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
updatePanelExpansionForKeyguard();
+ Trace.endSection();
}
private void updatePanelExpansionForKeyguard() {
@@ -3557,26 +3563,29 @@ public class StatusBar extends SystemUI implements
public void onStartedWakingUp() {
String tag = "StatusBar#onStartedWakingUp";
DejankUtils.startDetectingBlockingIpcs(tag);
- mDeviceInteractive = true;
- mWakeUpCoordinator.setWakingUp(true);
- if (!mKeyguardBypassController.getBypassEnabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
- updateVisibleToUser();
- updateIsKeyguard();
- mDozeServiceHost.stopDozing();
- // This is intentionally below the stopDozing call above, since it avoids that we're
- // unnecessarily animating the wakeUp transition. Animations should only be enabled
- // once we fully woke up.
- updateRevealEffect(true /* wakingUp */);
- updateNotificationPanelTouchState();
-
- // If we are waking up during the screen off animation, we should undo making the
- // expanded visible (we did that so the LightRevealScrim would be visible).
- if (mUnlockedScreenOffAnimationController.isScreenOffLightRevealAnimationPlaying()) {
- makeExpandedInvisible();
- }
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ mDeviceInteractive = true;
+ mWakeUpCoordinator.setWakingUp(true);
+ if (!mKeyguardBypassController.getBypassEnabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ updateVisibleToUser();
+ updateIsKeyguard();
+ mDozeServiceHost.stopDozing();
+ // This is intentionally below the stopDozing call above, since it avoids that we're
+ // unnecessarily animating the wakeUp transition. Animations should only be enabled
+ // once we fully woke up.
+ updateRevealEffect(true /* wakingUp */);
+ updateNotificationPanelTouchState();
+
+ // If we are waking up during the screen off animation, we should undo making the
+ // expanded visible (we did that so the LightRevealScrim would be visible).
+ if (mUnlockedScreenOffAnimationController
+ .isScreenOffLightRevealAnimationPlaying()) {
+ makeExpandedInvisible();
+ }
+ });
DejankUtils.stopDetectingBlockingIpcs(tag);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 48fe77482340..fd435d45934a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.util.Assert;
import java.util.ArrayList;
import java.util.List;
@@ -65,6 +66,8 @@ public interface StatusBarIconController {
void addIconGroup(IconManager iconManager);
/** */
void removeIconGroup(IconManager iconManager);
+ /** Refresh the state of an IconManager by recreating the views */
+ void refreshIconGroup(IconManager iconManager);
/** */
void setExternalIcon(String slot);
/** */
@@ -242,6 +245,7 @@ public interface StatusBarIconController {
protected final int mIconSize;
// Whether or not these icons show up in dumpsys
protected boolean mShouldLog = false;
+ private StatusBarIconController mController;
// Enables SystemUI demo mode to take effect in this group
protected boolean mDemoable = true;
@@ -266,13 +270,17 @@ public interface StatusBarIconController {
mDemoable = demoable;
}
+ void setController(StatusBarIconController controller) {
+ mController = controller;
+ }
+
public void setBlockList(@Nullable List<String> blockList) {
+ Assert.isMainThread();
mBlockList.clear();
- if (blockList == null || blockList.isEmpty()) {
- return;
- }
-
mBlockList.addAll(blockList);
+ if (mController != null) {
+ mController.refreshIconGroup(this);
+ }
}
public void setShouldLog(boolean should) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 88a7dc7bcd75..d6cf80ec70aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -99,6 +99,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
}
}
+ group.setController(this);
mIconGroups.add(group);
List<Slot> allSlots = getSlots();
for (int i = 0; i < allSlots.size(); i++) {
@@ -114,6 +115,12 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
}
}
+ @Override
+ public void refreshIconGroup(IconManager iconManager) {
+ removeIconGroup(iconManager);
+ addIconGroup(iconManager);
+ }
+
private void refreshIconGroups() {
for (int i = mIconGroups.size() - 1; i >= 0; --i) {
IconManager group = mIconGroups.get(i);
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 e7889286d195..fe96a5b9979f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -29,6 +29,7 @@ import android.content.res.ColorStateList;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.Trace;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -377,6 +378,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
*/
@Override
public void show(Bundle options) {
+ Trace.beginSection("StatusBarKeyguardViewManager#show");
mShowing = true;
mNotificationShadeWindowController.setKeyguardShowing(true);
mKeyguardStateController.notifyKeyguardState(mShowing,
@@ -384,6 +386,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
reset(true /* hideBouncerWhenShowing */);
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
+ Trace.endSection();
}
/**
@@ -722,6 +725,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void hide(long startTime, long fadeoutDuration) {
+ Trace.beginSection("StatusBarKeyguardViewManager#hide");
mShowing = false;
mKeyguardStateController.notifyKeyguardState(mShowing,
mKeyguardStateController.isOccluded());
@@ -821,6 +825,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
+ Trace.endSection();
}
private boolean needsBypassFading() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 14cca13b396b..8750845e57a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -60,6 +60,9 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -257,7 +260,9 @@ public abstract class StatusBarViewModule {
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
- OperatorNameViewController.Factory operatorNameViewControllerFactory
+ OperatorNameViewController.Factory operatorNameViewControllerFactory,
+ SecureSettings secureSettings,
+ @Main Executor mainExecutor
) {
return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory,
ongoingCallController,
@@ -274,6 +279,8 @@ public abstract class StatusBarViewModule {
statusBarStateController,
commandQueue,
collapsedStatusBarFragmentLogger,
- operatorNameViewControllerFactory);
+ operatorNameViewControllerFactory,
+ secureSettings,
+ mainExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index d6ba6f3ff97a..1a2f8a8e5db7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -29,8 +29,10 @@ import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Fragment;
+import android.database.ContentObserver;
import android.os.Bundle;
import android.os.Parcelable;
+import android.provider.Settings;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -38,8 +40,11 @@ import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.LinearLayout;
+import androidx.annotation.VisibleForTesting;
+
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -65,11 +70,13 @@ import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -113,6 +120,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final PanelExpansionStateManager mPanelExpansionStateManager;
private final StatusBarIconController mStatusBarIconController;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
+ private final SecureSettings mSecureSettings;
+ private final Executor mMainExecutor;
private List<String> mBlockedIcons = new ArrayList<>();
@@ -148,7 +157,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
- OperatorNameViewController.Factory operatorNameViewControllerFactory
+ OperatorNameViewController.Factory operatorNameViewControllerFactory,
+ SecureSettings secureSettings,
+ @Main Executor mainExecutor
) {
mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
mOngoingCallController = ongoingCallController;
@@ -166,6 +177,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue = commandQueue;
mCollapsedStatusBarFragmentLogger = collapsedStatusBarFragmentLogger;
mOperatorNameViewControllerFactory = operatorNameViewControllerFactory;
+ mSecureSettings = secureSettings;
+ mMainExecutor = mainExecutor;
}
@Override
@@ -190,10 +203,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags);
mDarkIconManager.setShouldLog(true);
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
- mDarkIconManager.setBlockList(mBlockedIcons);
+ updateBlockedIcons();
mStatusBarIconController.addIconGroup(mDarkIconManager);
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
@@ -206,6 +216,24 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mAnimationScheduler.addCallback(this);
}
+ @VisibleForTesting
+ void updateBlockedIcons() {
+ mBlockedIcons.clear();
+
+ if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) {
+ mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+ }
+ mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
+ mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
+
+ mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
+ }
+
+ @VisibleForTesting
+ List<String> getBlockedIcons() {
+ return mBlockedIcons;
+ }
+
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -220,6 +248,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
initOngoingCallChip();
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
+ false,
+ mVolumeSettingObserver);
}
@Override
@@ -228,6 +261,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener);
+ mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
}
@Override
@@ -597,6 +631,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mLocationPublisher.updateStatusBarMargin(leftMargin, rightMargin);
}
+ private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateBlockedIcons();
+ }
+ };
+
// Listen for view end changes of PhoneStatusBarView and publish that to the privacy dot
private View.OnLayoutChangeListener mStatusBarLayoutListener =
(view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java
new file mode 100644
index 000000000000..df845e53a36b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+
+/**
+ * USB Audio devices warning dialog messages help class.
+ */
+public class UsbAudioWarningDialogMessage {
+ private static final String TAG = "UsbAudioWarningDialogMessage";
+
+ @Retention(SOURCE)
+ @IntDef({TYPE_PERMISSION, TYPE_CONFIRM})
+ public @interface DialogType {}
+ public static final int TYPE_PERMISSION = 0;
+ public static final int TYPE_CONFIRM = 1;
+
+ private final int mDialogType;
+ private UsbDialogHelper mDialogHelper;
+
+ public UsbAudioWarningDialogMessage(Context context, Intent intent, @DialogType int type) {
+ mDialogType = type;
+ try {
+ mDialogHelper = new UsbDialogHelper(context, intent);
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Unable to initialize UsbDialogHelper!", e);
+ }
+ }
+
+ private boolean hasRecordPermission() {
+ return mDialogHelper.packageHasAudioRecordingPermission();
+ }
+
+ private boolean isUsbAudioDevice() {
+ return mDialogHelper.isUsbDevice() && (mDialogHelper.deviceHasAudioCapture()
+ || (mDialogHelper.deviceHasAudioPlayback()));
+ }
+
+ private boolean hasAudioPlayback() {
+ return mDialogHelper.deviceHasAudioPlayback();
+ }
+
+ private boolean hasAudioCapture() {
+ return mDialogHelper.deviceHasAudioCapture();
+ }
+
+ /**
+ * According to USB audio warning dialog matrix table to return warning message id.
+ * @return string resId for USB audio warning dialog message, otherwise {ID_NULL}.
+ * See usb_audio.md for USB audio Permission and Confirmation warning dialog resource
+ * string id matrix table.
+ */
+ public int getMessageId() {
+ if (!mDialogHelper.isUsbDevice()) {
+ return getUsbAccessoryPromptId();
+ }
+
+ if (hasRecordPermission() && isUsbAudioDevice()) {
+ // case# 1, 2, 3
+ return R.string.usb_audio_device_prompt;
+ } else if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioPlayback()
+ && !hasAudioCapture()) {
+ // case# 5
+ return R.string.usb_audio_device_prompt;
+ }
+
+ if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioCapture()) {
+ // case# 6,7
+ return R.string.usb_audio_device_prompt_warn;
+ }
+
+ Log.w(TAG, "Only shows title with empty content description!");
+ return Resources.ID_NULL;
+ }
+
+ /**
+ * Gets prompt dialog title.
+ * @return string id for USB prompt dialog title.
+ */
+ public int getPromptTitleId() {
+ return (mDialogType == TYPE_PERMISSION)
+ ? R.string.usb_audio_device_permission_prompt_title
+ : R.string.usb_audio_device_confirm_prompt_title;
+ }
+
+ /**
+ * Gets USB Accessory prompt message id.
+ * @return string id for USB Accessory prompt message.
+ */
+ public int getUsbAccessoryPromptId() {
+ return (mDialogType == TYPE_PERMISSION)
+ ? R.string.usb_accessory_permission_prompt : R.string.usb_accessory_confirm_prompt;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 21d700e41a40..a2bee05246ce 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
@@ -35,7 +36,6 @@ import android.os.UserHandle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -57,6 +57,7 @@ public class UsbConfirmActivity extends AlertActivity
private ResolveInfo mResolveInfo;
private boolean mPermissionGranted;
private UsbDisconnectedReceiver mDisconnectedReceiver;
+ private UsbAudioWarningDialogMessage mUsbConfirmMessageHandler;
@Override
public void onCreate(Bundle icicle) {
@@ -70,7 +71,9 @@ public class UsbConfirmActivity extends AlertActivity
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo");
String packageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
-
+ mUsbConfirmMessageHandler = new UsbAudioWarningDialogMessage(
+ getApplicationContext(), getIntent(),
+ UsbAudioWarningDialogMessage.TYPE_CONFIRM);
PackageManager packageManager = getPackageManager();
String appName = mResolveInfo.loadLabel(packageManager).toString();
@@ -78,8 +81,8 @@ public class UsbConfirmActivity extends AlertActivity
ap.mTitle = appName;
boolean useRecordWarning = false;
if (mDevice == null) {
- ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
- mAccessory.getDescription());
+ final int messageId = mUsbConfirmMessageHandler.getUsbAccessoryPromptId();
+ ap.mMessage = getString(messageId, appName, mAccessory.getDescription());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
@@ -91,11 +94,11 @@ public class UsbConfirmActivity extends AlertActivity
boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
- int strID = useRecordWarning
- ? R.string.usb_device_confirm_prompt_warn
- : R.string.usb_device_confirm_prompt;
-
- ap.mMessage = getString(strID, appName, mDevice.getProductName());
+ final int messageId = mUsbConfirmMessageHandler.getMessageId();
+ final int titleId = mUsbConfirmMessageHandler.getPromptTitleId();
+ ap.mTitle = getString(titleId, appName, mDevice.getProductName());
+ ap.mMessage = (messageId != Resources.ID_NULL) ? getString(messageId, appName,
+ mDevice.getProductName()) : null;
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
ap.mPositiveButtonText = getString(android.R.string.ok);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java
new file mode 100644
index 000000000000..ab29a9e970c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import static android.Manifest.permission.RECORD_AUDIO;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.PermissionChecker;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * Helper class to separate model and view for USB permission and confirm dialogs.
+ */
+public class UsbDialogHelper {
+ private static final String TAG = UsbDialogHelper.class.getSimpleName();
+ private static final String EXTRA_RESOLVE_INFO = "rinfo";
+
+ private final UsbDevice mDevice;
+ private final UsbAccessory mAccessory;
+ private final ResolveInfo mResolveInfo;
+ private final String mPackageName;
+ private final CharSequence mAppName;
+ private final Context mContext;
+ private final PendingIntent mPendingIntent;
+ private final IUsbManager mUsbService;
+ private final int mUid;
+ private final boolean mCanBeDefault;
+
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+ private boolean mIsUsbDevice;
+ private boolean mResponseSent;
+
+ /**
+ * @param context The Context of the caller.
+ * @param intent The intent of the caller.
+ * @throws IllegalStateException Thrown if both UsbDevice and UsbAccessory are null or if the
+ * query for the matching ApplicationInfo is unsuccessful.
+ */
+ public UsbDialogHelper(Context context, Intent intent) throws IllegalStateException {
+ mContext = context;
+ mDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ mAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ mCanBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false);
+ if (mDevice == null && mAccessory == null) {
+ throw new IllegalStateException("Device and accessory are both null.");
+ }
+ if (mDevice != null) {
+ mIsUsbDevice = true;
+ }
+ mResolveInfo = intent.getParcelableExtra(EXTRA_RESOLVE_INFO);
+ PackageManager packageManager = mContext.getPackageManager();
+ if (mResolveInfo != null) {
+ // If a ResolveInfo is provided it will be used to determine the activity to start
+ mUid = mResolveInfo.activityInfo.applicationInfo.uid;
+ mPackageName = mResolveInfo.activityInfo.packageName;
+ mPendingIntent = null;
+ } else {
+ mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
+ mPendingIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ }
+ try {
+ ApplicationInfo aInfo = packageManager.getApplicationInfo(mPackageName, 0);
+ mAppName = aInfo.loadLabel(packageManager);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("unable to look up package name", e);
+ }
+ IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+ mUsbService = IUsbManager.Stub.asInterface(b);
+ }
+
+ /**
+ * Registers UsbDisconnectedReceiver to dismiss dialog automatically when device or accessory
+ * gets disconnected
+ * @param activity The activity to finish when device / accessory gets disconnected.
+ */
+ public void registerUsbDisconnectedReceiver(Activity activity) {
+ if (mIsUsbDevice) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(activity, mDevice);
+ } else {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(activity, mAccessory);
+ }
+ }
+
+ /**
+ * Unregisters the UsbDisconnectedReceiver. To be called when the activity is destroyed.
+ * @param activity The activity registered to finish when device / accessory gets disconnected.
+ */
+ public void unregisterUsbDisconnectedReceiver(Activity activity) {
+ if (mDisconnectedReceiver != null) {
+ try {
+ activity.unregisterReceiver(mDisconnectedReceiver);
+ } catch (Exception e) {
+ // pass
+ }
+ mDisconnectedReceiver = null;
+ }
+ }
+
+ /**
+ * @return True if the intent contains a UsbDevice which can capture audio.
+ */
+ public boolean deviceHasAudioCapture() {
+ return mDevice != null && mDevice.getHasAudioCapture();
+ }
+
+ /**
+ * @return True if the intent contains a UsbDevice which can play audio.
+ */
+ public boolean deviceHasAudioPlayback() {
+ return mDevice != null && mDevice.getHasAudioPlayback();
+ }
+
+ /**
+ * @return True if the package has RECORD_AUDIO permission specified in its manifest.
+ */
+ public boolean packageHasAudioRecordingPermission() {
+ return PermissionChecker.checkPermissionForPreflight(mContext, RECORD_AUDIO,
+ PermissionChecker.PID_UNKNOWN, mUid, mPackageName)
+ == android.content.pm.PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * @return True if the intent contains a UsbDevice.
+ */
+ public boolean isUsbDevice() {
+ return mIsUsbDevice;
+ }
+
+ /**
+ * @return True if the intent contains a UsbAccessory.
+ */
+ public boolean isUsbAccessory() {
+ return !mIsUsbDevice;
+ }
+
+ /**
+ * Grants USB permission to the device / accessory to the calling uid.
+ */
+ public void grantUidAccessPermission() {
+ try {
+ if (mIsUsbDevice) {
+ mUsbService.grantDevicePermission(mDevice, mUid);
+ } else {
+ mUsbService.grantAccessoryPermission(mAccessory, mUid);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "IUsbService connection failed", e);
+ }
+ }
+
+ /**
+ * Sets the package as default for the device / accessory.
+ */
+ public void setDefaultPackage() {
+ final int userId = UserHandle.myUserId();
+ try {
+ if (mIsUsbDevice) {
+ mUsbService.setDevicePackage(mDevice, mPackageName, userId);
+ } else {
+ mUsbService.setAccessoryPackage(mAccessory, mPackageName, userId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "IUsbService connection failed", e);
+ }
+ }
+
+ /**
+ * Clears the default package of the device / accessory.
+ */
+ public void clearDefaultPackage() {
+ final int userId = UserHandle.myUserId();
+ try {
+ if (mIsUsbDevice) {
+ mUsbService.setDevicePackage(mDevice, null, userId);
+ } else {
+ mUsbService.setAccessoryPackage(mAccessory, null, userId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "IUsbService connection failed", e);
+ }
+ }
+
+ /**
+ * Starts the activity which was selected to handle the device / accessory.
+ */
+ public void confirmDialogStartActivity() {
+ final int userId = UserHandle.myUserId();
+ Intent intent;
+
+ if (mIsUsbDevice) {
+ intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+ } else {
+ intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+ }
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(
+ new ComponentName(mResolveInfo.activityInfo.packageName,
+ mResolveInfo.activityInfo.name));
+ try {
+ mContext.startActivityAsUser(intent, new UserHandle(userId));
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start activity", e);
+ }
+ }
+
+ /**
+ * Sends the result of the permission dialog via the provided PendingIntent.
+ *
+ * @param permissionGranted True if the user pressed ok in the permission dialog.
+ */
+ public void sendPermissionDialogResponse(boolean permissionGranted) {
+ if (!mResponseSent) {
+ // send response via pending intent
+ Intent intent = new Intent();
+ if (mIsUsbDevice) {
+ intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+ } else {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+ }
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, permissionGranted);
+ try {
+ mPendingIntent.send(mContext, 0, intent);
+ mResponseSent = true;
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "PendingIntent was cancelled");
+ }
+ }
+ }
+
+ /**
+ * @return A description of the device / accessory
+ */
+ public String getDeviceDescription() {
+ String desc;
+ if (mIsUsbDevice) {
+ desc = mDevice.getProductName();
+ if (desc == null) {
+ desc = mDevice.getDeviceName();
+ }
+ } else {
+ // UsbAccessory
+ desc = mAccessory.getDescription();
+ if (desc == null) {
+ desc = String.format("%s %s", mAccessory.getManufacturer(), mAccessory.getModel());
+ }
+ }
+ return desc;
+ }
+
+ /**
+ * Whether the calling package can set as default handler of the USB device or accessory.
+ * In case of a UsbAccessory this is the case if the calling package has an intent filter for
+ * {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
+ * attached accessory. In case of a UsbDevice this is the case if the calling package has an
+ * intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
+ * matching the attached device.
+ *
+ * @return True if the package can be default for the USB device.
+ */
+ public boolean canBeDefault() {
+ return mCanBeDefault;
+ }
+
+ /**
+ * @return The name of the app which requested permission or the name of the app which will be
+ * opened if the user allows it to handle the USB device.
+ */
+ public CharSequence getAppName() {
+ return mAppName;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index bfa50bcee270..b9a37b1918f2 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
@@ -59,6 +60,7 @@ public class UsbPermissionActivity extends AlertActivity
private int mUid;
private boolean mPermissionGranted;
private UsbDisconnectedReceiver mDisconnectedReceiver;
+ private UsbAudioWarningDialogMessage mUsbAudioPermissionMessageHandler;
@Override
public void onCreate(Bundle icicle) {
@@ -73,7 +75,9 @@ public class UsbPermissionActivity extends AlertActivity
mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
boolean canBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false);
-
+ mUsbAudioPermissionMessageHandler = new UsbAudioWarningDialogMessage(
+ getApplicationContext(), getIntent(),
+ UsbAudioWarningDialogMessage.TYPE_PERMISSION);
PackageManager packageManager = getPackageManager();
ApplicationInfo aInfo;
try {
@@ -91,8 +95,8 @@ public class UsbPermissionActivity extends AlertActivity
if (mDevice == null) {
// Accessory Case
- ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName,
- mAccessory.getDescription());
+ final int messageId = mUsbAudioPermissionMessageHandler.getUsbAccessoryPromptId();
+ ap.mMessage = getString(messageId, appName, mAccessory.getDescription());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
boolean hasRecordPermission =
@@ -103,10 +107,11 @@ public class UsbPermissionActivity extends AlertActivity
boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
- int strID = useRecordWarning
- ? R.string.usb_device_permission_prompt_warn
- : R.string.usb_device_permission_prompt;
- ap.mMessage = getString(strID, appName, mDevice.getProductName());
+ final int messageId = mUsbAudioPermissionMessageHandler.getMessageId();
+ final int titleId = mUsbAudioPermissionMessageHandler.getPromptTitleId();
+ ap.mTitle = getString(titleId, appName, mDevice.getProductName());
+ ap.mMessage = (messageId != Resources.ID_NULL) ? getString(messageId, appName,
+ mDevice.getProductName()) : null;
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}