Add ability to center a notification icon

Test: manual, atest CollapsedStatusBarFragmentTest
Test: atest HeadsUpAppearanceControllerTest
Bug: 124937207
Change-Id: Ie6b44fad2490ddede53116ebc1293876165695f8
This commit is contained in:
Beverly
2019-02-15 15:49:49 -05:00
parent 49c98a7b63
commit 4077065daa
10 changed files with 197 additions and 18 deletions

View File

@@ -58,6 +58,7 @@ public interface SensorManagerPlugin extends Plugin {
public static final int TYPE_WAKE_LOCK_SCREEN = 1;
public static final int TYPE_WAKE_DISPLAY = 2;
public static final int TYPE_SWIPE = 3;
public static final int TYPE_STATUS = 4;
private int mType;

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 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
-->
<com.android.keyguard.AlphaOptimizedLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/center_icon_area_inner"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:clipChildren="false">
<com.android.systemui.statusbar.phone.NotificationIconContainer
android:id="@+id/centeredIcon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal"
android:clipChildren="false"/>
</com.android.keyguard.AlphaOptimizedLinearLayout>

View File

@@ -102,6 +102,14 @@
android:gravity="center_horizontal|center_vertical"
/>
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/centered_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:clipChildren="false"
android:gravity="center_horizontal|center_vertical"/>
<com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
android:layout_width="0dp"
android:layout_height="match_parent"

View File

@@ -95,6 +95,7 @@ public final class NotificationEntry {
public int importance;
public StatusBarIconView icon;
public StatusBarIconView expandedIcon;
public StatusBarIconView centeredIcon;
private boolean interruption;
public boolean autoRedacted; // whether the redacted notification was generated by us
public int targetSdk;
@@ -325,6 +326,7 @@ public final class NotificationEntry {
expandedIcon = new StatusBarIconView(context,
sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
final StatusBarIcon ic = new StatusBarIcon(
sbn.getUser(),
sbn.getPackageName(),
@@ -332,9 +334,11 @@ public final class NotificationEntry {
n.iconLevel,
n.number,
StatusBarIconView.contentDescForNotification(context, n));
if (!icon.set(ic) || !expandedIcon.set(ic)) {
icon = null;
expandedIcon = null;
centeredIcon = null;
throw new InflationException("Couldn't create icon: " + ic);
}
expandedIcon.setVisibility(View.INVISIBLE);
@@ -344,6 +348,18 @@ public final class NotificationEntry {
row.setIconsVisible(newVisibility != View.VISIBLE);
}
});
// Construct the centered icon
if (notification.getNotification().isMediaNotification()) {
centeredIcon = new StatusBarIconView(context,
sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
centeredIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
if (!centeredIcon.set(ic)) {
centeredIcon = null;
throw new InflationException("Couldn't update centered icon: " + ic);
}
}
}
public void setIconTag(int key, Object tag) {
@@ -351,6 +367,10 @@ public final class NotificationEntry {
icon.setTag(key, tag);
expandedIcon.setTag(key, tag);
}
if (centeredIcon != null) {
centeredIcon.setTag(key, tag);
}
}
/**
@@ -377,6 +397,13 @@ public final class NotificationEntry {
if (!icon.set(ic) || !expandedIcon.set(ic)) {
throw new InflationException("Couldn't update icon: " + ic);
}
if (centeredIcon != null) {
centeredIcon.setNotification(sbn);
if (!centeredIcon.set(ic)) {
throw new InflationException("Couldn't update centered icon: " + ic);
}
}
}
}

View File

@@ -61,6 +61,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private LinearLayout mSystemIconArea;
private View mClockView;
private View mNotificationIconAreaInner;
private View mCenteredIconArea;
private int mDisabled1;
private StatusBar mStatusBarComponent;
private DarkIconManager mDarkIconManager;
@@ -150,6 +151,15 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
.removeView(mNotificationIconAreaInner);
}
notificationIconArea.addView(mNotificationIconAreaInner);
ViewGroup statusBarCenteredIconArea = mStatusBar.findViewById(R.id.centered_icon_area);
mCenteredIconArea = notificationIconAreaController.getCenteredNotificationAreaView();
if (mCenteredIconArea.getParent() != null) {
((ViewGroup) mCenteredIconArea.getParent())
.removeView(mCenteredIconArea);
}
statusBarCenteredIconArea.addView(mCenteredIconArea);
// Default to showing until we know otherwise.
showNotificationIconArea(false);
}
@@ -266,10 +276,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public void hideNotificationIconArea(boolean animate) {
animateHide(mNotificationIconAreaInner, animate);
animateHide(mCenteredIconArea, animate);
}
public void showNotificationIconArea(boolean animate) {
animateShow(mNotificationIconAreaInner, animate);
animateShow(mCenteredIconArea, animate);
}
public void hideOperatorName(boolean animate) {

View File

@@ -47,6 +47,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationStackScrollLayout mStackScroller;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mCenteredIconView;
private final View mClockView;
private final View mOperatorNameView;
private final DarkIconDispatcher mDarkIconDispatcher;
@@ -79,7 +80,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
statusbarView.findViewById(R.id.notification_stack_scroller),
statusbarView.findViewById(R.id.notification_panel),
statusbarView.findViewById(R.id.clock),
statusbarView.findViewById(R.id.operator_name_frame));
statusbarView.findViewById(R.id.operator_name_frame),
statusbarView.findViewById(R.id.centered_icon_area));
}
@VisibleForTesting
@@ -90,11 +92,13 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
NotificationStackScrollLayout stackScroller,
NotificationPanelView panelView,
View clockView,
View operatorNameView) {
View operatorNameView,
View centeredIconView) {
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(this);
mHeadsUpStatusBarView = headsUpStatusBarView;
mCenteredIconView = centeredIconView;
headsUpStatusBarView.setOnDrawingRectChangedListener(
() -> updateIsolatedIconLocation(true /* requireUpdate */));
mStackScroller = stackScroller;
@@ -238,11 +242,17 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
show(mHeadsUpStatusBarView);
hide(mClockView, View.INVISIBLE);
if (mCenteredIconView.getVisibility() != View.GONE) {
hide(mCenteredIconView, View.INVISIBLE);
}
if (mOperatorNameView != null) {
hide(mOperatorNameView, View.INVISIBLE);
}
} else {
show(mClockView);
if (mCenteredIconView.getVisibility() != View.GONE) {
show(mCenteredIconView);
}
if (mOperatorNameView != null) {
show(mOperatorNameView);
}

View File

@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Function;
/**
@@ -66,11 +67,15 @@ public class NotificationIconAreaController implements DarkReceiver,
private int mIconSize;
private int mIconHPadding;
private int mIconTint = Color.WHITE;
private int mCenteredIconTint = Color.WHITE;
private StatusBar mStatusBar;
protected View mNotificationIconArea;
private NotificationIconContainer mNotificationIcons;
private NotificationIconContainer mShelfIcons;
protected View mCenteredIconArea;
private NotificationIconContainer mCenteredIcon;
private StatusBarIconView mCenteredIconView;
private final Rect mTintArea = new Rect();
private ViewGroup mNotificationScrollLayout;
private Context mContext;
@@ -124,6 +129,9 @@ public class NotificationIconAreaController implements DarkReceiver,
mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);
}
public void setupShelf(NotificationShelf shelf) {
@@ -142,6 +150,10 @@ public class NotificationIconAreaController implements DarkReceiver,
View child = mShelfIcons.getChildAt(i);
child.setLayoutParams(params);
}
for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
View child = mCenteredIcon.getChildAt(i);
child.setLayoutParams(params);
}
}
@NonNull
@@ -166,6 +178,13 @@ public class NotificationIconAreaController implements DarkReceiver,
return mNotificationIconArea;
}
/**
* Returns the view that represents the centered notification area.
*/
public View getCenteredNotificationAreaView() {
return mCenteredIconArea;
}
/**
* See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}.
* Sets the color that should be used to tint any icons in the notification area.
@@ -179,6 +198,7 @@ public class NotificationIconAreaController implements DarkReceiver,
} else {
mTintArea.set(tintArea);
}
if (mNotificationIconArea != null) {
if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
mIconTint = iconTint;
@@ -187,6 +207,14 @@ public class NotificationIconAreaController implements DarkReceiver,
mIconTint = iconTint;
}
if (mCenteredIconArea != null) {
if (DarkIconDispatcher.isInArea(tintArea, mCenteredIconArea)) {
mCenteredIconTint = iconTint;
}
} else {
mCenteredIconTint = iconTint;
}
applyNotificationIconsTint();
}
@@ -196,7 +224,13 @@ public class NotificationIconAreaController implements DarkReceiver,
protected boolean shouldShowNotificationIcon(NotificationEntry entry,
boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
boolean hideRepliedMessages, boolean hideCurrentMedia) {
boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon) {
final boolean isCenteredNotificationIcon = entry.centeredIcon != null
&& Objects.equals(entry.centeredIcon, mCenteredIconView);
if (hideCenteredIcon == isCenteredNotificationIcon) {
return false;
}
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
return false;
}
@@ -229,26 +263,41 @@ public class NotificationIconAreaController implements DarkReceiver,
* Updates the notifications with the given list of notifications to display.
*/
public void updateNotificationIcons() {
updateStatusBarIcons();
updateShelfIcons();
updateCenterIcon();
applyNotificationIconsTint();
}
private void updateShelfIcons() {
updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
true /* showAmbient */, !mFullyDark /* showLowPriority */,
false /* hideDismissed */, mFullyDark /* hideRepliedMessages */,
mFullyDark /* hideCurrentMedia */);
true /* showAmbient */,
!mFullyDark /* showLowPriority */,
false /* hideDismissed */,
mFullyDark /* hideRepliedMessages */,
mFullyDark /* hideCurrentMedia */,
true /* hide centered icon */);
}
public void updateStatusBarIcons() {
updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
false /* showAmbient */, mShowLowPriority /* showLowPriority */,
false /* showAmbient */,
mShowLowPriority /* showLowPriority */,
true /* hideDismissed */,
true /* hideRepliedMessages */,
false /* hideCurrentMedia */);
false /* hideCurrentMedia */,
true /* hide centered icon */);
}
private void updateCenterIcon() {
updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
false /* showAmbient */,
!mFullyDark /* showLowPriority */,
false /* hideDismissed */,
false /* hideRepliedMessages */,
mFullyDark /* hideCurrentMedia */,
false /* hide centered icon */);
}
@VisibleForTesting
@@ -267,7 +316,8 @@ public class NotificationIconAreaController implements DarkReceiver,
*/
private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia) {
boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
boolean hideCenteredIcon) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
mNotificationScrollLayout.getChildCount());
@@ -277,8 +327,11 @@ public class NotificationIconAreaController implements DarkReceiver,
if (view instanceof ExpandableNotificationRow) {
NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
hideRepliedMessages, hideCurrentMedia)) {
toShow.add(function.apply(ent));
hideRepliedMessages, hideCurrentMedia, hideCenteredIcon)) {
StatusBarIconView iconView = function.apply(ent);
if (iconView != null) {
toShow.add(iconView);
}
}
}
}
@@ -368,32 +421,54 @@ public class NotificationIconAreaController implements DarkReceiver,
/**
* Applies {@link #mIconTint} to the notification icons.
* Applies {@link #mCenteredIconTint} to the center notification icon.
*/
private void applyNotificationIconsTint() {
for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
final StatusBarIconView iv = (StatusBarIconView) mNotificationIcons.getChildAt(i);
if (iv.getWidth() != 0) {
updateTintForIcon(iv);
updateTintForIcon(iv, mIconTint);
} else {
iv.executeOnLayout(() -> updateTintForIcon(iv));
iv.executeOnLayout(() -> updateTintForIcon(iv, mIconTint));
}
}
for (int i = 0; i < mCenteredIcon.getChildCount(); i++) {
final StatusBarIconView iv = (StatusBarIconView) mCenteredIcon.getChildAt(i);
if (iv.getWidth() != 0) {
updateTintForIcon(iv, mCenteredIconTint);
} else {
iv.executeOnLayout(() -> updateTintForIcon(iv, mCenteredIconTint));
}
}
}
private void updateTintForIcon(StatusBarIconView v) {
private void updateTintForIcon(StatusBarIconView v, int tint) {
boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
int color = StatusBarIconView.NO_COLOR;
boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mContrastColorUtil);
if (colorize) {
color = DarkIconDispatcher.getTint(mTintArea, v, mIconTint);
color = DarkIconDispatcher.getTint(mTintArea, v, tint);
}
v.setStaticDrawableColor(color);
v.setDecorColor(mIconTint);
v.setDecorColor(tint);
}
public void setDark(boolean dark) {
mNotificationIcons.setDark(dark, false, 0);
mShelfIcons.setDark(dark, false, 0);
mCenteredIcon.setDark(dark, false, 0);
}
/**
* Shows the icon view given in the center.
*/
public void showIconCentered(NotificationEntry entry) {
StatusBarIconView icon = entry == null ? null : entry.centeredIcon;
if (!Objects.equals(mCenteredIconView, icon)) {
mCenteredIconView = icon;
updateNotificationIcons();
}
}
public void showIconIsolated(StatusBarIconView icon, boolean animated) {
@@ -415,6 +490,8 @@ public class NotificationIconAreaController implements DarkReceiver,
if (mDarkAmount == 0 && !mStatusBarStateController.isDozing()) {
mNotificationIcons.setTranslationX(0);
mNotificationIcons.setTranslationY(0);
mCenteredIcon.setTranslationX(0);
mCenteredIcon.setTranslationY(0);
return;
}
@@ -423,6 +500,8 @@ public class NotificationIconAreaController implements DarkReceiver,
int translationY = getBurnInOffset(mBurnInOffset, false /* xAxis */) + yOffset;
mNotificationIcons.setTranslationX(translationX);
mNotificationIcons.setTranslationY(translationY);
mCenteredIcon.setTranslationX(translationX);
mCenteredIcon.setTranslationY(translationY);
}
@Override

