From be4116a3471184748bf6545506b59d48c720ea58 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Wed, 20 May 2015 20:04:08 -0700 Subject: Round rect clipping for notification contents Enable round rect clipping on notifications for the following kind of notifications: - Big picture style. - Big media narrow style. - Custom notifications. Bug: 16142505 Change-Id: I157650fe470636ed624a81557c08135827eac0cb --- packages/SystemUI/res/values/config.xml | 4 ++ .../NotificationBigMediaNarrowViewWrapper.java | 36 +++++++++++++ .../NotificationBigPictureViewWrapper.java | 35 +++++++++++++ .../statusbar/NotificationContentView.java | 60 ++++++++++++++++++++-- .../statusbar/NotificationCustomViewWrapper.java | 5 ++ .../statusbar/NotificationViewWrapper.java | 28 +++++++--- 6 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigMediaNarrowViewWrapper.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigPictureViewWrapper.java (limited to 'packages/SystemUI') diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 354e99d..139462d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -42,6 +42,10 @@ false + + true + @style/RecentsTheme.Wallpaper diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigMediaNarrowViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigMediaNarrowViewWrapper.java new file mode 100644 index 0000000..91e5404 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigMediaNarrowViewWrapper.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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.statusbar; + +import android.content.Context; +import android.view.View; + +/** + * Wraps a big media narrow notification template layout. + */ +public class NotificationBigMediaNarrowViewWrapper extends NotificationMediaViewWrapper { + + protected NotificationBigMediaNarrowViewWrapper(Context ctx, + View view) { + super(ctx, view); + } + + @Override + public boolean needsRoundRectClipping() { + return true; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigPictureViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigPictureViewWrapper.java new file mode 100644 index 0000000..ffe0cd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBigPictureViewWrapper.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 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.statusbar; + +import android.content.Context; +import android.view.View; + +/** + * Wraps a notification view inflated from a big picture style template. + */ +public class NotificationBigPictureViewWrapper extends NotificationTemplateViewWrapper { + + protected NotificationBigPictureViewWrapper(Context ctx, View view) { + super(ctx, view); + } + + @Override + public boolean needsRoundRectClipping() { + return true; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 110b14c..dec2fc7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar; import android.content.Context; +import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -24,6 +25,7 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; @@ -46,21 +48,26 @@ public class NotificationContentView extends FrameLayout { private final Rect mClipBounds = new Rect(); private final int mSmallHeight; private final int mHeadsUpHeight; + private final int mRoundRectRadius; private final Interpolator mLinearInterpolator = new LinearInterpolator(); + private final boolean mRoundRectClippingEnabled; private View mContractedChild; private View mExpandedChild; private View mHeadsUpChild; private NotificationViewWrapper mContractedWrapper; + private NotificationViewWrapper mExpandedWrapper; + private NotificationViewWrapper mHeadsUpWrapper; private int mClipTopAmount; private int mContentHeight; + private int mUnrestrictedContentHeight; private int mVisibleType = VISIBLE_TYPE_CONTRACTED; private boolean mDark; private final Paint mFadePaint = new Paint(); private boolean mAnimate; private boolean mIsHeadsUp; - private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener + private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -70,12 +77,25 @@ public class NotificationContentView extends FrameLayout { } }; + private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), mUnrestrictedContentHeight, + mRoundRectRadius); + } + }; + public NotificationContentView(Context context, AttributeSet attrs) { super(context, attrs); mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height); + mRoundRectRadius = getResources().getDimensionPixelSize( + R.dimen.notification_material_rounded_rect_radius); + mRoundRectClippingEnabled = getResources().getBoolean( + R.bool.config_notifications_round_rect_clipping); reset(true); + setOutlineProvider(mOutlineProvider); } @Override @@ -127,6 +147,7 @@ public class NotificationContentView extends FrameLayout { protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); updateClipping(); + invalidateOutline(); } @Override @@ -177,6 +198,7 @@ public class NotificationContentView extends FrameLayout { mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child); selectLayout(false /* animate */, true /* force */); mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); + updateRoundRectClipping(); } public void setExpandedChild(View child) { @@ -186,7 +208,9 @@ public class NotificationContentView extends FrameLayout { } addView(child); mExpandedChild = child; + mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child); selectLayout(false /* animate */, true /* force */); + updateRoundRectClipping(); } public void setHeadsUpChild(View child) { @@ -196,7 +220,9 @@ public class NotificationContentView extends FrameLayout { } addView(child); mHeadsUpChild = child; + mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child); selectLayout(false /* animate */, true /* force */); + updateRoundRectClipping(); } @Override @@ -222,10 +248,11 @@ public class NotificationContentView extends FrameLayout { } public void setContentHeight(int contentHeight) { - contentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight()); - mContentHeight = contentHeight; + mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());; + mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight()); selectLayout(mAnimate /* animate */, false /* force */); updateClipping(); + invalidateOutline(); } public int getContentHeight() { @@ -250,6 +277,27 @@ public class NotificationContentView extends FrameLayout { updateClipping(); } + private void updateRoundRectClipping() { + boolean enabled = needsRoundRectClipping(); + setClipToOutline(enabled); + } + + private boolean needsRoundRectClipping() { + if (!mRoundRectClippingEnabled) { + return false; + } + boolean needsForContracted = mContractedChild != null + && mContractedChild.getVisibility() == View.VISIBLE + && mContractedWrapper.needsRoundRectClipping(); + boolean needsForExpanded = mExpandedChild != null + && mExpandedChild.getVisibility() == View.VISIBLE + && mExpandedWrapper.needsRoundRectClipping(); + boolean needsForHeadsUp = mExpandedChild != null + && mExpandedChild.getVisibility() == View.VISIBLE + && mExpandedWrapper.needsRoundRectClipping(); + return needsForContracted || needsForExpanded || needsForHeadsUp; + } + private void updateClipping() { mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight); setClipBounds(mClipBounds); @@ -290,6 +338,7 @@ public class NotificationContentView extends FrameLayout { mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null); } setLayerType(LAYER_TYPE_NONE, null); + updateRoundRectClipping(); } private void runSwitchAnimation(int visibleType) { @@ -315,6 +364,7 @@ public class NotificationContentView extends FrameLayout { updateViewVisibilities(mVisibleType); } }); + updateRoundRectClipping(); } /** @@ -358,6 +408,10 @@ public class NotificationContentView extends FrameLayout { mContractedWrapper.notifyContentUpdated(); mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); } + if (mExpandedChild != null) { + mExpandedWrapper.notifyContentUpdated(); + } + updateRoundRectClipping(); } public boolean isContentExpandable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java index 0702d7e..6fd341b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java @@ -41,4 +41,9 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { mInvertHelper.update(dark); } } + + @Override + public boolean needsRoundRectClipping() { + return true; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java index 44e8b85..b362a29 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java @@ -25,15 +25,23 @@ import android.view.View; */ public abstract class NotificationViewWrapper { + private static final String TAG_BIG_MEDIA_NARROW = "bigMediaNarrow"; + private static final String TAG_MEDIA = "media"; + private static final String TAG_BIG_PICTURE = "bigPicture"; + protected final View mView; public static NotificationViewWrapper wrap(Context ctx, View v) { - - // TODO: Figure out a better way to find out which template the view is. - if (v.findViewById(com.android.internal.R.id.media_actions) != null) { - return new NotificationMediaViewWrapper(ctx, v); - } else if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) { - return new NotificationTemplateViewWrapper(ctx, v); + if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) { + if (TAG_BIG_MEDIA_NARROW.equals(v.getTag())) { + return new NotificationBigMediaNarrowViewWrapper(ctx, v); + } else if (TAG_MEDIA.equals(v.getTag())) { + return new NotificationMediaViewWrapper(ctx, v); + } else if (TAG_BIG_PICTURE.equals(v.getTag())) { + return new NotificationBigMediaNarrowViewWrapper(ctx, v); + } else { + return new NotificationTemplateViewWrapper(ctx, v); + } } else { return new NotificationCustomViewWrapper(v); } @@ -56,4 +64,12 @@ public abstract class NotificationViewWrapper { * Notifies this wrapper that the content of the view might have changed. */ public void notifyContentUpdated() {} + + /** + * @return true if this template might need to be clipped with a round rect to make it look + * nice, false otherwise + */ + public boolean needsRoundRectClipping() { + return false; + } } -- cgit v1.1