diff options
6 files changed, 424 insertions, 355 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java index fa3328417bd6..1e239b1e9ec9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java @@ -17,30 +17,44 @@ package com.android.systemui.qs; import com.android.systemui.R; +import com.android.systemui.util.ViewController; import javax.inject.Inject; -public class QSContainerImplController { - private final QSContainerImpl mView; +class QSContainerImplController extends ViewController<QSContainerImpl> { private final QuickStatusBarHeaderController mQuickStatusBarHeaderController; private QSContainerImplController(QSContainerImpl view, QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { - mView = view; + super(view); mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder .setQuickStatusBarHeader(mView.findViewById(R.id.header)).build(); } + @Override + public void init() { + super.init(); + mQuickStatusBarHeaderController.init(); + } + public void setListening(boolean listening) { mQuickStatusBarHeaderController.setListening(listening); } - public static class Builder { + @Override + protected void onViewAttached() { + } + + @Override + protected void onViewDetached() { + } + + static class Builder { private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder; private QSContainerImpl mView; @Inject - public Builder( + Builder( QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index f1bb8996e181..3a783653a2d8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -142,7 +142,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mQSContainerImplController = mQSContainerImplControllerBuilder .setQSContainerImpl((QSContainerImpl) view) .build(); - + mQSContainerImplController.init(); mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter); mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); @@ -367,14 +367,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca if (DEBUG) Log.d(TAG, "setListening " + listening); mListening = listening; mQSContainerImplController.setListening(listening); - mHeader.setListening(listening); mFooter.setListening(listening); mQSPanel.setListening(mListening, mQsExpanded); } @Override public void setHeaderListening(boolean listening) { - mHeader.setListening(listening); + mQSContainerImplController.setListening(listening); mFooter.setListening(listening); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 544249a51b08..a9fbc744b38e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -17,27 +17,16 @@ package com.android.systemui.qs; import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; - import android.annotation.ColorInt; -import android.app.AlarmManager; +import android.app.AlarmManager.AlarmClockInfo; import android.content.Context; -import android.content.Intent; import android.content.res.ColorStateList; 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.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.provider.AlarmClock; -import android.provider.Settings; -import android.service.notification.ZenModeConfig; -import android.text.format.DateUtils; import android.util.AttributeSet; -import android.util.Log; import android.util.MathUtils; import android.util.Pair; import android.view.ContextThemeWrapper; @@ -53,93 +42,48 @@ import android.widget.Space; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; -import com.android.internal.logging.UiEventLogger; import com.android.settingslib.Utils; import com.android.systemui.BatteryMeterView; import com.android.systemui.DualToneHandler; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.demomode.DemoMode; -import com.android.systemui.demomode.DemoModeController; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.privacy.OngoingPrivacyChip; -import com.android.systemui.privacy.PrivacyChipEvent; -import com.android.systemui.privacy.PrivacyItem; -import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.QSDetail.Callback; -import com.android.systemui.qs.carrier.QSCarrierGroup; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; import com.android.systemui.statusbar.phone.StatusBarWindowView; -import com.android.systemui.statusbar.phone.StatusIconContainer; import com.android.systemui.statusbar.policy.Clock; -import com.android.systemui.statusbar.policy.DateView; -import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.util.RingerModeTracker; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import java.util.Objects; -import javax.inject.Inject; -import javax.inject.Named; - /** * View that contains the top-most bits of the screen (primarily the status bar with date, time, and * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner * contents. */ -public class QuickStatusBarHeader extends RelativeLayout implements - View.OnClickListener, NextAlarmController.NextAlarmChangeCallback, - ZenModeController.Callback, LifecycleOwner { - private static final String TAG = "QuickStatusBarHeader"; - private static final boolean DEBUG = false; - - /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */ - private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6; - private static final int FADE_ANIMATION_DURATION_MS = 300; - private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0; - public static final int MAX_TOOLTIP_SHOWN_COUNT = 2; +public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwner { - private final NextAlarmController mAlarmController; - private final ZenModeController mZenController; - private final StatusBarIconController mStatusBarIconController; - private final ActivityStarter mActivityStarter; - - private QSPanel mQsPanel; + public static final int MAX_TOOLTIP_SHOWN_COUNT = 2; private boolean mExpanded; - private boolean mListening; private boolean mQsDisabled; - private QSCarrierGroup mCarrierGroup; protected QuickQSPanel mHeaderQsPanel; - protected QSTileHost mHost; - private TintedIconManager mIconManager; private TouchAnimator mStatusIconsAlphaAnimator; private TouchAnimator mHeaderTextContainerAlphaAnimator; private TouchAnimator mPrivacyChipAlphaAnimator; private DualToneHandler mDualToneHandler; - private final CommandQueue mCommandQueue; private View mSystemIconsView; private View mQuickQsStatusIcons; private View mHeaderTextContainerView; - 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; @@ -149,23 +93,13 @@ public class QuickStatusBarHeader extends RelativeLayout implements private TextView mRingerModeTextView; private View mRingerContainer; private Clock mClockView; - private DateView mDateView; private OngoingPrivacyChip mPrivacyChip; private Space mSpace; private BatteryMeterView mBatteryRemainingIcon; - private RingerModeTracker mRingerModeTracker; - private DemoModeController mDemoModeController; - private DemoMode mDemoModeReceiver; - private UserTracker mUserTracker; - private boolean mAllIndicatorsEnabled; - private boolean mMicCameraIndicatorsEnabled; - - private PrivacyItemController mPrivacyItemController; - private final UiEventLogger mUiEventLogger; + // Used for RingerModeTracker private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); - private boolean mHasTopCutout = false; private int mStatusBarPaddingTop = 0; private int mRoundedCornerPadding = 0; private int mContentMarginStart; @@ -175,59 +109,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements private int mCutOutPaddingRight; private float mExpandedHeaderAlpha = 1.0f; private float mKeyguardExpansionFraction; - private boolean mPrivacyChipLogged = false; - - private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() { - @Override - public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) { - mPrivacyChip.setPrivacyList(privacyItems); - setChipVisibility(!privacyItems.isEmpty()); - } - - @Override - public void onFlagAllChanged(boolean flag) { - if (mAllIndicatorsEnabled != flag) { - mAllIndicatorsEnabled = flag; - update(); - } - } - @Override - public void onFlagMicCameraChanged(boolean flag) { - if (mMicCameraIndicatorsEnabled != flag) { - mMicCameraIndicatorsEnabled = flag; - update(); - } - } - - private void update() { - StatusIconContainer iconContainer = requireViewById(R.id.statusIcons); - iconContainer.setIgnoredSlots(getIgnoredIconSlots()); - setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty()); - } - }; - - @Inject - public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - NextAlarmController nextAlarmController, ZenModeController zenModeController, - StatusBarIconController statusBarIconController, - ActivityStarter activityStarter, PrivacyItemController privacyItemController, - CommandQueue commandQueue, RingerModeTracker ringerModeTracker, - UiEventLogger uiEventLogger, DemoModeController demoModeController, - UserTracker userTracker) { + public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); - mAlarmController = nextAlarmController; - mZenController = zenModeController; - mStatusBarIconController = statusBarIconController; - mActivityStarter = activityStarter; - mPrivacyItemController = privacyItemController; mDualToneHandler = new DualToneHandler( new ContextThemeWrapper(context, R.style.QSHeaderTheme)); - mCommandQueue = commandQueue; - mRingerModeTracker = ringerModeTracker; - mUiEventLogger = uiEventLogger; - mDemoModeController = demoModeController; - mUserTracker = userTracker; } @Override @@ -237,11 +123,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mHeaderQsPanel = findViewById(R.id.quick_qs_panel); mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons); mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons); - StatusIconContainer iconContainer = findViewById(R.id.statusIcons); - // Ignore privacy icons because they show in the space above QQS - iconContainer.addIgnoredSlots(getIgnoredIconSlots()); - iconContainer.setShouldRestrictIcons(false); - mIconManager = new TintedIconManager(iconContainer, mCommandQueue); // Views corresponding to the header info section (e.g. ringer and next alarm). mHeaderTextContainerView = findViewById(R.id.header_text_container); @@ -249,36 +130,18 @@ public class QuickStatusBarHeader extends RelativeLayout implements mNextAlarmIcon = findViewById(R.id.next_alarm_icon); mNextAlarmTextView = findViewById(R.id.next_alarm_text); mNextAlarmContainer = findViewById(R.id.alarm_container); - mNextAlarmContainer.setOnClickListener(this::onClick); mRingerModeIcon = findViewById(R.id.ringer_mode_icon); mRingerModeTextView = findViewById(R.id.ringer_mode_text); mRingerContainer = findViewById(R.id.ringer_container); - mRingerContainer.setOnClickListener(this::onClick); mPrivacyChip = findViewById(R.id.privacy_chip); - mPrivacyChip.setOnClickListener(this::onClick); - mCarrierGroup = findViewById(R.id.carrier_group); - updateResources(); Rect tintArea = new Rect(0, 0, 0, 0); - int colorForeground = Utils.getColorAttrDefaultColor(getContext(), - android.R.attr.colorForeground); - float intensity = getColorIntensity(colorForeground); - int fillColor = mDualToneHandler.getSingleColor(intensity); - // Set light text on the header icons because they will always be on a black background applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT); - // Set the correct tint for the status icons so they contrast - mIconManager.setTint(fillColor); - mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor)); - mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor)); - mClockView = findViewById(R.id.clock); - mClockView.setOnClickListener(this); - mDemoModeReceiver = new ClockDemoModeReceiver(mClockView); - mDateView = findViewById(R.id.date); mSpace = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() @@ -290,33 +153,28 @@ public class QuickStatusBarHeader extends RelativeLayout implements mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); mRingerModeTextView.setSelected(true); mNextAlarmTextView.setSelected(true); + } - mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); - mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); + void onAttach(TintedIconManager iconManager) { + int colorForeground = Utils.getColorAttrDefaultColor(getContext(), + android.R.attr.colorForeground); + float intensity = getColorIntensity(colorForeground); + int fillColor = mDualToneHandler.getSingleColor(intensity); + + // Set the correct tint for the status icons so they contrast + iconManager.setTint(fillColor); + mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor)); + mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor)); } public QuickQSPanel getHeaderQsPanel() { return mHeaderQsPanel; } - private List<String> getIgnoredIconSlots() { - ArrayList<String> ignored = new ArrayList<>(); - if (getChipEnabled()) { - ignored.add(mContext.getResources().getString( - com.android.internal.R.string.status_bar_camera)); - ignored.add(mContext.getResources().getString( - com.android.internal.R.string.status_bar_microphone)); - if (mAllIndicatorsEnabled) { - ignored.add(mContext.getResources().getString( - com.android.internal.R.string.status_bar_location)); - } - } - - return ignored; - } - - private void updateStatusText() { - boolean changed = updateRingerStatus() || updateAlarmStatus(); + void updateStatusText(int ringerMode, AlarmClockInfo nextAlarm, boolean zenOverridingRinger, + boolean use24HourFormat) { + boolean changed = updateRingerStatus(ringerMode, zenOverridingRinger) + || updateAlarmStatus(nextAlarm, use24HourFormat); if (changed) { boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE; @@ -326,32 +184,17 @@ public class QuickStatusBarHeader extends RelativeLayout implements } } - private void setChipVisibility(boolean chipVisible) { - if (chipVisible && getChipEnabled()) { - mPrivacyChip.setVisibility(View.VISIBLE); - // Makes sure that the chip is logged as viewed at most once each time QS is opened - // mListening makes sure that the callback didn't return after the user closed QS - if (!mPrivacyChipLogged && mListening) { - mPrivacyChipLogged = true; - mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW); - } - } else { - mPrivacyChip.setVisibility(View.GONE); - } - } - - private boolean updateRingerStatus() { + private boolean updateRingerStatus(int ringerMode, boolean zenOverridingRinger) { boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE; CharSequence originalRingerText = mRingerModeTextView.getText(); boolean ringerVisible = false; - if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(), - mZenController.getConsolidatedPolicy())) { - if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { + if (!zenOverridingRinger) { + if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate); mRingerModeTextView.setText(R.string.qs_status_phone_vibrate); ringerVisible = true; - } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) { + } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) { mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute); mRingerModeTextView.setText(R.string.qs_status_phone_muted); ringerVisible = true; @@ -365,14 +208,14 @@ public class QuickStatusBarHeader extends RelativeLayout implements !Objects.equals(originalRingerText, mRingerModeTextView.getText()); } - private boolean updateAlarmStatus() { + private boolean updateAlarmStatus(AlarmClockInfo nextAlarm, boolean use24HourFormat) { boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE; CharSequence originalAlarmText = mNextAlarmTextView.getText(); boolean alarmVisible = false; - if (mNextAlarm != null) { + if (nextAlarm != null) { alarmVisible = true; - mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm)); + mNextAlarmTextView.setText(formatNextAlarm(nextAlarm, use24HourFormat)); } mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); @@ -419,7 +262,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements setMinimumHeight(sbHeight + qqsHeight); } - private void updateResources() { + void updateResources() { Resources resources = mContext.getResources(); updateMinimumHeight(); @@ -529,18 +372,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements } @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> { - mRingerMode = ringer; - updateStatusText(); - }); - mStatusBarIconController.addIconGroup(mIconManager); - mDemoModeController.addCallback(mDemoModeReceiver); - requestApplyInsets(); - } - - @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { // Handle padding of the clock DisplayCutout cutout = insets.getDisplayCutout(); @@ -563,17 +394,14 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (cutout != null) { Rect topCutout = cutout.getBoundingRectTop(); if (topCutout.isEmpty() || cornerCutout) { - mHasTopCutout = false; lp.width = 0; mSpace.setVisibility(View.GONE); } else { - mHasTopCutout = true; lp.width = topCutout.width(); mSpace.setVisibility(View.VISIBLE); } } mSpace.setLayoutParams(lp); - setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE); mCutOutPaddingLeft = padding.first; mCutOutPaddingRight = padding.second; mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top; @@ -611,103 +439,14 @@ public class QuickStatusBarHeader extends RelativeLayout implements 0); } - @Override - @VisibleForTesting - public void onDetachedFromWindow() { - setListening(false); - mRingerModeTracker.getRingerModeInternal().removeObservers(this); - mStatusBarIconController.removeIconGroup(mIconManager); - mDemoModeController.removeCallback(mDemoModeReceiver); - super.onDetachedFromWindow(); - } - - public void setListening(boolean listening) { - if (listening == mListening) { - return; - } - mHeaderQsPanel.setListening(listening); - if (mHeaderQsPanel.switchTileLayout()) { - updateResources(); - } - mListening = listening; - - if (listening) { - mZenController.addCallback(this); - mAlarmController.addCallback(this); - mLifecycle.setCurrentState(Lifecycle.State.RESUMED); - // Get the most up to date info - mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); - mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); - mPrivacyItemController.addCallback(mPICCallback); - } else { - mZenController.removeCallback(this); - mAlarmController.removeCallback(this); - mLifecycle.setCurrentState(Lifecycle.State.CREATED); - mPrivacyItemController.removeCallback(mPICCallback); - mPrivacyChipLogged = false; - } - } - - @Override - public void onClick(View v) { - if (v == mClockView) { - mActivityStarter.postStartActivityDismissingKeyguard(new Intent( - AlarmClock.ACTION_SHOW_ALARMS), 0); - } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) { - if (mNextAlarm.getShowIntent() != null) { - mActivityStarter.postStartActivityDismissingKeyguard( - mNextAlarm.getShowIntent()); - } else { - Log.d(TAG, "No PendingIntent for next alarm. Using default intent"); - mActivityStarter.postStartActivityDismissingKeyguard(new Intent( - AlarmClock.ACTION_SHOW_ALARMS), 0); - } - } else if (v == mPrivacyChip) { - // If the privacy chip is visible, it means there were some indicators - Handler mUiHandler = new Handler(Looper.getMainLooper()); - mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK); - mUiHandler.post(() -> { - mActivityStarter.postStartActivityDismissingKeyguard( - new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); - mHost.collapsePanels(); - }); - } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) { - mActivityStarter.postStartActivityDismissingKeyguard(new Intent( - Settings.ACTION_SOUND_SETTINGS), 0); - } - } - - @Override - public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { - mNextAlarm = nextAlarm; - updateStatusText(); - } - - @Override - public void onZenChanged(int zen) { - updateStatusText(); - } - - @Override - public void onConfigChanged(ZenModeConfig config) { - updateStatusText(); - } - public void updateEverything() { post(() -> setClickable(!mExpanded)); } public void setQSPanel(final QSPanel qsPanel) { - mQsPanel = qsPanel; - setupHost(qsPanel.getHost()); - } - - public void setupHost(final QSTileHost host) { - mHost = host; //host.setHeaderView(mExpandIndicator); - mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this); - mHeaderQsPanel.setHost(host, null /* No customization in header */); - + mHeaderQsPanel.setQSPanelAndHeader(qsPanel, this); + mHeaderQsPanel.setHost(qsPanel.getHost(), null /* No customization in header */); Rect tintArea = new Rect(0, 0, 0, 0); int colorForeground = Utils.getColorAttrDefaultColor(getContext(), @@ -721,12 +460,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements mHeaderQsPanel.setCallback(qsPanelCallback); } - private String formatNextAlarm(AlarmManager.AlarmClockInfo info) { + private String formatNextAlarm(AlarmClockInfo info, boolean use24HourFormat) { if (info == null) { return ""; } - String skeleton = android.text.format.DateFormat - .is24HourFormat(mContext, mUserTracker.getUserId()) ? "EHm" : "Ehma"; + String skeleton = use24HourFormat ? "EHm" : "Ehma"; String pattern = android.text.format.DateFormat .getBestDateTimePattern(Locale.getDefault(), skeleton); return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString(); @@ -777,37 +515,4 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateHeaderTextContainerAlphaAnimator(); } } - - private boolean getChipEnabled() { - return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled; - } - - private static class ClockDemoModeReceiver implements DemoMode { - private Clock mClockView; - - @Override - public List<String> demoCommands() { - return List.of(COMMAND_CLOCK); - } - - ClockDemoModeReceiver(Clock clockView) { - mClockView = clockView; - } - - @Override - public void dispatchDemoCommand(String command, Bundle args) { - mClockView.dispatchDemoCommand(command, args); - } - - @Override - public void onDemoModeStarted() { - mClockView.onDemoModeStarted(); - } - - @Override - public void onDemoModeFinished() { - mClockView.onDemoModeFinished(); - } - } - } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index d899acbade4a..676a300b0ff2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -16,36 +16,393 @@ package com.android.systemui.qs; +import android.app.AlarmManager.AlarmClockInfo; +import android.content.Intent; +import android.media.AudioManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.provider.AlarmClock; +import android.provider.Settings; +import android.service.notification.ZenModeConfig; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; + +import androidx.annotation.NonNull; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; + +import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.privacy.OngoingPrivacyChip; +import com.android.systemui.privacy.PrivacyChipEvent; +import com.android.systemui.privacy.PrivacyItem; +import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.carrier.QSCarrierGroupController; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusIconContainer; +import com.android.systemui.statusbar.policy.Clock; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.statusbar.policy.ZenModeController.Callback; +import com.android.systemui.util.RingerModeTracker; +import com.android.systemui.util.ViewController; + +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; -public class QuickStatusBarHeaderController { - private final QuickStatusBarHeader mView; +/** + * Controller for {@link QuickStatusBarHeader}. + */ +class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader> { + private static final String TAG = "QuickStatusBarHeader"; + + private final ZenModeController mZenModeController; + private final NextAlarmController mNextAlarmController; + private final PrivacyItemController mPrivacyItemController; + private final RingerModeTracker mRingerModeTracker; + private final ActivityStarter mActivityStarter; + private final UiEventLogger mUiEventLogger; private final QSCarrierGroupController mQSCarrierGroupController; + private final QuickQSPanel mHeaderQsPanel; + private final LifecycleRegistry mLifecycle; + private final OngoingPrivacyChip mPrivacyChip; + private final Clock mClockView; + private final View mNextAlarmContainer; + private final View mRingerContainer; + private final QSTileHost mQSTileHost; + private final StatusBarIconController mStatusBarIconController; + private final CommandQueue mCommandQueue; + private final DemoModeController mDemoModeController; + private final UserTracker mUserTracker; + private final StatusIconContainer mIconContainer; + private final StatusBarIconController.TintedIconManager mIconManager; + private final DemoMode mDemoModeReceiver; + + private boolean mListening; + private AlarmClockInfo mNextAlarm; + private boolean mAllIndicatorsEnabled; + private boolean mMicCameraIndicatorsEnabled; + private boolean mPrivacyChipLogged; + private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; + + private final ZenModeController.Callback mZenModeControllerCallback = new Callback() { + @Override + public void onZenChanged(int zen) { + mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(), + use24HourFormat()); + } + + @Override + public void onConfigChanged(ZenModeConfig config) { + mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(), + use24HourFormat()); + } + }; + + private boolean use24HourFormat() { + return android.text.format.DateFormat.is24HourFormat( + mView.getContext(), mUserTracker.getUserId()); + + } + + private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() { + @Override + public void onNextAlarmChanged(AlarmClockInfo nextAlarm) { + mNextAlarm = nextAlarm; + mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(), + use24HourFormat()); + } + }; + + private final LifecycleOwner mLifecycleOwner = new LifecycleOwner() { + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifecycle; + } + }; + + private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() { + @Override + public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) { + mPrivacyChip.setPrivacyList(privacyItems); + setChipVisibility(!privacyItems.isEmpty()); + } + + @Override + public void onFlagAllChanged(boolean flag) { + if (mAllIndicatorsEnabled != flag) { + mAllIndicatorsEnabled = flag; + update(); + } + } + + @Override + public void onFlagMicCameraChanged(boolean flag) { + if (mMicCameraIndicatorsEnabled != flag) { + mMicCameraIndicatorsEnabled = flag; + update(); + } + } + + private void update() { + StatusIconContainer iconContainer = mView.requireViewById(R.id.statusIcons); + iconContainer.setIgnoredSlots(getIgnoredIconSlots()); + setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty()); + } + }; + + private View.OnClickListener mOnClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + if (v == mClockView) { + mActivityStarter.postStartActivityDismissingKeyguard(new Intent( + AlarmClock.ACTION_SHOW_ALARMS), 0); + } else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) { + if (mNextAlarm.getShowIntent() != null) { + mActivityStarter.postStartActivityDismissingKeyguard( + mNextAlarm.getShowIntent()); + } else { + Log.d(TAG, "No PendingIntent for next alarm. Using default intent"); + mActivityStarter.postStartActivityDismissingKeyguard(new Intent( + AlarmClock.ACTION_SHOW_ALARMS), 0); + } + } else if (v == mPrivacyChip) { + // If the privacy chip is visible, it means there were some indicators + Handler mUiHandler = new Handler(Looper.getMainLooper()); + mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK); + mUiHandler.post(() -> { + mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); + mQSTileHost.collapsePanels(); + }); + } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) { + mActivityStarter.postStartActivityDismissingKeyguard(new Intent( + Settings.ACTION_SOUND_SETTINGS), 0); + } + } + }; private QuickStatusBarHeaderController(QuickStatusBarHeader view, + ZenModeController zenModeController, NextAlarmController nextAlarmController, + PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker, + ActivityStarter activityStarter, UiEventLogger uiEventLogger, + QSTileHost qsTileHost, StatusBarIconController statusBarIconController, + CommandQueue commandQueue, DemoModeController demoModeController, + UserTracker userTracker, QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { - mView = view; + super(view); + mZenModeController = zenModeController; + mNextAlarmController = nextAlarmController; + mPrivacyItemController = privacyItemController; + mRingerModeTracker = ringerModeTracker; + mActivityStarter = activityStarter; + mUiEventLogger = uiEventLogger; + mQSTileHost = qsTileHost; + mStatusBarIconController = statusBarIconController; + mCommandQueue = commandQueue; + mDemoModeController = demoModeController; + mUserTracker = userTracker; + mLifecycle = new LifecycleRegistry(mLifecycleOwner); + mQSCarrierGroupController = qsCarrierGroupControllerBuilder .setQSCarrierGroup(mView.findViewById(R.id.carrier_group)) .build(); + + + mPrivacyChip = mView.findViewById(R.id.privacy_chip); + mHeaderQsPanel = mView.findViewById(R.id.quick_qs_panel); + mNextAlarmContainer = mView.findViewById(R.id.alarm_container); + mClockView = mView.findViewById(R.id.clock); + mRingerContainer = mView.findViewById(R.id.ringer_container); + mIconContainer = mView.findViewById(R.id.statusIcons); + + mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mCommandQueue); + mDemoModeReceiver = new ClockDemoModeReceiver(mClockView); + } + + @Override + protected void onViewAttached() { + mRingerModeTracker.getRingerModeInternal().observe(mLifecycleOwner, ringer -> { + mRingerMode = ringer; + mView.updateStatusText(mRingerMode, mNextAlarm, isZenOverridingRinger(), + use24HourFormat()); + }); + + mClockView.setOnClickListener(mOnClickListener); + mNextAlarmContainer.setOnClickListener(mOnClickListener); + mRingerContainer.setOnClickListener(mOnClickListener); + mPrivacyChip.setOnClickListener(mOnClickListener); + + // Ignore privacy icons because they show in the space above QQS + mIconContainer.addIgnoredSlots(getIgnoredIconSlots()); + mIconContainer.setShouldRestrictIcons(false); + mStatusBarIconController.addIconGroup(mIconManager); + + mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); + mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); + + setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE); + + mView.onAttach(mIconManager); + + mDemoModeController.addCallback(mDemoModeReceiver); + } + + @Override + protected void onViewDetached() { + mRingerModeTracker.getRingerModeInternal().removeObservers(mLifecycleOwner); + mClockView.setOnClickListener(null); + mNextAlarmContainer.setOnClickListener(null); + mRingerContainer.setOnClickListener(null); + mPrivacyChip.setOnClickListener(null); + mStatusBarIconController.removeIconGroup(mIconManager); + mDemoModeController.removeCallback(mDemoModeReceiver); + setListening(false); } public void setListening(boolean listening) { mQSCarrierGroupController.setListening(listening); - // TODO: move mView.setListening logic into here. - mView.setListening(listening); + + if (listening == mListening) { + return; + } + mListening = listening; + + mHeaderQsPanel.setListening(listening); + if (mHeaderQsPanel.switchTileLayout()) { + mView.updateResources(); + } + + if (listening) { + mZenModeController.addCallback(mZenModeControllerCallback); + mNextAlarmController.addCallback(mNextAlarmChangeCallback); + mLifecycle.setCurrentState(Lifecycle.State.RESUMED); + // Get the most up to date info + mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable(); + mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable(); + mPrivacyItemController.addCallback(mPICCallback); + } else { + mZenModeController.removeCallback(mZenModeControllerCallback); + mNextAlarmController.removeCallback(mNextAlarmChangeCallback); + mLifecycle.setCurrentState(Lifecycle.State.CREATED); + mPrivacyItemController.removeCallback(mPICCallback); + mPrivacyChipLogged = false; + } } + private void setChipVisibility(boolean chipVisible) { + if (chipVisible && getChipEnabled()) { + mPrivacyChip.setVisibility(View.VISIBLE); + // Makes sure that the chip is logged as viewed at most once each time QS is opened + // mListening makes sure that the callback didn't return after the user closed QS + if (!mPrivacyChipLogged && mListening) { + mPrivacyChipLogged = true; + mUiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_VIEW); + } + } else { + mPrivacyChip.setVisibility(View.GONE); + } + } - public static class Builder { + private List<String> getIgnoredIconSlots() { + ArrayList<String> ignored = new ArrayList<>(); + if (getChipEnabled()) { + ignored.add(mView.getResources().getString( + com.android.internal.R.string.status_bar_camera)); + ignored.add(mView.getResources().getString( + com.android.internal.R.string.status_bar_microphone)); + if (mAllIndicatorsEnabled) { + ignored.add(mView.getResources().getString( + com.android.internal.R.string.status_bar_location)); + } + } + + return ignored; + } + + private boolean getChipEnabled() { + return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled; + } + + private boolean isZenOverridingRinger() { + return ZenModeConfig.isZenOverridingRinger(mZenModeController.getZen(), + mZenModeController.getConsolidatedPolicy()); + } + + + private static class ClockDemoModeReceiver implements DemoMode { + private Clock mClockView; + + @Override + public List<String> demoCommands() { + return List.of(COMMAND_CLOCK); + } + + ClockDemoModeReceiver(Clock clockView) { + mClockView = clockView; + } + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + mClockView.dispatchDemoCommand(command, args); + } + + @Override + public void onDemoModeStarted() { + mClockView.onDemoModeStarted(); + } + + @Override + public void onDemoModeFinished() { + mClockView.onDemoModeFinished(); + } + } + + static class Builder { + private final ZenModeController mZenModeController; + private final NextAlarmController mNextAlarmController; + private final PrivacyItemController mPrivacyItemController; + private final RingerModeTracker mRingerModeTracker; + private final ActivityStarter mActivityStarter; + private final UiEventLogger mUiEventLogger; + private final QSTileHost mQsTileHost; + private final StatusBarIconController mStatusBarIconController; + private final CommandQueue mCommandQueue; + private final DemoModeController mDemoModeController; + private final UserTracker mUserTracker; private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder; private QuickStatusBarHeader mView; @Inject - public Builder(QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { + Builder(ZenModeController zenModeController, NextAlarmController nextAlarmController, + PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker, + ActivityStarter activityStarter, UiEventLogger uiEventLogger, QSTileHost qsTileHost, + StatusBarIconController statusBarIconController, CommandQueue commandQueue, + DemoModeController demoModeController, UserTracker userTracker, + QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { + mZenModeController = zenModeController; + mNextAlarmController = nextAlarmController; + mPrivacyItemController = privacyItemController; + mRingerModeTracker = ringerModeTracker; + mActivityStarter = activityStarter; + mUiEventLogger = uiEventLogger; + mQsTileHost = qsTileHost; + mStatusBarIconController = statusBarIconController; + mCommandQueue = commandQueue; + mDemoModeController = demoModeController; + mUserTracker = userTracker; mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder; } @@ -54,8 +411,13 @@ public class QuickStatusBarHeaderController { return this; } - public QuickStatusBarHeaderController build() { - return new QuickStatusBarHeaderController(mView, mQSCarrierGroupControllerBuilder); + + QuickStatusBarHeaderController build() { + return new QuickStatusBarHeaderController(mView, mZenModeController, + mNextAlarmController, mPrivacyItemController, mRingerModeTracker, + mActivityStarter, mUiEventLogger, mQsTileHost, mStatusBarIconController, + mCommandQueue, mDemoModeController, mUserTracker, + mQSCarrierGroupControllerBuilder); } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index a6cd350b33ce..344f0d2f5506 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -27,7 +27,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.qs.QSFooterImpl; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QuickQSPanel; -import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -93,10 +92,6 @@ public class InjectionInflationController { } /** - * Creates the QuickStatusBarHeader. - */ - QuickStatusBarHeader createQsHeader(); - /** * Creates the QSFooterImpl. */ QSFooterImpl createQsFooter(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 1c2d08402e69..e472cb22ed6b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -37,7 +37,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.CarrierText; import com.android.systemui.Dependency; -import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -116,11 +115,6 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { qs.setListening(false); processAllMessages(); - - // Manually push header through detach so it can handle standard cleanup it does on - // removed from window. - ((QuickStatusBarHeader) qs.getView().findViewById(R.id.header)).onDetachedFromWindow(); - host.destroy(); processAllMessages(); } |