Merge "Refactor ToggleSliderView"

This commit is contained in:
Fabian Kozynski
2020-11-11 14:41:45 +00:00
committed by Android (Google) Code Review
29 changed files with 1214 additions and 375 deletions

View File

@@ -669,7 +669,7 @@
</activity>
<activity
android:name=".settings.BrightnessDialog"
android:name=".settings.brightness.BrightnessDialog"
android:label="@string/quick_settings_brightness_dialog_title"
android:theme="@*android:style/Theme.DeviceDefault.QuickSettings.Dialog"
android:finishOnCloseSystemDialogs="true"

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack">
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<clip
android:drawable="@drawable/brightness_progress_full_drawable"
android:clipOrientation="horizontal"
android:gravity="left"
/>
</item>
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle"
android:tint="?android:attr/colorControlNormal">
<size android:height="48dp" />
<solid android:color="@color/white_disabled" />
<corners android:radius="24dp" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:tint="?android:attr/colorControlActivated">
<size android:height="48dp" />
<solid android:color="@android:color/white" />
<corners android:radius="24dp"/>
</shape>

View File

@@ -0,0 +1,29 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z"
/>
<path
android:pathData=" M20,8.69 V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69z M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7z"
android:fillColor="#FFFFFF" />
</vector>

View File

@@ -21,12 +21,5 @@
android:layout_height="@dimen/brightness_mirror_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:visibility="invisible">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/notification_side_paddings"
android:layout_marginRight="@dimen/notification_side_paddings"
android:background="@drawable/brightness_mirror_background">
<include layout="@layout/quick_settings_brightness_dialog" />
</FrameLayout>
</FrameLayout>

View File

@@ -20,7 +20,7 @@
android:layout_gravity="center_vertical"
style="@style/BrightnessDialogContainer">
<com.android.systemui.settings.ToggleSliderView
<com.android.systemui.settings.brightness.BrightnessSliderView
android:id="@+id/brightness_slider"
android:layout_width="0dp"
android:layout_height="48dp"
@@ -28,6 +28,54 @@
android:layout_weight="1"
android:contentDescription="@string/accessibility_brightness"
android:importantForAccessibility="no"
systemui:text="@string/status_bar_settings_auto_brightness_label" />
systemui:text="@string/status_bar_settings_auto_brightness_label" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<CheckBox
android:id="@+id/toggle"
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:button="@null"
android:background="@*android:drawable/switch_track_material"
android:visibility="gone"
/>
<com.android.systemui.settings.brightness.ToggleSeekBar
android:id="@+id/slider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/toggle"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:thumb="@drawable/ic_brightness_thumb"
android:progressDrawable="@drawable/brightness_progress_drawable"
android:splitTrack="false"
/>
<TextView
android:id="@+id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignStart="@id/toggle"
android:layout_alignEnd="@id/toggle"
android:layout_centerVertical="true"
android:gravity="center"
android:paddingTop="26dp"
android:textColor="#666666"
android:textSize="12sp"
android:visibility="gone"
/>
</RelativeLayout>
</com.android.systemui.settings.brightness.BrightnessSliderView>
</LinearLayout>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_gravity="center"
style="@style/BrightnessDialogContainer">
<com.android.systemui.settings.brightness.BrightnessSliderView
android:id="@+id/brightness_slider"
android:layout_width="match_parent"
android:layout_height="@dimen/brightness_mirror_height"
android:layout_gravity="center_vertical"
android:contentDescription="@string/accessibility_brightness"
android:importantForAccessibility="no" >
<com.android.systemui.settings.brightness.ToggleSeekBar
android:id="@+id/slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:minHeight="48dp"
android:thumb="@null"
android:background="@null"
android:progressDrawable="@drawable/brightness_progress_drawable_thick"
android:splitTrack="false"
/>
<ImageView
android:id="@+id/image"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="48dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_brightness"
android:tint="?android:attr/textColorTertiary"
android:visibility="visible"
/>
</com.android.systemui.settings.brightness.BrightnessSliderView>
</FrameLayout>

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2010 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.
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBox
android:id="@+id/toggle"
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:button="@null"
android:background="@*android:drawable/switch_track_material"
android:visibility="gone"
/>
<com.android.systemui.settings.ToggleSeekBar
android:id="@+id/slider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/toggle"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:thumb="@drawable/ic_brightness_thumb"
android:progressDrawable="@drawable/brightness_progress_drawable"
android:splitTrack="false"
/>
<TextView
android:id="@+id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignStart="@id/toggle"
android:layout_alignEnd="@id/toggle"
android:layout_centerVertical="true"
android:gravity="center"
android:paddingTop="26dp"
android:textColor="#666666"
android:textSize="12sp"
android:visibility="gone"
/>
</merge>

