QuickStatusBarHeader.java revision 104d9de3a53334a436b2645b25973248e7468e57
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 || !mExpanded ? 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