From 252efd708aa042b98b6087fc12a7dc0140a9ca21 Mon Sep 17 00:00:00 2001 From: felkachang Date: Thu, 24 May 2018 15:38:04 +0800 Subject: [PATCH] Fix the icon overlay after density change After showing the heads up for the fullscreen notification, to change the density by user will have the status bar icons not show normally. It will the only one icon overlay on the clock but actually there are more than one icons. And, it can't back to normal after expandable notification and collapse the notification panel. The root cause is that all of instances of PhoneStatusBarView, Clock, HeadsUpStatusBarView, and HeadsUpAppearanceController are recreated by FragmentManager after configuration density and font changing. The new HeadsUpAppearanceController status is neither consistent with HeadsUpManager's status nor the state of the previous instances. The solution is that to apply the onSaveInstanceState and onRestoreInstanceState in PhoneStatusBarView, Clock, PanelBar, and HeadsUpStatusBarView. To make sure that the values of the fields in the new instance, which are set by other source, have the consistence with the state of the old instances. HeadsUpAppearanceController's Constructor. To hook onLayoutChangedListener to sync the status with HeadsUpManager's status to HeadsUpStatusBarView if there is a pinnded heads up notification. In original, PanelBar.mState is the only one state to save. Instead of only saving one, to save the view tree state in CollapsedStatusBarFragment.onSaveInstanceState and restore the view state in CollapsedStatusBarFragment.onViewCreated. CollapsedStatusBarFragment.mDisabled1 doesn't need to save and restore because CommandQueue.recomputeDisableFlags will give it the correct value. After density changed, RemoteViews will reinflate the instances of NotificationHeaderView and the wrapper instances of NoticationContentView will also recreated in NotificationContentView.setAmbientChild. The recreated instance should synchronized with the ExpandableNotificationRow intance. Bug: 80224819 Fixes: 111996469 Fixes: 117818441 Test: atest SystemUITests Change-Id: Ia3f8a0f138f403c8e0c74c00d56bd93baf604d3a Merged-In: Ia3f8a0f138f403c8e0c74c00d56bd93baf604d3a --- .../statusbar/ExpandableNotificationRow.java | 3 +- .../statusbar/HeadsUpStatusBarView.java | 41 +++++++++++++++++++ .../NotificationHeaderViewWrapper.java | 5 +++ .../phone/CollapsedStatusBarFragment.java | 9 +++- .../phone/HeadsUpAppearanceController.java | 32 +++++++++++++-- .../systemui/statusbar/phone/PanelBar.java | 26 +++++++++++- .../systemui/statusbar/phone/StatusBar.java | 14 +++++++ .../systemui/statusbar/policy/Clock.java | 41 +++++++++++++++++++ .../HeadsUpAppearanceControllerTest.java | 21 ++++++++++ 9 files changed, 184 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index d647e21888dd0..603ddd8f11c5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -108,6 +108,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private static final int COLORED_DIVIDER_ALPHA = 0x7B; private static final int MENU_VIEW_INDEX = 0; private static final String TAG = "ExpandableNotifRow"; + public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f; /** * Listener for when {@link ExpandableNotificationRow} is laid out. @@ -157,7 +158,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mSensitiveHiddenInGeneral; private boolean mShowingPublicInitialized; private boolean mHideSensitiveForIntrinsicHeight; - private float mHeaderVisibleAmount = 1.0f; + private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT; /** * Is this notification expanded by the system. The expansion state can be overridden by the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java index 29e0edaf25cc6..ac289d7d6262d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java @@ -21,6 +21,8 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; +import android.os.Bundle; +import android.os.Parcelable; import android.util.AttributeSet; import android.view.Display; import android.view.DisplayCutout; @@ -38,6 +40,12 @@ import java.util.List; * The view in the statusBar that contains part of the heads-up information */ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { + private static final String HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE = + "heads_up_status_bar_view_super_parcelable"; + private static final String FIRST_LAYOUT = "first_layout"; + private static final String PUBLIC_MODE = "public_mode"; + private static final String VISIBILITY = "visibility"; + private static final String ALPHA = "alpha"; private int mAbsoluteStartPadding; private int mEndMargin; private View mIconPlaceholder; @@ -107,6 +115,39 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { updateMaxWidth(); } + @Override + public Bundle onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE, + super.onSaveInstanceState()); + bundle.putBoolean(FIRST_LAYOUT, mFirstLayout); + bundle.putBoolean(PUBLIC_MODE, mPublicMode); + bundle.putInt(VISIBILITY, getVisibility()); + bundle.putFloat(ALPHA, getAlpha()); + + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state == null || !(state instanceof Bundle)) { + super.onRestoreInstanceState(state); + return; + } + + Bundle bundle = (Bundle) state; + Parcelable superState = bundle.getParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE); + super.onRestoreInstanceState(superState); + mFirstLayout = bundle.getBoolean(FIRST_LAYOUT, true); + mPublicMode = bundle.getBoolean(PUBLIC_MODE, false); + if (bundle.containsKey(VISIBILITY)) { + setVisibility(bundle.getInt(VISIBILITY)); + } + if (bundle.containsKey(ALPHA)) { + setAlpha(bundle.getFloat(ALPHA)); + } + } + @VisibleForTesting public HeadsUpStatusBarView(Context context, View iconPlaceholder, TextView textView) { this(context); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java index 2fc2cdbd5e33a..ade27f9f3ad2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification; +import static com.android.systemui.statusbar.ExpandableNotificationRow + .DEFAULT_HEADER_VISIBLE_AMOUNT; import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y; import android.app.Notification; @@ -123,6 +125,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { // Reinspect the notification. resolveHeaderViews(); + if (row.getHeaderVisibleAmount() != DEFAULT_HEADER_VISIBLE_AMOUNT) { + setHeaderVisibleAmount(row.getHeaderVisibleAmount()); + } updateTransformedTypes(); addRemainingTransformTypes(); updateCropToPaddingForImageViews(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index 43c83288dc967..a781be69c93e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -22,6 +22,8 @@ import android.annotation.Nullable; import android.app.Fragment; import android.app.StatusBarManager; import android.os.Bundle; +import android.os.Parcelable; +import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -89,7 +91,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue super.onViewCreated(view, savedInstanceState); mStatusBar = (PhoneStatusBarView) view; if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) { - mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE)); + mStatusBar.restoreHierarchyState( + savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE)); } mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons)); mDarkIconManager.setShouldLog(true); @@ -105,7 +108,9 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - outState.putInt(EXTRA_PANEL_STATE, mStatusBar.getState()); + SparseArray states = new SparseArray<>(); + mStatusBar.saveHierarchyState(states); + outState.putSparseParcelableArray(EXTRA_PANEL_STATE, states); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 4e7f4f38ebd3a..e1936fadb17a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -54,9 +54,12 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mSetTrackingHeadsUp = this::setTrackingHeadsUp; private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation; private final BiConsumer mSetExpandedHeight = this::setExpandedHeight; - private float mExpandedHeight; - private boolean mIsExpanded; - private float mExpandFraction; + @VisibleForTesting + float mExpandedHeight; + @VisibleForTesting + boolean mIsExpanded; + @VisibleForTesting + float mExpandFraction; private ExpandableNotificationRow mTrackedChild; private boolean mShown; private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener = @@ -100,6 +103,20 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mClockView = clockView; mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); mDarkIconDispatcher.addDarkReceiver(this); + + mHeadsUpStatusBarView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + if (shouldBeVisible()) { + updateTopEntry(); + + // trigger scroller to notify the latest panel translation + mStackScroller.requestLayout(); + } + mHeadsUpStatusBarView.removeOnLayoutChangeListener(this); + } + }); } @@ -301,4 +318,13 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mHeadsUpStatusBarView.setPublicMode(publicMode); updateTopEntry(); } + + void readFrom(HeadsUpAppearanceController oldController) { + if (oldController != null) { + mTrackedChild = oldController.mTrackedChild; + mExpandedHeight = oldController.mExpandedHeight; + mIsExpanded = oldController.mIsExpanded; + mExpandFraction = oldController.mExpandFraction; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 6f4a3cd821407..5d234947de298 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone; import android.content.Context; +import android.os.Bundle; +import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -27,6 +29,8 @@ public abstract class PanelBar extends FrameLayout { public static final boolean DEBUG = false; public static final String TAG = PanelBar.class.getSimpleName(); private static final boolean SPEW = false; + private static final String PANEL_BAR_SUPER_PARCELABLE = "panel_bar_super_parcelable"; + private static final String STATE = "state"; private boolean mBouncerShowing; private boolean mExpanded; protected float mPanelFraction; @@ -49,8 +53,26 @@ public abstract class PanelBar extends FrameLayout { mState = state; } - public int getState() { - return mState; + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable(PANEL_BAR_SUPER_PARCELABLE, super.onSaveInstanceState()); + bundle.putInt(STATE, mState); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state == null || !(state instanceof Bundle)) { + super.onRestoreInstanceState(state); + return; + } + + Bundle bundle = (Bundle) state; + super.onRestoreInstanceState(bundle.getParcelable(PANEL_BAR_SUPER_PARCELABLE)); + if (((Bundle) state).containsKey(STATE)) { + go(bundle.getInt(STATE, STATE_CLOSED)); + } } public PanelBar(Context context, AttributeSet attrs) { 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 9f5ebe4d434e0..70bca8d410942 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -850,12 +850,25 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarView.setBar(this); mStatusBarView.setPanel(mNotificationPanel); mStatusBarView.setScrimController(mScrimController); + + // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of + // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false. + // PhoneStatusBarView's new instance will set to be gone in + // PanelBar.updateVisibility after calling mStatusBarView.setBouncerShowing + // that will trigger PanelBar.updateVisibility. If there is a heads up showing, + // it needs to notify PhoneStatusBarView's new instance to update the correct + // status by calling mNotificationPanel.notifyBarPanelExpansionChanged(). + if (mHeadsUpManager.hasPinnedHeadsUp()) { + mNotificationPanel.notifyBarPanelExpansionChanged(); + } mStatusBarView.setBouncerShowing(mBouncerShowing); if (oldStatusBarView != null) { float fraction = oldStatusBarView.getExpansionFraction(); boolean expanded = oldStatusBarView.isExpanded(); mStatusBarView.panelExpansionChanged(fraction, expanded); } + + HeadsUpAppearanceController oldController = mHeadsUpAppearanceController; if (mHeadsUpAppearanceController != null) { // This view is being recreated, let's destroy the old one mHeadsUpAppearanceController.destroy(); @@ -863,6 +876,7 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpAppearanceController = new HeadsUpAppearanceController( mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow); mStatusBarWindow.setStatusBarView(mStatusBarView); + mHeadsUpAppearanceController.readFrom(oldController); setAreThereNotifications(); checkBarModes(); }).getFragmentManager() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index 9aa8044847160..8517d9086fc7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -25,6 +25,7 @@ import android.content.res.TypedArray; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; +import android.os.Parcelable; import android.os.SystemClock; import android.os.UserHandle; import android.text.Spannable; @@ -65,6 +66,12 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C DarkReceiver, ConfigurationListener { public static final String CLOCK_SECONDS = "clock_seconds"; + private static final String CLOCK_SUPER_PARCELABLE = "clock_super_parcelable"; + private static final String CURRENT_USER_ID = "current_user_id"; + private static final String VISIBLE_BY_POLICY = "visible_by_policy"; + private static final String VISIBLE_BY_USER = "visible_by_user"; + private static final String SHOW_SECONDS = "show_seconds"; + private static final String VISIBILITY = "visibility"; private final CurrentUserTracker mCurrentUserTracker; private int mCurrentUserId; @@ -128,6 +135,40 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C }; } + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable(CLOCK_SUPER_PARCELABLE, super.onSaveInstanceState()); + bundle.putInt(CURRENT_USER_ID, mCurrentUserId); + bundle.putBoolean(VISIBLE_BY_POLICY, mClockVisibleByPolicy); + bundle.putBoolean(VISIBLE_BY_USER, mClockVisibleByUser); + bundle.putBoolean(SHOW_SECONDS, mShowSeconds); + bundle.putInt(VISIBILITY, getVisibility()); + + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state == null || !(state instanceof Bundle)) { + super.onRestoreInstanceState(state); + return; + } + + Bundle bundle = (Bundle) state; + Parcelable superState = bundle.getParcelable(CLOCK_SUPER_PARCELABLE); + super.onRestoreInstanceState(superState); + if (bundle.containsKey(CURRENT_USER_ID)) { + mCurrentUserId = bundle.getInt(CURRENT_USER_ID); + } + mClockVisibleByPolicy = bundle.getBoolean(VISIBLE_BY_POLICY, true); + mClockVisibleByUser = bundle.getBoolean(VISIBLE_BY_USER, true); + mShowSeconds = bundle.getBoolean(SHOW_SECONDS, false); + if (bundle.containsKey(VISIBILITY)) { + setVisibility(bundle.getInt(VISIBILITY)); + } + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index 537bfd4be66cd..fe7bf2537085c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -122,6 +122,27 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 1.0f, 0.0f); } + @Test + public void testHeaderReadFromOldController() { + mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f); + + HeadsUpAppearanceController newController = new HeadsUpAppearanceController( + mock(NotificationIconAreaController.class), + mHeadsUpManager, + mHeadsUpStatusBarView, + mStackScroller, + mPanelView, + new View(mContext)); + newController.readFrom(mHeadsUpAppearanceController); + + Assert.assertEquals(mHeadsUpAppearanceController.mExpandedHeight, + newController.mExpandedHeight, 0.0f); + Assert.assertEquals(mHeadsUpAppearanceController.mExpandFraction, + newController.mExpandFraction, 0.0f); + Assert.assertEquals(mHeadsUpAppearanceController.mIsExpanded, + newController.mIsExpanded); + } + @Test public void testDestroy() { reset(mHeadsUpManager);