ZenModePanel.java revision 8600534df66c2ff5846ed230b50c56229322d48a
1/*
2 * Copyright (C) 2014 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.volume;
18
19import android.content.Context;
20import android.content.Intent;
21import android.net.Uri;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.provider.Settings;
26import android.service.notification.Condition;
27import android.util.AttributeSet;
28import android.view.ContextThemeWrapper;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.widget.CompoundButton;
32import android.widget.CompoundButton.OnCheckedChangeListener;
33import android.widget.ImageView;
34import android.widget.LinearLayout;
35import android.widget.RadioButton;
36import android.widget.TextView;
37
38import com.android.systemui.R;
39import com.android.systemui.statusbar.policy.ZenModeController;
40
41import java.util.Arrays;
42import java.util.HashSet;
43
44public class ZenModePanel extends LinearLayout {
45    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
46    public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
47
48    private final LayoutInflater mInflater;
49    private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
50    private final H mHandler = new H();
51    private LinearLayout mConditions;
52    private int mMinutesIndex = Arrays.binarySearch(MINUTES, 60);  // default to one hour
53    private Callback mCallback;
54    private ZenModeController mController;
55    private boolean mRequestingConditions;
56
57    public ZenModePanel(Context context, AttributeSet attrs) {
58        super(context, attrs);
59        mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
60    }
61
62    @Override
63    protected void onFinishInflate() {
64        super.onFinishInflate();
65        mConditions = (LinearLayout) findViewById(android.R.id.content);
66        findViewById(android.R.id.button2).setOnClickListener(new View.OnClickListener() {
67            @Override
68            public void onClick(View v) {
69                fireMoreSettings();
70            }
71        });
72    }
73
74    @Override
75    public void setVisibility(int visibility) {
76        super.setVisibility(visibility);
77        setRequestingConditions(visibility == VISIBLE);
78    }
79
80    /** Start or stop requesting relevant zen mode exit conditions */
81    private void setRequestingConditions(boolean requesting) {
82        if (mRequestingConditions == requesting) return;
83        mRequestingConditions = requesting;
84        if (mRequestingConditions) {
85            mController.addCallback(mZenCallback);
86        } else {
87            mController.removeCallback(mZenCallback);
88        }
89        mController.requestConditions(mRequestingConditions);
90    }
91
92    public void init(ZenModeController controller) {
93        mController = controller;
94        mConditions.removeAllViews();
95        bind(updateTimeCondition(), mConditions.getChildAt(0));
96        handleUpdateConditions(new Condition[0]);
97    }
98
99    public void setCallback(Callback callback) {
100        mCallback = callback;
101    }
102
103    private Condition updateTimeCondition() {
104        final int minutes = MINUTES[mMinutesIndex];
105        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
106        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
107                .appendPath("countdown").appendPath(Long.toString(millis)).build();
108        final int num = minutes < 60 ? minutes : minutes / 60;
109        final int resId = minutes < 60
110                ? R.plurals.zen_mode_duration_minutes
111                : R.plurals.zen_mode_duration_hours;
112        final String caption = mContext.getResources().getQuantityString(resId, num, num);
113        return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
114                Condition.FLAG_RELEVANT_NOW);
115    }
116
117    private void handleUpdateConditions(Condition[] conditions) {
118        final int newCount = conditions == null ? 0 : conditions.length;
119        for (int i = mConditions.getChildCount() - 1; i > newCount; i--) {
120            mConditions.removeViewAt(i);
121        }
122        for (int i = 0; i < newCount; i++) {
123            bind(conditions[i], mConditions.getChildAt(i + 1));
124        }
125        bind(null, mConditions.getChildAt(newCount + 1));
126    }
127
128    private void editTimeCondition(int delta) {
129        final int i = mMinutesIndex + delta;
130        if (i < 0 || i >= MINUTES.length) return;
131        mMinutesIndex = i;
132        final Condition c = updateTimeCondition();
133        bind(c, mConditions.getChildAt(0));
134    }
135
136    private void bind(final Condition condition, View convertView) {
137        final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE;
138        final View row;
139        if (convertView == null) {
140            row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
141            mConditions.addView(row);
142        } else {
143            row = convertView;
144        }
145        final int position = mConditions.indexOfChild(row);
146        final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
147        mRadioButtons.add(rb);
148        rb.setEnabled(enabled);
149        rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
150            @Override
151            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
152                if (isChecked) {
153                    for (RadioButton otherButton : mRadioButtons) {
154                        if (otherButton == rb) continue;
155                        otherButton.setChecked(false);
156                    }
157                    mController.select(condition);
158                    fireInteraction();
159                }
160            }
161        });
162        final TextView title = (TextView) row.findViewById(android.R.id.title);
163        if (condition == null) {
164            title.setText(R.string.zen_mode_forever);
165        } else {
166            title.setText(condition.summary);
167        }
168        title.setEnabled(enabled);
169        title.setAlpha(enabled ? 1 : .5f);
170        final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
171        button1.setOnClickListener(new OnClickListener() {
172            @Override
173            public void onClick(View v) {
174                rb.setChecked(true);
175                editTimeCondition(-1);
176                fireInteraction();
177            }
178        });
179
180        final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
181        button2.setOnClickListener(new OnClickListener() {
182            @Override
183            public void onClick(View v) {
184                rb.setChecked(true);
185                editTimeCondition(1);
186                fireInteraction();
187            }
188        });
189        title.setOnClickListener(new OnClickListener() {
190            @Override
191            public void onClick(View v) {
192                rb.setChecked(true);
193                fireInteraction();
194            }
195        });
196        if (position == 0) {
197            button1.setEnabled(mMinutesIndex > 0);
198            button2.setEnabled(mMinutesIndex < MINUTES.length - 1);
199            button1.setImageAlpha(button1.isEnabled() ? 0xff : 0x7f);
200            button2.setImageAlpha(button2.isEnabled() ? 0xff : 0x7f);
201        } else {
202            button1.setVisibility(View.GONE);
203            button2.setVisibility(View.GONE);
204        }
205        if (position == 0 &&  mConditions.getChildCount() == 1) {
206            rb.setChecked(true);
207        }
208    }
209
210    private void fireMoreSettings() {
211        if (mCallback != null) {
212            mCallback.onMoreSettings();
213        }
214    }
215
216    private void fireInteraction() {
217        if (mCallback != null) {
218            mCallback.onInteraction();
219        }
220    }
221
222    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
223        @Override
224        public void onConditionsChanged(Condition[] conditions) {
225            mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
226        }
227    };
228
229    private final class H extends Handler {
230        private static final int UPDATE_CONDITIONS = 1;
231
232        private H() {
233            super(Looper.getMainLooper());
234        }
235
236        @Override
237        public void handleMessage(Message msg) {
238            if (msg.what == UPDATE_CONDITIONS) {
239                handleUpdateConditions((Condition[])msg.obj);
240            }
241        }
242    }
243
244    public interface Callback {
245        void onMoreSettings();
246        void onInteraction();
247    }
248}
249