1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.systemui.statusbar.notification.row.wrapper; 18 19 import android.content.Context; 20 import android.graphics.drawable.AnimatedImageDrawable; 21 import android.graphics.drawable.Drawable; 22 import android.view.View; 23 import android.view.ViewGroup; 24 25 import com.android.internal.widget.MessagingGroup; 26 import com.android.internal.widget.MessagingImageMessage; 27 import com.android.internal.widget.MessagingLayout; 28 import com.android.internal.widget.MessagingLinearLayout; 29 import com.android.systemui.res.R; 30 import com.android.systemui.statusbar.TransformableView; 31 import com.android.systemui.statusbar.ViewTransformationHelper; 32 import com.android.systemui.statusbar.notification.NotificationUtils; 33 import com.android.systemui.statusbar.notification.TransformState; 34 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; 35 import com.android.systemui.statusbar.notification.row.HybridNotificationView; 36 37 /** 38 * Wraps a notification containing a messaging template 39 */ 40 public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper { 41 42 private final int mMinHeightWithActions; 43 private final View mTitle; 44 private final View mTitleInHeader; 45 private MessagingLayout mMessagingLayout; 46 private MessagingLinearLayout mMessagingLinearLayout; 47 private ViewGroup mImageMessageContainer; 48 NotificationMessagingTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row)49 protected NotificationMessagingTemplateViewWrapper(Context ctx, View view, 50 ExpandableNotificationRow row) { 51 super(ctx, view, row); 52 mTitle = mView.findViewById(com.android.internal.R.id.title); 53 mTitleInHeader = mView.findViewById(com.android.internal.R.id.header_text_secondary); 54 mMessagingLayout = (MessagingLayout) view; 55 mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx, 56 R.dimen.notification_messaging_actions_min_height); 57 } 58 resolveViews()59 private void resolveViews() { 60 mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout(); 61 mImageMessageContainer = mMessagingLayout.getImageMessageContainer(); 62 } 63 64 @Override onContentUpdated(ExpandableNotificationRow row)65 public void onContentUpdated(ExpandableNotificationRow row) { 66 // Reinspect the notification. Before the super call, because the super call also updates 67 // the transformation types and we need to have our values set by then. 68 resolveViews(); 69 super.onContentUpdated(row); 70 } 71 72 @Override updateTransformedTypes()73 protected void updateTransformedTypes() { 74 // This also clears the existing types 75 super.updateTransformedTypes(); 76 if (mMessagingLinearLayout != null) { 77 mTransformationHelper.addTransformedView(mMessagingLinearLayout); 78 } 79 // The title is not as important for messaging, and stays in the header when expanded, 80 // but this ensures it animates cleanly between the two positions 81 if (mTitle == null && mTitleInHeader != null) { 82 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, 83 mTitleInHeader); 84 } 85 setCustomImageMessageTransform(mTransformationHelper, mImageMessageContainer); 86 } 87 setCustomImageMessageTransform( ViewTransformationHelper transformationHelper, ViewGroup imageMessageContainer)88 static void setCustomImageMessageTransform( 89 ViewTransformationHelper transformationHelper, ViewGroup imageMessageContainer) { 90 if (imageMessageContainer != null) { 91 // Let's ignore the image message container since that is transforming as part of the 92 // messages already. This is also required to prevent a clipping artifact caused by the 93 // alpha layering triggering hardware rendering mode that in turn results in more 94 // aggressive clipping than we want. 95 transformationHelper.setCustomTransformation( 96 new ViewTransformationHelper.CustomTransformation() { 97 @Override 98 public boolean transformTo( 99 TransformState ownState, 100 TransformableView otherView, 101 float transformationAmount) { 102 if (otherView instanceof HybridNotificationView) { 103 return false; 104 } 105 // we're hidden by default by the transformState 106 ownState.ensureVisible(); 107 // Let's do nothing otherwise, this is already handled by the messages 108 return true; 109 } 110 111 @Override 112 public boolean transformFrom( 113 TransformState ownState, 114 TransformableView otherView, 115 float transformationAmount) { 116 return transformTo(ownState, otherView, transformationAmount); 117 } 118 }, imageMessageContainer.getId()); 119 } 120 } 121 122 @Override setRemoteInputVisible(boolean visible)123 public void setRemoteInputVisible(boolean visible) { 124 mMessagingLayout.showHistoricMessages(visible); 125 } 126 127 @Override getMinLayoutHeight()128 public int getMinLayoutHeight() { 129 if (mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE) { 130 return mMinHeightWithActions; 131 } 132 return super.getMinLayoutHeight(); 133 } 134 135 /** 136 * Starts or stops the animations in any drawables contained in this Messaging Notification. 137 * 138 * @param running Whether the animations should be set to run. 139 */ 140 @Override setAnimationsRunning(boolean running)141 public void setAnimationsRunning(boolean running) { 142 if (mMessagingLayout == null) { 143 return; 144 } 145 146 for (MessagingGroup group : mMessagingLayout.getMessagingGroups()) { 147 for (int i = 0; i < group.getMessageContainer().getChildCount(); i++) { 148 View view = group.getMessageContainer().getChildAt(i); 149 // We only need to set animations in MessagingImageMessages. 150 if (!(view instanceof MessagingImageMessage)) { 151 continue; 152 } 153 MessagingImageMessage imageMessage = 154 (com.android.internal.widget.MessagingImageMessage) view; 155 156 // If the drawable isn't an AnimatedImageDrawable, we can't set it to animate. 157 Drawable d = imageMessage.getDrawable(); 158 if (!(d instanceof AnimatedImageDrawable)) { 159 continue; 160 } 161 AnimatedImageDrawable animatedImageDrawable = (AnimatedImageDrawable) d; 162 if (running) { 163 animatedImageDrawable.start(); 164 } else { 165 animatedImageDrawable.stop(); 166 } 167 } 168 } 169 } 170 } 171