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