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
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:tag="base"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="big"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:background="#00000000"
|
||||
android:tag="bigMedia"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:background="#00000000"
|
||||
android:tag="bigMediaNarrow"
|
||||
>
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="128dp"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:tag="bigPicture"
|
||||
>
|
||||
<ImageView
|
||||
android:id="@+id/big_picture"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="bigText"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="inbox"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:layout_height="64dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="#00000000"
|
||||
android:tag="media"
|
||||
>
|
||||
<include layout="@layout/notification_template_icon_group"
|
||||
android:layout_width="@dimen/notification_large_icon_width"
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
<!-- Whether to use cheap, less good looking shadows for recents -->
|
||||
<bool name="config_recents_fake_shadows">false</bool>
|
||||
|
||||
<!-- Whether to clip notification contents with a rounded rectangle. Might be expensive on
|
||||
certain GPU's and thus can be turned off with only minimal visual impact. -->
|
||||
<bool name="config_notifications_round_rect_clipping">true</bool>
|
||||
|
||||
<!-- The theme to use for RecentsActivity. -->
|
||||
<item type="style" name="config_recents_activity_theme">@style/RecentsTheme.Wallpaper</item>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -41,4 +41,9 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
|
||||
mInvertHelper.update(dark);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsRoundRectClipping() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user