Merge "Revert "Create SettingsLibSeekBarPreference"" into sc-dev

This commit is contained in:
Giuliano Procida
2021-06-08 09:55:58 +00:00
committed by Android (Google) Code Review
21 changed files with 92 additions and 1435 deletions

View File

@@ -73,7 +73,6 @@ java_defaults {
"SettingsLibCollapsingToolbarBaseActivity",
"SettingsLibTwoTargetPreference",
"SettingsLibSettingsTransition",
"SettingsLibSeekBarPreference",
],
}

View File

@@ -1,14 +0,0 @@
android_library {
name: "SettingsLibSeekBarPreference",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
static_libs: [
"androidx.annotation_annotation",
"androidx.preference_preference",
"SettingsLibSettingsTheme",
],
min_sdk_version: "28",
}

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.widget">
<uses-sdk android:minSdkVersion="28" />
</manifest>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
<issue
id="NewApi"
message="Call requires API level R (current min is 28): android.widget.ProgressBar#setStateDescription"
errorLine1=" mSeekBar.setStateDescription(mSeekBarStateDescription);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SeekBarPreference/src/com/android/settingslib/widget/SeekBarPreference.java"
line="115"
column="22"/>
</issue>
</issues>

View File

@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="16dp"
android:paddingBottom="8dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_alignParentTop="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorPrimary" />
<SeekBar
android:id="@*android:id/seekbar"
android:layout_below="@android:id/title"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="-20dp"
android:layout_marginBottom="-28dp"
style="@android:style/Widget.Material.SeekBar.Discrete" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@*android:id/seekbar"
android:paddingBottom="8dp"
android:orientation="horizontal">
<TextView
android:id="@android:id/text1"
android:layout_marginStart="16dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start|top"
android:gravity="start"
android:layout_weight="1"/>
<TextView
android:id="@android:id/text2"
android:layout_marginEnd="16dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
android:gravity="end"
android:layout_weight="1"/>
</LinearLayout>
</RelativeLayout>

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:clickable="false"
android:orientation="horizontal">
<include layout="@layout/settingslib_icon_frame"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@android:id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingStart="12dp"
android:singleLine="true"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
<!-- Preference should place its actual preference widget here. -->
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:paddingStart="12dp"
android:orientation="vertical"/>
</LinearLayout>
<SeekBar
android:id="@*android:id/seekbar"
android:layout_gravity="center_vertical"
android:paddingStart="12dp"
android:layout_width="match_parent"
android:layout_height="48dp"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<declare-styleable name="LabeledSeekBarPreference">
<attr name="textStart" format="reference"/>
<attr name="textEnd" format="reference"/>
<attr name="tickMark" format="reference" />
</declare-styleable>
</resources>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<resources>
<!-- DO NOT TRANSLATE Summary placeholder -->
<string name="summary_placeholder" translatable="false">&#160;</string>
</resources>

View File

@@ -1,89 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
/** A slider preference with left and right labels **/
public class LabeledSeekBarPreference extends SeekBarPreference {
private final int mTextStartId;
private final int mTextEndId;
private final int mTickMarkId;
private OnPreferenceChangeListener mStopListener;
public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_labeled_slider);
final TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
R.styleable.LabeledSeekBarPreference);
mTextStartId = styledAttrs.getResourceId(
R.styleable.LabeledSeekBarPreference_textStart,
R.string.summary_placeholder);
mTextEndId = styledAttrs.getResourceId(
R.styleable.LabeledSeekBarPreference_textEnd,
R.string.summary_placeholder);
mTickMarkId = styledAttrs.getResourceId(
R.styleable.LabeledSeekBarPreference_tickMark, /* defValue= */ 0);
styledAttrs.recycle();
}
public LabeledSeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle, 0);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final TextView startText = (TextView) holder.findViewById(android.R.id.text1);
final TextView endText = (TextView) holder.findViewById(android.R.id.text2);
startText.setText(mTextStartId);
endText.setText(mTextEndId);
if (mTickMarkId != 0) {
final Drawable tickMark = getContext().getDrawable(mTickMarkId);
final SeekBar seekBar = (SeekBar) holder.findViewById(
com.android.internal.R.id.seekbar);
seekBar.setTickMark(tickMark);
}
}
public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
mStopListener = listener;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar);
if (mStopListener != null) {
mStopListener.onPreferenceChange(this, seekBar.getProgress());
}
}
}

