Merge changes I69310ae7,I3de887b0,If64490a6

* changes:
  Style the Magnification Window - Window Mode
  Style panel with Material designs (5/n)
  Style panel with Material designs (4/n)
This commit is contained in:
Candice Lo
2023-01-31 07:23:04 +00:00
committed by Android (Google) Code Review
17 changed files with 591 additions and 34 deletions

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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">
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/magnifier_corner_radius" />
<stroke
android:color="@color/magnification_border_color"
android:width="@dimen/magnifier_border_width"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/magnifier_outer_corner_radius" />
<stroke
android:color="@android:color/black"
android:width="@dimen/magnifier_stroke_width"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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">
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/magnifier_edit_corner_radius" />
<stroke
android:color="@color/magnification_border_color"
android:width="@dimen/magnifier_border_width"
android:dashWidth="@dimen/magnifier_edit_dash_gap"
android:dashGap="@dimen/magnifier_edit_dash_gap"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="@dimen/magnifier_edit_outer_corner_radius" />
<stroke
android:color="@android:color/black"
android:width="@dimen/magnifier_stroke_width"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?><!--
~ Copyright (C) 2023 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">
<size
android:width="@dimen/magnification_window_drag_corner_size"
android:height="@dimen/magnification_window_drag_corner_size"/>
<stroke
android:color="@android:color/black"
android:width="@dimen/magnification_window_drag_corner_stroke"/>
<solid android:color="@color/magnification_drag_corner_background" />
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?><!--
~ Copyright (C) 2023 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">
<stroke
android:color="@android:color/black"
android:width="@dimen/magnifier_stroke_width"/>
<corners android:radius="@dimen/magnifier_corner_radius" />
<solid android:color="@color/magnification_border_color" />
</shape>

View File

@@ -0,0 +1,26 @@
<!--
~ Copyright (C) 2023 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="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M4.304,5.717L8.731,10.141L6.903,11.969L11.959,11.953L11.973,6.899L10.131,8.74L5.703,4.318L3.229,1.843L5.073,0L0,0L0,5.071L1.83,3.243L4.304,5.717Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>

View File

@@ -0,0 +1,32 @@
<!--
~ Copyright (C) 2023 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="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<group
android:pivotX="6"
android:pivotY="6"
android:rotation="90">
<path
android:pathData="M4.304,5.717L8.731,10.141L6.903,11.969L11.959,11.953L11.973,6.899L10.131,8.74L5.703,4.318L3.229,1.843L5.073,0L0,0L0,5.071L1.83,3.243L4.304,5.717Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</group>
</vector>

View File

@@ -20,6 +20,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:fillColor="@color/magnification_drag_handle_tint"
android:pathData="M12,15Q10.75,15 9.875,14.125Q9,13.25 9,12Q9,10.75 9.875,9.875Q10.75,9 12,9Q13.25,9 14.125,9.875Q15,10.75 15,12Q15,13.25 14.125,14.125Q13.25,15 12,15ZM12,22 L7.75,17.75 9.15,16.35 12,19.15 14.85,16.35 16.25,17.75ZM6.25,16.25 L2,12 6.25,7.75 7.65,9.15 4.85,12 7.65,14.85ZM9.15,7.65 L7.75,6.25 12,2 16.25,6.25 14.85,7.65 12,4.85ZM17.75,16.25 L16.35,14.85 19.15,12 16.35,9.15 17.75,7.75 22,12Z"/>
</vector>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/seekbar_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:parentTag="android.widget.LinearLayout">
<ImageView
android:id="@+id/icon_start"
android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:adjustViewBounds="true"
android:focusable="true"
android:src="@drawable/ic_remove"
android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in" />
<SeekBar
android:id="@+id/seekbar"
style="@android:style/Widget.Material.SeekBar.Discrete"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_weight="1" />
<ImageView
android:id="@+id/icon_end"
android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:adjustViewBounds="true"
android:focusable="true"
android:src="@drawable/ic_add"
android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in" />
</merge>

View File

