blob: 02e8f590979396f8aa83275910c80788afa2c0de [file] [log] [blame]
Jason Monke5b770e2017-03-03 21:49:29 -05001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.qs;
16
Charles Hece2a7c02017-10-11 20:25:20 +010017import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
Charles Hece2a7c02017-10-11 20:25:20 +010018
Jason Monkea54e8a2018-12-20 10:01:48 -050019import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
Matt Pietal5a19cb62019-10-30 12:31:07 -040020import static com.android.systemui.util.Utils.useQsMediaPlayer;
Jason Monkea54e8a2018-12-20 10:01:48 -050021
Amin Shaikh0e003312018-03-08 11:39:01 -050022import android.annotation.ColorInt;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080023import android.app.ActivityManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080024import android.app.AlarmManager;
Amin Shaikh761c5662018-03-27 16:55:43 -040025import android.content.BroadcastReceiver;
Jason Monke5b770e2017-03-03 21:49:29 -050026import android.content.Context;
Evan Laird4ea2a492018-01-22 11:29:12 -050027import android.content.Intent;
Amin Shaikh761c5662018-03-27 16:55:43 -040028import android.content.IntentFilter;
Fabian Kozynskif86df992019-04-22 14:23:47 -040029import android.content.res.ColorStateList;
Jason Monke5b770e2017-03-03 21:49:29 -050030import android.content.res.Configuration;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000031import android.content.res.Resources;
Jason Monke5b770e2017-03-03 21:49:29 -050032import android.graphics.Color;
33import android.graphics.Rect;
Amin Shaikh761c5662018-03-27 16:55:43 -040034import android.media.AudioManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080035import android.os.Handler;
Fabian Kozynski12638242018-10-12 15:33:41 -040036import android.os.Looper;
Evan Laird4ea2a492018-01-22 11:29:12 -050037import android.provider.AlarmClock;
Fabian Kozynski16b26992019-05-06 10:18:41 -040038import android.provider.DeviceConfig;
Fabian Kozynskib1aee812019-04-04 14:17:48 -040039import android.provider.Settings;
Beverlyb9826dd2018-04-12 15:02:45 -040040import android.service.notification.ZenModeConfig;
Rohan Shahd3cf7562018-02-23 11:12:28 -080041import android.text.format.DateUtils;
Jason Monke5b770e2017-03-03 21:49:29 -050042import android.util.AttributeSet;
Fabian Kozynskia3544712019-04-25 17:05:21 -040043import android.util.Log;
Adrian Roos13836052018-03-15 21:06:37 +010044import android.util.Pair;
Fabian Kozynskibfd6d852019-02-15 15:08:16 -050045import android.util.StatsLog;
Fabian Kozynskif86df992019-04-22 14:23:47 -040046import android.view.ContextThemeWrapper;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050047import android.view.DisplayCutout;
Jason Monk824ffff2017-04-11 15:49:06 -040048import android.view.View;
Adrian Roos13836052018-03-15 21:06:37 +010049import android.view.WindowInsets;
Beverlyff2df9b2018-10-10 16:54:10 -040050import android.widget.FrameLayout;
Amin Shaikh761c5662018-03-27 16:55:43 -040051import android.widget.ImageView;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050052import android.widget.LinearLayout;
Jason Monke5b770e2017-03-03 21:49:29 -050053import android.widget.RelativeLayout;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050054import android.widget.Space;
Rohan Shahd3cf7562018-02-23 11:12:28 -080055import android.widget.TextView;
Jason Monke5b770e2017-03-03 21:49:29 -050056
Beverlyff2df9b2018-10-10 16:54:10 -040057import androidx.annotation.VisibleForTesting;
58
Fabian Kozynski16b26992019-05-06 10:18:41 -040059import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
Jason Monke5b770e2017-03-03 21:49:29 -050060import com.android.settingslib.Utils;
61import com.android.systemui.BatteryMeterView;
Fabian Kozynskif86df992019-04-22 14:23:47 -040062import com.android.systemui.DualToneHandler;
Jason Monke5b770e2017-03-03 21:49:29 -050063import com.android.systemui.R;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +000064import com.android.systemui.broadcast.BroadcastDispatcher;
Jason Monke5b770e2017-03-03 21:49:29 -050065import com.android.systemui.plugins.ActivityStarter;
Beverly1be62f42018-12-19 17:17:48 -050066import com.android.systemui.plugins.DarkIconDispatcher;
67import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
Fabian Kozynski12638242018-10-12 15:33:41 -040068import com.android.systemui.privacy.OngoingPrivacyChip;
Fabian Kozynskiafd50022019-02-05 09:41:42 -050069import com.android.systemui.privacy.PrivacyDialogBuilder;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050070import com.android.systemui.privacy.PrivacyItem;
71import com.android.systemui.privacy.PrivacyItemController;
Fabian Kozynski16b26992019-05-06 10:18:41 -040072import com.android.systemui.privacy.PrivacyItemControllerKt;
Jason Monke5b770e2017-03-03 21:49:29 -050073import com.android.systemui.qs.QSDetail.Callback;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040074import com.android.systemui.statusbar.CommandQueue;
Adrian Roos13836052018-03-15 21:06:37 +010075import com.android.systemui.statusbar.phone.PhoneStatusBarView;
Evan Laird95896952018-01-22 19:30:05 -050076import com.android.systemui.statusbar.phone.StatusBarIconController;
77import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
Evan Laird20b87bf2018-04-12 09:54:11 -040078import com.android.systemui.statusbar.phone.StatusIconContainer;
Beverlyff2df9b2018-10-10 16:54:10 -040079import com.android.systemui.statusbar.policy.Clock;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000080import com.android.systemui.statusbar.policy.DateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -080081import com.android.systemui.statusbar.policy.NextAlarmController;
Beverlyb9826dd2018-04-12 15:02:45 -040082import com.android.systemui.statusbar.policy.ZenModeController;
Jason Monke5b770e2017-03-03 21:49:29 -050083
Evan Lairdf435fd22019-02-15 13:35:45 -050084import java.util.ArrayList;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050085import java.util.List;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080086import java.util.Locale;
Beverlyb9826dd2018-04-12 15:02:45 -040087import java.util.Objects;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080088
Jason Monkea54e8a2018-12-20 10:01:48 -050089import javax.inject.Inject;
90import javax.inject.Named;
91
Rohan Shahd3cf7562018-02-23 11:12:28 -080092/**
93 * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
94 * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
95 * contents.
96 */
Amin Shaikhf09450b2018-04-06 17:32:45 -040097public class QuickStatusBarHeader extends RelativeLayout implements
Beverlyb9826dd2018-04-12 15:02:45 -040098 View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
99 ZenModeController.Callback {
Rohan Shaha160ab12018-03-09 15:47:36 -0800100 private static final String TAG = "QuickStatusBarHeader";
101 private static final boolean DEBUG = false;
Jason Monke5b770e2017-03-03 21:49:29 -0500102
Rohan Shahd3cf7562018-02-23 11:12:28 -0800103 /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
104 private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
105 private static final int FADE_ANIMATION_DURATION_MS = 300;
106 private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
Rohan Shahb6a915c2018-03-01 11:57:00 -0800107 public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800108
109 private final Handler mHandler = new Handler();
Jason Monkea54e8a2018-12-20 10:01:48 -0500110 private final NextAlarmController mAlarmController;
111 private final ZenModeController mZenController;
112 private final StatusBarIconController mStatusBarIconController;
113 private final ActivityStarter mActivityStarter;
Jason Monke5b770e2017-03-03 21:49:29 -0500114
115 private QSPanel mQsPanel;
116
117 private boolean mExpanded;
118 private boolean mListening;
Charles Hece2a7c02017-10-11 20:25:20 +0100119 private boolean mQsDisabled;
Jason Monke5b770e2017-03-03 21:49:29 -0500120
Fabian Kozynski4e76d1f2019-02-25 16:30:04 -0500121 private QSCarrierGroup mCarrierGroup;
Jason Monke5b770e2017-03-03 21:49:29 -0500122 protected QuickQSPanel mHeaderQsPanel;
123 protected QSTileHost mHost;
Evan Laird95896952018-01-22 19:30:05 -0500124 private TintedIconManager mIconManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800125 private TouchAnimator mStatusIconsAlphaAnimator;
126 private TouchAnimator mHeaderTextContainerAlphaAnimator;
Fabian Kozynski216812e2019-02-01 13:49:00 -0500127 private TouchAnimator mPrivacyChipAlphaAnimator;
Fabian Kozynskif86df992019-04-22 14:23:47 -0400128 private DualToneHandler mDualToneHandler;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400129 private final CommandQueue mCommandQueue;
Evan Laird95896952018-01-22 19:30:05 -0500130
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000131 private View mSystemIconsView;
Evan Laird95896952018-01-22 19:30:05 -0500132 private View mQuickQsStatusIcons;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800133 private View mHeaderTextContainerView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400134
135 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
136 private AlarmManager.AlarmClockInfo mNextAlarm;
137
138 private ImageView mNextAlarmIcon;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800139 /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
140 private TextView mNextAlarmTextView;
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400141 private View mNextAlarmContainer;
Amin Shaikh761c5662018-03-27 16:55:43 -0400142 private View mStatusSeparator;
143 private ImageView mRingerModeIcon;
144 private TextView mRingerModeTextView;
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400145 private View mRingerContainer;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000146 private Clock mClockView;
147 private DateView mDateView;
Fabian Kozynski12638242018-10-12 15:33:41 -0400148 private OngoingPrivacyChip mPrivacyChip;
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500149 private Space mSpace;
Evan Laird4bf21df2018-10-22 14:24:32 -0400150 private BatteryMeterView mBatteryRemainingIcon;
Fabian Kozynski16b26992019-05-06 10:18:41 -0400151 private boolean mPermissionsHubEnabled;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800152
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500153 private PrivacyItemController mPrivacyItemController;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000154 private BroadcastDispatcher mBroadcastDispatcher;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800155
Amin Shaikh761c5662018-03-27 16:55:43 -0400156 private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
157 @Override
158 public void onReceive(Context context, Intent intent) {
159 mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
160 updateStatusText();
161 }
162 };
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500163 private boolean mHasTopCutout = false;
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500164 private boolean mPrivacyChipLogged = false;
Amin Shaikh761c5662018-03-27 16:55:43 -0400165
Matt Papecb888792019-05-22 15:32:32 -0700166 private final DeviceConfig.OnPropertiesChangedListener mPropertiesListener =
167 new DeviceConfig.OnPropertiesChangedListener() {
Fabian Kozynski16b26992019-05-06 10:18:41 -0400168 @Override
Matt Papecb888792019-05-22 15:32:32 -0700169 public void onPropertiesChanged(DeviceConfig.Properties properties) {
170 if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace())
171 && properties.getKeyset()
172 .contains(SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) {
173 mPermissionsHubEnabled = properties.getBoolean(
174 SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false);
Fabian Kozynski16b26992019-05-06 10:18:41 -0400175 StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
176 iconContainer.setIgnoredSlots(getIgnoredIconSlots());
177 }
178 }
179 };
180
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500181 private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
182 @Override
183 public void privacyChanged(List<PrivacyItem> privacyItems) {
184 mPrivacyChip.setPrivacyList(privacyItems);
185 setChipVisibility(!privacyItems.isEmpty());
186 }
187 };
188
Jason Monkea54e8a2018-12-20 10:01:48 -0500189 @Inject
190 public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
191 NextAlarmController nextAlarmController, ZenModeController zenModeController,
Evan Laird85ee4a32019-03-06 18:09:20 -0500192 StatusBarIconController statusBarIconController,
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400193 ActivityStarter activityStarter, PrivacyItemController privacyItemController,
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000194 CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) {
Jason Monke5b770e2017-03-03 21:49:29 -0500195 super(context, attrs);
Jason Monkea54e8a2018-12-20 10:01:48 -0500196 mAlarmController = nextAlarmController;
197 mZenController = zenModeController;
Jason Monkea54e8a2018-12-20 10:01:48 -0500198 mStatusBarIconController = statusBarIconController;
199 mActivityStarter = activityStarter;
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500200 mPrivacyItemController = privacyItemController;
Fabian Kozynskif86df992019-04-22 14:23:47 -0400201 mDualToneHandler = new DualToneHandler(
202 new ContextThemeWrapper(context, R.style.QSHeaderTheme));
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000203 mBroadcastDispatcher = broadcastDispatcher;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400204 mCommandQueue = commandQueue;
Jason Monke5b770e2017-03-03 21:49:29 -0500205 }
206
207 @Override
208 protected void onFinishInflate() {
209 super.onFinishInflate();
Jason Monke5b770e2017-03-03 21:49:29 -0500210
211 mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000212 mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
Evan Laird95896952018-01-22 19:30:05 -0500213 mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
Evan Laird20b87bf2018-04-12 09:54:11 -0400214 StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
Evan Lairdf435fd22019-02-15 13:35:45 -0500215 // Ignore privacy icons because they show in the space above QQS
216 iconContainer.addIgnoredSlots(getIgnoredIconSlots());
Evan Laird20b87bf2018-04-12 09:54:11 -0400217 iconContainer.setShouldRestrictIcons(false);
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400218 mIconManager = new TintedIconManager(iconContainer, mCommandQueue);
Jason Monke5b770e2017-03-03 21:49:29 -0500219
Fabian Kozynski121adb42019-04-22 15:10:43 -0400220 // Views corresponding to the header info section (e.g. ringer and next alarm).
Rohan Shahd3cf7562018-02-23 11:12:28 -0800221 mHeaderTextContainerView = findViewById(R.id.header_text_container);
Amin Shaikh761c5662018-03-27 16:55:43 -0400222 mStatusSeparator = findViewById(R.id.status_separator);
223 mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800224 mNextAlarmTextView = findViewById(R.id.next_alarm_text);
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400225 mNextAlarmContainer = findViewById(R.id.alarm_container);
226 mNextAlarmContainer.setOnClickListener(this::onClick);
Amin Shaikh761c5662018-03-27 16:55:43 -0400227 mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
228 mRingerModeTextView = findViewById(R.id.ringer_mode_text);
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400229 mRingerContainer = findViewById(R.id.ringer_container);
230 mRingerContainer.setOnClickListener(this::onClick);
Fabian Kozynski216812e2019-02-01 13:49:00 -0500231 mPrivacyChip = findViewById(R.id.privacy_chip);
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400232 mPrivacyChip.setOnClickListener(this::onClick);
Fabian Kozynski4e76d1f2019-02-25 16:30:04 -0500233 mCarrierGroup = findViewById(R.id.carrier_group);
Jason Monke5b770e2017-03-03 21:49:29 -0500234
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500235
Jason Monke5b770e2017-03-03 21:49:29 -0500236 updateResources();
237
Jason Monk824ffff2017-04-11 15:49:06 -0400238 Rect tintArea = new Rect(0, 0, 0, 0);
Jason Changb4e879d2018-04-11 11:17:58 +0800239 int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
240 android.R.attr.colorForeground);
Amin Shaikh0e003312018-03-08 11:39:01 -0500241 float intensity = getColorIntensity(colorForeground);
Fabian Kozynskif86df992019-04-22 14:23:47 -0400242 int fillColor = mDualToneHandler.getSingleColor(intensity);
Evan Laird95896952018-01-22 19:30:05 -0500243
244 // Set light text on the header icons because they will always be on a black background
Evan Laird39254d42018-01-18 16:05:30 -0500245 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Laird95896952018-01-22 19:30:05 -0500246
247 // Set the correct tint for the status icons so they contrast
248 mIconManager.setTint(fillColor);
Fabian Kozynskif86df992019-04-22 14:23:47 -0400249 mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
250 mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
Jason Monke5b770e2017-03-03 21:49:29 -0500251
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000252 mClockView = findViewById(R.id.clock);
Amin Shaikh39bdc502018-05-15 23:43:34 -0400253 mClockView.setOnClickListener(this);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000254 mDateView = findViewById(R.id.date);
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500255 mSpace = findViewById(R.id.space);
Evan Laird4bf21df2018-10-22 14:24:32 -0400256
257 // Tint for the battery icons are handled in setupHost()
258 mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
Evan Laird698839b2018-12-05 15:49:12 -0500259 // Don't need to worry about tuner settings for this icon
260 mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
Evan Laird85ee4a32019-03-06 18:09:20 -0500261 // QS will always show the estimate, and BatteryMeterView handles the case where
262 // it's unavailable or charging
263 mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400264 mRingerModeTextView.setSelected(true);
265 mNextAlarmTextView.setSelected(true);
Fabian Kozynski16b26992019-05-06 10:18:41 -0400266
267 mPermissionsHubEnabled = PrivacyItemControllerKt.isPermissionsHubEnabled();
Jason Monke5b770e2017-03-03 21:49:29 -0500268 }
269
Evan Lairdf435fd22019-02-15 13:35:45 -0500270 private List<String> getIgnoredIconSlots() {
271 ArrayList<String> ignored = new ArrayList<>();
272 ignored.add(mContext.getResources().getString(
273 com.android.internal.R.string.status_bar_camera));
274 ignored.add(mContext.getResources().getString(
275 com.android.internal.R.string.status_bar_microphone));
Fabian Kozynski16b26992019-05-06 10:18:41 -0400276 if (mPermissionsHubEnabled) {
277 ignored.add(mContext.getResources().getString(
278 com.android.internal.R.string.status_bar_location));
279 }
Evan Lairdf435fd22019-02-15 13:35:45 -0500280
281 return ignored;
282 }
283
Amin Shaikh761c5662018-03-27 16:55:43 -0400284 private void updateStatusText() {
Beverlyb9826dd2018-04-12 15:02:45 -0400285 boolean changed = updateRingerStatus() || updateAlarmStatus();
286
287 if (changed) {
288 boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
289 boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
290 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE
291 : View.GONE);
Beverlyb9826dd2018-04-12 15:02:45 -0400292 }
293 }
294
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500295 private void setChipVisibility(boolean chipVisible) {
Fabian Kozynski16b26992019-05-06 10:18:41 -0400296 if (chipVisible && mPermissionsHubEnabled) {
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500297 mPrivacyChip.setVisibility(View.VISIBLE);
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500298 // Makes sure that the chip is logged as viewed at most once each time QS is opened
299 // mListening makes sure that the callback didn't return after the user closed QS
300 if (!mPrivacyChipLogged && mListening) {
301 mPrivacyChipLogged = true;
302 StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
303 StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_VIEWED);
304 }
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500305 } else {
306 mPrivacyChip.setVisibility(View.GONE);
307 }
308 }
309
Beverlyb9826dd2018-04-12 15:02:45 -0400310 private boolean updateRingerStatus() {
311 boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
312 CharSequence originalRingerText = mRingerModeTextView.getText();
313
Amin Shaikh761c5662018-03-27 16:55:43 -0400314 boolean ringerVisible = false;
Beverlyb9826dd2018-04-12 15:02:45 -0400315 if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
Beverlyff2df9b2018-10-10 16:54:10 -0400316 mZenController.getConsolidatedPolicy())) {
Beverlyb9826dd2018-04-12 15:02:45 -0400317 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400318 mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
Beverlyb9826dd2018-04-12 15:02:45 -0400319 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
320 ringerVisible = true;
321 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400322 mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
Beverlyb9826dd2018-04-12 15:02:45 -0400323 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
324 ringerVisible = true;
325 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400326 }
327 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
328 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
Fabian Kozynskiceb057b2019-05-17 14:06:38 -0400329 mRingerContainer.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400330
Beverlyb9826dd2018-04-12 15:02:45 -0400331 return isOriginalVisible != ringerVisible ||
332 !Objects.equals(originalRingerText, mRingerModeTextView.getText());
333 }
334
335 private boolean updateAlarmStatus() {
336 boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
337 CharSequence originalAlarmText = mNextAlarmTextView.getText();
338
Amin Shaikh761c5662018-03-27 16:55:43 -0400339 boolean alarmVisible = false;
340 if (mNextAlarm != null) {
341 alarmVisible = true;
342 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
343 }
344 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
345 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
Fabian Kozynskiceb057b2019-05-17 14:06:38 -0400346 mNextAlarmContainer.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400347
Beverlyb9826dd2018-04-12 15:02:45 -0400348 return isOriginalVisible != alarmVisible ||
349 !Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
350 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400351
Jason Monk824ffff2017-04-11 15:49:06 -0400352 private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
353 View v = findViewById(id);
354 if (v instanceof DarkReceiver) {
355 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
356 }
357 }
358
Jason Monke5b770e2017-03-03 21:49:29 -0500359 @Override
360 protected void onConfigurationChanged(Configuration newConfig) {
361 super.onConfigurationChanged(newConfig);
362 updateResources();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000363
364 // Update color schemes in landscape to use wallpaperTextColor
365 boolean shouldUseWallpaperTextColor =
366 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000367 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500368 }
369
370 @Override
371 public void onRtlPropertiesChanged(int layoutDirection) {
372 super.onRtlPropertiesChanged(layoutDirection);
373 updateResources();
374 }
375
Evan Laird84b98952018-07-02 17:43:59 -0400376 /**
377 * The height of QQS should always be the status bar height + 128dp. This is normally easy, but
378 * when there is a notch involved the status bar can remain a fixed pixel size.
379 */
380 private void updateMinimumHeight() {
381 int sbHeight = mContext.getResources().getDimensionPixelSize(
382 com.android.internal.R.dimen.status_bar_height);
383 int qqsHeight = mContext.getResources().getDimensionPixelSize(
384 R.dimen.qs_quick_header_panel_height);
385
386 setMinimumHeight(sbHeight + qqsHeight);
387 }
388
Jason Monke5b770e2017-03-03 21:49:29 -0500389 private void updateResources() {
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000390 Resources resources = mContext.getResources();
Evan Laird84b98952018-07-02 17:43:59 -0400391 updateMinimumHeight();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000392
393 // Update height for a few views, especially due to landscape mode restricting space.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800394 mHeaderTextContainerView.getLayoutParams().height =
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000395 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800396 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
397
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000398 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
399 com.android.internal.R.dimen.quick_qs_offset_height);
400 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
401
Evan Laird84b98952018-07-02 17:43:59 -0400402 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400403
Evan Laird84b98952018-07-02 17:43:59 -0400404 if (mQsDisabled) {
405 lp.height = resources.getDimensionPixelSize(
406 com.android.internal.R.dimen.quick_qs_offset_height);
Matt Pietal5a19cb62019-10-30 12:31:07 -0400407 } else if (useQsMediaPlayer(mContext)) {
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400408 lp.height = Math.max(getMinimumHeight(),
409 resources.getDimensionPixelSize(
410 com.android.internal.R.dimen.quick_qs_total_height_with_media));
Evan Laird84b98952018-07-02 17:43:59 -0400411 } else {
412 lp.height = Math.max(getMinimumHeight(),
413 resources.getDimensionPixelSize(
Evan Lairdbf3794a2018-07-17 15:55:40 -0400414 com.android.internal.R.dimen.quick_qs_total_height));
Evan Laird84b98952018-07-02 17:43:59 -0400415 }
416
417 setLayoutParams(lp);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000418
Rohan Shahd3cf7562018-02-23 11:12:28 -0800419 updateStatusIconAlphaAnimator();
420 updateHeaderTextContainerAlphaAnimator();
Fabian Kozynski216812e2019-02-01 13:49:00 -0500421 updatePrivacyChipAlphaAnimator();
Evan Laird95896952018-01-22 19:30:05 -0500422 }
423
Rohan Shahd3cf7562018-02-23 11:12:28 -0800424 private void updateStatusIconAlphaAnimator() {
425 mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
Fabian Kozynski0e8449f2019-03-14 15:03:48 -0400426 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0, 0)
Evan Laird95896952018-01-22 19:30:05 -0500427 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500428 }
429
Rohan Shahd3cf7562018-02-23 11:12:28 -0800430 private void updateHeaderTextContainerAlphaAnimator() {
431 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
Fabian Kozynski0e8449f2019-03-14 15:03:48 -0400432 .addFloat(mHeaderTextContainerView, "alpha", 0, 0, 1)
Rohan Shahd3cf7562018-02-23 11:12:28 -0800433 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500434 }
435
Fabian Kozynski216812e2019-02-01 13:49:00 -0500436 private void updatePrivacyChipAlphaAnimator() {
437 mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
438 .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
439 .build();
440 }
441
Jason Monke5b770e2017-03-03 21:49:29 -0500442 public void setExpanded(boolean expanded) {
443 if (mExpanded == expanded) return;
444 mExpanded = expanded;
445 mHeaderQsPanel.setExpanded(expanded);
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000446 updateEverything();
Jason Monke5b770e2017-03-03 21:49:29 -0500447 }
448
Rohan Shahd3cf7562018-02-23 11:12:28 -0800449 /**
450 * Animates the inner contents based on the given expansion details.
451 *
Selim Cinekb0fada62019-06-17 19:03:59 -0700452 * @param forceExpanded whether we should show the state expanded forcibly
Rohan Shahd3cf7562018-02-23 11:12:28 -0800453 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
454 * @param panelTranslationY how much the panel has physically moved down vertically (required
455 * for keyguard animations only)
456 */
Selim Cinekb0fada62019-06-17 19:03:59 -0700457 public void setExpansion(boolean forceExpanded, float expansionFraction,
Rohan Shahd3cf7562018-02-23 11:12:28 -0800458 float panelTranslationY) {
Selim Cinekb0fada62019-06-17 19:03:59 -0700459 final float keyguardExpansionFraction = forceExpanded ? 1f : expansionFraction;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800460 if (mStatusIconsAlphaAnimator != null) {
461 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
Evan Laird95896952018-01-22 19:30:05 -0500462 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800463
Selim Cinekb0fada62019-06-17 19:03:59 -0700464 if (forceExpanded) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800465 // If the keyguard is showing, we want to offset the text so that it comes in at the
466 // same time as the panel as it slides down.
467 mHeaderTextContainerView.setTranslationY(panelTranslationY);
468 } else {
469 mHeaderTextContainerView.setTranslationY(0f);
470 }
471
472 if (mHeaderTextContainerAlphaAnimator != null) {
473 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
Aran Ink7dd05dc2019-05-31 11:47:23 -0400474 if (keyguardExpansionFraction > 0) {
475 mHeaderTextContainerView.setVisibility(VISIBLE);
476 } else {
477 mHeaderTextContainerView.setVisibility(INVISIBLE);
478 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800479 }
Fabian Kozynski216812e2019-02-01 13:49:00 -0500480 if (mPrivacyChipAlphaAnimator != null) {
481 mPrivacyChip.setExpanded(expansionFraction > 0.5);
482 mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
483 }
Jason Monke5b770e2017-03-03 21:49:29 -0500484 }
485
Charles Hece2a7c02017-10-11 20:25:20 +0100486 public void disable(int state1, int state2, boolean animate) {
487 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
488 if (disabled == mQsDisabled) return;
489 mQsDisabled = disabled;
490 mHeaderQsPanel.setDisabledByPolicy(disabled);
Amin Shaikhf09450b2018-04-06 17:32:45 -0400491 mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
492 mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
493 updateResources();
Charles Hece2a7c02017-10-11 20:25:20 +0100494 }
495
496 @Override
497 public void onAttachedToWindow() {
Amin Shaikha59215a2018-04-23 08:52:38 -0400498 super.onAttachedToWindow();
Jason Monkea54e8a2018-12-20 10:01:48 -0500499 mStatusBarIconController.addIconGroup(mIconManager);
Adrian Roos13836052018-03-15 21:06:37 +0100500 requestApplyInsets();
Winson Chungefaacc32019-09-25 14:44:05 -0700501 // Change the ignored slots when DeviceConfig flag changes
502 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY,
503 mContext.getMainExecutor(), mPropertiesListener);
Adrian Roos13836052018-03-15 21:06:37 +0100504 }
505
506 @Override
507 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500508 DisplayCutout cutout = insets.getDisplayCutout();
Adrian Roos13836052018-03-15 21:06:37 +0100509 Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500510 cutout, getDisplay());
Adrian Roos13836052018-03-15 21:06:37 +0100511 if (padding == null) {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400512 mSystemIconsView.setPaddingRelative(
513 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
514 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
Adrian Roos13836052018-03-15 21:06:37 +0100515 } else {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400516 mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
517
Adrian Roos13836052018-03-15 21:06:37 +0100518 }
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500519 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams();
520 if (cutout != null) {
521 Rect topCutout = cutout.getBoundingRectTop();
522 if (topCutout.isEmpty()) {
523 mHasTopCutout = false;
524 lp.width = 0;
525 mSpace.setVisibility(View.GONE);
526 } else {
527 mHasTopCutout = true;
528 lp.width = topCutout.width();
529 mSpace.setVisibility(View.VISIBLE);
530 }
531 }
532 mSpace.setLayoutParams(lp);
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500533 setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
Adrian Roos13836052018-03-15 21:06:37 +0100534 return super.onApplyWindowInsets(insets);
Charles Hece2a7c02017-10-11 20:25:20 +0100535 }
536
537 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500538 @VisibleForTesting
539 public void onDetachedFromWindow() {
540 setListening(false);
Jason Monkea54e8a2018-12-20 10:01:48 -0500541 mStatusBarIconController.removeIconGroup(mIconManager);
Winson Chungefaacc32019-09-25 14:44:05 -0700542 DeviceConfig.removeOnPropertiesChangedListener(mPropertiesListener);
Jason Monke5b770e2017-03-03 21:49:29 -0500543 super.onDetachedFromWindow();
544 }
545
546 public void setListening(boolean listening) {
547 if (listening == mListening) {
548 return;
549 }
550 mHeaderQsPanel.setListening(listening);
551 mListening = listening;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800552
553 if (listening) {
Beverlyb9826dd2018-04-12 15:02:45 -0400554 mZenController.addCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800555 mAlarmController.addCallback(this);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000556 mBroadcastDispatcher.registerReceiver(mRingerReceiver,
Amin Shaikh761c5662018-03-27 16:55:43 -0400557 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500558 mPrivacyItemController.addCallback(mPICCallback);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800559 } else {
Beverlyb9826dd2018-04-12 15:02:45 -0400560 mZenController.removeCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800561 mAlarmController.removeCallback(this);
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500562 mPrivacyItemController.removeCallback(mPICCallback);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000563 mBroadcastDispatcher.unregisterReceiver(mRingerReceiver);
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500564 mPrivacyChipLogged = false;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800565 }
Jason Monke5b770e2017-03-03 21:49:29 -0500566 }
567
Evan Laird95896952018-01-22 19:30:05 -0500568 @Override
569 public void onClick(View v) {
Fabian Kozynskif3db35c2019-04-24 14:37:35 -0400570 if (v == mClockView) {
Jason Monkea54e8a2018-12-20 10:01:48 -0500571 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
Fabian Kozynskif3db35c2019-04-24 14:37:35 -0400572 AlarmClock.ACTION_SHOW_ALARMS), 0);
Fabian Kozynski1bdb0b92019-04-26 10:25:30 -0400573 } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
Fabian Kozynskia3544712019-04-25 17:05:21 -0400574 if (mNextAlarm.getShowIntent() != null) {
Fabian Kozynskif3db35c2019-04-24 14:37:35 -0400575 mActivityStarter.postStartActivityDismissingKeyguard(
Fabian Kozynskia3544712019-04-25 17:05:21 -0400576 mNextAlarm.getShowIntent());
Fabian Kozynskif3db35c2019-04-24 14:37:35 -0400577 } else {
Fabian Kozynskia3544712019-04-25 17:05:21 -0400578 Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
Fabian Kozynskif3db35c2019-04-24 14:37:35 -0400579 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
580 AlarmClock.ACTION_SHOW_ALARMS), 0);
581 }
Fabian Kozynski12638242018-10-12 15:33:41 -0400582 } else if (v == mPrivacyChip) {
Fabian Kozynskiafd50022019-02-05 09:41:42 -0500583 // Makes sure that the builder is grabbed as soon as the chip is pressed
584 PrivacyDialogBuilder builder = mPrivacyChip.getBuilder();
585 if (builder.getAppsAndTypes().size() == 0) return;
Fabian Kozynski12638242018-10-12 15:33:41 -0400586 Handler mUiHandler = new Handler(Looper.getMainLooper());
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500587 StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
588 StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED);
Fabian Kozynski12638242018-10-12 15:33:41 -0400589 mUiHandler.post(() -> {
Joel Galensonf8b62922019-03-15 12:51:16 -0700590 mActivityStarter.postStartActivityDismissingKeyguard(
591 new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
Fabian Kozynski12638242018-10-12 15:33:41 -0400592 mHost.collapsePanels();
593 });
Fabian Kozynski1bdb0b92019-04-26 10:25:30 -0400594 } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400595 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
596 Settings.ACTION_SOUND_SETTINGS), 0);
Evan Laird95896952018-01-22 19:30:05 -0500597 }
598 }
599
Rohan Shahd3cf7562018-02-23 11:12:28 -0800600 @Override
601 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Amin Shaikh761c5662018-03-27 16:55:43 -0400602 mNextAlarm = nextAlarm;
603 updateStatusText();
604 }
Rohan Shaha160ab12018-03-09 15:47:36 -0800605
Beverlyb9826dd2018-04-12 15:02:45 -0400606 @Override
607 public void onZenChanged(int zen) {
608 updateStatusText();
Beverlyb9826dd2018-04-12 15:02:45 -0400609 }
610
611 @Override
612 public void onConfigChanged(ZenModeConfig config) {
613 updateStatusText();
614 }
615
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000616 public void updateEverything() {
Fabian Kozynski9a15b7c2019-01-10 11:13:27 -0500617 post(() -> setClickable(!mExpanded));
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000618 }
619
Jason Monke5b770e2017-03-03 21:49:29 -0500620 public void setQSPanel(final QSPanel qsPanel) {
621 mQsPanel = qsPanel;
622 setupHost(qsPanel.getHost());
623 }
624
625 public void setupHost(final QSTileHost host) {
626 mHost = host;
627 //host.setHeaderView(mExpandIndicator);
628 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
629 mHeaderQsPanel.setHost(host, null /* No customization in header */);
Evan Lairdef160f22018-01-29 14:08:45 -0500630
Evan Laird4bf21df2018-10-22 14:24:32 -0400631
632 Rect tintArea = new Rect(0, 0, 0, 0);
633 int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
634 android.R.attr.colorForeground);
635 float intensity = getColorIntensity(colorForeground);
Fabian Kozynskif86df992019-04-22 14:23:47 -0400636 int fillColor = mDualToneHandler.getSingleColor(intensity);
Evan Laird4bf21df2018-10-22 14:24:32 -0400637 mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500638 }
639
640 public void setCallback(Callback qsPanelCallback) {
641 mHeaderQsPanel.setCallback(qsPanelCallback);
642 }
Lucas Dupin1f7374a2018-02-26 18:08:33 -0800643
644 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
645 if (info == null) {
646 return "";
647 }
648 String skeleton = android.text.format.DateFormat
649 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
650 String pattern = android.text.format.DateFormat
651 .getBestDateTimePattern(Locale.getDefault(), skeleton);
652 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
653 }
Amin Shaikh0e003312018-03-08 11:39:01 -0500654
655 public static float getColorIntensity(@ColorInt int color) {
656 return color == Color.WHITE ? 0 : 1;
657 }
Amin Shaikh50d2d1e2018-04-25 14:48:13 -0400658
659 public void setMargins(int sideMargins) {
660 for (int i = 0; i < getChildCount(); i++) {
661 View v = getChildAt(i);
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400662 // Prevents these views from getting set a margin.
663 // The Icon views all have the same padding set in XML to be aligned.
Fabian Kozynskief124492018-11-02 11:02:11 -0400664 if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400665 || v == mHeaderTextContainerView) {
Amin Shaikh50d2d1e2018-04-25 14:48:13 -0400666 continue;
667 }
668 RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
669 lp.leftMargin = sideMargins;
670 lp.rightMargin = sideMargins;
671 }
672 }
Jason Monke5b770e2017-03-03 21:49:29 -0500673}