QuickStatusBarHeader.java revision b46059a1d464d13f983d1aa102d5f872fa2a6e47
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.statusbar.phone;
18
19import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.Context;
22import android.content.Intent;
23import android.content.res.Configuration;
24import android.graphics.drawable.Drawable;
25import android.graphics.drawable.RippleDrawable;
26import android.os.UserManager;
27import android.util.AttributeSet;
28import android.view.View;
29import android.view.View.OnClickListener;
30import android.view.ViewGroup;
31import android.widget.ImageView;
32import android.widget.TextView;
33import android.widget.Toast;
34
35import com.android.internal.logging.MetricsLogger;
36import com.android.internal.logging.MetricsProto;
37import com.android.keyguard.KeyguardStatusView;
38import com.android.systemui.FontSizeUtils;
39import com.android.systemui.R;
40import com.android.systemui.qs.QSAnimator;
41import com.android.systemui.qs.QSPanel;
42import com.android.systemui.qs.QSPanel.Callback;
43import com.android.systemui.qs.QuickQSPanel;
44import com.android.systemui.qs.TouchAnimator;
45import com.android.systemui.statusbar.policy.BatteryController;
46import com.android.systemui.statusbar.policy.NextAlarmController;
47import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
48import com.android.systemui.statusbar.policy.UserInfoController;
49import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
50import com.android.systemui.tuner.TunerService;
51
52public class QuickStatusBarHeader extends BaseStatusBarHeader implements
53        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener {
54
55    private static final String TAG = "QuickStatusBarHeader";
56
57    private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
58
59    private ActivityStarter mActivityStarter;
60    private NextAlarmController mNextAlarmController;
61    private SettingsButton mSettingsButton;
62    protected View mSettingsContainer;
63
64    private TextView mAlarmStatus;
65    private View mAlarmStatusCollapsed;
66
67    private QSPanel mQsPanel;
68
69    private boolean mExpanded;
70    private boolean mAlarmShowing;
71
72    private ViewGroup mDateTimeGroup;
73    private ViewGroup mDateTimeAlarmGroup;
74    private TextView mEmergencyOnly;
75
76    protected ExpandableIndicator mExpandIndicator;
77
78    private boolean mListening;
79    private AlarmManager.AlarmClockInfo mNextAlarm;
80
81    private QuickQSPanel mHeaderQsPanel;
82    private boolean mShowEmergencyCallsOnly;
83    protected MultiUserSwitch mMultiUserSwitch;
84    private ImageView mMultiUserAvatar;
85
86
87    private TouchAnimator mSecondHalfAnimator;
88    private TouchAnimator mFirstHalfAnimator;
89    protected TouchAnimator mSettingsAlpha;
90    private float mExpansionAmount;
91    private QSTileHost mHost;
92    private View mEdit;
93    private boolean mShowFullAlarm;
94
95    public QuickStatusBarHeader(Context context, AttributeSet attrs) {
96        super(context, attrs);
97    }
98
99    @Override
100    protected void onFinishInflate() {
101        super.onFinishInflate();
102
103        mEmergencyOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
104
105        mEdit = findViewById(android.R.id.edit);
106        findViewById(android.R.id.edit).setOnClickListener(view ->
107                mHost.startRunnableDismissingKeyguard(() -> mQsPanel.showEdit(view)));
108
109        mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
110        mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
111        mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
112        mDateTimeGroup.setPivotX(0);
113        mDateTimeGroup.setPivotY(0);
114        mShowFullAlarm = getResources().getBoolean(R.bool.quick_settings_show_full_alarm);
115
116        mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
117
118        mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
119
120        mSettingsButton = (SettingsButton) findViewById(R.id.settings_button);
121        mSettingsContainer = findViewById(R.id.settings_button_container);
122        mSettingsButton.setOnClickListener(this);
123
124        mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
125        mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
126        mAlarmStatus.setOnClickListener(this);
127
128        mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
129        mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
130
131        // RenderThread is doing more harm than good when touching the header (to expand quick
132        // settings), so disable it for this view
133        ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
134        ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
135
136        updateResources();
137    }
138
139    @Override
140    protected void onConfigurationChanged(Configuration newConfig) {
141        super.onConfigurationChanged(newConfig);
142        updateResources();
143    }
144
145    @Override
146    public void onRtlPropertiesChanged(int layoutDirection) {
147        super.onRtlPropertiesChanged(layoutDirection);
148        updateResources();
149    }
150
151    private void updateResources() {
152        FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
153        FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
154
155        mSecondHalfAnimator = new TouchAnimator.Builder()
156                .addFloat(mShowFullAlarm ? mAlarmStatus : findViewById(R.id.date), "alpha", 0, 1)
157                .addFloat(mEmergencyOnly, "alpha", 0, 1)
158                .build();
159        if (mShowFullAlarm) {
160            mFirstHalfAnimator = new TouchAnimator.Builder()
161                    .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0)
162                    .build();
163        }
164
165        updateSettingsAnimator();
166    }
167
168    protected void updateSettingsAnimator() {
169        mSettingsAlpha = new TouchAnimator.Builder()
170                .addFloat(mEdit, "alpha", 0, 1)
171                .addFloat(mMultiUserSwitch, "alpha", 0, 1)
172                .build();
173
174        final boolean isRtl = isLayoutRtl();
175        if (isRtl && mDateTimeGroup.getWidth() == 0) {
176            mDateTimeGroup.addOnLayoutChangeListener(new OnLayoutChangeListener() {
177                @Override
178                public void onLayoutChange(View v, int left, int top, int right, int bottom,
179                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
180                    mDateTimeGroup.setPivotX(getWidth());
181                    mDateTimeGroup.removeOnLayoutChangeListener(this);
182                }
183            });
184        } else {
185            mDateTimeGroup.setPivotX(isRtl ? mDateTimeGroup.getWidth() : 0);
186        }
187    }
188
189    @Override
190    public int getCollapsedHeight() {
191        return getHeight();
192    }
193
194    @Override
195    public int getExpandedHeight() {
196        return getHeight();
197    }
198
199    @Override
200    public void setExpanded(boolean expanded) {
201        mExpanded = expanded;
202        mHeaderQsPanel.setExpanded(expanded);
203        updateEverything();
204    }
205
206    @Override
207    public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
208        mNextAlarm = nextAlarm;
209        if (nextAlarm != null) {
210            String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
211            mAlarmStatus.setText(alarmString);
212            mAlarmStatus.setContentDescription(mContext.getString(
213                    R.string.accessibility_quick_settings_alarm, alarmString));
214            mAlarmStatusCollapsed.setContentDescription(mContext.getString(
215                    R.string.accessibility_quick_settings_alarm, alarmString));
216        }
217        if (mAlarmShowing != (nextAlarm != null)) {
218            mAlarmShowing = nextAlarm != null;
219            updateEverything();
220        }
221    }
222
223    @Override
224    public void setExpansion(float headerExpansionFraction) {
225        mExpansionAmount = headerExpansionFraction;
226        mSecondHalfAnimator.setPosition(headerExpansionFraction);
227        if (mShowFullAlarm) {
228            mFirstHalfAnimator.setPosition(headerExpansionFraction);
229        }
230        mSettingsAlpha.setPosition(headerExpansionFraction);
231
232        updateAlarmVisibilities();
233
234        mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
235    }
236
237    @Override
238    protected void onDetachedFromWindow() {
239        setListening(false);
240        mHost.getUserInfoController().remListener(this);
241        mHost.getNetworkController().removeEmergencyListener(this);
242        super.onDetachedFromWindow();
243    }
244
245    private void updateAlarmVisibilities() {
246        mAlarmStatus.setVisibility(mAlarmShowing && mShowFullAlarm ? View.VISIBLE : View.INVISIBLE);
247        mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
248    }
249
250    public void setListening(boolean listening) {
251        if (listening == mListening) {
252            return;
253        }
254        mHeaderQsPanel.setListening(listening);
255        mListening = listening;
256        updateListeners();
257    }
258
259    @Override
260    public void updateEverything() {
261        updateVisibilities();
262        setClickable(false);
263    }
264
265    protected void updateVisibilities() {
266        updateAlarmVisibilities();
267        mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
268                ? View.VISIBLE : View.INVISIBLE);
269        mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
270                TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
271        final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
272        mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo
273                ? View.VISIBLE : View.INVISIBLE);
274        mEdit.setVisibility(isDemo ? View.INVISIBLE : View.VISIBLE);
275    }
276
277    private void updateListeners() {
278        if (mListening) {
279            mNextAlarmController.addStateChangedCallback(this);
280        } else {
281            mNextAlarmController.removeStateChangedCallback(this);
282        }
283    }
284
285    @Override
286    public void setActivityStarter(ActivityStarter activityStarter) {
287        mActivityStarter = activityStarter;
288    }
289
290    @Override
291    public void setQSPanel(final QSPanel qsPanel) {
292        mQsPanel = qsPanel;
293        setupHost(qsPanel.getHost());
294        if (mQsPanel != null) {
295            mMultiUserSwitch.setQsPanel(qsPanel);
296        }
297    }
298
299    public void setupHost(final QSTileHost host) {
300        mHost = host;
301        host.setHeaderView(mExpandIndicator);
302        mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
303        mHeaderQsPanel.setHost(host, null /* No customization in header */);
304        setUserInfoController(host.getUserInfoController());
305        setBatteryController(host.getBatteryController());
306        setNextAlarmController(host.getNextAlarmController());
307
308        final boolean isAPhone = mHost.getNetworkController().hasVoiceCallingFeature();
309        if (isAPhone) {
310            mHost.getNetworkController().addEmergencyListener(this);
311        }
312    }
313
314    @Override
315    public void onClick(View v) {
316        if (v == mSettingsButton) {
317            MetricsLogger.action(mContext,
318                    MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH);
319            if (mSettingsButton.isTunerClick()) {
320                if (TunerService.isTunerEnabled(mContext)) {
321                    TunerService.showResetRequest(mContext, new Runnable() {
322                        @Override
323                        public void run() {
324                            // Relaunch settings so that the tuner disappears.
325                            startSettingsActivity();
326                        }
327                    });
328                } else {
329                    Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show();
330                    TunerService.setTunerEnabled(mContext, true);
331                }
332            }
333            startSettingsActivity();
334        } else if (v == mAlarmStatus && mNextAlarm != null) {
335            PendingIntent showIntent = mNextAlarm.getShowIntent();
336            if (showIntent != null && showIntent.isActivity()) {
337                mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
338            }
339        }
340    }
341
342    private void startSettingsActivity() {
343        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
344                true /* dismissShade */);
345    }
346
347    @Override
348    public void setNextAlarmController(NextAlarmController nextAlarmController) {
349        mNextAlarmController = nextAlarmController;
350    }
351
352    @Override
353    public void setBatteryController(BatteryController batteryController) {
354        // Don't care
355    }
356
357    @Override
358    public void setUserInfoController(UserInfoController userInfoController) {
359        userInfoController.addListener(this);
360    }
361
362    @Override
363    public void setCallback(Callback qsPanelCallback) {
364        mHeaderQsPanel.setCallback(qsPanelCallback);
365    }
366
367    @Override
368    public void setEmergencyCallsOnly(boolean show) {
369        boolean changed = show != mShowEmergencyCallsOnly;
370        if (changed) {
371            mShowEmergencyCallsOnly = show;
372            if (mExpanded) {
373                updateEverything();
374            }
375        }
376    }
377
378    @Override
379    public void onUserInfoChanged(String name, Drawable picture) {
380        mMultiUserAvatar.setImageDrawable(picture);
381    }
382}
383