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