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