diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 39a6ed12c02d8..3de0fbdf8fb10 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -669,7 +669,7 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml new file mode 100644 index 0000000000000..a38b8b4e62dbb --- /dev/null +++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_brightness.xml b/packages/SystemUI/res/drawable/ic_brightness.xml new file mode 100644 index 0000000000000..f44333236a12d --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_brightness.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/brightness_mirror.xml b/packages/SystemUI/res/layout/brightness_mirror.xml index e3440b53d2151..8b47ab915fb41 100644 --- a/packages/SystemUI/res/layout/brightness_mirror.xml +++ b/packages/SystemUI/res/layout/brightness_mirror.xml @@ -21,12 +21,5 @@ android:layout_height="@dimen/brightness_mirror_height" android:layout_gravity="@integer/notification_panel_layout_gravity" android:visibility="invisible"> - - - + diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml index 12127f5290546..11814a1caffae 100644 --- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml @@ -20,7 +20,7 @@ android:layout_gravity="center_vertical" style="@style/BrightnessDialogContainer"> - + systemui:text="@string/status_bar_settings_auto_brightness_label" > + + + + + + + + + diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml new file mode 100644 index 0000000000000..e08b44af10681 --- /dev/null +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml deleted file mode 100644 index 942f3dd03a8d4..0000000000000 --- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - diff --git a/packages/SystemUI/res/values-h740dp-port/dimens.xml b/packages/SystemUI/res/values-h740dp-port/dimens.xml index 966066ffe56b7..4a23ee637e2db 100644 --- a/packages/SystemUI/res/values-h740dp-port/dimens.xml +++ b/packages/SystemUI/res/values-h740dp-port/dimens.xml @@ -19,9 +19,9 @@ 24dp - 46dp + 54dp 18dp \ No newline at end of file diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index e45f4eb3f2cae..51d7b8eff5fc3 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -22,8 +22,6 @@ 2dp 16dp - 40dp - 8dp 0dp diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4a5e890d56b1d..d946f7cb11c15 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -430,7 +430,7 @@ @dimen/match_parent - 48dp + 56dp @dimen/notification_panel_width @@ -496,10 +496,10 @@ 12dp -12dp - 28dp + 36dp 0dp -1dp 44dp diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index d13e194a0d447..13ff3f5c4e6cd 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -21,7 +21,7 @@ import android.app.Activity; import com.android.systemui.ForegroundServicesDialog; import com.android.systemui.keyguard.WorkLockActivity; import com.android.systemui.screenrecord.ScreenRecordDialog; -import com.android.systemui.settings.BrightnessDialog; +import com.android.systemui.settings.brightness.BrightnessDialog; import com.android.systemui.tuner.TunerActivity; import com.android.systemui.usb.UsbDebuggingActivity; import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 758e0c566e5d6..08f38a83a4114 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -47,9 +47,8 @@ import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.settings.ToggleSliderView; +import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.statusbar.policy.BrightnessMirrorController; -import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.animation.DisappearParameters; @@ -62,7 +61,7 @@ import javax.inject.Inject; import javax.inject.Named; /** View that represents the quick settings tile panel (when expanded/pulled down). **/ -public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorListener { +public class QSPanel extends LinearLayout implements Tunable { public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness"; public static final String QS_SHOW_HEADER = "qs_show_header"; @@ -75,10 +74,12 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi /** * The index where the content starts that needs to be moved between parents */ - private final int mMovableContentStartIndex; + private int mMovableContentStartIndex; @Nullable protected View mBrightnessView; + @Nullable + protected BrightnessSlider mToggleSliderController; private final H mHandler = new H(); private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -153,7 +154,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi setOrientation(VERTICAL); - addViewsAboveTiles(); mMovableContentStartIndex = getChildCount(); mRegularTileLayout = createRegularTileLayout(); mTileLayout = mRegularTileLayout; @@ -191,10 +191,19 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi } } - protected void addViewsAboveTiles() { - mBrightnessView = LayoutInflater.from(mContext).inflate( - R.layout.quick_settings_brightness_dialog, this, false); - addView(mBrightnessView); + /** + * Add brightness view above the tile layout. + * + * Used to add the brightness slider after construction. + */ + public void setBrightnessView(@NonNull View view) { + if (mBrightnessView != null) { + removeView(mBrightnessView); + mMovableContentStartIndex--; + } + addView(view, 0); + mBrightnessView = view; + mMovableContentStartIndex++; } /** */ @@ -321,22 +330,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi } } - public void setBrightnessMirror(BrightnessMirrorController c) { - if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.removeCallback(this); - } - mBrightnessMirrorController = c; - if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.addCallback(this); - } - updateBrightnessMirror(); - } - - @Override - public void onBrightnessMirrorReinflated(View brightnessMirror) { - updateBrightnessMirror(); - } - @Nullable View getBrightnessView() { return mBrightnessView; @@ -415,8 +408,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi super.onConfigurationChanged(newConfig); mOnConfigurationChangedListeners.forEach( listener -> listener.onConfigurationChange(newConfig)); - - updateBrightnessMirror(); } @Override @@ -578,16 +569,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi } } - public void updateBrightnessMirror() { - if (mBrightnessMirrorController != null) { - ToggleSliderView brightnessSlider = findViewById(R.id.brightness_slider); - ToggleSliderView mirrorSlider = mBrightnessMirrorController.getMirror() - .findViewById(R.id.brightness_slider); - brightnessSlider.setMirror(mirrorSlider); - brightnessSlider.setMirrorController(mBrightnessMirrorController); - } - } - public void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mQSLogger.logPanelExpanded(expanded, getDumpableTag()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index eef7e39c992d5..addaf7e456b84 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -26,14 +26,14 @@ import android.view.ViewGroup; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.R; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.customize.QSCustomizerController; import com.android.systemui.qs.dagger.QSScope; -import com.android.systemui.settings.BrightnessController; +import com.android.systemui.settings.brightness.BrightnessController; +import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.tuner.TunerService; @@ -50,6 +50,8 @@ public class QSPanelController extends QSPanelControllerBase { private final TunerService mTunerService; private final QSCustomizerController mQsCustomizerController; private final BrightnessController mBrightnessController; + private final BrightnessSlider.Factory mBrightnessSliderFactory; + private final BrightnessSlider mBrightnessSlider; private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener = new QSPanel.OnConfigurationChangedListener() { @@ -60,29 +62,39 @@ public class QSPanelController extends QSPanelControllerBase { if (mView.isListening()) { refreshAllTiles(); } + updateBrightnessMirror(); } }; private BrightnessMirrorController mBrightnessMirrorController; + private final BrightnessMirrorController.BrightnessMirrorListener mBrightnessMirrorListener = + mirror -> updateBrightnessMirror(); + @Inject QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService, QSTileHost qstileHost, QSCustomizerController qsCustomizerController, QSTileRevealController.Factory qsTileRevealControllerFactory, DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, - BrightnessController.Factory brightnessControllerFactory) { + BrightnessController.Factory brightnessControllerFactory, + BrightnessSlider.Factory brightnessSliderFactory) { super(view, qstileHost, qsCustomizerController, qsTileRevealControllerFactory, metricsLogger, uiEventLogger, dumpManager); mQsSecurityFooter = qsSecurityFooter; mTunerService = tunerService; mQsCustomizerController = qsCustomizerController; mQsSecurityFooter.setHostEnvironment(qstileHost); - mBrightnessController = brightnessControllerFactory.create( - mView.findViewById(R.id.brightness_slider)); + mBrightnessSliderFactory = brightnessSliderFactory; + + mBrightnessSlider = mBrightnessSliderFactory.create(getContext(), mView); + mView.setBrightnessView(mBrightnessSlider.getRootView()); + + mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider); } @Override public void onInit() { mQsCustomizerController.init(); + mBrightnessSlider.init(); } @Override @@ -97,7 +109,7 @@ public class QSPanelController extends QSPanelControllerBase { mView.setSecurityFooter(mQsSecurityFooter.getView()); switchTileLayout(true); if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.addCallback(mView); + mBrightnessMirrorController.addCallback(mBrightnessMirrorListener); } } @@ -106,7 +118,7 @@ public class QSPanelController extends QSPanelControllerBase { mTunerService.removeTunable(mView); mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener); if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.removeCallback(mView); + mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener); } super.onViewDetached(); } @@ -154,7 +166,20 @@ public class QSPanelController extends QSPanelControllerBase { /** */ public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) { mBrightnessMirrorController = brightnessMirrorController; - mView.setBrightnessMirror(brightnessMirrorController); + if (mBrightnessMirrorController != null) { + mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener); + } + mBrightnessMirrorController = brightnessMirrorController; + if (mBrightnessMirrorController != null) { + mBrightnessMirrorController.addCallback(mBrightnessMirrorListener); + } + updateBrightnessMirror(); + } + + private void updateBrightnessMirror() { + if (mBrightnessMirrorController != null) { + mBrightnessSlider.setMirrorControllerAndMirror(mBrightnessMirrorController); + } } /** Get the QSTileHost this panel uses. */ diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 9c421b0e4f6e5..dde9a1fdf01bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -75,8 +75,8 @@ public class QuickQSPanel extends QSPanel { } @Override - protected void addViewsAboveTiles() { - // Nothing to add above the tiles + public void setBrightnessView(View view) { + // Don't add brightness view } @Override diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java deleted file mode 100644 index 90744a62677dd..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -package com.android.systemui.settings; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.RelativeLayout; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; - -import com.android.settingslib.RestrictedLockUtils; -import com.android.systemui.R; -import com.android.systemui.statusbar.policy.BrightnessMirrorController; - -public class ToggleSliderView extends RelativeLayout implements ToggleSlider { - private Listener mListener; - private boolean mTracking; - - private CompoundButton mToggle; - private ToggleSeekBar mSlider; - private TextView mLabel; - - private ToggleSliderView mMirror; - private BrightnessMirrorController mMirrorController; - - public ToggleSliderView(Context context) { - this(context, null); - } - - public ToggleSliderView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ToggleSliderView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - View.inflate(context, R.layout.status_bar_toggle_slider, this); - - final Resources res = context.getResources(); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.ToggleSliderView, defStyle, 0); - - mToggle = findViewById(R.id.toggle); - mToggle.setOnCheckedChangeListener(mCheckListener); - - mSlider = findViewById(R.id.slider); - mSlider.setOnSeekBarChangeListener(mSeekListener); - - mLabel = findViewById(R.id.label); - mLabel.setText(a.getString(R.styleable.ToggleSliderView_text)); - - mSlider.setAccessibilityLabel(getContentDescription().toString()); - - a.recycle(); - } - - public void setMirror(ToggleSliderView toggleSlider) { - mMirror = toggleSlider; - if (mMirror != null) { - mMirror.setChecked(mToggle.isChecked()); - mMirror.setMax(mSlider.getMax()); - mMirror.setValue(mSlider.getProgress()); - } - } - - public void setMirrorController(BrightnessMirrorController c) { - mMirrorController = c; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (mListener != null) { - mListener.onInit(this); - } - } - - public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) { - mToggle.setEnabled(admin == null); - mSlider.setEnabled(admin == null); - mSlider.setEnforcedAdmin(admin); - } - - public void setOnChangedListener(Listener l) { - mListener = l; - } - - @Override - public void setChecked(boolean checked) { - mToggle.setChecked(checked); - } - - @Override - public boolean isChecked() { - return mToggle.isChecked(); - } - - @Override - public void setMax(int max) { - mSlider.setMax(max); - if (mMirror != null) { - mMirror.setMax(max); - } - } - - @Override - public void setValue(int value) { - mSlider.setProgress(value); - if (mMirror != null) { - mMirror.setValue(value); - } - } - - @Override - public int getValue() { - return mSlider.getProgress(); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - if (mMirror != null) { - MotionEvent copy = ev.copy(); - mMirror.dispatchTouchEvent(copy); - copy.recycle(); - } - return super.dispatchTouchEvent(ev); - } - - private final OnCheckedChangeListener mCheckListener = new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton toggle, boolean checked) { - mSlider.setEnabled(!checked); - - if (mListener != null) { - mListener.onChanged( - ToggleSliderView.this, mTracking, checked, mSlider.getProgress(), false); - } - - if (mMirror != null) { - mMirror.mToggle.setChecked(checked); - } - } - }; - - private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (mListener != null) { - mListener.onChanged( - ToggleSliderView.this, mTracking, mToggle.isChecked(), progress, false); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - mTracking = true; - - if (mListener != null) { - mListener.onChanged(ToggleSliderView.this, mTracking, mToggle.isChecked(), - mSlider.getProgress(), false); - } - - mToggle.setChecked(false); - - if (mMirrorController != null) { - mMirrorController.showMirror(); - mMirrorController.setLocation((View) getParent()); - } - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - mTracking = false; - - if (mListener != null) { - mListener.onChanged(ToggleSliderView.this, mTracking, mToggle.isChecked(), - mSlider.getProgress(), true); - } - - if (mMirrorController != null) { - mMirrorController.hideMirror(); - } - } - }; -} - diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java similarity index 97% rename from packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java rename to packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java index 72034f84fd309..be10c26df5bf6 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.settings; +package com.android.systemui.settings.brightness; import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; import static com.android.settingslib.display.BrightnessUtils.convertGammaToLinearFloat; @@ -47,6 +47,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.systemui.Dependency; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.settings.CurrentUserTracker; import java.util.ArrayList; @@ -100,13 +101,14 @@ public class BrightnessController implements ToggleSlider.Listener { private ValueAnimator mSliderAnimator; public interface BrightnessStateChangeCallback { - public void onBrightnessLevelChanged(); + /** Indicates that some of the brightness settings have changed */ + void onBrightnessLevelChanged(); } /** ContentObserver to watch brightness */ private class BrightnessObserver extends ContentObserver { - public BrightnessObserver(Handler handler) { + BrightnessObserver(Handler handler) { super(handler); } @@ -339,11 +341,6 @@ public class BrightnessController implements ToggleSlider.Listener { return mChangeCallbacks.remove(cb); } - @Override - public void onInit(ToggleSlider control) { - // Do nothing - } - public void registerCallbacks() { mBackgroundHandler.post(mStartListeningRunnable); } @@ -355,7 +352,7 @@ public class BrightnessController implements ToggleSlider.Listener { } @Override - public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic, + public void onChanged(boolean tracking, boolean automatic, int value, boolean stopTracking) { if (mExternalChange) return; @@ -409,7 +406,7 @@ public class BrightnessController implements ToggleSlider.Listener { mBackgroundHandler.post(new Runnable() { @Override public void run() { - ((ToggleSliderView)mControl).setEnforcedAdmin( + mControl.setEnforcedAdmin( RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_CONFIG_BRIGHTNESS, mUserTracker.getCurrentUserId())); @@ -493,4 +490,5 @@ public class BrightnessController implements ToggleSlider.Listener { return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher); } } + } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java new file mode 100644 index 0000000000000..a151fd0b48ff0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.systemui.settings.brightness; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.util.settings.SecureSettings; + +import javax.inject.Inject; + +/** + * Settings for prototyping thick brightness slider + */ +@SysUISingleton +public class BrightnessControllerSettings { + + private static final String THICK_BRIGHTNESS_SLIDER = "sysui_thick_brighthness"; + private final boolean mUseThickSlider; + private final boolean mUseMirrorOnThickSlider; + + @Inject + public BrightnessControllerSettings(SecureSettings settings) { + mUseThickSlider = settings.getInt(THICK_BRIGHTNESS_SLIDER, 0) != 0; + mUseMirrorOnThickSlider = settings.getInt(THICK_BRIGHTNESS_SLIDER, 0) != 2; + } + + // Changing this setting between zero and non-zero may crash systemui down the line. Better to + // restart systemui after changing it. + /** */ + boolean useThickSlider() { + return mUseThickSlider; + } + + /** */ + boolean useMirrorOnThickSlider() { + return mUseMirrorOnThickSlider; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java similarity index 70% rename from packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java rename to packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java index 70c2531ca6d41..1961bfc9ee27c 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.systemui.settings; +package com.android.systemui.settings.brightness; import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; import android.view.Window; import android.view.WindowManager; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import javax.inject.Inject; @@ -36,11 +33,15 @@ import javax.inject.Inject; public class BrightnessDialog extends Activity { private BrightnessController mBrightnessController; + private final BrightnessSlider.Factory mToggleSliderFactory; private final BroadcastDispatcher mBroadcastDispatcher; @Inject - public BrightnessDialog(BroadcastDispatcher broadcastDispatcher) { + public BrightnessDialog( + BroadcastDispatcher broadcastDispatcher, + BrightnessSlider.Factory factory) { mBroadcastDispatcher = broadcastDispatcher; + mToggleSliderFactory = factory; } @@ -50,16 +51,21 @@ public class BrightnessDialog extends Activity { final Window window = getWindow(); - window.setGravity(Gravity.TOP); + window.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); window.requestFeature(Window.FEATURE_NO_TITLE); - View v = LayoutInflater.from(this).inflate( - R.layout.quick_settings_brightness_dialog, null); - setContentView(v); + // Calling this creates the decor View, so setLayout takes proper effect + // (see Dialog#onWindowAttributesChanged) + window.getDecorView(); + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); - final ToggleSliderView slider = findViewById(R.id.brightness_slider); - mBrightnessController = new BrightnessController(this, slider, mBroadcastDispatcher); + + BrightnessSlider controller = mToggleSliderFactory.create(this, null); + controller.init(); + setContentView(controller.getRootView()); + mBrightnessController = new BrightnessController(this, controller, mBroadcastDispatcher); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java new file mode 100644 index 0000000000000..6c4f8083788a0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.systemui.settings.brightness; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.SeekBar; + +import androidx.annotation.Nullable; + +import com.android.settingslib.RestrictedLockUtils; +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.BrightnessMirrorController; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; + +/** + * {@code ViewController} for a {@code BrightnessSliderView} + * + * This class allows to control the views of a {@code BrightnessSliderViewView} and get callbacks + * when the views change value. It also propagates and manipulates another {@link ToggleSlider} as a + * mirror. + * + * @see BrightnessMirrorController + */ +public class BrightnessSlider + extends ViewController + implements ToggleSlider { + + private Listener mListener; + private ToggleSlider mMirror; + private final BrightnessSliderView mBrightnessSliderView; + private BrightnessMirrorController mMirrorController; + private boolean mTracking; + private final boolean mUseMirror; + + BrightnessSlider( + View rootView, + BrightnessSliderView brightnessSliderView, + boolean useMirror + ) { + super(rootView); + mBrightnessSliderView = brightnessSliderView; + mUseMirror = useMirror; + } + + /** + * Returns a top level view in the hierarchy that can be attached where necessary + */ + public View getRootView() { + return mView; + } + + private void enableSlider(boolean enable) { + mBrightnessSliderView.enableSlider(enable); + } + + @Override + protected void onViewAttached() { + mBrightnessSliderView.setOnSeekBarChangeListener(mSeekListener); + mBrightnessSliderView.setOnCheckedChangeListener(mCheckListener); + } + + @Override + protected void onViewDetached() { + mBrightnessSliderView.setOnSeekBarChangeListener(null); + mBrightnessSliderView.setOnCheckedChangeListener(null); + mBrightnessSliderView.setOnDispatchTouchEventListener(null); + } + + @Override + public boolean mirrorTouchEvent(MotionEvent ev) { + if (mMirror != null) { + return copyEventToMirror(ev); + } else { + // We are the mirror, so we have to dispatch the event + return mBrightnessSliderView.dispatchTouchEvent(ev); + } + } + + private boolean copyEventToMirror(MotionEvent ev) { + MotionEvent copy = ev.copy(); + boolean out = mMirror.mirrorTouchEvent(copy); + copy.recycle(); + return out; + } + + @Override + public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) { + mBrightnessSliderView.setEnforcedAdmin(admin); + } + + private void setMirror(ToggleSlider toggleSlider) { + mMirror = toggleSlider; + if (mMirror != null) { + mMirror.setChecked(mBrightnessSliderView.isChecked()); + mMirror.setMax(mBrightnessSliderView.getMax()); + mMirror.setValue(mBrightnessSliderView.getValue()); + mBrightnessSliderView.setOnDispatchTouchEventListener(this::mirrorTouchEvent); + } else { + // If there's no mirror, we may be the ones dispatching, events but we should not mirror + // them + mBrightnessSliderView.setOnDispatchTouchEventListener(null); + } + } + + /** + * This will set the mirror from the controller using + * {@link BrightnessMirrorController#getToggleSlider} as a side-effect. + * @param c + */ + @Override + public void setMirrorControllerAndMirror(BrightnessMirrorController c) { + if (!mUseMirror) return; + mMirrorController = c; + if (c != null) { + setMirror(c.getToggleSlider()); + } else { + // If there's no mirror, we may be the ones dispatching, events but we should not mirror + // them + mBrightnessSliderView.setOnDispatchTouchEventListener(null); + } + } + + @Override + public void setOnChangedListener(Listener l) { + mListener = l; + } + + @Override + public void setChecked(boolean checked) { + mBrightnessSliderView.setChecked(checked); + } + + @Override + public boolean isChecked() { + return mBrightnessSliderView.isChecked(); + } + + @Override + public void setMax(int max) { + mBrightnessSliderView.setMax(max); + if (mMirror != null) { + mMirror.setMax(max); + } + } + + @Override + public int getMax() { + return mBrightnessSliderView.getMax(); + } + + @Override + public void setValue(int value) { + mBrightnessSliderView.setValue(value); + if (mMirror != null) { + mMirror.setValue(value); + } + } + + @Override + public int getValue() { + return mBrightnessSliderView.getValue(); + } + + private final SeekBar.OnSeekBarChangeListener mSeekListener = + new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mListener != null) { + mListener.onChanged(mTracking, isChecked(), progress, false); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mTracking = true; + + if (mListener != null) { + mListener.onChanged(mTracking, isChecked(), + getValue(), false); + } + + setChecked(false); + + if (mMirrorController != null) { + mMirrorController.showMirror(); + mMirrorController.setLocation((View) mBrightnessSliderView.getParent()); + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mTracking = false; + + if (mListener != null) { + mListener.onChanged(mTracking, isChecked(), + getValue(), true); + } + + if (mMirrorController != null) { + mMirrorController.hideMirror(); + } + } + }; + + private final CompoundButton.OnCheckedChangeListener mCheckListener = + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton toggle, boolean checked) { + enableSlider(!checked); + + if (mListener != null) { + mListener.onChanged(mTracking, checked, getValue(), false); + } + + if (mMirror != null) { + mMirror.setChecked(checked); + } + } + }; + + /** + * Creates a {@link BrightnessSlider} with its associated view. + * + * The views inflated are determined by {@link BrightnessControllerSettings#useThickSlider()}. + */ + public static class Factory { + + BrightnessControllerSettings mSettings; + + @Inject + public Factory(BrightnessControllerSettings settings) { + mSettings = settings; + } + + /** + * Creates the view hierarchy and controller + * + * @param context a {@link Context} to inflate the hierarchy + * @param viewRoot the {@link ViewGroup} that will contain the hierarchy. The inflated + * hierarchy will not be attached + */ + public BrightnessSlider create(Context context, @Nullable ViewGroup viewRoot) { + int layout = getLayout(); + ViewGroup root = (ViewGroup) LayoutInflater.from(context) + .inflate(layout, viewRoot, false); + return fromTree(root, mSettings.useMirrorOnThickSlider()); + } + + private BrightnessSlider fromTree(ViewGroup root, boolean useMirror) { + BrightnessSliderView v = root.requireViewById(R.id.brightness_slider); + return new BrightnessSlider(root, v, useMirror); + } + + /** Get the layout to inflate based on what slider to use */ + public int getLayout() { + return mSettings.useThickSlider() + ? R.layout.quick_settings_brightness_dialog_thick + : R.layout.quick_settings_brightness_dialog; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java new file mode 100644 index 0000000000000..cbf4e88b3241e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.systemui.settings.brightness; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.FrameLayout; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.RestrictedLockUtils; +import com.android.systemui.R; + +/** + * {@code FrameLayout} used to show and manipulate a {@link ToggleSeekBar}. + * + * It can additionally control a {@link CompoundButton} and display a label. For the class to work, + * add children before inflation with the following ids: + *
    + *
  • {@code @id/slider} of type {@link ToggleSeekBar}
  • + *
  • {@code @id/toggle} of type {@link CompoundButton} (optional)
  • + *
  • {@code @id/label} of type {@link TextView} (optional)
  • + *
+ */ +public class BrightnessSliderView extends FrameLayout { + + @Nullable + private CompoundButton mToggle; + @NonNull + private ToggleSeekBar mSlider; + @Nullable + private TextView mLabel; + private final CharSequence mText; + private DispatchTouchEventListener mListener; + + public BrightnessSliderView(Context context) { + this(context, null); + } + + public BrightnessSliderView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BrightnessSliderView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ToggleSliderView, defStyle, 0); + mText = a.getString(R.styleable.ToggleSliderView_text); + + a.recycle(); + } + + // Inflated from quick_settings_brightness_dialog or quick_settings_brightness_dialog_thick + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mToggle = findViewById(R.id.toggle); + + mSlider = requireViewById(R.id.slider); + + mLabel = findViewById(R.id.label); + if (mLabel != null) { + mLabel.setText(mText); + } + mSlider.setAccessibilityLabel(getContentDescription().toString()); + } + + /** + * Attaches a listener to relay touch events. + * @param listener use {@code null} to remove listener + */ + public void setOnDispatchTouchEventListener( + DispatchTouchEventListener listener) { + mListener = listener; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (mListener != null) { + mListener.onDispatchTouchEvent(ev); + } + return super.dispatchTouchEvent(ev); + } + + /** + * Attaches a listener to the {@link ToggleSeekBar} in the view so changes can be observed + * @param seekListener use {@code null} to remove listener + */ + public void setOnSeekBarChangeListener(OnSeekBarChangeListener seekListener) { + mSlider.setOnSeekBarChangeListener(seekListener); + } + + /** + * Attaches a listener to the {@link CompoundButton} in the view (if present) so changes to its + * state can be observed + * @param checkListener use {@code null} to remove listener + */ + public void setOnCheckedChangeListener(OnCheckedChangeListener checkListener) { + if (mToggle != null) { + mToggle.setOnCheckedChangeListener(checkListener); + } + } + + /** + * Enforces admin rules for toggling auto-brightness and changing value of brightness + * @param admin + * @see ToggleSeekBar#setEnforcedAdmin + */ + public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) { + if (mToggle != null) { + mToggle.setEnabled(admin == null); + } + mSlider.setEnabled(admin == null); + mSlider.setEnforcedAdmin(admin); + } + + /** + * Enables or disables the slider + * @param enable + */ + public void enableSlider(boolean enable) { + mSlider.setEnabled(enable); + } + + /** + * Sets the state of the {@link CompoundButton} if present + * @param checked + */ + public void setChecked(boolean checked) { + if (mToggle != null) { + mToggle.setChecked(checked); + } + } + + /** + * @return the state of the {@link CompoundButton} if present, or {@code true} if not. + */ + public boolean isChecked() { + if (mToggle != null) { + return mToggle.isChecked(); + } + return true; + } + + /** + * @return the maximum value of the {@link ToggleSeekBar}. + */ + public int getMax() { + return mSlider.getMax(); + } + + /** + * Sets the maximum value of the {@link ToggleSeekBar}. + * @param max + */ + public void setMax(int max) { + mSlider.setMax(max); + } + + /** + * Sets the current value of the {@link ToggleSeekBar}. + * @param value + */ + public void setValue(int value) { + mSlider.setProgress(value); + } + + /** + * @return the current value of the {@link ToggleSeekBar} + */ + public int getValue() { + return mSlider.getProgress(); + } + + /** + * Interface to attach a listener for {@link View#dispatchTouchEvent}. + */ + @FunctionalInterface + interface DispatchTouchEventListener { + boolean onDispatchTouchEvent(MotionEvent ev); + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java similarity index 95% rename from packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java rename to packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java index 8ed4c75e86737..a5a0ae70045ea 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.settings; +package com.android.systemui.settings.brightness; import android.content.Context; import android.content.Intent; diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java similarity index 60% rename from packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java rename to packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java index 135f89d3f3431..71e4818c605ac 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,22 +11,31 @@ * 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 + * limitations under the License. */ -package com.android.systemui.settings; +package com.android.systemui.settings.brightness; + +import android.view.MotionEvent; + +import com.android.settingslib.RestrictedLockUtils; +import com.android.systemui.statusbar.policy.BrightnessMirrorController; public interface ToggleSlider { interface Listener { - void onInit(ToggleSlider control); - void onChanged(ToggleSlider slider, boolean tracking, boolean automatic, int value, + void onChanged(boolean tracking, boolean automatic, int value, boolean stopTracking); } + void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin); + void setMirrorControllerAndMirror(BrightnessMirrorController c); + boolean mirrorTouchEvent(MotionEvent ev); + void setOnChangedListener(Listener l); default void setChecked(boolean checked) {} default boolean isChecked() { return false; } void setMax(int max); + int getMax(); void setValue(int value); int getValue(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 3b530971d5211..09de57509c2a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -173,6 +173,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSFragment; import com.android.systemui.qs.QSPanelController; import com.android.systemui.recents.ScreenPinningRequest; +import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.AutoHideUiElement; @@ -432,6 +433,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final NotificationViewHierarchyManager mViewHierarchyManager; private final KeyguardViewMediator mKeyguardViewMediator; protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider; + private final BrightnessSlider.Factory mBrightnessSliderFactory; // for disabling the status bar private int mDisabled1 = 0; @@ -744,7 +746,8 @@ public class StatusBar extends SystemUI implements DemoMode, DemoModeController demoModeController, Lazy notificationShadeDepthControllerLazy, StatusBarTouchableRegionManager statusBarTouchableRegionManager, - NotificationIconAreaController notificationIconAreaController) { + NotificationIconAreaController notificationIconAreaController, + BrightnessSlider.Factory brightnessSliderFactory) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -821,6 +824,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDismissCallbackRegistry = dismissCallbackRegistry; mDemoModeController = demoModeController; mNotificationIconAreaController = notificationIconAreaController; + mBrightnessSliderFactory = brightnessSliderFactory; mBubbleExpandListener = (isExpanding, key) -> { @@ -1205,6 +1209,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowView, mNotificationPanelViewController, mNotificationShadeDepthControllerLazy.get(), + mBrightnessSliderFactory, (visible) -> { mBrightnessMirrorVisible = visible; updateScrimController(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 13d5bf59fb4b6..f6631ce1414ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -43,6 +43,7 @@ import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.recents.ScreenPinningRequest; +import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -198,7 +199,8 @@ public interface StatusBarPhoneModule { Lazy notificationShadeDepthController, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager, - NotificationIconAreaController notificationIconAreaController) { + NotificationIconAreaController notificationIconAreaController, + BrightnessSlider.Factory brightnessSliderFactory) { return new StatusBar( context, notificationsController, @@ -276,6 +278,7 @@ public interface StatusBarPhoneModule { demoModeController, notificationShadeDepthController, statusBarTouchableRegionManager, - notificationIconAreaController); + notificationIconAreaController, + brightnessSliderFactory); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index a0b03e1c54c24..07d3f0122aa00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -17,13 +17,18 @@ package com.android.systemui.statusbar.policy; import android.annotation.NonNull; +import android.content.Context; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.util.ArraySet; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.settings.brightness.BrightnessSlider; +import com.android.systemui.settings.brightness.ToggleSlider; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; @@ -42,15 +47,20 @@ public class BrightnessMirrorController private final NotificationPanelViewController mNotificationPanel; private final NotificationShadeDepthController mDepthController; private final ArraySet mBrightnessMirrorListeners = new ArraySet<>(); + private final BrightnessSlider.Factory mToggleSliderFactory; + private BrightnessSlider mToggleSliderController; private final int[] mInt2Cache = new int[2]; - private View mBrightnessMirror; + private FrameLayout mBrightnessMirror; public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow, NotificationPanelViewController notificationPanelViewController, NotificationShadeDepthController notificationShadeDepthController, + BrightnessSlider.Factory factory, @NonNull Consumer visibilityCallback) { mStatusBarWindow = statusBarWindow; + mToggleSliderFactory = factory; mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror); + mToggleSliderController = setMirrorLayout(); mNotificationPanel = notificationPanelViewController; mDepthController = notificationShadeDepthController; mNotificationPanel.setPanelAlphaEndAction(() -> { @@ -88,8 +98,8 @@ public class BrightnessMirrorController mBrightnessMirror.setTranslationY(originalY - mirrorY); } - public View getMirror() { - return mBrightnessMirror; + public ToggleSlider getToggleSlider() { + return mToggleSliderController; } public void updateResources() { @@ -110,11 +120,33 @@ public class BrightnessMirrorController reinflate(); } + private BrightnessSlider setMirrorLayout() { + Context context = mBrightnessMirror.getContext(); + BrightnessSlider controller = mToggleSliderFactory.create(context, mBrightnessMirror); + controller.init(); + Drawable mirrorBackground = context.getDrawable(R.drawable.brightness_mirror_background); + + View rootView = controller.getRootView(); + rootView.setBackground(mirrorBackground); + + ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) rootView.getLayoutParams(); + lp.height = ViewGroup.LayoutParams.MATCH_PARENT; + lp.width = ViewGroup.LayoutParams.MATCH_PARENT; + int margin = context.getResources() + .getDimensionPixelSize(R.dimen.notification_side_paddings); + lp.leftMargin = margin; + lp.rightMargin = margin; + mBrightnessMirror.addView(rootView, lp); + + return controller; + } + private void reinflate() { int index = mStatusBarWindow.indexOfChild(mBrightnessMirror); mStatusBarWindow.removeView(mBrightnessMirror); - mBrightnessMirror = LayoutInflater.from(mBrightnessMirror.getContext()).inflate( - R.layout.brightness_mirror, mStatusBarWindow, false); + mBrightnessMirror = (FrameLayout) LayoutInflater.from(mBrightnessMirror.getContext()) + .inflate(R.layout.brightness_mirror, mStatusBarWindow, false); + mToggleSliderController = setMirrorLayout(); mStatusBarWindow.addView(mBrightnessMirror, index); for (int i = 0; i < mBrightnessMirrorListeners.size(); i++) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java index bce376a13b7b3..f57e3c2892ea6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java @@ -37,8 +37,9 @@ import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.customize.QSCustomizerController; import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.settings.BrightnessController; -import com.android.systemui.settings.ToggleSlider; +import com.android.systemui.settings.brightness.BrightnessController; +import com.android.systemui.settings.brightness.BrightnessSlider; +import com.android.systemui.settings.brightness.ToggleSlider; import com.android.systemui.tuner.TunerService; import org.junit.Before; @@ -79,6 +80,10 @@ public class QSPanelControllerTest extends SysuiTestCase { @Mock private BrightnessController mBrightnessController; @Mock + private BrightnessSlider.Factory mToggleSliderViewControllerFactory; + @Mock + private BrightnessSlider mBrightnessSlider; + @Mock QSTileImpl mQSTile; @Mock QSTileView mQSTileView; @@ -98,13 +103,16 @@ public class QSPanelControllerTest extends SysuiTestCase { when(mQSPanel.createRegularTileLayout()).thenReturn(mPagedTileLayout); when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile)); when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView); + when(mToggleSliderViewControllerFactory.create(any(), any())) + .thenReturn(mBrightnessSlider); when(mBrightnessControllerFactory.create(any(ToggleSlider.class))) .thenReturn(mBrightnessController); when(mQSTileRevealControllerFactory.create(any())).thenReturn(mQSTileRevealController); mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService, mQSTileHost, mQSCustomizerController, mQSTileRevealControllerFactory, mDumpManager, - mMetricsLogger, mUiEventLogger, mBrightnessControllerFactory); + mMetricsLogger, mUiEventLogger, mBrightnessControllerFactory, + mToggleSliderViewControllerFactory); mController.init(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt new file mode 100644 index 0000000000000..0cc2072b367fa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2020 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. + */ + +package com.android.systemui.settings.brightness + +import android.testing.AndroidTestingRunner +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.CompoundButton +import android.widget.SeekBar +import androidx.test.filters.SmallTest +import com.android.settingslib.RestrictedLockUtils +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.policy.BrightnessMirrorController +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.eq +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.isNull +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.notNull +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class BrightnessSliderTest : SysuiTestCase() { + + @Mock + private lateinit var rootView: View + @Mock + private lateinit var brightnessSliderView: BrightnessSliderView + @Mock + private lateinit var enforcedAdmin: RestrictedLockUtils.EnforcedAdmin + @Mock + private lateinit var mirrorController: BrightnessMirrorController + @Mock + private lateinit var mirror: ToggleSlider + @Mock + private lateinit var motionEvent: MotionEvent + @Mock + private lateinit var listener: ToggleSlider.Listener + + @Captor + private lateinit var seekBarChangeCaptor: ArgumentCaptor + @Mock + private lateinit var seekBar: SeekBar + @Captor + private lateinit var checkedChangeCaptor: ArgumentCaptor + @Mock + private lateinit var compoundButton: CompoundButton + + private lateinit var mController: BrightnessSlider + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + whenever(mirrorController.toggleSlider).thenReturn(mirror) + whenever(motionEvent.copy()).thenReturn(motionEvent) + + mController = BrightnessSlider(rootView, brightnessSliderView, true) + mController.init() + mController.setOnChangedListener(listener) + } + + @After + fun tearDown() { + mController.onViewDetached() + } + + @Test + fun testListenersAddedOnAttach() { + mController.onViewAttached() + + verify(brightnessSliderView).setOnCheckedChangeListener(notNull()) + verify(brightnessSliderView).setOnSeekBarChangeListener(notNull()) + } + + @Test + fun testAllListenersRemovedOnDettach() { + mController.onViewAttached() + mController.onViewDetached() + + verify(brightnessSliderView).setOnSeekBarChangeListener(isNull()) + verify(brightnessSliderView).setOnCheckedChangeListener(isNull()) + verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull()) + } + + @Test + fun testEnforceAdminRelayed() { + mController.setEnforcedAdmin(enforcedAdmin) + verify(brightnessSliderView).setEnforcedAdmin(enforcedAdmin) + } + + @Test + fun testNullMirrorControllerNotTrackingTouch() { + mController.setMirrorControllerAndMirror(null) + + verify(brightnessSliderView, never()).max + verify(brightnessSliderView, never()).value + verify(brightnessSliderView, never()).isChecked + verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull()) + } + + @Test + fun testNullMirrorNotTrackingTouch() { + whenever(mirrorController.toggleSlider).thenReturn(null) + + mController.setMirrorControllerAndMirror(mirrorController) + + verify(brightnessSliderView, never()).max + verify(brightnessSliderView, never()).value + verify(brightnessSliderView, never()).isChecked + verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull()) + } + + @Test + fun testSettingMirrorControllerReliesValuesAndSetsTouchTracking() { + val maxValue = 100 + val progress = 30 + val checked = true + whenever(brightnessSliderView.max).thenReturn(maxValue) + whenever(brightnessSliderView.value).thenReturn(progress) + whenever(brightnessSliderView.isChecked).thenReturn(checked) + + mController.setMirrorControllerAndMirror(mirrorController) + + verify(mirror).max = maxValue + verify(mirror).isChecked = checked + verify(mirror).value = progress + verify(brightnessSliderView).setOnDispatchTouchEventListener(notNull()) + } + + @Test + fun testSettingMirrorWhenNotUseMirrorIsNoOp() { + val otherController = BrightnessSlider(rootView, brightnessSliderView, false) + otherController.init() + + otherController.setMirrorControllerAndMirror(mirrorController) + + verify(brightnessSliderView, never()).max + verify(brightnessSliderView, never()).value + verify(brightnessSliderView, never()).isChecked + verify(brightnessSliderView, never()).setOnDispatchTouchEventListener( + any(BrightnessSliderView.DispatchTouchEventListener::class.java)) + } + + @Test + fun testSetCheckedRelayed_true() { + mController.isChecked = true + verify(brightnessSliderView).isChecked = true + } + + @Test + fun testSetCheckedRelayed_false() { + mController.isChecked = false + verify(brightnessSliderView).isChecked = false + } + + @Test + fun testGetChecked() { + whenever(brightnessSliderView.isChecked).thenReturn(true) + + assertThat(mController.isChecked).isTrue() + + whenever(brightnessSliderView.isChecked).thenReturn(false) + + assertThat(mController.isChecked).isFalse() + } + + @Test + fun testSetMaxRelayed() { + mController.max = 120 + verify(brightnessSliderView).max = 120 + } + + @Test + fun testGetMax() { + whenever(brightnessSliderView.max).thenReturn(40) + + assertThat(mController.max).isEqualTo(40) + } + + @Test + fun testSetValue() { + mController.value = 30 + verify(brightnessSliderView).value = 30 + } + + @Test + fun testGetValue() { + whenever(brightnessSliderView.value).thenReturn(20) + + assertThat(mController.value).isEqualTo(20) + } + + @Test + fun testMirrorEventWithMirror() { + mController.setMirrorControllerAndMirror(mirrorController) + + mController.mirrorTouchEvent(motionEvent) + + verify(mirror).mirrorTouchEvent(motionEvent) + verify(brightnessSliderView, never()).dispatchTouchEvent(any(MotionEvent::class.java)) + } + + @Test + fun testMirrorEventWithoutMirror_dispatchToView() { + mController.mirrorTouchEvent(motionEvent) + + verify(brightnessSliderView).dispatchTouchEvent(motionEvent) + } + + @Test + fun testSeekBarProgressChanged() { + mController.onViewAttached() + whenever(brightnessSliderView.isChecked).thenReturn(true) + + verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor)) + + seekBarChangeCaptor.value.onProgressChanged(seekBar, 23, true) + + verify(listener).onChanged(anyBoolean(), eq(true), eq(23), eq(false)) + } + + @Test + fun testSeekBarTrackingStarted() { + val parent = mock(ViewGroup::class.java) + whenever(brightnessSliderView.value).thenReturn(42) + whenever(brightnessSliderView.parent).thenReturn(parent) + whenever(brightnessSliderView.isChecked).thenReturn(true) + + mController.onViewAttached() + mController.setMirrorControllerAndMirror(mirrorController) + verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor)) + + seekBarChangeCaptor.value.onStartTrackingTouch(seekBar) + + verify(listener).onChanged(eq(true), eq(true), eq(42), eq(false)) + verify(mirrorController).showMirror() + verify(mirrorController).setLocation(parent) + } + + @Test + fun testSeekBarTrackingStopped() { + whenever(brightnessSliderView.value).thenReturn(23) + whenever(brightnessSliderView.isChecked).thenReturn(true) + + mController.onViewAttached() + mController.setMirrorControllerAndMirror(mirrorController) + verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor)) + + seekBarChangeCaptor.value.onStopTrackingTouch(seekBar) + + verify(listener).onChanged(eq(false), eq(true), eq(23), eq(true)) + verify(mirrorController).hideMirror() + } + + @Test + fun testButtonCheckedChanged_false() { + val checked = false + + mController.onViewAttached() + mController.setMirrorControllerAndMirror(mirrorController) + verify(brightnessSliderView).setOnCheckedChangeListener(capture(checkedChangeCaptor)) + + checkedChangeCaptor.value.onCheckedChanged(compoundButton, checked) + + verify(brightnessSliderView).enableSlider(!checked) + verify(listener).onChanged(anyBoolean(), eq(checked), anyInt(), eq(false)) + // Called once with false when the mirror is set + verify(mirror, times(2)).isChecked = checked + } + + @Test + fun testButtonCheckedChanged_true() { + val checked = true + + mController.onViewAttached() + mController.setMirrorControllerAndMirror(mirrorController) + verify(brightnessSliderView).setOnCheckedChangeListener(capture(checkedChangeCaptor)) + + checkedChangeCaptor.value.onCheckedChanged(compoundButton, checked) + + verify(brightnessSliderView).enableSlider(!checked) + verify(listener).onChanged(anyBoolean(), eq(checked), anyInt(), eq(false)) + verify(mirror).isChecked = checked + } +} \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 2f9b6010b42de..710122d83b221 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -97,6 +97,7 @@ import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.ScreenPinningRequest; +import com.android.systemui.settings.brightness.BrightnessSlider; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -260,6 +261,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy; @Mock private DemoModeController mDemoModeController; @Mock private Lazy mNotificationShadeDepthControllerLazy; + @Mock private BrightnessSlider.Factory mBrightnessSliderFactory; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @@ -419,7 +421,8 @@ public class StatusBarTest extends SysuiTestCase { mDemoModeController, mNotificationShadeDepthControllerLazy, mStatusBarTouchableRegionManager, - mNotificationIconAreaController); + mNotificationIconAreaController, + mBrightnessSliderFactory); when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn( mLockIconContainer);