1 /*
2  * Copyright (C) 2015 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.qs.tiles;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.SharedPreferences;
24 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
25 import android.provider.Settings;
26 import android.provider.Settings.Global;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.View.OnAttachStateChangeListener;
30 import android.view.ViewGroup;
31 import android.widget.Toast;
32 
33 import com.android.internal.logging.MetricsLogger;
34 import com.android.systemui.Prefs;
35 import com.android.systemui.R;
36 import com.android.systemui.SysUIToast;
37 import com.android.systemui.qs.QSTile;
38 import com.android.systemui.statusbar.policy.ZenModeController;
39 import com.android.systemui.volume.ZenModePanel;
40 
41 /** Quick settings tile: Do not disturb **/
42 public class DndTile extends QSTile<QSTile.BooleanState> {
43 
44     private static final Intent ZEN_SETTINGS =
45             new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
46 
47     private static final Intent ZEN_PRIORITY_SETTINGS =
48             new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
49 
50     private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
51     private static final String EXTRA_VISIBLE = "visible";
52 
53     private static final QSTile.Icon TOTAL_SILENCE =
54             ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
55 
56     private final AnimationIcon mDisable =
57             new AnimationIcon(R.drawable.ic_dnd_disable_animation);
58     private final AnimationIcon mDisableTotalSilence =
59             new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation);
60 
61     private final ZenModeController mController;
62     private final DndDetailAdapter mDetailAdapter;
63 
64     private boolean mListening;
65     private boolean mShowingDetail;
66 
DndTile(Host host)67     public DndTile(Host host) {
68         super(host);
69         mController = host.getZenModeController();
70         mDetailAdapter = new DndDetailAdapter();
71         mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
72     }
73 
setVisible(Context context, boolean visible)74     public static void setVisible(Context context, boolean visible) {
75         Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
76     }
77 
isVisible(Context context)78     public static boolean isVisible(Context context) {
79         return Prefs.getBoolean(context, Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */);
80     }
81 
setCombinedIcon(Context context, boolean combined)82     public static void setCombinedIcon(Context context, boolean combined) {
83         Prefs.putBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, combined);
84     }
85 
isCombinedIcon(Context context)86     public static boolean isCombinedIcon(Context context) {
87         return Prefs.getBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON,
88                 false /* defaultValue */);
89     }
90 
91     @Override
getDetailAdapter()92     public DetailAdapter getDetailAdapter() {
93         return mDetailAdapter;
94     }
95 
96     @Override
newTileState()97     protected BooleanState newTileState() {
98         return new BooleanState();
99     }
100 
101     @Override
handleClick()102     public void handleClick() {
103         if (mController.isVolumeRestricted()) {
104             // Collapse the panels, so the user can see the toast.
105             mHost.collapsePanels();
106             SysUIToast.makeText(mContext, mContext.getString(
107                     com.android.internal.R.string.error_message_change_not_allowed),
108                     Toast.LENGTH_LONG).show();
109             return;
110         }
111         mDisable.setAllowAnimation(true);
112         mDisableTotalSilence.setAllowAnimation(true);
113         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
114         if (mState.value) {
115             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
116         } else {
117             int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
118             mController.setZen(zen, null, TAG);
119             showDetail(true);
120         }
121     }
122 
123     @Override
handleUpdateState(BooleanState state, Object arg)124     protected void handleUpdateState(BooleanState state, Object arg) {
125         final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
126         final boolean newValue = zen != Global.ZEN_MODE_OFF;
127         final boolean valueChanged = state.value != newValue;
128         state.value = newValue;
129         state.visible = isVisible(mContext);
130         switch (zen) {
131             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
132                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
133                 state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
134                 state.contentDescription = mContext.getString(
135                         R.string.accessibility_quick_settings_dnd_priority_on);
136                 break;
137             case Global.ZEN_MODE_NO_INTERRUPTIONS:
138                 state.icon = TOTAL_SILENCE;
139                 state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
140                 state.contentDescription = mContext.getString(
141                         R.string.accessibility_quick_settings_dnd_none_on);
142                 break;
143             case Global.ZEN_MODE_ALARMS:
144                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
145                 state.label = mContext.getString(R.string.quick_settings_dnd_alarms_label);
146                 state.contentDescription = mContext.getString(
147                         R.string.accessibility_quick_settings_dnd_alarms_on);
148                 break;
149             default:
150                 state.icon = TOTAL_SILENCE.equals(state.icon) ? mDisableTotalSilence : mDisable;
151                 state.label = mContext.getString(R.string.quick_settings_dnd_label);
152                 state.contentDescription =  mContext.getString(
153                         R.string.accessibility_quick_settings_dnd_off);
154                 break;
155         }
156         if (mShowingDetail && !state.value) {
157             showDetail(false);
158         }
159         if (valueChanged) {
160             fireToggleStateChanged(state.value);
161         }
162     }
163 
164     @Override
getMetricsCategory()165     public int getMetricsCategory() {
166         return MetricsLogger.QS_DND;
167     }
168 
169     @Override
composeChangeAnnouncement()170     protected String composeChangeAnnouncement() {
171         if (mState.value) {
172             return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
173         } else {
174             return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
175         }
176     }
177 
178     @Override
setListening(boolean listening)179     public void setListening(boolean listening) {
180         if (mListening == listening) return;
181         mListening = listening;
182         if (mListening) {
183             mController.addCallback(mZenCallback);
184             Prefs.registerListener(mContext, mPrefListener);
185         } else {
186             mController.removeCallback(mZenCallback);
187             Prefs.unregisterListener(mContext, mPrefListener);
188         }
189     }
190 
191     private final OnSharedPreferenceChangeListener mPrefListener
192             = new OnSharedPreferenceChangeListener() {
193         @Override
194         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
195                 @Prefs.Key String key) {
196             if (Prefs.Key.DND_TILE_COMBINED_ICON.equals(key) ||
197                     Prefs.Key.DND_TILE_VISIBLE.equals(key)) {
198                 refreshState();
199             }
200         }
201     };
202 
203     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
204         public void onZenChanged(int zen) {
205             refreshState(zen);
206         }
207     };
208 
209     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
210         @Override
211         public void onReceive(Context context, Intent intent) {
212             final boolean visible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
213             setVisible(mContext, visible);
214             refreshState();
215         }
216     };
217 
218     private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
219 
220         @Override
getTitle()221         public int getTitle() {
222             return R.string.quick_settings_dnd_label;
223         }
224 
225         @Override
getToggleState()226         public Boolean getToggleState() {
227             return mState.value;
228         }
229 
230         @Override
getSettingsIntent()231         public Intent getSettingsIntent() {
232             return ZEN_SETTINGS;
233         }
234 
235         @Override
setToggleState(boolean state)236         public void setToggleState(boolean state) {
237             MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state);
238             if (!state) {
239                 mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
240                 showDetail(false);
241             }
242         }
243 
244         @Override
getMetricsCategory()245         public int getMetricsCategory() {
246             return MetricsLogger.QS_DND_DETAILS;
247         }
248 
249         @Override
createDetailView(Context context, View convertView, ViewGroup parent)250         public View createDetailView(Context context, View convertView, ViewGroup parent) {
251             final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
252                     : (ZenModePanel) LayoutInflater.from(context).inflate(
253                             R.layout.zen_mode_panel, parent, false);
254             if (convertView == null) {
255                 zmp.init(mController);
256                 zmp.addOnAttachStateChangeListener(this);
257                 zmp.setCallback(mZenModePanelCallback);
258             }
259             return zmp;
260         }
261 
262         @Override
onViewAttachedToWindow(View v)263         public void onViewAttachedToWindow(View v) {
264             mShowingDetail = true;
265         }
266 
267         @Override
onViewDetachedFromWindow(View v)268         public void onViewDetachedFromWindow(View v) {
269             mShowingDetail = false;
270         }
271     }
272 
273     private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
274         @Override
275         public void onPrioritySettings() {
276             mHost.startActivityDismissingKeyguard(ZEN_PRIORITY_SETTINGS);
277         }
278 
279         @Override
280         public void onInteraction() {
281             // noop
282         }
283 
284         @Override
285         public void onExpanded(boolean expanded) {
286             // noop
287         }
288     };
289 
290 }
291