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
This commit is contained in:
felkachang
2018-05-24 15:38:04 +08:00
committed by Felka Chang
parent e905bdb194
commit 252efd708a
9 changed files with 184 additions and 8 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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<Parcelable> states = new SparseArray<>();
mStatusBar.saveHierarchyState(states);
outState.putSparseParcelableArray(EXTRA_PANEL_STATE, states);
}
@Override

View File

@@ -54,9 +54,12 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mSetTrackingHeadsUp = this::setTrackingHeadsUp;
private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
private final BiConsumer<Float, Float> 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;
}
}
}

View File

@@ -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) {

View File

@@ -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()

View File

@@ -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();

View File

@@ -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);