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