QuickStatusBarHeader.java revision 50805412c8de7ccac7fa63aa87283fdf6a35c812
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.QSPanel; 41import com.android.systemui.qs.QSPanel.Callback; 42import com.android.systemui.qs.QuickQSPanel; 43import com.android.systemui.qs.TouchAnimator; 44import com.android.systemui.qs.TouchAnimator.Builder; 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 mAnimator; 88 protected TouchAnimator mSettingsAlpha; 89 private float mExpansionAmount; 90 private QSTileHost mHost; 91 private View mEdit; 92 private boolean mShowFullAlarm; 93 private float mDateTimeTranslation; 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 mDateTimeTranslation = getResources().getDimension(R.dimen.qs_date_time_translation); 115 mShowFullAlarm = getResources().getBoolean(R.bool.quick_settings_show_full_alarm); 116 117 mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator); 118 119 mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel); 120 121 mSettingsButton = (SettingsButton) findViewById(R.id.settings_button); 122 mSettingsContainer = findViewById(R.id.settings_button_container); 123 mSettingsButton.setOnClickListener(this); 124 125 mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed); 126 mAlarmStatus = (TextView) findViewById(R.id.alarm_status); 127 mAlarmStatus.setOnClickListener(this); 128 129 mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); 130 mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar); 131 132 // RenderThread is doing more harm than good when touching the header (to expand quick 133 // settings), so disable it for this view 134 ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); 135 ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true); 136 137 updateResources(); 138 } 139 140 @Override 141 protected void onConfigurationChanged(Configuration newConfig) { 142 super.onConfigurationChanged(newConfig); 143 updateResources(); 144 } 145 146 @Override 147 public void onRtlPropertiesChanged(int layoutDirection) { 148 super.onRtlPropertiesChanged(layoutDirection); 149 updateResources(); 150 } 151 152 private void updateResources() { 153 FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size); 154 FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size); 155 156 Builder builder = new Builder() 157 .addFloat(mShowFullAlarm ? mAlarmStatus : findViewById(R.id.date), "alpha", 0, 1) 158 .addFloat(mEmergencyOnly, "alpha", 0, 1); 159 if (mShowFullAlarm) { 160 builder.addFloat(mAlarmStatusCollapsed, "alpha", 1, 0); 161 } 162 mAnimator = builder.build(); 163 164 updateSettingsAnimator(); 165 } 166 167 protected void updateSettingsAnimator() { 168 mSettingsAlpha = new TouchAnimator.Builder() 169 .addFloat(mEdit, "alpha", 0, 1) 170 .addFloat(mMultiUserSwitch, "alpha", 0, 1) 171 .build(); 172 173 final boolean isRtl = isLayoutRtl(); 174 if (isRtl && mDateTimeGroup.getWidth() == 0) { 175 mDateTimeGroup.addOnLayoutChangeListener(new OnLayoutChangeListener() { 176 @Override 177 public void onLayoutChange(View v, int left, int top, int right, int bottom, 178 int oldLeft, int oldTop, int oldRight, int oldBottom) { 179 mDateTimeGroup.setPivotX(getWidth()); 180 mDateTimeGroup.removeOnLayoutChangeListener(this); 181 } 182 }); 183 } else { 184 mDateTimeGroup.setPivotX(isRtl ? mDateTimeGroup.getWidth() : 0); 185 } 186 } 187 188 @Override 189 public int getCollapsedHeight() { 190 return getHeight(); 191 } 192 193 @Override 194 public int getExpandedHeight() { 195 return getHeight(); 196 } 197 198 @Override 199 public void setExpanded(boolean expanded) { 200 mExpanded = expanded; 201 mHeaderQsPanel.setExpanded(expanded); 202 updateEverything(); 203 } 204 205 @Override 206 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 207 mNextAlarm = nextAlarm; 208 if (nextAlarm != null) { 209 String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm); 210 mAlarmStatus.setText(alarmString); 211 mAlarmStatus.setContentDescription(mContext.getString( 212 R.string.accessibility_quick_settings_alarm, alarmString)); 213 mAlarmStatusCollapsed.setContentDescription(mContext.getString( 214 R.string.accessibility_quick_settings_alarm, alarmString)); 215 } 216 if (mAlarmShowing != (nextAlarm != null)) { 217 mAlarmShowing = nextAlarm != null; 218 updateEverything(); 219 } 220 } 221 222 @Override 223 public void setExpansion(float headerExpansionFraction) { 224 mExpansionAmount = headerExpansionFraction; 225 updateDateTimePosition(); 226 mAnimator.setPosition(headerExpansionFraction); 227 mSettingsAlpha.setPosition(headerExpansionFraction); 228 229 updateAlarmVisibilities(); 230 231 mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD); 232 } 233 234 @Override 235 protected void onDetachedFromWindow() { 236 setListening(false); 237 mHost.getUserInfoController().remListener(this); 238 mHost.getNetworkController().removeEmergencyListener(this); 239 super.onDetachedFromWindow(); 240 } 241 242 private void updateAlarmVisibilities() { 243 mAlarmStatus.setVisibility(mAlarmShowing && mShowFullAlarm ? View.VISIBLE : View.INVISIBLE); 244 mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 245 } 246 247 public void setListening(boolean listening) { 248 if (listening == mListening) { 249 return; 250 } 251 mHeaderQsPanel.setListening(listening); 252 mListening = listening; 253 updateListeners(); 254 } 255 256 @Override 257 public void updateEverything() { 258 updateVisibilities(); 259 setClickable(false); 260 } 261 262 protected void updateVisibilities() { 263 updateAlarmVisibilities(); 264 updateDateTimePosition(); 265 mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly 266 ? View.VISIBLE : View.INVISIBLE); 267 mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( 268 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); 269 final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); 270 mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo 271 ? View.VISIBLE : View.INVISIBLE); 272 mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); 273 } 274 275 private void updateDateTimePosition() { 276 mDateTimeAlarmGroup.setTranslationY(mShowEmergencyCallsOnly 277 ? mExpansionAmount * mDateTimeTranslation : 0); 278 } 279 280 private void updateListeners() { 281 if (mListening) { 282 mNextAlarmController.addStateChangedCallback(this); 283 } else { 284 mNextAlarmController.removeStateChangedCallback(this); 285 } 286 } 287 288 @Override 289 public void setActivityStarter(ActivityStarter activityStarter) { 290 mActivityStarter = activityStarter; 291 } 292 293 @Override 294 public void setQSPanel(final QSPanel qsPanel) { 295 mQsPanel = qsPanel; 296 setupHost(qsPanel.getHost()); 297 if (mQsPanel != null) { 298 mMultiUserSwitch.setQsPanel(qsPanel); 299 } 300 } 301 302 public void setupHost(final QSTileHost host) { 303 mHost = host; 304 host.setHeaderView(mExpandIndicator); 305 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this); 306 mHeaderQsPanel.setHost(host, null /* No customization in header */); 307 setUserInfoController(host.getUserInfoController()); 308 setBatteryController(host.getBatteryController()); 309 setNextAlarmController(host.getNextAlarmController()); 310 311 final boolean isAPhone = mHost.getNetworkController().hasVoiceCallingFeature(); 312 if (isAPhone) { 313 mHost.getNetworkController().addEmergencyListener(this); 314 } 315 } 316 317 @Override 318 public void onClick(View v) { 319 if (v == mSettingsButton) { 320 MetricsLogger.action(mContext, 321 mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH 322 : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH); 323 if (mSettingsButton.isTunerClick()) { 324 mHost.startRunnableDismissingKeyguard(() -> post(() -> { 325 if (TunerService.isTunerEnabled(mContext)) { 326 TunerService.showResetRequest(mContext, () -> { 327 // Relaunch settings so that the tuner disappears. 328 startSettingsActivity(); 329 }); 330 } else { 331 Toast.makeText(getContext(), R.string.tuner_toast, 332 Toast.LENGTH_LONG).show(); 333 TunerService.setTunerEnabled(mContext, true); 334 } 335 startSettingsActivity(); 336 337 })); 338 } else { 339 startSettingsActivity(); 340 } 341 } else if (v == mAlarmStatus && mNextAlarm != null) { 342 PendingIntent showIntent = mNextAlarm.getShowIntent(); 343 if (showIntent != null && showIntent.isActivity()) { 344 mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */); 345 } 346 } 347 } 348 349 private void startSettingsActivity() { 350 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), 351 true /* dismissShade */); 352 } 353 354 @Override 355 public void setNextAlarmController(NextAlarmController nextAlarmController) { 356 mNextAlarmController = nextAlarmController; 357 } 358 359 @Override 360 public void setBatteryController(BatteryController batteryController) { 361 // Don't care 362 } 363 364 @Override 365 public void setUserInfoController(UserInfoController userInfoController) { 366 userInfoController.addListener(this); 367 } 368 369 @Override 370 public void setCallback(Callback qsPanelCallback) { 371 mHeaderQsPanel.setCallback(qsPanelCallback); 372 } 373 374 @Override 375 public void setEmergencyCallsOnly(boolean show) { 376 boolean changed = show != mShowEmergencyCallsOnly; 377 if (changed) { 378 mShowEmergencyCallsOnly = show; 379 if (mExpanded) { 380 updateEverything(); 381 } 382 } 383 } 384 385 @Override 386 public void onUserInfoChanged(String name, Drawable picture) { 387 mMultiUserAvatar.setImageDrawable(picture); 388 } 389} 390