Merge changes Id51293db,Ib7586997 into sc-dev
* changes: Tests for media player on the left side on lockscreen in split shade mode Moving media player in split shade mode on the lockscreen to the left side
This commit is contained in:
committed by
Android (Google) Code Review
commit
1632dd9610
@@ -20,12 +20,14 @@
|
||||
<!-- This is a view that shows general status information in Keyguard. -->
|
||||
<com.android.keyguard.KeyguardStatusView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/keyguard_status_view"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal|top">
|
||||
systemui:layout_constraintStart_toStartOf="parent"
|
||||
systemui:layout_constraintEnd_toEndOf="parent"
|
||||
systemui:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:id="@+id/status_view_container"
|
||||
android:layout_width="match_parent"
|
||||
@@ -70,5 +72,11 @@
|
||||
android:letterSpacing="0.05"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true" />
|
||||
<FrameLayout
|
||||
android:id="@+id/status_view_media_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/qs_media_padding"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</com.android.keyguard.KeyguardStatusView>
|
||||
|
||||
@@ -37,10 +37,6 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent" />
|
||||
|
||||
<include
|
||||
layout="@layout/keyguard_status_view"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -49,6 +45,10 @@
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false">
|
||||
|
||||
<include
|
||||
layout="@layout/keyguard_status_view"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<include layout="@layout/dock_info_overlay" />
|
||||
|
||||
<FrameLayout
|
||||
|
||||
@@ -35,6 +35,7 @@ import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.CrossFadeHelper;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -44,6 +45,7 @@ import java.io.PrintWriter;
|
||||
* - keyguard clock
|
||||
* - logout button (on certain managed devices)
|
||||
* - owner information (if set)
|
||||
* - media player (split shade mode only)
|
||||
*/
|
||||
public class KeyguardStatusView extends GridLayout {
|
||||
private static final boolean DEBUG = KeyguardConstants.DEBUG;
|
||||
@@ -60,6 +62,7 @@ public class KeyguardStatusView extends GridLayout {
|
||||
private KeyguardSliceView mKeyguardSlice;
|
||||
private Runnable mPendingMarqueeStart;
|
||||
private Handler mHandler;
|
||||
private View mMediaHostContainer;
|
||||
|
||||
private float mDarkAmount = 0;
|
||||
private int mTextColor;
|
||||
@@ -148,6 +151,8 @@ public class KeyguardStatusView extends GridLayout {
|
||||
mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
|
||||
onSliceContentChanged();
|
||||
|
||||
mMediaHostContainer = findViewById(R.id.status_view_media_container);
|
||||
|
||||
updateOwnerInfo();
|
||||
updateDark();
|
||||
}
|
||||
@@ -223,6 +228,9 @@ public class KeyguardStatusView extends GridLayout {
|
||||
}
|
||||
mDarkAmount = darkAmount;
|
||||
mClockView.setDarkAmount(darkAmount);
|
||||
if (mMediaHostContainer.getVisibility() != View.GONE) {
|
||||
CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
|
||||
}
|
||||
updateDark();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.media
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
@@ -29,8 +30,8 @@ import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* A class that controls the media notifications on the lock screen, handles its visibility and
|
||||
* is responsible for the embedding of he media experience.
|
||||
* Controls the media notifications on the lock screen, handles its visibility and placement -
|
||||
* switches media player positioning between split pane container vs single pane container
|
||||
*/
|
||||
@SysUISingleton
|
||||
class KeyguardMediaController @Inject constructor(
|
||||
@@ -43,46 +44,114 @@ class KeyguardMediaController @Inject constructor(
|
||||
init {
|
||||
statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
|
||||
override fun onStateChanged(newState: Int) {
|
||||
updateVisibility()
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
override fun onDozingChanged(isDozing: Boolean) {
|
||||
if (!isDozing) {
|
||||
mediaHost.visible = true
|
||||
refreshMediaPosition()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var visibilityChangedListener: ((Boolean) -> Unit)? = null
|
||||
var view: MediaHeaderView? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* Attach this controller to a media view, initializing its state
|
||||
* single pane media container placed at the top of the notifications list
|
||||
*/
|
||||
fun attach(mediaView: MediaHeaderView) {
|
||||
view = mediaView
|
||||
var singlePaneContainer: MediaHeaderView? = null
|
||||
private set
|
||||
private var splitShadeContainer: ViewGroup? = null
|
||||
private var useSplitShadeContainer: () -> Boolean = { false }
|
||||
|
||||
/**
|
||||
* Attaches media container in single pane mode, situated at the top of the notifications list
|
||||
*/
|
||||
fun attachSinglePaneContainer(mediaView: MediaHeaderView?) {
|
||||
singlePaneContainer = mediaView
|
||||
// First let's set the desired state that we want for this host
|
||||
mediaHost.addVisibilityChangeListener { updateVisibility() }
|
||||
mediaHost.expansion = 0.0f
|
||||
mediaHost.expansion = MediaHostState.COLLAPSED
|
||||
mediaHost.showsOnlyActiveMedia = true
|
||||
mediaHost.falsingProtectionNeeded = true
|
||||
|
||||
// Let's now initialize this view, which also creates the host view for us.
|
||||
mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN)
|
||||
mediaView.setContentView(mediaHost.hostView)
|
||||
|
||||
// Ensure the visibility is correct
|
||||
updateVisibility()
|
||||
// Required to show it for the first time, afterwards visibility is managed automatically
|
||||
mediaHost.visible = true
|
||||
mediaHost.addVisibilityChangeListener { visible ->
|
||||
refreshMediaPosition()
|
||||
if (visible) {
|
||||
mediaHost.hostView.layoutParams.apply {
|
||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
}
|
||||
}
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
private fun updateVisibility() {
|
||||
/**
|
||||
* Attaches media container in split shade mode, situated to the left of notifications
|
||||
*/
|
||||
fun attachSplitShadeContainer(container: ViewGroup, useContainer: () -> Boolean) {
|
||||
splitShadeContainer = container
|
||||
useSplitShadeContainer = useContainer
|
||||
}
|
||||
|
||||
fun refreshMediaPosition() {
|
||||
val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD ||
|
||||
statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
|
||||
// mediaHost.visible required for proper animations handling
|
||||
val shouldBeVisible = mediaHost.visible &&
|
||||
!bypassController.bypassEnabled &&
|
||||
keyguardOrUserSwitcher &&
|
||||
notifLockscreenUserManager.shouldShowLockscreenNotifications()
|
||||
val previousVisibility = view?.visibility ?: View.GONE
|
||||
val newVisibility = if (shouldBeVisible) View.VISIBLE else View.GONE
|
||||
if (shouldBeVisible) {
|
||||
showMediaPlayer()
|
||||
} else {
|
||||
hideMediaPlayer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMediaPlayer() {
|
||||
if (useSplitShadeContainer()) {
|
||||
showMediaPlayer(
|
||||
activeContainer = splitShadeContainer,
|
||||
inactiveContainer = singlePaneContainer)
|
||||
} else {
|
||||
showMediaPlayer(
|
||||
activeContainer = singlePaneContainer,
|
||||
inactiveContainer = splitShadeContainer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMediaPlayer(activeContainer: ViewGroup?, inactiveContainer: ViewGroup?) {
|
||||
if (inactiveContainer?.childCount == 1) {
|
||||
inactiveContainer.removeAllViews()
|
||||
}
|
||||
// might be called a few times for the same view, no need to add hostView again
|
||||
if (activeContainer?.childCount == 0) {
|
||||
activeContainer.addView(mediaHost.hostView)
|
||||
}
|
||||
setVisibility(activeContainer, View.VISIBLE)
|
||||
setVisibility(inactiveContainer, View.GONE)
|
||||
}
|
||||
|
||||
private fun hideMediaPlayer() {
|
||||
if (useSplitShadeContainer()) {
|
||||
setVisibility(splitShadeContainer, View.GONE)
|
||||
} else {
|
||||
setVisibility(singlePaneContainer, View.GONE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVisibility(view: ViewGroup?, newVisibility: Int) {
|
||||
val previousVisibility = view?.visibility
|
||||
view?.visibility = newVisibility
|
||||
if (previousVisibility != newVisibility) {
|
||||
visibilityChangedListener?.invoke(shouldBeVisible)
|
||||
visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,15 +264,20 @@ class MediaHost constructor(
|
||||
*/
|
||||
interface MediaHostState {
|
||||
|
||||
companion object {
|
||||
const val EXPANDED: Float = 1.0f
|
||||
const val COLLAPSED: Float = 0.0f
|
||||
}
|
||||
|
||||
/**
|
||||
* The last measurement input that this state was measured with. Infers with and height of
|
||||
* The last measurement input that this state was measured with. Infers width and height of
|
||||
* the players.
|
||||
*/
|
||||
var measurementInput: MeasurementInput?
|
||||
|
||||
/**
|
||||
* The expansion of the player, 0 for fully collapsed (up to 3 actions), 1 for fully expanded
|
||||
* (up to 5 actions.)
|
||||
* The expansion of the player, [COLLAPSED] for fully collapsed (up to 3 actions),
|
||||
* [EXPANDED] for fully expanded (up to 5 actions).
|
||||
*/
|
||||
var expansion: Float
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||
|
||||
@@ -43,11 +42,4 @@ public class MediaHeaderView extends ExpandableView {
|
||||
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
|
||||
// No animation, it doesn't need it, this would be local
|
||||
}
|
||||
|
||||
public void setContentView(ViewGroup contentView) {
|
||||
addView(contentView);
|
||||
ViewGroup.LayoutParams layoutParams = contentView.getLayoutParams();
|
||||
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ class NotificationSectionsManager @Inject internal constructor(
|
||||
incomingHeaderController.reinflateView(parent)
|
||||
mediaControlsView =
|
||||
reinflateView(mediaControlsView, layoutInflater, R.layout.keyguard_media_header)
|
||||
.also(keyguardMediaController::attach)
|
||||
keyguardMediaController.attachSinglePaneContainer(mediaControlsView)
|
||||
}
|
||||
|
||||
override fun beginsSection(view: View, previous: View?): Boolean =
|
||||
|
||||
@@ -708,9 +708,10 @@ public class NotificationStackScrollLayoutController {
|
||||
mView.setKeyguardMediaControllorVisible(visible);
|
||||
if (visible) {
|
||||
mView.generateAddAnimation(
|
||||
mKeyguardMediaController.getView(), false /*fromMoreCard */);
|
||||
mKeyguardMediaController.getSinglePaneContainer(),
|
||||
false /*fromMoreCard */);
|
||||
} else {
|
||||
mView.generateRemoveAnimation(mKeyguardMediaController.getView());
|
||||
mView.generateRemoveAnimation(mKeyguardMediaController.getSinglePaneContainer());
|
||||
}
|
||||
mView.requestChildrenUpdate();
|
||||
return Unit.INSTANCE;
|
||||
|
||||
@@ -155,6 +155,8 @@ public class KeyguardClockPositionAlgorithm {
|
||||
|
||||
private int mLockScreenMode;
|
||||
|
||||
private boolean mIsSplitShade;
|
||||
|
||||
/**
|
||||
* Refreshes the dimension values.
|
||||
*/
|
||||
@@ -180,7 +182,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY,
|
||||
int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
|
||||
float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
|
||||
float qsExpansion, int cutoutTopInset) {
|
||||
float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
|
||||
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
|
||||
userSwitchHeight);
|
||||
mMaxShadeBottom = maxShadeBottom;
|
||||
@@ -199,6 +201,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
|
||||
mQsExpansion = qsExpansion;
|
||||
mCutoutTopInset = cutoutTopInset;
|
||||
mIsSplitShade = isSplitShade;
|
||||
}
|
||||
|
||||
public void run(Result result) {
|
||||
@@ -208,14 +211,23 @@ public class KeyguardClockPositionAlgorithm {
|
||||
result.clockYFullyDozing = getClockY(
|
||||
1.0f /* panelExpansion */, 1.0f /* darkAmount */);
|
||||
result.clockAlpha = getClockAlpha(y);
|
||||
result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding
|
||||
: y + mKeyguardStatusHeight;
|
||||
result.stackScrollerPadding = getStackScrollerPadding(y);
|
||||
result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
|
||||
: getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
|
||||
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
|
||||
result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
|
||||
}
|
||||
|
||||
private int getStackScrollerPadding(int clockYPosition) {
|
||||
if (mBypassEnabled) {
|
||||
return mUnlockedStackScrollerPadding;
|
||||
} else if (mIsSplitShade) {
|
||||
return clockYPosition;
|
||||
} else {
|
||||
return clockYPosition + mKeyguardStatusHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update lock screen mode for testing different layouts
|
||||
*/
|
||||
@@ -232,15 +244,11 @@ public class KeyguardClockPositionAlgorithm {
|
||||
return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin;
|
||||
}
|
||||
|
||||
private int getPreferredClockY() {
|
||||
return mClockPreferredY;
|
||||
}
|
||||
|
||||
private int getExpandedPreferredClockY() {
|
||||
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
|
||||
return mMinTopMargin + mUserSwitchHeight;
|
||||
}
|
||||
return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY()
|
||||
return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? mClockPreferredY
|
||||
: getExpandedClockPosition();
|
||||
}
|
||||
|
||||
@@ -271,7 +279,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
|
||||
private int getClockY(float panelExpansion, float darkAmount) {
|
||||
// Dark: Align the bottom edge of the clock at about half of the screen:
|
||||
float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY())
|
||||
float clockYDark = (mHasCustomClock ? mClockPreferredY : getMaxClockY())
|
||||
+ burnInPreventionOffsetY();
|
||||
clockYDark = MathUtils.max(0, clockYDark);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
|
||||
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
|
||||
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
|
||||
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
|
||||
import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
|
||||
|
||||
import static java.lang.Float.isNaN;
|
||||
|
||||
@@ -99,6 +100,7 @@ import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.doze.DozeLog;
|
||||
import com.android.systemui.fragments.FragmentHostManager;
|
||||
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
|
||||
import com.android.systemui.media.KeyguardMediaController;
|
||||
import com.android.systemui.media.MediaDataManager;
|
||||
import com.android.systemui.media.MediaHierarchyManager;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
@@ -527,6 +529,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
|
||||
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
|
||||
private int mScrimCornerRadius;
|
||||
private KeyguardMediaController mKeyguardMediaController;
|
||||
|
||||
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
|
||||
@Override
|
||||
@@ -597,6 +600,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
LockIconViewController lockIconViewController,
|
||||
FeatureFlags featureFlags,
|
||||
QuickAccessWalletClient quickAccessWalletClient,
|
||||
KeyguardMediaController keyguardMediaController,
|
||||
@Main Executor uiExecutor) {
|
||||
super(view, falsingManager, dozeLog, keyguardStateController,
|
||||
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
|
||||
@@ -604,6 +608,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
statusBarTouchableRegionManager, ambientState);
|
||||
mView = view;
|
||||
mVibratorHelper = vibratorHelper;
|
||||
mKeyguardMediaController = keyguardMediaController;
|
||||
mMetricsLogger = metricsLogger;
|
||||
mActivityManager = activityManager;
|
||||
mConfigurationController = configurationController;
|
||||
@@ -771,7 +776,6 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
});
|
||||
|
||||
mView.setAccessibilityDelegate(mAccessibilityDelegate);
|
||||
// dynamically apply the split shade value overrides.
|
||||
if (mShouldUseSplitNotificationShade) {
|
||||
updateResources();
|
||||
}
|
||||
@@ -889,13 +893,17 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
constraintSet.connect(
|
||||
R.id.notification_stack_scroller, START,
|
||||
R.id.qs_edge_guideline, START);
|
||||
constraintSet.connect(R.id.keyguard_status_view, END, R.id.qs_edge_guideline, END);
|
||||
} else {
|
||||
constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
|
||||
constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
|
||||
constraintSet.connect(R.id.keyguard_status_view, END, PARENT_ID, END);
|
||||
}
|
||||
constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
|
||||
constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
|
||||
constraintSet.applyTo(mNotificationContainerParent);
|
||||
|
||||
mKeyguardMediaController.refreshMediaPosition();
|
||||
}
|
||||
|
||||
private static void ensureAllViewsHaveIds(ViewGroup parentView) {
|
||||
@@ -929,12 +937,18 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
private void reInflateViews() {
|
||||
if (DEBUG) Log.d(TAG, "reInflateViews");
|
||||
// Re-inflate the status view group.
|
||||
KeyguardStatusView keyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
|
||||
int index = mView.indexOfChild(keyguardStatusView);
|
||||
mView.removeView(keyguardStatusView);
|
||||
KeyguardStatusView keyguardStatusView =
|
||||
mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
|
||||
int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView);
|
||||
mNotificationContainerParent.removeView(keyguardStatusView);
|
||||
keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate(
|
||||
R.layout.keyguard_status_view, mView, false);
|
||||
mView.addView(keyguardStatusView, index);
|
||||
R.layout.keyguard_status_view, mNotificationContainerParent, false);
|
||||
mNotificationContainerParent.addView(keyguardStatusView, statusIndex);
|
||||
attachSplitShadeMediaPlayerContainer(
|
||||
keyguardStatusView.findViewById(R.id.status_view_media_container));
|
||||
|
||||
// we need to update KeyguardStatusView constraints after reinflating it
|
||||
updateResources();
|
||||
|
||||
// Re-inflate the keyguard user switcher group.
|
||||
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
|
||||
@@ -956,11 +970,11 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
showKeyguardUserSwitcher /* enabled */);
|
||||
|
||||
mBigClockContainer.removeAllViews();
|
||||
updateViewControllers(
|
||||
keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView);
|
||||
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
|
||||
mKeyguardStatusBar, keyguardUserSwitcherView);
|
||||
|
||||
// Update keyguard bottom area
|
||||
index = mView.indexOfChild(mKeyguardBottomArea);
|
||||
int index = mView.indexOfChild(mKeyguardBottomArea);
|
||||
mView.removeView(mKeyguardBottomArea);
|
||||
KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
|
||||
mKeyguardBottomArea = (KeyguardBottomAreaView) mLayoutInflater.inflate(
|
||||
@@ -998,6 +1012,11 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
setKeyguardBottomAreaVisibility(mBarState, false);
|
||||
}
|
||||
|
||||
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
|
||||
mKeyguardMediaController.attachSplitShadeContainer(container,
|
||||
() -> mShouldUseSplitNotificationShade);
|
||||
}
|
||||
|
||||
private void initBottomArea() {
|
||||
mAffordanceHelper = new KeyguardAffordanceHelper(
|
||||
mKeyguardAffordanceHelperCallback, mView.getContext(), mFalsingManager);
|
||||
@@ -1110,7 +1129,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
|
||||
bypassEnabled, getUnlockedStackScrollerPadding(),
|
||||
getQsExpansionFraction(),
|
||||
mDisplayCutoutTopInset);
|
||||
mDisplayCutoutTopInset,
|
||||
shouldUseSplitNotificationShade(mFeatureFlags, mResources));
|
||||
mClockPositionAlgorithm.run(mClockPositionResult);
|
||||
mKeyguardStatusViewController.updatePosition(
|
||||
mClockPositionResult.clockX, mClockPositionResult.clockY,
|
||||
|
||||
@@ -19,26 +19,23 @@ package com.android.systemui.media
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.FrameLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||
import com.android.systemui.statusbar.notification.stack.MediaHeaderView
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.animation.UniqueObjectHostView
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.atLeastOnce
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -52,51 +49,81 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
private lateinit var statusBarStateController: SysuiStatusBarStateController
|
||||
@Mock
|
||||
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
|
||||
@Mock
|
||||
private lateinit var mediaHeaderView: MediaHeaderView
|
||||
@Captor
|
||||
private lateinit var visibilityListener: ArgumentCaptor<((Boolean) -> Unit)>
|
||||
@JvmField @Rule
|
||||
val mockito = MockitoJUnit.rule()
|
||||
|
||||
private val mediaHeaderView: MediaHeaderView = MediaHeaderView(context, null)
|
||||
private lateinit var keyguardMediaController: KeyguardMediaController
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
// default state is positive, media should show up
|
||||
whenever(mediaHost.visible).thenReturn(true)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
|
||||
.thenReturn(true)
|
||||
whenever(mediaHost.hostView).thenReturn(UniqueObjectHostView(context))
|
||||
|
||||
keyguardMediaController = KeyguardMediaController(mediaHost, bypassController,
|
||||
statusBarStateController, notificationLockscreenUserManager)
|
||||
keyguardMediaController.attachSinglePaneContainer(mediaHeaderView)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAttach_hiddenWhenHostIsHidden() {
|
||||
`when`(mediaHost.visible).thenReturn(false)
|
||||
triggerVisibilityListener()
|
||||
fun testHiddenWhenHostIsHidden() {
|
||||
whenever(mediaHost.visible).thenReturn(false)
|
||||
|
||||
verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE)
|
||||
}
|
||||
@Test
|
||||
fun testAttach_visibleOnKeyguard() {
|
||||
`when`(mediaHost.visible).thenReturn(true)
|
||||
`when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
`when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
|
||||
.thenReturn(true)
|
||||
triggerVisibilityListener()
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
|
||||
verify(mediaHeaderView, atLeastOnce()).visibility = eq(VISIBLE)
|
||||
assertThat(mediaHeaderView.visibility).isEqualTo(GONE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAttach_hiddenOnKeyguard_whenNotificationsAreHidden() {
|
||||
`when`(mediaHost.visible).thenReturn(true)
|
||||
`when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
`when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
|
||||
fun testVisibleOnKeyguardOrFullScreenUserSwitcher() {
|
||||
testStateVisibility(StatusBarState.SHADE, GONE)
|
||||
testStateVisibility(StatusBarState.SHADE_LOCKED, GONE)
|
||||
testStateVisibility(StatusBarState.FULLSCREEN_USER_SWITCHER, VISIBLE)
|
||||
testStateVisibility(StatusBarState.KEYGUARD, VISIBLE)
|
||||
}
|
||||
|
||||
private fun testStateVisibility(state: Int, visibility: Int) {
|
||||
whenever(statusBarStateController.state).thenReturn(state)
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
assertThat(mediaHeaderView.visibility).isEqualTo(visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHiddenOnKeyguard_whenNotificationsAreHidden() {
|
||||
whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
|
||||
.thenReturn(false)
|
||||
triggerVisibilityListener()
|
||||
|
||||
verify(mediaHeaderView, atLeastOnce()).visibility = eq(GONE)
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
|
||||
assertThat(mediaHeaderView.visibility).isEqualTo(GONE)
|
||||
}
|
||||
|
||||
private fun triggerVisibilityListener() {
|
||||
keyguardMediaController.attach(mediaHeaderView)
|
||||
verify(mediaHost).addVisibilityChangeListener(capture(visibilityListener))
|
||||
visibilityListener.value.invoke(true)
|
||||
@Test
|
||||
fun testActivatesSplitShadeContainerInSplitShadeMode() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(
|
||||
splitShadeContainer,
|
||||
useContainer = { true })
|
||||
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
|
||||
assertThat(splitShadeContainer.visibility).isEqualTo(VISIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testActivatesSinglePaneContainerInSinglePaneMode() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(
|
||||
splitShadeContainer,
|
||||
useContainer = { false })
|
||||
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
|
||||
assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
|
||||
assertThat(mediaHeaderView.visibility).isEqualTo(VISIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
private boolean mHasVisibleNotifs;
|
||||
private float mQsExpansion;
|
||||
private int mCutoutTopInset = 0; // in pixels
|
||||
private boolean mIsSplitShade = false;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -264,6 +265,19 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(810);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notifPositionAlignedWithClockInSplitShadeMode() {
|
||||
// GIVEN on lock screen and split shade mode
|
||||
givenLockScreen();
|
||||
mIsSplitShade = true;
|
||||
mPreferredClockY = 100;
|
||||
mHasCustomClock = true;
|
||||
// WHEN the position algorithm is run
|
||||
positionClock();
|
||||
// THEN the notif padding DOESN'T adjust for keyguard status height.
|
||||
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(mPreferredClockY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notifPositionWithLargeClockOnLockScreen() {
|
||||
// GIVEN on lock screen and clock has a nonzero height
|
||||
@@ -397,7 +411,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
0 /* userSwitchHeight */, mPreferredClockY, 0 /* userSwitchPreferredY */,
|
||||
mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
|
||||
0 /* unlockedStackScrollerPadding */, mQsExpansion,
|
||||
mCutoutTopInset);
|
||||
mCutoutTopInset, mIsSplitShade);
|
||||
mClockPositionAlgorithm.run(mClockPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ import com.android.systemui.biometrics.AuthController;
|
||||
import com.android.systemui.classifier.FalsingCollectorFake;
|
||||
import com.android.systemui.classifier.FalsingManagerFake;
|
||||
import com.android.systemui.doze.DozeLog;
|
||||
import com.android.systemui.media.KeyguardMediaController;
|
||||
import com.android.systemui.media.MediaDataManager;
|
||||
import com.android.systemui.media.MediaHierarchyManager;
|
||||
import com.android.systemui.qs.QSDetailDisplayer;
|
||||
@@ -240,6 +241,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
private LockIconViewController mLockIconViewController;
|
||||
@Mock
|
||||
private QuickAccessWalletClient mQuickAccessWalletClient;
|
||||
@Mock
|
||||
private KeyguardMediaController mKeyguardMediaController;
|
||||
|
||||
private SysuiStatusBarStateController mStatusBarStateController;
|
||||
private NotificationPanelViewController mNotificationPanelViewController;
|
||||
@@ -282,6 +285,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
|
||||
when(mView.findViewById(R.id.notification_container_parent))
|
||||
.thenReturn(mNotificationContainerParent);
|
||||
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
|
||||
@@ -346,6 +350,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mLockIconViewController,
|
||||
mFeatureFlags,
|
||||
mQuickAccessWalletClient,
|
||||
mKeyguardMediaController,
|
||||
new FakeExecutor(new FakeSystemClock()));
|
||||
mNotificationPanelViewController.initDependencies(
|
||||
mStatusBar,
|
||||
@@ -475,6 +480,20 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
.isEqualTo(ConstraintSet.PARENT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyguardStatusView_isAlignedToGuidelineInSplitShadeMode() {
|
||||
mNotificationPanelViewController.updateResources();
|
||||
|
||||
assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd)
|
||||
.isEqualTo(ConstraintSet.PARENT_ID);
|
||||
|
||||
enableSplitShade();
|
||||
mNotificationPanelViewController.updateResources();
|
||||
|
||||
assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd)
|
||||
.isEqualTo(R.id.qs_edge_guideline);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitShadeLayout_isAlignedToGuideline() {
|
||||
enableSplitShade();
|
||||
|
||||
Reference in New Issue
Block a user