QuickStatusBarHeader.java revision df5459daaa0f61f9c15d17f45a547420cdf83ae6
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.QSTile; 39import com.android.systemui.qs.QuickQSPanel; 40import com.android.systemui.qs.TouchAnimator; 41import com.android.systemui.statusbar.policy.BatteryController; 42import com.android.systemui.statusbar.policy.NextAlarmController; 43import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; 44import com.android.systemui.statusbar.policy.UserInfoController; 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 mAnimator; 87 private TouchAnimator mSecondHalfAnimator; 88 private TouchAnimator mFirstHalfAnimator; 89 private TouchAnimator mDateSizeAnimator; 90 private TouchAnimator mAlarmTranslation; 91 private TouchAnimator mSettingsAlpha; 92 private float mExpansionAmount; 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) getBackground()).setForceSoftware(true); 128 ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true); 129 130 updateResources(); 131 } 132 133 @Override 134 protected void onConfigurationChanged(Configuration newConfig) { 135 super.onConfigurationChanged(newConfig); 136 updateResources(); 137 } 138 139 private void updateResources() { 140 FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size); 141 FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size); 142 143 mGearTranslation = mContext.getResources().getDimension(R.dimen.qs_header_gear_translation); 144 145 mDateTimeTranslation = mContext.getResources().getDimension( 146 R.dimen.qs_date_anim_translation); 147 mDateTimeAlarmTranslation = mContext.getResources().getDimension( 148 R.dimen.qs_date_alarm_anim_translation); 149 float dateCollapsedSize = mContext.getResources().getDimension( 150 R.dimen.qs_date_collapsed_text_size); 151 float dateExpandedSize = mContext.getResources().getDimension( 152 R.dimen.qs_date_text_size); 153 mDateScaleFactor = dateExpandedSize / dateCollapsedSize; 154 updateDateTimePosition(); 155 156 mAnimator = new TouchAnimator.Builder() 157 .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0) 158 .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0) 159 .build(); 160 mSecondHalfAnimator = new TouchAnimator.Builder() 161 .addFloat(mSettingsButton, "rotation", -180, 0) 162 .addFloat(mAlarmStatus, "alpha", 0, 1) 163 .addFloat(mEmergencyOnly, "alpha", 0, 1) 164 .setStartDelay(.5f) 165 .build(); 166 mFirstHalfAnimator = new TouchAnimator.Builder() 167 .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0) 168 .setEndDelay(.5f) 169 .build(); 170 mDateSizeAnimator = new TouchAnimator.Builder() 171 .addFloat(mDateTimeGroup, "scaleX", 1, mDateScaleFactor) 172 .addFloat(mDateTimeGroup, "scaleY", 1, mDateScaleFactor) 173 .setStartDelay(.36f) 174 .build(); 175 mSettingsAlpha = new TouchAnimator.Builder() 176 .addFloat(mSettingsContainer, "alpha", 0, 1) 177 .addFloat(mMultiUserSwitch, "alpha", 0, 1) 178 .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY) 179 .build(); 180 } 181 182 @Override 183 public int getCollapsedHeight() { 184 return getHeight(); 185 } 186 187 @Override 188 public int getExpandedHeight() { 189 return getHeight(); 190 } 191 192 @Override 193 public void setExpanded(boolean expanded) { 194 mExpanded = expanded; 195 updateEverything(); 196 } 197 198 @Override 199 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 200 mNextAlarm = nextAlarm; 201 if (nextAlarm != null) { 202 mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm)); 203 } 204 if (mAlarmShowing != (nextAlarm != null)) { 205 mAlarmShowing = nextAlarm != null; 206 updateEverything(); 207 } 208 } 209 210 @Override 211 public void setExpansion(float headerExpansionFraction) { 212 mExpansionAmount = headerExpansionFraction; 213 mAnimator.setPosition(headerExpansionFraction); 214 mSecondHalfAnimator.setPosition(headerExpansionFraction); 215 mFirstHalfAnimator.setPosition(headerExpansionFraction); 216 mDateSizeAnimator.setPosition(headerExpansionFraction); 217 mAlarmTranslation.setPosition(headerExpansionFraction); 218 mSettingsAlpha.setPosition(headerExpansionFraction); 219 220 updateAlarmVisibilities(); 221 222 mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD); 223 } 224 225 private void updateAlarmVisibilities() { 226 mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 227 mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 228 } 229 230 private void updateDateTimePosition() { 231 // This one has its own because we have to rebuild it every time the alarm state changes. 232 mAlarmTranslation = new TouchAnimator.Builder() 233 .addFloat(mDateTimeAlarmGroup, "translationY", 0, mAlarmShowing 234 ? mDateTimeAlarmTranslation : mDateTimeTranslation) 235 .build(); 236 mAlarmTranslation.setPosition(mExpansionAmount); 237 } 238 239 public void setListening(boolean listening) { 240 if (listening == mListening) { 241 return; 242 } 243 mHeaderQsPanel.setListening(listening); 244 mListening = listening; 245 updateListeners(); 246 } 247 248 @Override 249 public void updateEverything() { 250 updateDateTimePosition(); 251 updateVisibilities(); 252 } 253 254 private void updateVisibilities() { 255 updateAlarmVisibilities(); 256 mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly 257 ? View.VISIBLE : View.INVISIBLE); 258 mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( 259 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); 260 mMultiUserSwitch.setVisibility(mMultiUserSwitch.hasMultipleUsers() ? View.VISIBLE 261 : View.GONE); 262 } 263 264 private void updateListeners() { 265 if (mListening) { 266 mNextAlarmController.addStateChangedCallback(this); 267 } else { 268 mNextAlarmController.removeStateChangedCallback(this); 269 } 270 } 271 272 @Override 273 public void setActivityStarter(ActivityStarter activityStarter) { 274 mActivityStarter = activityStarter; 275 } 276 277 @Override 278 public void setQSPanel(final QSPanel qsPanel) { 279 mQsPanel = qsPanel; 280 setupHost(qsPanel.getHost()); 281 if (mQsPanel != null) { 282 mMultiUserSwitch.setQsPanel(qsPanel); 283 } 284 } 285 286 public void setupHost(final QSTileHost host) { 287 host.setHeaderView(this); 288 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this); 289 mHeaderQsPanel.setHost(host); 290 mHeaderQsPanel.setMaxTiles(5); 291 mHeaderQsPanel.setTiles(host.getTiles()); 292 host.addCallback(new QSTile.Host.Callback() { 293 @Override 294 public void onTilesChanged() { 295 mHeaderQsPanel.setTiles(host.getTiles()); 296 } 297 }); 298 } 299 300 @Override 301 public void onClick(View v) { 302 if (v == mSettingsButton) { 303 if (mSettingsButton.isTunerClick()) { 304 if (TunerService.isTunerEnabled(mContext)) { 305 TunerService.showResetRequest(mContext, new Runnable() { 306 @Override 307 public void run() { 308 // Relaunch settings so that the tuner disappears. 309 startSettingsActivity(); 310 } 311 }); 312 } else { 313 Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show(); 314 TunerService.setTunerEnabled(mContext, true); 315 } 316 } 317 startSettingsActivity(); 318 } else if (v == mAlarmStatus && mNextAlarm != null) { 319 PendingIntent showIntent = mNextAlarm.getShowIntent(); 320 if (showIntent != null && showIntent.isActivity()) { 321 mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */); 322 } 323 } 324 } 325 326 private void startSettingsActivity() { 327 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), 328 true /* dismissShade */); 329 } 330 331 @Override 332 public void setNextAlarmController(NextAlarmController nextAlarmController) { 333 mNextAlarmController = nextAlarmController; 334 } 335 336 @Override 337 public void setBatteryController(BatteryController batteryController) { 338 // Don't care 339 } 340 341 @Override 342 public void setUserInfoController(UserInfoController userInfoController) { 343 userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { 344 @Override 345 public void onUserInfoChanged(String name, Drawable picture) { 346 mMultiUserAvatar.setImageDrawable(picture); 347 } 348 }); 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