View File

@@ -19,9 +19,9 @@
<dimen name="qs_tile_margin_vertical">24dp</dimen>
<!-- The height of the qs customize header. Should be
(qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
(qs_panel_padding_top (48dp) + brightness_mirror_height (56dp) + qs_tile_margin_top (18dp)) -
(Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
-->
<dimen name="qs_customize_header_min_height">46dp</dimen>
<dimen name="qs_customize_header_min_height">54dp</dimen>
<dimen name="qs_tile_margin_top">18dp</dimen>
</resources>

View File

@@ -22,8 +22,6 @@
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
<dimen name="brightness_mirror_height">40dp</dimen>
<dimen name="qs_tile_margin_top">8dp</dimen>
<dimen name="qs_tile_margin_vertical">0dp</dimen>

View File

@@ -430,7 +430,7 @@
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
<dimen name="brightness_mirror_height">48dp</dimen>
<dimen name="brightness_mirror_height">56dp</dimen>
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
@@ -496,10 +496,10 @@
<dimen name="qs_tile_margin_top_bottom">12dp</dimen>
<dimen name="qs_tile_margin_top_bottom_negative">-12dp</dimen>
<!-- The height of the qs customize header. Should be
(qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (0dp)) -
(qs_panel_padding_top (48dp) + brightness_mirror_height (56dp) + qs_tile_margin_top (0dp)) -
(Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
-->
<dimen name="qs_customize_header_min_height">28dp</dimen>
<dimen name="qs_customize_header_min_height">36dp</dimen>
<dimen name="qs_tile_margin_top">0dp</dimen>
<dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
<dimen name="qs_tile_background_size">44dp</dimen>

View File

@@ -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;

View File

@@ -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());

View File

@@ -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<QSPanel> {
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<QSPanel> {
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<QSPanel> {
mView.setSecurityFooter(mQsSecurityFooter.getView());
switchTileLayout(true);
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.addCallback(mView);
mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
}
}
@@ -106,7 +118,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
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<QSPanel> {
/** */
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. */

View File

@@ -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

View File

@@ -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();
}
}
};
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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<View>
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;
}
}
}

View File

@@ -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:
* <ul>
* <li>{@code @id/slider} of type {@link ToggleSeekBar}</li>
* <li>{@code @id/toggle} of type {@link CompoundButton} (optional)</li>
* <li>{@code @id/label} of type {@link TextView} (optional)</li>
* </ul>
*/
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);
}
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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<NotificationShadeDepthController> 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();

View File

@@ -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> 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);
}
}

View File

@@ -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<BrightnessMirrorListener> 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<Boolean> 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++) {

View File

@@ -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();
}

View File

@@ -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<SeekBar.OnSeekBarChangeListener>
@Mock
private lateinit var seekBar: SeekBar
@Captor
private lateinit var checkedChangeCaptor: ArgumentCaptor<CompoundButton.OnCheckedChangeListener>
@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
}
}

View File

@@ -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<NotificationShadeDepthController> 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);