• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.emptyshade.ui.view;
18 
19 import android.annotation.ColorInt;
20 import android.annotation.DrawableRes;
21 import android.annotation.StringRes;
22 import android.content.Context;
23 import android.content.res.ColorStateList;
24 import android.content.res.Configuration;
25 import android.graphics.Rect;
26 import android.graphics.drawable.Drawable;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.view.View;
30 import android.widget.TextView;
31 
32 import androidx.annotation.NonNull;
33 
34 import com.android.systemui.animation.LaunchableView;
35 import com.android.systemui.animation.LaunchableViewDelegate;
36 import com.android.systemui.res.R;
37 import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix;
38 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
39 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
40 
41 import kotlin.Unit;
42 
43 import java.util.Objects;
44 
45 public class EmptyShadeView extends StackScrollerDecorView implements LaunchableView {
46     private static final String TAG = "EmptyShadeView";
47 
48     private TextView mEmptyText;
49     private TextView mEmptyFooterText;
50 
51     private @StringRes int mTextId = R.string.empty_shade_text;
52     private String mTextString;
53 
54     private @DrawableRes int mFooterIcon;
55     private @StringRes int mFooterText;
56     // This view is initially gone in the xml.
57     private @Visibility int mFooterVisibility = View.GONE;
58     private int mSize;
59 
60     private final LaunchableViewDelegate mLaunchableViewDelegate = new LaunchableViewDelegate(this,
61             visibility -> {
62                 super.setVisibility(visibility);
63                 return Unit.INSTANCE;
64             });
65 
EmptyShadeView(Context context, AttributeSet attrs)66     public EmptyShadeView(Context context, AttributeSet attrs) {
67         super(context, attrs);
68         mSize = getResources().getDimensionPixelSize(
69                 R.dimen.notifications_unseen_footer_icon_size);
70         if (ModesEmptyShadeFix.isEnabled()) {
71             mTextString = getContext().getString(R.string.empty_shade_text);
72         } else {
73             // These will be set by the binder when appropriate if ModesEmptyShadeFix is on.
74             mFooterIcon = R.drawable.ic_friction_lock_closed;
75             mFooterText = R.string.unlock_to_see_notif_text;
76         }
77     }
78 
79     @Override
setVisibility(int visibility)80     public void setVisibility(int visibility) {
81         mLaunchableViewDelegate.setVisibility(visibility);
82     }
83 
84     @Override
setShouldBlockVisibilityChanges(boolean block)85     public void setShouldBlockVisibilityChanges(boolean block) {
86         /* check if */ ModesEmptyShadeFix.isUnexpectedlyInLegacyMode();
87         mLaunchableViewDelegate.setShouldBlockVisibilityChanges(block);
88     }
89 
90     @Override
onActivityLaunchAnimationEnd()91     public void onActivityLaunchAnimationEnd() {
92         /* check if */ ModesEmptyShadeFix.isUnexpectedlyInLegacyMode();
93     }
94 
95     @Override
96     @NonNull
getPaddingForLaunchAnimation()97     public Rect getPaddingForLaunchAnimation() {
98         /* check if */ ModesEmptyShadeFix.isUnexpectedlyInLegacyMode();
99         return new Rect();
100     }
101 
102     @Override
onConfigurationChanged(Configuration newConfig)103     protected void onConfigurationChanged(Configuration newConfig) {
104         super.onConfigurationChanged(newConfig);
105         mSize = getResources().getDimensionPixelSize(
106                 R.dimen.notifications_unseen_footer_icon_size);
107         if (ModesEmptyShadeFix.isEnabled()) {
108             mEmptyText.setText(mTextString);
109         } else {
110             mEmptyText.setText(mTextId);
111         }
112         mEmptyFooterText.setVisibility(mFooterVisibility);
113         setFooterText(mFooterText);
114         setFooterIcon(mFooterIcon);
115     }
116 
117     @Override
findContentView()118     protected View findContentView() {
119         return findViewById(R.id.no_notifications);
120     }
121 
122     @Override
findSecondaryView()123     protected View findSecondaryView() {
124         return findViewById(R.id.no_notifications_footer);
125     }
126 
127     /** Update view colors. */
setTextColors(@olorInt int onSurface, @ColorInt int onSurfaceVariant)128     public void setTextColors(@ColorInt int onSurface, @ColorInt int onSurfaceVariant) {
129         mEmptyText.setTextColor(onSurfaceVariant);
130         mEmptyFooterText.setTextColor(onSurface);
131         mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
132     }
133 
134     /** Set the resource ID for the main text shown by the view. */
setText(@tringRes int text)135     public void setText(@StringRes int text) {
136         ModesEmptyShadeFix.assertInLegacyMode();
137         mTextId = text;
138         mEmptyText.setText(mTextId);
139     }
140 
141     /** Set the string for the main text shown by the view. */
setText(String text)142     public void setText(String text) {
143         if (ModesEmptyShadeFix.isUnexpectedlyInLegacyMode() || Objects.equals(mTextString, text)) {
144             return;
145         }
146         mTextString = text;
147         mEmptyText.setText(text);
148     }
149 
150     /** Visibility for the footer (the additional icon+text shown below the main text). */
setFooterVisibility(@isibility int visibility)151     public void setFooterVisibility(@Visibility int visibility) {
152         if (ModesEmptyShadeFix.isEnabled() && mFooterVisibility == visibility) {
153             return; // nothing to change
154         }
155         mFooterVisibility = visibility;
156         setSecondaryVisible(/* visible = */ visibility == View.VISIBLE,
157                 /* animate = */false,
158                 /* onAnimationEnded = */ null);
159     }
160 
161     /** Text resource ID for the footer (the additional icon+text shown below the main text). */
setFooterText(@tringRes int text)162     public void setFooterText(@StringRes int text) {
163         if (ModesEmptyShadeFix.isEnabled() && mFooterText == text) {
164             return; // nothing to change
165         }
166         mFooterText = text;
167         if (text != 0) {
168             mEmptyFooterText.setText(mFooterText);
169         } else {
170             mEmptyFooterText.setText(null);
171         }
172     }
173 
174     /** Icon resource ID for the footer (the additional icon+text shown below the main text). */
setFooterIcon(@rawableRes int icon)175     public void setFooterIcon(@DrawableRes int icon) {
176         if (ModesEmptyShadeFix.isEnabled() && mFooterIcon == icon) {
177             return; // nothing to change
178         }
179         mFooterIcon = icon;
180         Drawable drawable;
181         if (icon == 0) {
182             drawable = null;
183         } else {
184             drawable = getContext().getDrawable(icon);
185             if (drawable != null) {
186                 drawable.setBounds(0, 0, mSize, mSize);
187             } else {
188                 Log.w(TAG, "Invalid footer icon resource ID");
189             }
190         }
191         mEmptyFooterText.setCompoundDrawablesRelative(drawable, null, null, null);
192     }
193 
194     /** Get resource ID for main text. */
195     @StringRes
getTextResource()196     public int getTextResource() {
197         ModesEmptyShadeFix.assertInLegacyMode();
198         return mTextId;
199     }
200 
201     /** Get resource ID for footer text. */
202     @StringRes
getFooterTextResource()203     public int getFooterTextResource() {
204         ModesEmptyShadeFix.assertInLegacyMode();
205         return mFooterText;
206     }
207 
208     /** Get resource ID for footer icon. */
209     @DrawableRes
getFooterIconResource()210     public int getFooterIconResource() {
211         ModesEmptyShadeFix.assertInLegacyMode();
212         return mFooterIcon;
213     }
214 
215     @Override
onFinishInflate()216     protected void onFinishInflate() {
217         super.onFinishInflate();
218         mEmptyText = (TextView) findContentView();
219         mEmptyFooterText = (TextView) findSecondaryView();
220         mEmptyFooterText.setCompoundDrawableTintList(mEmptyFooterText.getTextColors());
221     }
222 
223     @Override
224     @NonNull
createExpandableViewState()225     public ExpandableViewState createExpandableViewState() {
226         return new EmptyShadeViewState();
227     }
228 
229     public class EmptyShadeViewState extends ExpandableViewState {
230         @Override
applyToView(View view)231         public void applyToView(View view) {
232             super.applyToView(view);
233             if (view instanceof EmptyShadeView emptyShadeView) {
234                 boolean visible = this.clipTopAmount <= mEmptyText.getPaddingTop() * 0.6f;
235                 emptyShadeView.setContentVisibleAnimated(visible && emptyShadeView.isVisible());
236             }
237         }
238     }
239 }
240