@@ -15,6 +15,7 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/magnifier_panel_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -129,13 +130,19 @@
android:layout_weight="1"
android:singleLine="true"
android:text="@string/accessibility_allow_diagonal_scrolling"
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title" />
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:layout_gravity="center_vertical" />
<Switch
android:id="@+id/magnifier_horizontal_lock_switch"
android:layout_width="wrap_content"
android:switchMinWidth="@dimen/settingslib_switch_track_width"
android:layout_gravity="right|center_vertical"
android:layout_width="@dimen/settingslib_switch_track_width"
android:layout_height="wrap_content"
android:layout_gravity="right" />
android:track="@drawable/settingslib_track_selector"
android:thumb="@drawable/settingslib_thumb_selector"
android:theme="@style/MainSwitch.Settingslib"/>
</LinearLayout>
<TextView
@@ -145,13 +152,14 @@
android:textAppearance="@style/TextAppearance.MagnificationSetting.Title"
android:focusable="true" />
<SeekBar
android:id="@+id/magnifier_zoom_seekbar"
android:layout_height="wrap_content"
<com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
android:id="@+id/magnifier_zoom_slider"
android:layout_width="match_parent"
android:layout_marginTop="@dimen/magnification_setting_seekbar_margin"
android:progress="0"
android:max="6" />
android:layout_height="wrap_content"
app:max="6"
app:progress="0"
app:iconStartContentDescription="@string/accessibility_control_zoom_out"
app:iconEndContentDescription="@string/accessibility_control_zoom_in"/>
<Button
android:id="@+id/magnifier_done_button"

View File

@@ -16,6 +16,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
@@ -24,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:background="@color/magnification_border_color"/>
android:background="@drawable/accessibility_window_magnification_background"/>
<RelativeLayout
android:layout_width="match_parent"
@@ -66,54 +67,50 @@
<ImageView
android:id="@+id/top_right_corner"
android:background="@drawable/accessibility_window_magnification_drag_corner_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_margin="@dimen/magnification_drag_corner_margin"
android:layout_gravity="right|top"
android:paddingTop="@dimen/magnifier_drag_handle_padding"
android:paddingEnd="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:contentDescription="@string/magnification_drag_corner_to_resize"
android:src="@drawable/ic_magnification_corner_top_right"
android:src="@drawable/ic_arrow_top_right_and_bottom_left"
android:accessibilityTraversalAfter="@id/top_left_corner"/>
<ImageView
android:id="@+id/top_left_corner"
android:background="@drawable/accessibility_window_magnification_drag_corner_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_margin="@dimen/magnification_drag_corner_margin"
android:layout_gravity="left|top"
android:paddingTop="@dimen/magnifier_drag_handle_padding"
android:paddingStart="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:contentDescription="@string/magnification_drag_corner_to_resize"
android:src="@drawable/ic_magnification_corner_top_left"
android:src="@drawable/ic_arrow_top_left_and_bottom_right"
android:accessibilityTraversalAfter="@id/bottom_handle"/>
<ImageView
android:id="@+id/bottom_right_corner"
android:background="@drawable/accessibility_window_magnification_drag_corner_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_margin="@dimen/magnification_drag_corner_margin"
android:layout_gravity="right|bottom"
android:paddingEnd="@dimen/magnifier_drag_handle_padding"
android:paddingBottom="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:contentDescription="@string/magnification_drag_corner_to_resize"
android:src="@drawable/ic_magnification_corner_bottom_right"
android:src="@drawable/ic_arrow_top_left_and_bottom_right"
android:accessibilityTraversalAfter="@id/top_right_corner"/>
<ImageView
android:id="@+id/bottom_left_corner"
android:background="@drawable/accessibility_window_magnification_drag_corner_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_margin="@dimen/magnification_drag_corner_margin"
android:layout_gravity="left|bottom"
android:paddingStart="@dimen/magnifier_drag_handle_padding"
android:paddingBottom="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:contentDescription="@string/magnification_drag_corner_to_resize"
android:src="@drawable/ic_magnification_corner_bottom_left"
android:src="@drawable/ic_arrow_top_right_and_bottom_left"
android:accessibilityTraversalAfter="@id/bottom_right_corner"/>
<ImageView
@@ -124,7 +121,8 @@
android:layout_gravity="right|bottom"
android:padding="@dimen/magnifier_drag_handle_padding"
android:scaleType="center"
android:src="@drawable/ic_move_magnification"/>
android:src="@drawable/ic_move_magnification"
android:background="@drawable/accessibility_window_magnification_drag_handle_background"/>
<ImageView
android:id="@+id/close_button"

