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.android.systemui.statusbar;
18 
19 import android.content.Context;
20 import android.graphics.Rect;
21 import android.os.Bundle;
22 import android.os.Parcelable;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.widget.TextView;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 import com.android.keyguard.AlphaOptimizedLinearLayout;
29 import com.android.systemui.plugins.DarkIconDispatcher;
30 import com.android.systemui.res.R;
31 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
32 import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
33 
34 import java.util.ArrayList;
35 
36 /**
37  * The view in the statusBar that contains part of the heads-up information
38  */
39 public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
40     private static final String HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE =
41             "heads_up_status_bar_view_super_parcelable";
42     private static final String VISIBILITY = "visibility";
43     private static final String ALPHA = "alpha";
44     private final Rect mLayoutedIconRect = new Rect();
45     private final int[] mTmpPosition = new int[2];
46     private final Rect mIconDrawingRect = new Rect();
47     private View mIconPlaceholder;
48     private TextView mTextView;
49     private NotificationEntry mShowingEntry;
50     private Runnable mOnDrawingRectChangedListener;
51 
HeadsUpStatusBarView(Context context)52     public HeadsUpStatusBarView(Context context) {
53         this(context, null);
54     }
55 
HeadsUpStatusBarView(Context context, AttributeSet attrs)56     public HeadsUpStatusBarView(Context context, AttributeSet attrs) {
57         this(context, attrs, 0);
58     }
59 
HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr)60     public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
61         this(context, attrs, defStyleAttr, 0);
62     }
63 
HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)64     public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr,
65             int defStyleRes) {
66         super(context, attrs, defStyleAttr, defStyleRes);
67     }
68 
69     @Override
onSaveInstanceState()70     public Bundle onSaveInstanceState() {
71         Bundle bundle = new Bundle();
72         bundle.putParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE,
73                 super.onSaveInstanceState());
74         bundle.putInt(VISIBILITY, getVisibility());
75         bundle.putFloat(ALPHA, getAlpha());
76 
77         return bundle;
78     }
79 
80     @Override
onRestoreInstanceState(Parcelable state)81     public void onRestoreInstanceState(Parcelable state) {
82         if (!(state instanceof Bundle)) {
83             super.onRestoreInstanceState(state);
84             return;
85         }
86 
87         Bundle bundle = (Bundle) state;
88         Parcelable superState = bundle.getParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE);
89         super.onRestoreInstanceState(superState);
90         if (bundle.containsKey(VISIBILITY)) {
91             setVisibility(bundle.getInt(VISIBILITY));
92         }
93         if (bundle.containsKey(ALPHA)) {
94             setAlpha(bundle.getFloat(ALPHA));
95         }
96     }
97 
98     @VisibleForTesting
HeadsUpStatusBarView(Context context, View iconPlaceholder, TextView textView)99     public HeadsUpStatusBarView(Context context, View iconPlaceholder, TextView textView) {
100         this(context);
101         mIconPlaceholder = iconPlaceholder;
102         mTextView = textView;
103     }
104 
105     @Override
onFinishInflate()106     protected void onFinishInflate() {
107         super.onFinishInflate();
108         mIconPlaceholder = findViewById(R.id.icon_placeholder);
109         mTextView = findViewById(R.id.text);
110     }
111 
setEntry(NotificationEntry entry)112     public void setEntry(NotificationEntry entry) {
113         if (mShowingEntry != null) {
114             mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener);
115         }
116         mShowingEntry = entry;
117 
118         if (mShowingEntry != null) {
119             CharSequence text = entry.getHeadsUpStatusBarText().getValue();
120             if (entry.isSensitive().getValue()) {
121                 text = entry.getHeadsUpStatusBarTextPublic().getValue();
122             }
123             mTextView.setText(text);
124             mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener);
125         }
126     }
127 
128     private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> {
129         if (entry != mShowingEntry) {
130             throw new IllegalStateException("Got a sensitivity change for " + entry
131                     + " but mShowingEntry is " + mShowingEntry);
132         }
133         // Update the text
134         setEntry(entry);
135     };
136 
137     @Override
onLayout(boolean changed, int l, int t, int r, int b)138     protected void onLayout(boolean changed, int l, int t, int r, int b) {
139         super.onLayout(changed, l, t, r, b);
140         mIconPlaceholder.getLocationOnScreen(mTmpPosition);
141         int left = mTmpPosition[0];
142         int top = mTmpPosition[1];
143         int right = left + mIconPlaceholder.getWidth();
144         int bottom = top + mIconPlaceholder.getHeight();
145         mLayoutedIconRect.set(left, top, right, bottom);
146         updateDrawingRect();
147     }
148 
updateDrawingRect()149     private void updateDrawingRect() {
150         float oldLeft = mIconDrawingRect.left;
151         mIconDrawingRect.set(mLayoutedIconRect);
152         if (oldLeft != mIconDrawingRect.left && mOnDrawingRectChangedListener != null) {
153             mOnDrawingRectChangedListener.run();
154         }
155     }
156 
getShowingEntry()157     public NotificationEntry getShowingEntry() {
158         return mShowingEntry;
159     }
160 
getIconDrawingRect()161     public Rect getIconDrawingRect() {
162         return mIconDrawingRect;
163     }
164 
onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint)165     public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
166         mTextView.setTextColor(DarkIconDispatcher.getTint(areas, this, tint));
167     }
168 
setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener)169     public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
170         mOnDrawingRectChangedListener = onDrawingRectChangedListener;
171     }
172 }
173