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