1 /*
2  * Copyright (C) 2018 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.example.sampleleanbacklauncher.notifications;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.content.res.Resources;
22 import android.graphics.Canvas;
23 import android.graphics.Color;
24 import android.graphics.Paint;
25 import android.graphics.RectF;
26 import android.text.Layout;
27 import android.text.TextUtils;
28 import android.util.AttributeSet;
29 import android.view.View;
30 import android.view.ViewTreeObserver;
31 import android.widget.ImageView;
32 import android.widget.LinearLayout;
33 import android.widget.TextView;
34 
35 import com.example.sampleleanbacklauncher.R;
36 
37 /**
38  * View for a non-dismissible notification displayed in the notifications side panel.
39  */
40 public class NotificationPanelItemView extends LinearLayout
41         implements ViewTreeObserver.OnGlobalFocusChangeListener {
42     private RectF mProgressBounds;
43     private Paint mProgressPaint;
44     private Paint mProgressMaxPaint;
45     private int mProgressStrokeWidth;
46     private int mProgressDiameter;
47     private int mProgressPaddingStart;
48     private int mProgressPaddingTop;
49     private int mProgressColor;
50     private int mProgressMaxColor;
51     private int mProgress;
52     private int mProgressMax;
53     private boolean mIsRtl;
54     private ImageView mIcon;
55     private TextView mTitle;
56     private TextView mText;
57     private TextView mExpandedText;
58     protected View mMainContentText;
59     protected String mNotificationKey;
60     private TvNotification mNotification;
61 
NotificationPanelItemView(Context context)62     public NotificationPanelItemView(Context context) {
63         super(context);
64         initializeLayoutValues();
65     }
66 
NotificationPanelItemView(Context context, AttributeSet attrs)67     public NotificationPanelItemView(Context context, AttributeSet attrs) {
68         super(context, attrs);
69         initializeLayoutValues();
70     }
71 
initializeLayoutValues()72     private void initializeLayoutValues() {
73         Configuration config = getContext().getResources().getConfiguration();
74         mIsRtl = (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
75 
76         Resources res = getResources();
77         mProgressStrokeWidth = res.getDimensionPixelSize(
78                 R.dimen.notification_progress_stroke_width);
79         mProgressColor = res.getColor(R.color.notification_progress_stroke_color, null);
80         mProgressMaxColor = res.getColor(R.color.notification_progress_stroke_max_color, null);
81         mProgressDiameter = res.getDimensionPixelSize(R.dimen.notification_progress_circle_size);
82         mProgressPaddingTop = res.getDimensionPixelOffset(
83                 R.dimen.notification_progress_circle_padding_top);
84         mProgressPaddingStart = res.getDimensionPixelOffset(
85                 R.dimen.notification_progress_circle_padding_start);
86 
87         mProgressPaint = new Paint();
88         mProgressPaint.setAntiAlias(true);
89         mProgressPaint.setStyle(Paint.Style.STROKE);
90         mProgressPaint.setColor(mProgressColor);
91         mProgressPaint.setStrokeWidth(mProgressStrokeWidth);
92 
93         mProgressMaxPaint = new Paint();
94         mProgressMaxPaint.setAntiAlias(true);
95         mProgressMaxPaint.setStyle(Paint.Style.STROKE);
96         mProgressMaxPaint.setColor(mProgressMaxColor);
97         mProgressMaxPaint.setStrokeWidth(mProgressStrokeWidth);
98     }
99 
100     @Override
onAttachedToWindow()101     protected void onAttachedToWindow() {
102         super.onAttachedToWindow();
103         getViewTreeObserver().addOnGlobalFocusChangeListener(this);
104     }
105 
106     @Override
onDetachedFromWindow()107     protected void onDetachedFromWindow() {
108         super.onDetachedFromWindow();
109         getViewTreeObserver().removeOnGlobalFocusChangeListener(this);
110     }
111 
112     @Override
onFinishInflate()113     protected void onFinishInflate() {
114         super.onFinishInflate();
115         mIcon = findViewById(R.id.notification_icon);
116         mTitle = findViewById(R.id.notification_title);
117         mText = findViewById(R.id.notification_text);
118         mMainContentText = findViewById(R.id.notification_container);
119         mExpandedText = findViewById(R.id.notification_expanded_text);
120 
121         mMainContentText.setOnClickListener(new View.OnClickListener() {
122             @Override
123             public void onClick(View view) {
124                 if (mNotificationKey != null) {
125                     NotificationsUtils.openNotification(view.getContext(), mNotificationKey);
126                 }
127             }
128         });
129     }
130 
setNotification(TvNotification notif)131     public void setNotification(TvNotification notif) {
132         mNotification = notif;
133         mNotificationKey = notif.getNotificationKey();
134         mTitle.setText(notif.getTitle());
135         mText.setText(notif.getText());
136         if (!TextUtils.isEmpty(notif.getTitle())) {
137             if (!TextUtils.isEmpty(notif.getText())) {
138                 String formatting = getResources().getString(
139                         R.string.notification_content_description_format);
140                 mMainContentText.setContentDescription(
141                         String.format(formatting, notif.getTitle(), notif.getText()));
142             } else {
143                 mMainContentText.setContentDescription(notif.getTitle());
144             }
145         } else {
146             mMainContentText.setContentDescription(notif.getText());
147         }
148         mExpandedText.setText(notif.getText());
149         mIcon.setImageIcon(notif.getSmallIcon());
150         setProgress(notif.getProgress(), notif.getProgressMax());
151         mMainContentText.setVisibility(VISIBLE);
152     }
153 
setProgress(int progress, int progressMax)154     public void setProgress(int progress, int progressMax) {
155         mProgress = progress;
156         mProgressMax = progressMax;
157         if (mProgressMax != 0) {
158             if (mProgressBounds == null) {
159                 mProgressBounds = new RectF();
160             }
161             setWillNotDraw(false);
162         } else {
163             mProgressBounds = null;
164             setWillNotDraw(true);
165         }
166         requestLayout();
167     }
168 
169     @Override
onLayout(boolean changed, int l, int t, int r, int b)170     protected void onLayout(boolean changed, int l, int t, int r, int b) {
171         super.onLayout(changed, l, t, r, b);
172         if (mProgressBounds != null) {
173             int left, right;
174             int top = mProgressPaddingTop;
175             int bottom = top + mProgressDiameter;
176             if (mIsRtl) {
177                 right = r - mProgressPaddingStart;
178                 left = right - mProgressDiameter;
179             } else {
180                 left = mProgressPaddingStart;
181                 right = left + mProgressDiameter;
182             }
183 
184             mProgressBounds.set(left, top, right, bottom);
185         }
186     }
187 
188     @Override
onDraw(Canvas canvas)189     protected void onDraw(Canvas canvas) {
190         super.onDraw(canvas);
191 
192         if (mProgressMax != 0) {
193             float sweepAngle = 360f * mProgress / mProgressMax;
194             if (mIsRtl) {
195                 canvas.drawArc(mProgressBounds, -90, -sweepAngle, false, mProgressPaint);
196                 canvas.drawArc(mProgressBounds, -90, 360 - sweepAngle, false,
197                         mProgressMaxPaint);
198             } else {
199                 canvas.drawArc(mProgressBounds, -90, sweepAngle, false, mProgressPaint);
200                 canvas.drawArc(mProgressBounds, sweepAngle - 90, 360 - sweepAngle, false,
201                         mProgressMaxPaint);
202             }
203         }
204     }
205 
isContentTextCutOff()206     private boolean isContentTextCutOff() {
207         Layout layout = mText.getLayout();
208         if (layout != null) {
209             int lines = layout.getLineCount();
210             if (lines > 0) {
211                 int ellipsisCount = layout.getEllipsisCount(lines - 1);
212                 if (ellipsisCount > 0) {
213                     return true;
214                 }
215             }
216         }
217         return false;
218     }
219 
expandText()220     protected void expandText() {
221         mText.setVisibility(GONE);
222         mTitle.setMaxLines(2);
223         mExpandedText.setVisibility(VISIBLE);
224         setBackgroundColor(
225                 getResources().getColor(R.color.notification_expanded_text_background));
226     }
227 
collapseText()228     protected void collapseText() {
229         mExpandedText.setVisibility(GONE);
230         mTitle.setMaxLines(1);
231         mText.setVisibility(VISIBLE);
232         setBackgroundColor(Color.TRANSPARENT);
233     }
234 
235     @Override
onGlobalFocusChanged(View oldFocus, View newFocus)236     public void onGlobalFocusChanged(View oldFocus, View newFocus) {
237         View currentFocus = getFocusedChild();
238         if (currentFocus == null) {
239             collapseText();
240         } else if ((newFocus == currentFocus || newFocus.getParent() == currentFocus)
241                 && isContentTextCutOff()) {
242             expandText();
243         }
244     }
245 }
246