View File

@@ -73,6 +73,8 @@ public class PhoneStatusBarView extends PanelBar {
private DarkReceiver mBattery;
private int mLastOrientation;
@Nullable
private View mCenterIconSpace;
@Nullable
private View mCutoutSpace;
@Nullable
private DisplayCutout mDisplayCutout;
@@ -105,6 +107,7 @@ public class PhoneStatusBarView extends PanelBar {
mBarTransitions.init();
mBattery = findViewById(R.id.battery);
mCutoutSpace = findViewById(R.id.cutout_space_view);
mCenterIconSpace = findViewById(R.id.centered_icon_area);
updateResources();
}
@@ -312,10 +315,12 @@ public class PhoneStatusBarView extends PanelBar {
if (mDisplayCutout == null || mDisplayCutout.isEmpty()
|| mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins != null) {
mCenterIconSpace.setVisibility(View.VISIBLE);
mCutoutSpace.setVisibility(View.GONE);
return;
}
mCenterIconSpace.setVisibility(View.GONE);
mCutoutSpace.setVisibility(View.VISIBLE);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();

View File

@@ -49,6 +49,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private NotificationIconAreaController mMockNotificiationAreaController;
private View mNotificationAreaInner;
private View mCenteredNotificationAreaView;
private StatusBarStateController mStatusBarStateController;
public CollapsedStatusBarFragmentTest() {
@@ -66,10 +67,14 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
mNotificationAreaInner = mock(View.class);
mCenteredNotificationAreaView = mock(View.class);
when(statusBar.getPanel()).thenReturn(mock(NotificationPanelView.class));
when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
mNotificationAreaInner);
when(mCenteredNotificationAreaView.animate()).thenReturn(mock(ViewPropertyAnimator.class));
when(mMockNotificiationAreaController.getCenteredNotificationAreaView()).thenReturn(
mCenteredNotificationAreaView);
}
@Test

View File

@@ -74,7 +74,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mStackScroller,
mPanelView,
new View(mContext),
mOperatorNameView);
mOperatorNameView,
new View(mContext));
mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
}
@@ -147,6 +148,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mStackScroller,
mPanelView,
new View(mContext),
new View(mContext),
new View(mContext));
newController.readFrom(mHeadsUpAppearanceController);