1 /* 2 * Copyright (C) 2017 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.launcher3.notification; 18 19 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED; 20 21 import android.animation.AnimatorSet; 22 import android.animation.ObjectAnimator; 23 import android.animation.ValueAnimator; 24 import android.annotation.TargetApi; 25 import android.content.Context; 26 import android.graphics.Color; 27 import android.graphics.drawable.ColorDrawable; 28 import android.os.Build; 29 import android.text.TextUtils; 30 import android.util.AttributeSet; 31 import android.util.FloatProperty; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.FrameLayout; 35 import android.widget.TextView; 36 37 import com.android.launcher3.Launcher; 38 import com.android.launcher3.R; 39 import com.android.launcher3.model.data.ItemInfo; 40 import com.android.launcher3.touch.SingleAxisSwipeDetector; 41 42 /** 43 * A {@link android.widget.FrameLayout} that contains a single notification, 44 * e.g. icon + title + text. 45 */ 46 @TargetApi(Build.VERSION_CODES.N) 47 public class NotificationMainView extends FrameLayout { 48 49 private static final FloatProperty<NotificationMainView> CONTENT_TRANSLATION = 50 new FloatProperty<NotificationMainView>("contentTranslation") { 51 @Override 52 public void setValue(NotificationMainView view, float v) { 53 view.setContentTranslation(v); 54 } 55 56 @Override 57 public Float get(NotificationMainView view) { 58 return view.mTextAndBackground.getTranslationX(); 59 } 60 }; 61 62 // This is used only to track the notification view, so that it can be properly logged. 63 public static final ItemInfo NOTIFICATION_ITEM_INFO = new ItemInfo(); 64 65 private NotificationInfo mNotificationInfo; 66 private ViewGroup mTextAndBackground; 67 private int mBackgroundColor; 68 private TextView mTitleView; 69 private TextView mTextView; 70 private View mIconView; 71 72 private SingleAxisSwipeDetector mSwipeDetector; 73 74 private final ColorDrawable mColorDrawable; 75 NotificationMainView(Context context)76 public NotificationMainView(Context context) { 77 this(context, null, 0); 78 } 79 NotificationMainView(Context context, AttributeSet attrs)80 public NotificationMainView(Context context, AttributeSet attrs) { 81 this(context, attrs, 0); 82 } 83 NotificationMainView(Context context, AttributeSet attrs, int defStyle)84 public NotificationMainView(Context context, AttributeSet attrs, int defStyle) { 85 super(context, attrs, defStyle); 86 87 mColorDrawable = new ColorDrawable(Color.TRANSPARENT); 88 } 89 90 @Override onFinishInflate()91 protected void onFinishInflate() { 92 super.onFinishInflate(); 93 94 mTextAndBackground = findViewById(R.id.text_and_background); 95 mTitleView = mTextAndBackground.findViewById(R.id.title); 96 mTextView = mTextAndBackground.findViewById(R.id.text); 97 mIconView = findViewById(R.id.popup_item_icon); 98 99 ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground(); 100 updateBackgroundColor(colorBackground.getColor()); 101 } 102 updateBackgroundColor(int color)103 private void updateBackgroundColor(int color) { 104 mBackgroundColor = color; 105 mColorDrawable.setColor(color); 106 mTextAndBackground.setBackground(mColorDrawable); 107 if (mNotificationInfo != null) { 108 mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(), 109 mBackgroundColor)); 110 } 111 } 112 113 /** 114 * Animates the background color to a new color. 115 * @param color The color to change to. 116 * @param animatorSetOut The AnimatorSet where we add the color animator to. 117 */ updateBackgroundColor(int color, AnimatorSet animatorSetOut)118 public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) { 119 int oldColor = mBackgroundColor; 120 ValueAnimator colors = ValueAnimator.ofArgb(oldColor, color); 121 colors.addUpdateListener(valueAnimator -> { 122 int newColor = (int) valueAnimator.getAnimatedValue(); 123 updateBackgroundColor(newColor); 124 }); 125 animatorSetOut.play(colors); 126 } 127 128 /** 129 * Sets the content of this view, animating it after a new icon shifts up if necessary. 130 */ applyNotificationInfo(NotificationInfo mainNotification, boolean animate)131 public void applyNotificationInfo(NotificationInfo mainNotification, boolean animate) { 132 mNotificationInfo = mainNotification; 133 NotificationListener listener = NotificationListener.getInstanceIfConnected(); 134 if (listener != null) { 135 listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey}); 136 } 137 CharSequence title = mNotificationInfo.title; 138 CharSequence text = mNotificationInfo.text; 139 if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(text)) { 140 mTitleView.setText(title.toString()); 141 mTextView.setText(text.toString()); 142 } else { 143 mTitleView.setMaxLines(2); 144 mTitleView.setText(TextUtils.isEmpty(title) ? text.toString() : title.toString()); 145 mTextView.setVisibility(GONE); 146 } 147 mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(), 148 mBackgroundColor)); 149 if (mNotificationInfo.intent != null) { 150 setOnClickListener(mNotificationInfo); 151 } 152 setContentTranslation(0); 153 // Add a stub ItemInfo so that logging populates the correct container and item types 154 // instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively. 155 setTag(NOTIFICATION_ITEM_INFO); 156 if (animate) { 157 ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start(); 158 } 159 } 160 setContentTranslation(float translation)161 public void setContentTranslation(float translation) { 162 mTextAndBackground.setTranslationX(translation); 163 mIconView.setTranslationX(translation); 164 } 165 getNotificationInfo()166 public NotificationInfo getNotificationInfo() { 167 return mNotificationInfo; 168 } 169 170 canChildBeDismissed()171 public boolean canChildBeDismissed() { 172 return mNotificationInfo != null && mNotificationInfo.dismissable; 173 } 174 onChildDismissed()175 public void onChildDismissed() { 176 Launcher launcher = Launcher.getLauncher(getContext()); 177 launcher.getPopupDataProvider().cancelNotification( 178 mNotificationInfo.notificationKey); 179 launcher.getStatsLogManager().logger().log(LAUNCHER_NOTIFICATION_DISMISSED); 180 } 181 } 182