Loading packages/SystemUI/res/drawable/qs_header_status_dot.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@android:color/white"/> </shape> packages/SystemUI/res/layout/quick_settings_header_info.xml +25 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ android:visibility="invisible" /> <LinearLayout android:id="@+id/next_alarm" android:id="@+id/status_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" Loading @@ -41,6 +41,7 @@ android:visibility="invisible"> <ImageView android:id="@+id/next_alarm_icon" android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" android:src="@drawable/stat_sys_alarm" Loading @@ -53,6 +54,29 @@ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> <ImageView android:id="@+id/status_separator" android:layout_width="2dp" android:layout_height="2dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:layout_gravity="center_vertical" android:src="@drawable/qs_header_status_dot" android:tint="?android:attr/textColorPrimary" /> <ImageView android:id="@+id/ringer_mode_icon" android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" android:tint="?android:attr/textColorPrimary" /> <TextView android:id="@+id/ringer_mode_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> </LinearLayout> </FrameLayout> packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +89 −39 Original line number Diff line number Diff line Loading @@ -21,22 +21,25 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.ColorInt; import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; import android.os.Handler; import android.provider.AlarmClock; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; import android.view.View; import android.view.WindowInsets; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; Loading Loading @@ -95,21 +98,36 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue private View mQuickQsStatusIcons; private View mDate; private View mHeaderTextContainerView; /** View corresponding to the next alarm info (including the icon). */ private View mNextAlarmView; /** View containing the next alarm and ringer mode info. */ private View mStatusContainer; /** Tooltip for educating users that they can long press on icons to see more details. */ private View mLongPressTooltipView; private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; private AlarmManager.AlarmClockInfo mNextAlarm; private ImageView mNextAlarmIcon; /** {@link TextView} containing the actual text indicating when the next alarm will go off. */ private TextView mNextAlarmTextView; private View mStatusSeparator; private ImageView mRingerModeIcon; private TextView mRingerModeTextView; private BatteryMeterView mBatteryMeterView; private Clock mClockView; private DateView mDateView; private NextAlarmController mAlarmController; private String mNextAlarmText; /** Counts how many times the long press tooltip has been shown to the user. */ private int mShownCount; private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); updateStatusText(); } }; /** * Runnable for automatically fading out the long press tooltip (as if it were animating away). */ Loading @@ -117,7 +135,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); mAlarmController = Dependency.get(NextAlarmController.class); mShownCount = getStoredShownCount(); } Loading @@ -136,8 +153,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue // Views corresponding to the header info section (e.g. tooltip and next alarm). mHeaderTextContainerView = findViewById(R.id.header_text_container); mLongPressTooltipView = findViewById(R.id.long_press_tooltip); mNextAlarmView = findViewById(R.id.next_alarm); mStatusContainer = findViewById(R.id.status_container); mStatusSeparator = findViewById(R.id.status_separator); mNextAlarmIcon = findViewById(R.id.next_alarm_icon); mNextAlarmTextView = findViewById(R.id.next_alarm_text); mRingerModeIcon = findViewById(R.id.ringer_mode_icon); mRingerModeTextView = findViewById(R.id.ringer_mode_text); updateResources(); Loading @@ -159,6 +180,32 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue mDateView = findViewById(R.id.date); } private void updateStatusText() { boolean ringerVisible = false; if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate); mRingerModeTextView.setText(R.string.volume_ringer_status_vibrate); ringerVisible = true; } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) { mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent); mRingerModeTextView.setText(R.string.volume_ringer_status_silent); ringerVisible = true; } mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); boolean alarmVisible = false; if (mNextAlarm != null) { alarmVisible = true; mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm)); } mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE : View.GONE); updateTooltipShow(); } private void applyDarkness(int id, Rect tintArea, float intensity, int color) { View v = findViewById(id); if (v instanceof DarkReceiver) { Loading Loading @@ -323,8 +370,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue if (listening) { mAlarmController.addCallback(this); mContext.registerReceiver(mRingerReceiver, new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); } else { mAlarmController.removeCallback(this); mContext.unregisterReceiver(mRingerReceiver); } } Loading @@ -338,23 +388,31 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue @Override public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null; mNextAlarm = nextAlarm; updateStatusText(); } if (mNextAlarmText != null) { hideLongPressTooltip(true /* shouldFadeInAlarmText */); private void updateTooltipShow() { if (hasStatusText()) { hideLongPressTooltip(true /* shouldShowStatusText */); } else { hideAlarmText(); hideStatusText(); } updateHeaderTextContainerAlphaAnimator(); } private boolean hasStatusText() { return mNextAlarmTextView.getVisibility() == View.VISIBLE || mRingerModeTextView.getVisibility() == View.VISIBLE; } /** * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying * the space). */ public void showLongPressTooltip() { // If we have alarm text to show, don't bother fading in the tooltip. if (!TextUtils.isEmpty(mNextAlarmText)) { // If we have status text to show, don't bother fading in the tooltip. if (hasStatusText()) { return; } Loading Loading @@ -384,11 +442,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue /** * Fades out the long press tooltip if it's partially visible - short circuits any running * animation. Additionally has the ability to fade in the alarm info text. * animation. Additionally has the ability to fade in the status info text. * * @param shouldShowAlarmText whether we should fade in the next alarm text * @param shouldShowStatusText whether we should fade in the status text */ private void hideLongPressTooltip(boolean shouldShowAlarmText) { private void hideLongPressTooltip(boolean shouldShowStatusText) { mLongPressTooltipView.animate().cancel(); if (mLongPressTooltipView.getVisibility() == View.VISIBLE && mLongPressTooltipView.getAlpha() != 0f) { Loading @@ -402,44 +460,40 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip"); mLongPressTooltipView.setVisibility(View.INVISIBLE); if (shouldShowAlarmText) { showAlarmText(); if (shouldShowStatusText) { showStatus(); } } }) .start(); } else { mLongPressTooltipView.setVisibility(View.INVISIBLE); if (shouldShowAlarmText) { showAlarmText(); if (shouldShowStatusText) { showStatus(); } } } /** * Fades in the updated alarm text. Note that if there's already an alarm showing, this will * immediately hide it and fade in the updated time. * Fades in the updated status text. Note that if there's already a status showing, this will * immediately hide it and fade in the updated status. */ private void showAlarmText() { mNextAlarmView.setAlpha(0f); mNextAlarmView.setVisibility(View.VISIBLE); mNextAlarmTextView.setText(mNextAlarmText); private void showStatus() { mStatusContainer.setAlpha(0f); mStatusContainer.setVisibility(View.VISIBLE); // Animate the alarm back in. Make sure to clear the animator listener for the animation! mNextAlarmView.animate() mStatusContainer.animate() .alpha(1f) .setDuration(FADE_ANIMATION_DURATION_MS) .setListener(null) .start(); } /** * Fades out and hides the next alarm text. This also resets the text contents to null in * preparation for the next alarm update. */ private void hideAlarmText() { if (mNextAlarmView.getVisibility() == View.VISIBLE) { mNextAlarmView.animate() /** Fades out and hides the status text. */ private void hideStatusText() { if (mStatusContainer.getVisibility() == View.VISIBLE) { mStatusContainer.animate() .alpha(0f) .setListener(new AnimatorListenerAdapter() { @Override Loading @@ -448,15 +502,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue // Reset the alpha regardless of how the animation ends for the next // time we show this view/want to animate it. mNextAlarmView.setVisibility(View.INVISIBLE); mNextAlarmView.setAlpha(1f); mNextAlarmTextView.setText(null); mStatusContainer.setVisibility(View.INVISIBLE); mStatusContainer.setAlpha(1f); } }) .start(); } else { // Next alarm view is already hidden, only need to clear the text. mNextAlarmTextView.setText(null); } } Loading Loading
packages/SystemUI/res/drawable/qs_header_status_dot.xml 0 → 100644 +19 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@android:color/white"/> </shape>
packages/SystemUI/res/layout/quick_settings_header_info.xml +25 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ android:visibility="invisible" /> <LinearLayout android:id="@+id/next_alarm" android:id="@+id/status_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" Loading @@ -41,6 +41,7 @@ android:visibility="invisible"> <ImageView android:id="@+id/next_alarm_icon" android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" android:src="@drawable/stat_sys_alarm" Loading @@ -53,6 +54,29 @@ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> <ImageView android:id="@+id/status_separator" android:layout_width="2dp" android:layout_height="2dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:layout_gravity="center_vertical" android:src="@drawable/qs_header_status_dot" android:tint="?android:attr/textColorPrimary" /> <ImageView android:id="@+id/ringer_mode_icon" android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" android:tint="?android:attr/textColorPrimary" /> <TextView android:id="@+id/ringer_mode_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> </LinearLayout> </FrameLayout>
packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +89 −39 Original line number Diff line number Diff line Loading @@ -21,22 +21,25 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.ColorInt; import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; import android.os.Handler; import android.provider.AlarmClock; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; import android.view.View; import android.view.WindowInsets; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; Loading Loading @@ -95,21 +98,36 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue private View mQuickQsStatusIcons; private View mDate; private View mHeaderTextContainerView; /** View corresponding to the next alarm info (including the icon). */ private View mNextAlarmView; /** View containing the next alarm and ringer mode info. */ private View mStatusContainer; /** Tooltip for educating users that they can long press on icons to see more details. */ private View mLongPressTooltipView; private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; private AlarmManager.AlarmClockInfo mNextAlarm; private ImageView mNextAlarmIcon; /** {@link TextView} containing the actual text indicating when the next alarm will go off. */ private TextView mNextAlarmTextView; private View mStatusSeparator; private ImageView mRingerModeIcon; private TextView mRingerModeTextView; private BatteryMeterView mBatteryMeterView; private Clock mClockView; private DateView mDateView; private NextAlarmController mAlarmController; private String mNextAlarmText; /** Counts how many times the long press tooltip has been shown to the user. */ private int mShownCount; private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); updateStatusText(); } }; /** * Runnable for automatically fading out the long press tooltip (as if it were animating away). */ Loading @@ -117,7 +135,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); mAlarmController = Dependency.get(NextAlarmController.class); mShownCount = getStoredShownCount(); } Loading @@ -136,8 +153,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue // Views corresponding to the header info section (e.g. tooltip and next alarm). mHeaderTextContainerView = findViewById(R.id.header_text_container); mLongPressTooltipView = findViewById(R.id.long_press_tooltip); mNextAlarmView = findViewById(R.id.next_alarm); mStatusContainer = findViewById(R.id.status_container); mStatusSeparator = findViewById(R.id.status_separator); mNextAlarmIcon = findViewById(R.id.next_alarm_icon); mNextAlarmTextView = findViewById(R.id.next_alarm_text); mRingerModeIcon = findViewById(R.id.ringer_mode_icon); mRingerModeTextView = findViewById(R.id.ringer_mode_text); updateResources(); Loading @@ -159,6 +180,32 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue mDateView = findViewById(R.id.date); } private void updateStatusText() { boolean ringerVisible = false; if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate); mRingerModeTextView.setText(R.string.volume_ringer_status_vibrate); ringerVisible = true; } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) { mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent); mRingerModeTextView.setText(R.string.volume_ringer_status_silent); ringerVisible = true; } mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); boolean alarmVisible = false; if (mNextAlarm != null) { alarmVisible = true; mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm)); } mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE : View.GONE); updateTooltipShow(); } private void applyDarkness(int id, Rect tintArea, float intensity, int color) { View v = findViewById(id); if (v instanceof DarkReceiver) { Loading Loading @@ -323,8 +370,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue if (listening) { mAlarmController.addCallback(this); mContext.registerReceiver(mRingerReceiver, new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); } else { mAlarmController.removeCallback(this); mContext.unregisterReceiver(mRingerReceiver); } } Loading @@ -338,23 +388,31 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue @Override public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null; mNextAlarm = nextAlarm; updateStatusText(); } if (mNextAlarmText != null) { hideLongPressTooltip(true /* shouldFadeInAlarmText */); private void updateTooltipShow() { if (hasStatusText()) { hideLongPressTooltip(true /* shouldShowStatusText */); } else { hideAlarmText(); hideStatusText(); } updateHeaderTextContainerAlphaAnimator(); } private boolean hasStatusText() { return mNextAlarmTextView.getVisibility() == View.VISIBLE || mRingerModeTextView.getVisibility() == View.VISIBLE; } /** * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying * the space). */ public void showLongPressTooltip() { // If we have alarm text to show, don't bother fading in the tooltip. if (!TextUtils.isEmpty(mNextAlarmText)) { // If we have status text to show, don't bother fading in the tooltip. if (hasStatusText()) { return; } Loading Loading @@ -384,11 +442,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue /** * Fades out the long press tooltip if it's partially visible - short circuits any running * animation. Additionally has the ability to fade in the alarm info text. * animation. Additionally has the ability to fade in the status info text. * * @param shouldShowAlarmText whether we should fade in the next alarm text * @param shouldShowStatusText whether we should fade in the status text */ private void hideLongPressTooltip(boolean shouldShowAlarmText) { private void hideLongPressTooltip(boolean shouldShowStatusText) { mLongPressTooltipView.animate().cancel(); if (mLongPressTooltipView.getVisibility() == View.VISIBLE && mLongPressTooltipView.getAlpha() != 0f) { Loading @@ -402,44 +460,40 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip"); mLongPressTooltipView.setVisibility(View.INVISIBLE); if (shouldShowAlarmText) { showAlarmText(); if (shouldShowStatusText) { showStatus(); } } }) .start(); } else { mLongPressTooltipView.setVisibility(View.INVISIBLE); if (shouldShowAlarmText) { showAlarmText(); if (shouldShowStatusText) { showStatus(); } } } /** * Fades in the updated alarm text. Note that if there's already an alarm showing, this will * immediately hide it and fade in the updated time. * Fades in the updated status text. Note that if there's already a status showing, this will * immediately hide it and fade in the updated status. */ private void showAlarmText() { mNextAlarmView.setAlpha(0f); mNextAlarmView.setVisibility(View.VISIBLE); mNextAlarmTextView.setText(mNextAlarmText); private void showStatus() { mStatusContainer.setAlpha(0f); mStatusContainer.setVisibility(View.VISIBLE); // Animate the alarm back in. Make sure to clear the animator listener for the animation! mNextAlarmView.animate() mStatusContainer.animate() .alpha(1f) .setDuration(FADE_ANIMATION_DURATION_MS) .setListener(null) .start(); } /** * Fades out and hides the next alarm text. This also resets the text contents to null in * preparation for the next alarm update. */ private void hideAlarmText() { if (mNextAlarmView.getVisibility() == View.VISIBLE) { mNextAlarmView.animate() /** Fades out and hides the status text. */ private void hideStatusText() { if (mStatusContainer.getVisibility() == View.VISIBLE) { mStatusContainer.animate() .alpha(0f) .setListener(new AnimatorListenerAdapter() { @Override Loading @@ -448,15 +502,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue // Reset the alpha regardless of how the animation ends for the next // time we show this view/want to animate it. mNextAlarmView.setVisibility(View.INVISIBLE); mNextAlarmView.setAlpha(1f); mNextAlarmTextView.setText(null); mStatusContainer.setVisibility(View.INVISIBLE); mStatusContainer.setAlpha(1f); } }) .start(); } else { // Next alarm view is already hidden, only need to clear the text. mNextAlarmTextView.setText(null); } } Loading