View File

@@ -1,428 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
/**
* Based on android.preference.SeekBarPreference, but uses support preference as base.
*/
public class SeekBarPreference extends Preference
implements OnSeekBarChangeListener, View.OnKeyListener {
public static final int HAPTIC_FEEDBACK_MODE_NONE = 0;
public static final int HAPTIC_FEEDBACK_MODE_ON_TICKS = 1;
public static final int HAPTIC_FEEDBACK_MODE_ON_ENDS = 2;
protected int mDefaultProgress = -1;
protected SeekBar mSeekBar;
private int mProgress;
private int mMax;
private int mMin;
private boolean mTrackingTouch;
private boolean mContinuousUpdates;
private int mHapticFeedbackMode = HAPTIC_FEEDBACK_MODE_NONE;
private boolean mShouldBlink;
private int mAccessibilityRangeInfoType = AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT;
private CharSequence mSeekBarContentDescription;
private CharSequence mSeekBarStateDescription;
public SeekBarPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
setMin(a.getInt(com.android.internal.R.styleable.ProgressBar_min, mMin));
a.recycle();
a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Preference, defStyleAttr, defStyleRes);
final boolean isSelectable = a.getBoolean(
R.styleable.Preference_android_selectable, false);
setSelectable(isSelectable);
a.recycle();
setLayoutResource(R.layout.preference_widget_slider);
}
public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, androidx.preference.R.attr.seekBarPreferenceStyle);
}
public SeekBarPreference(Context context) {
this(context, null);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
view.itemView.setOnKeyListener(this);
mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
if (mSeekBar == null) {
return;
}
mSeekBar.setOnSeekBarChangeListener(this);
mSeekBar.setMax(mMax);
mSeekBar.setMin(mMin);
mSeekBar.setProgress(mProgress);
mSeekBar.setEnabled(isEnabled());
final CharSequence title = getTitle();
if (!TextUtils.isEmpty(mSeekBarContentDescription)) {
mSeekBar.setContentDescription(mSeekBarContentDescription);
} else if (!TextUtils.isEmpty(title)) {
mSeekBar.setContentDescription(title);
}
if (!TextUtils.isEmpty(mSeekBarStateDescription) && (Build.VERSION.SDK_INT
>= Build.VERSION_CODES.R)) {
mSeekBar.setStateDescription(mSeekBarStateDescription);
}
if (mShouldBlink) {
View v = view.itemView;
v.post(() -> {
if (v.getBackground() != null) {
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
v.getBackground().setHotspot(centerX, centerY);
}
v.setPressed(true);
v.setPressed(false);
mShouldBlink = false;
});
}
mSeekBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View view, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(view, info);
// Update the range info with the correct type
final AccessibilityNodeInfo.RangeInfo rangeInfo = info.getRangeInfo();
if (rangeInfo != null) {
info.setRangeInfo(AccessibilityNodeInfo.RangeInfo.obtain(
mAccessibilityRangeInfoType, rangeInfo.getMin(),
rangeInfo.getMax(), rangeInfo.getCurrent()));
}
}
});
}
@Override
public CharSequence getSummary() {
return null;
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setProgress(restoreValue ? getPersistedInt(mProgress)
: (Integer) defaultValue);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, 0);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return false;
}
final SeekBar seekBar = v.findViewById(com.android.internal.R.id.seekbar);
if (seekBar == null) {
return false;
}
return seekBar.onKeyDown(keyCode, event);
}
public int getMax() {
return mMax;
}
/**
* Sets the upper bound on the {@link SeekBar}.
*
* @param max The upper bound to set
*/
public void setMax(int max) {
if (max != mMax) {
mMax = max;
notifyChanged();
}
}
public int getMin() {
return mMin;
}
/**
* Sets the lower bound on the {@link SeekBar}.
*
* @param min The lower bound to set
*/
public void setMin(int min) {
if (min != mMin) {
mMin = min;
notifyChanged();
}
}
/**
* Sets the progress point to draw a single tick mark representing a default value.
*/
public void setDefaultProgress(int defaultProgress) {
if (mDefaultProgress != defaultProgress) {
mDefaultProgress = defaultProgress;
}
}
/**
* When {@code continuousUpdates} is true, update the persisted setting immediately as the thumb
* is dragged along the SeekBar. Otherwise, only update the value of the setting when the thumb
* is dropped.
*/
public void setContinuousUpdates(boolean continuousUpdates) {
mContinuousUpdates = continuousUpdates;
}
/**
* Sets the haptic feedback mode. HAPTIC_FEEDBACK_MODE_ON_TICKS means to perform haptic feedback
* as the SeekBar's progress is updated; HAPTIC_FEEDBACK_MODE_ON_ENDS means to perform haptic
* feedback as the SeekBar's progress value is equal to the min/max value.
*
* @param hapticFeedbackMode the haptic feedback mode.
*/
public void setHapticFeedbackMode(int hapticFeedbackMode) {
mHapticFeedbackMode = hapticFeedbackMode;
}
private void setProgress(int progress, boolean notifyChanged) {
if (progress > mMax) {
progress = mMax;
}
if (progress < mMin) {
progress = mMin;
}
if (progress != mProgress) {
mProgress = progress;
persistInt(progress);
if (notifyChanged) {
notifyChanged();
}
}
}
public int getProgress() {
return mProgress;
}
/**
* Sets the current progress of the {@link SeekBar}.
*
* @param progress The current progress of the {@link SeekBar}
*/
public void setProgress(int progress) {
setProgress(progress, true);
}
/**
* Persist the seekBar's progress value if callChangeListener
* returns true, otherwise set the seekBar's progress to the stored value
*/
void syncProgress(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (progress != mProgress) {
if (callChangeListener(progress)) {
setProgress(progress, false);
switch (mHapticFeedbackMode) {
case HAPTIC_FEEDBACK_MODE_ON_TICKS:
seekBar.performHapticFeedback(CLOCK_TICK);
break;
case HAPTIC_FEEDBACK_MODE_ON_ENDS:
if (progress == mMax || progress == mMin) {
seekBar.performHapticFeedback(CLOCK_TICK);
}
break;
}
} else {
seekBar.setProgress(mProgress);
}
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser && (mContinuousUpdates || !mTrackingTouch)) {
syncProgress(seekBar);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mTrackingTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTrackingTouch = false;
if (seekBar.getProgress() != mProgress) {
syncProgress(seekBar);
}
}
/**
* Specify the type of range this seek bar represents.
*
* @param rangeInfoType The type of range to be shared with accessibility
* @see android.view.accessibility.AccessibilityNodeInfo.RangeInfo
*/
public void setAccessibilityRangeInfoType(int rangeInfoType) {
mAccessibilityRangeInfoType = rangeInfoType;
}
/**
* Specify the content description for this seek bar represents.
*
* @param contentDescription the content description of seek bar
*/
public void setSeekBarContentDescription(CharSequence contentDescription) {
mSeekBarContentDescription = contentDescription;
if (mSeekBar != null) {
mSeekBar.setContentDescription(contentDescription);
}
}
/**
* Specify the state description for this seek bar represents.
*
* @param stateDescription the state description of seek bar
*/
@RequiresApi(Build.VERSION_CODES.R)
public void setSeekBarStateDescription(CharSequence stateDescription) {
mSeekBarStateDescription = stateDescription;
if (mSeekBar != null) {
mSeekBar.setStateDescription(stateDescription);
}
}
@Override
protected Parcelable onSaveInstanceState() {
/*
* Suppose a client uses this preference type without persisting. We
* must save the instance state so it is able to, for example, survive
* orientation changes.
*/
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
// Save the instance state
final SavedState myState = new SavedState(superState);
myState.mProgress = mProgress;
myState.mMax = mMax;
myState.mMin = mMin;
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
// Restore the instance state
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
mProgress = myState.mProgress;
mMax = myState.mMax;
mMin = myState.mMin;
notifyChanged();
}
/**
* SavedState, a subclass of {@link BaseSavedState}, will store the state
* of MyPreference, a subclass of Preference.
* <p>
* It is important to always call through to super methods.
*/
private static class SavedState extends BaseSavedState {
@SuppressWarnings("unused")
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
int mProgress;
int mMax;
int mMin;
SavedState(Parcel source) {
super(source);
// Restore the click counter
mProgress = source.readInt();
mMax = source.readInt();
mMin = source.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Save the click counter
dest.writeInt(mProgress);
dest.writeInt(mMax);
dest.writeInt(mMin);
}
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib;
import android.os.UserHandle;
/**
* A collection of API making a Preference "restrictable"
*/
public interface Restrictable {
/**
* Returns RestrictedPreferenceHelper
* @return
*/
RestrictedPreferenceHelper getHelper();
/**
* call preference notifyChanged()
*/
void notifyPreferenceChanged();
/**
* Set if show restriction message in Preference summary or not.
* @param useSummary.
*/
default void useAdminDisabledSummary(boolean useSummary) {
getHelper().useAdminDisabledSummary(useSummary);
}
/**
* Set the user restriction and disable this preference.
*
* @param userRestriction constant from {@link android.os.UserManager}
*/
default void checkRestrictionAndSetDisabled(String userRestriction) {
getHelper().checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
/**
* Set the user restriction and disable this preference for the given user.
*
* @param userRestriction constant from {@link android.os.UserManager}
* @param userId user to check the restriction for.
*/
default void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
getHelper().checkRestrictionAndSetDisabled(userRestriction, userId);
}
/**
* Disable preference based on the enforce admin.
*
* @param admin details of the admin who enforced the restriction. If it is {@code null}, then
* this preference will be enabled. Otherwise, it will be disabled.
*/
default void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
if (getHelper().setDisabledByAdmin(admin)) {
notifyPreferenceChanged();
}
}
/**
* Check whether this preference is disabled by admin.
*
* @return true if this preference is disabled by admin.
*/
default boolean isDisabledByAdmin() {
return getHelper().isDisabledByAdmin();
}
}

View File

@@ -16,7 +16,10 @@
package com.android.settingslib;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.content.Context;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.view.View;
@@ -30,8 +33,8 @@ import com.android.settingslib.widget.TwoTargetPreference;
* Preference class that supports being disabled by a user restriction
* set by a device admin.
*/
public class RestrictedPreference extends TwoTargetPreference implements Restrictable {
private RestrictedPreferenceHelper mHelper;
public class RestrictedPreference extends TwoTargetPreference {
RestrictedPreferenceHelper mHelper;
public RestrictedPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
@@ -79,14 +82,8 @@ public class RestrictedPreference extends TwoTargetPreference implements Restric
}
}
@Override
public RestrictedPreferenceHelper getHelper() {
return mHelper;
}
@Override
public void notifyPreferenceChanged() {
notifyChanged();
public void useAdminDisabledSummary(boolean useSummary) {
mHelper.useAdminDisabledSummary(useSummary);
}
@Override
@@ -95,6 +92,14 @@ public class RestrictedPreference extends TwoTargetPreference implements Restric
super.onAttachedToHierarchy(preferenceManager);
}
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
@Override
public void setEnabled(boolean enabled) {
if (enabled && isDisabledByAdmin()) {
@@ -103,4 +108,14 @@ public class RestrictedPreference extends TwoTargetPreference implements Restric
}
super.setEnabled(enabled);
}
public void setDisabledByAdmin(EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
}
}
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
}

