1 /*
2  * Copyright (C) 2020 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.settings.notification.app;
18 
19 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
20 import static android.app.NotificationManager.IMPORTANCE_LOW;
21 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
22 import static android.view.View.GONE;
23 import static android.view.View.VISIBLE;
24 
25 import android.content.Context;
26 import android.content.res.ColorStateList;
27 import android.transition.AutoTransition;
28 import android.transition.TransitionManager;
29 import android.util.AttributeSet;
30 import android.util.Pair;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.widget.ImageView;
34 import android.widget.TextView;
35 
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceViewHolder;
38 
39 import com.android.settings.R;
40 import com.android.settings.Utils;
41 
42 public class ConversationPriorityPreference extends Preference {
43 
44     private boolean mIsConfigurable = true;
45     private int mImportance;
46     private int mOriginalImportance;
47     private boolean mPriorityConversation;
48     private View mSilenceButton;
49     private View mAlertButton;
50     private View mPriorityButton;
51     private Context mContext;
52     private static final int BUTTON_ANIM_TIME_MS = 100;
53 
ConversationPriorityPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)54     public ConversationPriorityPreference(Context context, AttributeSet attrs,
55             int defStyleAttr, int defStyleRes) {
56         super(context, attrs, defStyleAttr, defStyleRes);
57         init(context);
58     }
59 
ConversationPriorityPreference(Context context, AttributeSet attrs, int defStyleAttr)60     public ConversationPriorityPreference(Context context, AttributeSet attrs, int defStyleAttr) {
61         super(context, attrs, defStyleAttr);
62         init(context);
63     }
64 
ConversationPriorityPreference(Context context, AttributeSet attrs)65     public ConversationPriorityPreference(Context context, AttributeSet attrs) {
66         super(context, attrs);
67         init(context);
68     }
69 
ConversationPriorityPreference(Context context)70     public ConversationPriorityPreference(Context context) {
71         super(context);
72         init(context);
73     }
74 
init(Context context)75     private void init(Context context) {
76         mContext = context;
77         setLayoutResource(R.layout.notif_priority_conversation_preference);
78     }
79 
setImportance(int importance)80     public void setImportance(int importance) {
81         mImportance = importance;
82     }
83 
setConfigurable(boolean configurable)84     public void setConfigurable(boolean configurable) {
85         mIsConfigurable = configurable;
86     }
87 
setPriorityConversation(boolean priorityConversation)88     public void setPriorityConversation(boolean priorityConversation) {
89         mPriorityConversation = priorityConversation;
90     }
91 
setOriginalImportance(int importance)92     public void setOriginalImportance(int importance) {
93         mOriginalImportance = importance;
94     }
95 
96     @Override
onBindViewHolder(final PreferenceViewHolder holder)97     public void onBindViewHolder(final PreferenceViewHolder holder) {
98         super.onBindViewHolder(holder);
99         holder.itemView.setClickable(false);
100 
101         mSilenceButton = holder.findViewById(R.id.silence);
102         mAlertButton = holder.findViewById(R.id.alert);
103         mPriorityButton = holder.findViewById(R.id.priority_group);
104 
105         if (!mIsConfigurable) {
106             mSilenceButton.setEnabled(false);
107             mAlertButton.setEnabled(false);
108             mPriorityButton.setEnabled(false);
109         }
110 
111         updateToggles((ViewGroup) holder.itemView, mImportance, mPriorityConversation,
112                 false);
113 
114         mSilenceButton.setOnClickListener(v -> {
115             callChangeListener(new Pair(IMPORTANCE_LOW, false));
116             updateToggles((ViewGroup) holder.itemView, IMPORTANCE_LOW, false, true);
117         });
118         mAlertButton.setOnClickListener(v -> {
119             int newImportance = Math.max(mOriginalImportance, IMPORTANCE_DEFAULT);
120             callChangeListener(new Pair(newImportance, false));
121             updateToggles((ViewGroup) holder.itemView, newImportance, false, true);
122         });
123         mPriorityButton.setOnClickListener(v -> {
124             int newImportance = Math.max(mOriginalImportance, IMPORTANCE_DEFAULT);
125             callChangeListener(new Pair(newImportance, true));
126             updateToggles((ViewGroup) holder.itemView, newImportance, true, true);
127         });
128     }
129 
getSelectedColor()130     private ColorStateList getSelectedColor() {
131         return Utils.getColorAttr(getContext(),
132                 R.attr.notification_importance_button_foreground_color_selected);
133     }
134 
getUnselectedColor()135     private ColorStateList getUnselectedColor() {
136         return Utils.getColorAttr(getContext(),
137                 R.attr.notification_importance_button_foreground_color_unselected);
138     }
139 
updateToggles(ViewGroup parent, int importance, boolean isPriority, boolean fromUser)140     void updateToggles(ViewGroup parent, int importance, boolean isPriority,
141             boolean fromUser) {
142         if (fromUser) {
143             AutoTransition transition = new AutoTransition();
144             transition.setDuration(BUTTON_ANIM_TIME_MS);
145             TransitionManager.beginDelayedTransition(parent, transition);
146         }
147 
148         if (importance <= IMPORTANCE_LOW && importance > IMPORTANCE_UNSPECIFIED) {
149             setSelected(mPriorityButton, false);
150             setSelected(mAlertButton, false);
151             setSelected(mSilenceButton, true);
152         } else {
153             if (isPriority) {
154                 setSelected(mPriorityButton, true);
155                 setSelected(mAlertButton, false);
156                 setSelected(mSilenceButton, false);
157             } else {
158                 setSelected(mPriorityButton, false);
159                 setSelected(mAlertButton, true);
160                 setSelected(mSilenceButton, false);
161             }
162         }
163     }
164 
setSelected(View view, boolean selected)165     void setSelected(View view, boolean selected) {
166         ColorStateList colorSelected = getSelectedColor();
167         ColorStateList colorUnselected = getUnselectedColor();
168 
169         ImageView icon = view.findViewById(R.id.icon);
170         TextView label = view.findViewById(R.id.label);
171         TextView summary = view.findViewById(R.id.summary);
172 
173         icon.setImageTintList(selected ? colorSelected : colorUnselected);
174         label.setTextColor(selected ? colorSelected : colorUnselected);
175         summary.setTextColor(selected ? colorSelected : colorUnselected);
176         summary.setVisibility(selected ? VISIBLE : GONE);
177 
178         view.setBackground(mContext.getDrawable(selected
179                 ? R.drawable.notification_importance_button_background_selected
180                 : R.drawable.notification_importance_button_background_unselected));
181         // a11y service won't always read the newly appearing text in the right order if the
182         // selection happens too soon (readback happens on a different thread as layout). post
183         // the selection to make that conflict less likely
184         view.post(() -> {
185             view.setSelected(selected);
186         });
187     }
188 }
189