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