View File

@@ -219,5 +219,12 @@
<attr name="biometricsEnrollProgressHelp" format="reference|color" />
<attr name="biometricsEnrollProgressHelpWithTalkback" format="reference|color" />
</declare-styleable>
<declare-styleable name="SeekBarWithIconButtonsView_Layout">
<attr name="max" format="integer" />
<attr name="progress" format="integer" />
<attr name="iconStartContentDescription" format="reference" />
<attr name="iconEndContentDescription" format="reference" />
</declare-styleable>
</resources>

View File

@@ -168,10 +168,11 @@
<color name="GM2_yellow_200">#FDE293</color>
<!-- Window magnification colors -->
<color name="magnification_border_color">#FF9900</color>
<color name="magnification_border_color_change">#0000FF</color>
<color name="magnification_border_color">#F29900</color>
<color name="magnification_switch_button_color">#7F000000</color>
<color name="magnification_drag_corner_background">#E5FFFFFF</color>
<color name="magnification_drag_handle_color">#B3000000</color>
<color name="magnification_drag_handle_tint">#111111</color>
<color name="accessibility_magnifier_bg">#FCFCFC</color>
<color name="accessibility_magnifier_bg_stroke">#E0E0E0</color>
<color name="accessibility_magnifier_icon_color">#252525</color>

View File

@@ -1099,6 +1099,7 @@
<dimen name="magnification_outer_border_margin">15dp</dimen>
<dimen name="magnification_inner_border_margin">17dp</dimen>
<dimen name="magnification_mirror_surface_margin">20dp</dimen>
<dimen name="magnification_drag_corner_margin">8dp</dimen>
<dimen name="magnification_frame_move_short">5dp</dimen>
<dimen name="magnification_frame_move_long">25dp</dimen>
<dimen name="magnification_drag_view_size">36dp</dimen>
@@ -1111,6 +1112,15 @@
<dimen name="magnifier_left_right_controls_height">45dp</dimen>
<dimen name="magnifier_up_down_controls_width">45dp</dimen>
<dimen name="magnifier_up_down_controls_height">40dp</dimen>
<dimen name="magnifier_outer_corner_radius">30dp</dimen>
<dimen name="magnifier_corner_radius">28dp</dimen>
<dimen name="magnifier_edit_corner_radius">16dp</dimen>
<dimen name="magnifier_edit_outer_corner_radius">18dp</dimen>
<dimen name="magnifier_border_width">8dp</dimen>
<dimen name="magnifier_stroke_width">2dp</dimen>
<dimen name="magnifier_edit_dash_gap">20dp</dimen>
<dimen name="magnification_window_drag_corner_size">26dp</dimen>
<dimen name="magnification_window_drag_corner_stroke">3dp</dimen>
<!-- The extra padding to show the whole outer border -->
<dimen name="magnifier_drag_handle_padding">3dp</dimen>
<dimen name="magnification_max_frame_size">300dp</dimen>
@@ -1134,6 +1144,8 @@
<dimen name="magnification_setting_image_button_padding_horizontal">24dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_vertical">16dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
<dimen name="magnification_setting_seekbar_icon_size">24dp</dimen>
<!-- How far from the right edge of the screen you need to drag the window before the button
repositions to the other side. -->

View File