View File

@@ -1,140 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.widget.DefaultIndicatorSeekBar;
import com.android.settingslib.widget.SeekBarPreference;
/**
* Based on android.preference.SeekBarPreference, but uses support preference as base.
*/
public class RestrictedSeekBarPreference extends SeekBarPreference implements Restrictable {
private CharSequence mSeekBarStateDescription;
private RestrictedPreferenceHelper mHelper;
public RestrictedSeekBarPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
final int secondTargetResId = getSecondTargetResId();
if (secondTargetResId != 0) {
setWidgetLayoutResource(secondTargetResId);
}
}
public RestrictedSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public RestrictedSeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, androidx.preference.R.attr.seekBarPreferenceStyle);
}
public RestrictedSeekBarPreference(Context context) {
this(context, null);
}
@Override
public boolean isSelectable() {
if (isDisabledByAdmin()) {
return true;
} else {
return super.isSelectable();
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
if (mSeekBar instanceof DefaultIndicatorSeekBar) {
((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
}
mHelper.onBindViewHolder(holder);
final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
if (restrictedIcon != null) {
restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
}
final View widgetFrame = holder.findViewById(android.R.id.widget_frame);
if (widgetFrame != null) {
widgetFrame.setVisibility(shouldHideSecondTarget() ? View.GONE : View.VISIBLE);
}
}
@Override
public void performClick() {
if (!mHelper.performClick()) {
super.performClick();
}
}
@Override
public void setEnabled(boolean enabled) {
if (enabled && isDisabledByAdmin()) {
mHelper.setDisabledByAdmin(null);
return;
}
super.setEnabled(enabled);
}
/**
* Sets the progress point to draw a single tick mark representing a default value.
*/
public void setDefaultProgress(int defaultProgress) {
if (mDefaultProgress != defaultProgress) {
mDefaultProgress = defaultProgress;
if (mSeekBar instanceof DefaultIndicatorSeekBar) {
((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
}
}
}
@Override
public RestrictedPreferenceHelper getHelper() {
return mHelper;
}
@Override
public void notifyPreferenceChanged() {
notifyChanged();
}
@Override
protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
mHelper.onAttachedToHierarchy();
super.onAttachedToHierarchy(preferenceManager);
}
protected int getSecondTargetResId() {
return R.layout.restricted_icon;
}
protected boolean shouldHideSecondTarget() {
return !isDisabledByAdmin();
}
}

View File

@@ -16,8 +16,11 @@
package com.android.settingslib;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
@@ -34,10 +37,10 @@ import androidx.preference.SwitchPreference;
* Version of SwitchPreference that can be disabled by a device admin
* using a user restriction.
*/
public class RestrictedSwitchPreference extends SwitchPreference implements Restrictable {
private RestrictedPreferenceHelper mHelper;
private boolean mUseAdditionalSummary = false;
private CharSequence mRestrictedSwitchSummary;
public class RestrictedSwitchPreference extends SwitchPreference {
RestrictedPreferenceHelper mHelper;
boolean mUseAdditionalSummary = false;
CharSequence mRestrictedSwitchSummary;
private int mIconSize;
public RestrictedSwitchPreference(Context context, AttributeSet attrs,
@@ -150,14 +153,8 @@ public class RestrictedSwitchPreference extends SwitchPreference implements Rest
}
}
@Override
public RestrictedPreferenceHelper getHelper() {
return mHelper;
}
@Override
public void notifyPreferenceChanged() {
notifyChanged();
public void useAdminDisabledSummary(boolean useSummary) {
mHelper.useAdminDisabledSummary(useSummary);
}
@Override
@@ -166,6 +163,14 @@ public class RestrictedSwitchPreference extends SwitchPreference implements Rest
super.onAttachedToHierarchy(preferenceManager);
}
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
@Override
public void setEnabled(boolean enabled) {
if (enabled && isDisabledByAdmin()) {
@@ -174,4 +179,14 @@ public class RestrictedSwitchPreference extends SwitchPreference implements Rest
}
super.setEnabled(enabled);
}
public void setDisabledByAdmin(EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
}
}
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
}

View File

@@ -16,7 +16,10 @@
package com.android.settingslib;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.content.Context;
import android.os.UserHandle;
import android.util.AttributeSet;
import androidx.core.content.res.TypedArrayUtils;
@@ -25,7 +28,7 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
/** Top level preference that can be disabled by a device admin using a user restriction. */
public class RestrictedTopLevelPreference extends Preference implements Restrictable {
public class RestrictedTopLevelPreference extends Preference {
private RestrictedPreferenceHelper mHelper;
public RestrictedTopLevelPreference(Context context, AttributeSet attrs,
@@ -66,14 +69,23 @@ public class RestrictedTopLevelPreference extends Preference implements Restrict
super.onAttachedToHierarchy(preferenceManager);
}
@Override
public RestrictedPreferenceHelper getHelper() {
return mHelper;
/**
* Set the user restriction and disable this preference.
*
* @param userRestriction constant from {@link android.os.UserManager}
*/
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
@Override
public void notifyPreferenceChanged() {
notifyChanged();
/**
* Set the user restriction and disable this preference for the given user.
*
* @param userRestriction constant from {@link android.os.UserManager}
* @param userId user to check the restriction for.
*/
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
@Override
@@ -84,4 +96,25 @@ public class RestrictedTopLevelPreference extends Preference implements Restrict
}
super.setEnabled(enabled);
}
/**
* Check whether this preference is disabled by admin.
*
* @return true if this preference is disabled by admin.
*/
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
/**
* Disable preference based on the enforce admin.
*
* @param admin details of the admin who enforced the restriction. If it is {@code null}, then
* this preference will be enabled. Otherwise, it will be disabled.
*/
public void setDisabledByAdmin(EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
}
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.SeekBar;
/**
* Customized default indicator seekbar
*/
public class DefaultIndicatorSeekBar extends SeekBar {
private int mDefaultProgress = -1;
public DefaultIndicatorSeekBar(Context context) {
super(context);
}
public DefaultIndicatorSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DefaultIndicatorSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public DefaultIndicatorSeekBar(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
/**
* N.B. Only draws the default indicator tick mark, NOT equally spaced tick marks.
*/
@Override
protected void drawTickMarks(Canvas canvas) {
if (isEnabled() && mDefaultProgress <= getMax() && mDefaultProgress >= getMin()) {
final Drawable defaultIndicator = getTickMark();
// Adjust the drawable's bounds to center it at the point where it's drawn.
final int w = defaultIndicator.getIntrinsicWidth();
final int h = defaultIndicator.getIntrinsicHeight();
final int halfW = w >= 0 ? w / 2 : 1;
final int halfH = h >= 0 ? h / 2 : 1;
defaultIndicator.setBounds(-halfW, -halfH, halfW, halfH);
// This mimics the computation of the thumb position, to get the true "default."
final int availableWidth = getWidth() - mPaddingLeft - mPaddingRight;
final int range = getMax() - getMin();
final float scale = range > 0f ? mDefaultProgress / (float) range : 0f;
final int offset = (int) ((scale * availableWidth) + 0.5f);
final int indicatorPosition = isLayoutRtl() && getMirrorForRtl()
? availableWidth - offset + mPaddingRight : offset + mPaddingLeft;
final int saveCount = canvas.save();
canvas.translate(indicatorPosition, getHeight() / 2);
defaultIndicator.draw(canvas);
canvas.restoreToCount(saveCount);
}
}
/**
* N.B. This sets the default *unadjusted* progress, i.e. in the SeekBar's [0 - max] terms.
*/
public void setDefaultProgress(int defaultProgress) {
if (mDefaultProgress != defaultProgress) {
mDefaultProgress = defaultProgress;
invalidate();
}
}
public int getDefaultProgress() {
return mDefaultProgress;
}
}

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.settingslib.widget.SeekBarPreference
android:key="seek_bar"
android:title="seek_bar_title"/>
</PreferenceScreen >

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.settingslib.widget.SeekBarPreference
android:key="seek_bar"
android:selectable="true"
android:title="seek_bar_title"/>
</PreferenceScreen >

View File

@@ -1,49 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class DefaultIndicatorSeekBarTest {
private DefaultIndicatorSeekBar mDefaultIndicatorSeekBar;
@Before
public void setUp() {
mDefaultIndicatorSeekBar = new DefaultIndicatorSeekBar(RuntimeEnvironment.application);
mDefaultIndicatorSeekBar.setMax(100);
}
@After
public void tearDown() {
mDefaultIndicatorSeekBar = null;
}
@Test
public void defaultProgress_setSucceeds() {
mDefaultIndicatorSeekBar.setDefaultProgress(40);
assertEquals(40, mDefaultIndicatorSeekBar.getDefaultProgress());
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import androidx.preference.Preference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class LabeledSeekBarPreferenceTest {
private Context mContext;
private SeekBar mSeekBar;
private LabeledSeekBarPreference mSeekBarPreference;
@Mock
private Preference.OnPreferenceChangeListener mListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mSeekBarPreference = new LabeledSeekBarPreference(mContext, null);
LayoutInflater inflater = LayoutInflater.from(mContext);
final View view =
inflater.inflate(mSeekBarPreference.getLayoutResource(),
new LinearLayout(mContext), false);
mSeekBar = view.findViewById(com.android.internal.R.id.seekbar);
}
@Test
public void seekBarPreferenceOnStopTrackingTouch_callsListener() {
mSeekBar.setProgress(2);
mSeekBarPreference.setOnPreferenceChangeStopListener(mListener);
mSeekBarPreference.onStopTrackingTouch(mSeekBar);
verify(mListener, times(1)).onPreferenceChange(mSeekBarPreference, 2);
}
}

View File

@@ -1,172 +0,0 @@
/*
* Copyright (C) 2021 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.settingslib.widget;
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.SeekBar;
import androidx.preference.PreferenceFragmentCompat;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.androidx.fragment.FragmentController;
@RunWith(RobolectricTestRunner.class)
public class SeekBarPreferenceTest {
private static final int MAX = 75;
private static final int MIN = 5;
private static final int PROGRESS = 16;
private static final int NEW_PROGRESS = 17;
private Context mContext;
private SeekBarPreference mSeekBarPreference;
private SeekBar mSeekBar;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mSeekBarPreference = spy(new SeekBarPreference(mContext));
mSeekBarPreference.setMax(MAX);
mSeekBarPreference.setMin(MIN);
mSeekBarPreference.setProgress(PROGRESS);
mSeekBarPreference.setPersistent(false);
mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_NONE);
mSeekBar = new SeekBar(mContext);
mSeekBar.setMax(MAX);
mSeekBar.setMin(MIN);
}
@Test
public void testSaveAndRestoreInstanceState() {
final Parcelable parcelable = mSeekBarPreference.onSaveInstanceState();
final SeekBarPreference preference = new SeekBarPreference(mContext);
preference.onRestoreInstanceState(parcelable);
assertThat(preference.getMax()).isEqualTo(MAX);
assertThat(preference.getMin()).isEqualTo(MIN);
assertThat(preference.getProgress()).isEqualTo(PROGRESS);
}
@Test
@Config(qualifiers = "mcc998")
@Ignore("b/188888268")
public void isSelectable_default_returnFalse() {
final PreferenceFragmentCompat fragment = FragmentController.of(new TestFragment(),
new Bundle())
.create()
.start()
.resume()
.get();
final SeekBarPreference seekBarPreference = fragment.findPreference("seek_bar");
assertThat(seekBarPreference.isSelectable()).isFalse();
}
@Test
@Config(qualifiers = "mcc999")
@Ignore("b/188888268")
public void isSelectable_selectableInXml_returnTrue() {
final PreferenceFragmentCompat fragment = FragmentController.of(new TestFragment(),
new Bundle())
.create()
.start()
.resume()
.get();
final SeekBarPreference seekBarPreference = fragment.findPreference("seek_bar");
assertThat(seekBarPreference.isSelectable()).isTrue();
}
@Test
public void onProgressChanged_hapticFeedbackModeNone_clockTickFeedbackNotPerformed() {
mSeekBar.setProgress(NEW_PROGRESS);
when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true);
mSeekBar.performHapticFeedback(CONTEXT_CLICK);
mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true);
assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isNotEqualTo(CLOCK_TICK);
}
@Test
public void onProgressChanged_hapticFeedbackModeOnTicks_clockTickFeedbackPerformed() {
mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_TICKS);
mSeekBar.setProgress(NEW_PROGRESS);
when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true);
mSeekBar.performHapticFeedback(CONTEXT_CLICK);
mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true);
assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
}
@Test
public void onProgressChanged_hapticFeedbackModeOnEnds_clockTickFeedbackNotPerformed() {
mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS);
mSeekBar.setProgress(NEW_PROGRESS);
when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true);
mSeekBar.performHapticFeedback(CONTEXT_CLICK);
mSeekBarPreference.onProgressChanged(mSeekBar, NEW_PROGRESS, true);
assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isNotEqualTo(CLOCK_TICK);
}
@Test
public void onProgressChanged_hapticFeedbackModeOnEndsAndMinValue_clockTickFeedbackPerformed() {
mSeekBarPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS);
mSeekBar.setProgress(MIN);
when(mSeekBarPreference.callChangeListener(anyInt())).thenReturn(true);
mSeekBar.performHapticFeedback(CONTEXT_CLICK);
mSeekBarPreference.onProgressChanged(mSeekBar, MIN, true);
assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
}
public static class TestFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.seekbar_preference);
}
}
}