@@ -49,6 +49,7 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.util.TypedValue;
import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
@@ -1273,9 +1274,19 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
private void applyResourcesValues() {
mMirrorBorderView.setBackgroundColor(mResources.getColor(mEditSizeEnable
? R.color.magnification_border_color_change : R.color.magnification_border_color));
// Sets the border appearance for the magnifier window
mMirrorBorderView.setBackground(mResources.getDrawable(mEditSizeEnable
? R.drawable.accessibility_window_magnification_background_change
: R.drawable.accessibility_window_magnification_background));
// Changes the corner radius of the mMirrorSurfaceView
mMirrorSurfaceView.setCornerRadius(
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
mEditSizeEnable ? 16f : 28f,
mContext.getResources().getDisplayMetrics()));
// Sets visibility of components for the magnifier window
if (mEditSizeEnable) {
mDragView.setVisibility(View.GONE);
mCloseView.setVisibility(View.VISIBLE);

View File

@@ -53,6 +53,7 @@ import android.widget.Switch;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView;
import com.android.systemui.util.settings.SecureSettings;
import java.lang.annotation.Retention;
@@ -79,7 +80,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
private final MagnificationGestureDetector mGestureDetector;
private boolean mSingleTapDetected = false;
private SeekBar mZoomSeekbar;
private SeekBarWithIconButtonsView mZoomSeekbar;
private Switch mAllowDiagonalScrollingSwitch;
private LinearLayout mPanelView;
private LinearLayout mSettingView;
@@ -393,7 +394,8 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
mEditButton = mSettingView.findViewById(R.id.magnifier_edit_button);
mChangeModeButton = mSettingView.findViewById(R.id.magnifier_full_button);
mZoomSeekbar = mSettingView.findViewById(R.id.magnifier_zoom_seekbar);
mZoomSeekbar = mSettingView.findViewById(R.id.magnifier_zoom_slider);
mZoomSeekbar.setOnSeekBarChangeListener(new ZoomSeekbarChangeListener());
float scale = mSecureSettings.getFloatForUser(

View File

@@ -0,0 +1,185 @@
/*
* Copyright (C) 2023 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.common.ui.view;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import com.android.systemui.R;
/**
* The layout contains a seekbar whose progress could be modified
* through the icons on two ends of the seekbar.
*/
public class SeekBarWithIconButtonsView extends LinearLayout {
private static final int DEFAULT_SEEKBAR_MAX = 6;
private static final int DEFAULT_SEEKBAR_PROGRESS = 0;
private ImageView mIconStart;
private ImageView mIconEnd;
private SeekBar mSeekbar;
private SeekBarChangeListener mSeekBarListener = new SeekBarChangeListener();
public SeekBarWithIconButtonsView(Context context) {
this(context, null);
}
public SeekBarWithIconButtonsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SeekBarWithIconButtonsView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SeekBarWithIconButtonsView(Context context,
AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(
R.layout.seekbar_with_icon_buttons, this, /* attachToRoot= */ true);
mIconStart = findViewById(R.id.icon_start);
mIconEnd = findViewById(R.id.icon_end);
mSeekbar = findViewById(R.id.seekbar);
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(
attrs,
R.styleable.SeekBarWithIconButtonsView_Layout,
defStyleAttr, defStyleRes
);
int max = typedArray.getInt(
R.styleable.SeekBarWithIconButtonsView_Layout_max, DEFAULT_SEEKBAR_MAX);
int progress = typedArray.getInt(
R.styleable.SeekBarWithIconButtonsView_Layout_progress,
DEFAULT_SEEKBAR_PROGRESS);
mSeekbar.setMax(max);
setProgress(progress);
int iconStartContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconStartContentDescription,
/* defValue= */ 0);
int iconEndContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconEndContentDescription,
/* defValue= */ 0);
if (iconStartContentDescriptionId != 0) {
final String contentDescription =
context.getString(iconStartContentDescriptionId);
mIconStart.setContentDescription(contentDescription);
}
if (iconEndContentDescriptionId != 0) {
final String contentDescription =
context.getString(iconEndContentDescriptionId);
mIconEnd.setContentDescription(contentDescription);
}
typedArray.recycle();
} else {
mSeekbar.setMax(DEFAULT_SEEKBAR_MAX);
setProgress(DEFAULT_SEEKBAR_PROGRESS);
}
mSeekbar.setOnSeekBarChangeListener(mSeekBarListener);
mIconStart.setOnClickListener((view) -> {
final int progress = mSeekbar.getProgress();
if (progress > 0) {
mSeekbar.setProgress(progress - 1);
setIconViewEnabled(mIconStart, mSeekbar.getProgress() > 0);
}
});
mIconEnd.setOnClickListener((view) -> {
final int progress = mSeekbar.getProgress();
if (progress < mSeekbar.getMax()) {
mSeekbar.setProgress(progress + 1);
setIconViewEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
}
});
}
private static void setIconViewEnabled(View iconView, boolean enabled) {
iconView.setEnabled(enabled);
}
/**
* Sets a onSeekbarChangeListener to the seekbar in the layout.
* We update the Start Icon and End Icon if needed when the seekbar progress is changed.
*/
public void setOnSeekBarChangeListener(
@Nullable SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) {
mSeekBarListener.setOnSeekBarChangeListener(onSeekBarChangeListener);
}
/**
* Start and End icons might need to be updated when there is a change in seekbar progress.
* Icon Start will need to be enabled when the seekbar progress is larger than 0.
* Icon End will need to be enabled when the seekbar progress is less than Max.
*/
private void updateIconViewIfNeeded(int progress) {
setIconViewEnabled(mIconStart, progress > 0);
setIconViewEnabled(mIconEnd, progress < mSeekbar.getMax());
}
/**
* Sets progress to the seekbar in the layout.
*/
public void setProgress(int progress) {
mSeekbar.setProgress(progress);
updateIconViewIfNeeded(progress);
}
private class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = null;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
}
updateIconViewIfNeeded(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
}
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
}
}
void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
mOnSeekBarChangeListener = listener;
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2023 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.common.ui.view;
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.widget.ImageView;
import android.widget.SeekBar;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests for {@link SeekBarWithIconButtonsView}
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
private ImageView mIconStart;
private ImageView mIconEnd;
private SeekBar mSeekbar;
private SeekBarWithIconButtonsView mIconDiscreteSliderLinearLayout;
@Before
public void setUp() {
mIconDiscreteSliderLinearLayout = new SeekBarWithIconButtonsView(mContext);
mIconStart = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start);
mIconEnd = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end);
mSeekbar = mIconDiscreteSliderLinearLayout.findViewById(R.id.seekbar);
}
@Test
public void setSeekBarProgressZero_startIconAndFrameDisabled() {
mIconDiscreteSliderLinearLayout.setProgress(0);
assertThat(mIconStart.isEnabled()).isFalse();
assertThat(mIconEnd.isEnabled()).isTrue();
}
@Test
public void setSeekBarProgressMax_endIconAndFrameDisabled() {
mIconDiscreteSliderLinearLayout.setProgress(mSeekbar.getMax());
assertThat(mIconEnd.isEnabled()).isFalse();
assertThat(mIconStart.isEnabled()).isTrue();
}
@Test
public void setSeekBarProgressMax_allIconsAndFramesEnabled() {
// We are using the default value for the max of seekbar.
// Therefore, the max value will be DEFAULT_SEEKBAR_MAX = 6.
mIconDiscreteSliderLinearLayout.setProgress(1);
assertThat(mIconStart.isEnabled()).isTrue();
assertThat(mIconEnd.isEnabled()).isTrue();
}
@Test
public void clickIconEnd_currentProgressIsOneToMax_reachesMax() {
mIconDiscreteSliderLinearLayout.setProgress(mSeekbar.getMax() - 1);
mIconEnd.performClick();
assertThat(mSeekbar.getProgress()).isEqualTo(mSeekbar.getMax());
}
@Test
public void clickIconStart_currentProgressIsOne_reachesZero() {
mIconDiscreteSliderLinearLayout.setProgress(1);
mIconStart.performClick();
assertThat(mSeekbar.getProgress()).isEqualTo(0);
}
}