fix: 首次提交

This commit is contained in:
2024-12-09 11:25:23 +08:00
parent d0c01071e9
commit 2c2109a5f3
4741 changed files with 290641 additions and 0 deletions

View File

@@ -0,0 +1,392 @@
/*
* 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.settingslib.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.utils.BuildCompatUtils;
import com.android.settingslib.widget.preference.banner.R;
/**
* Banner message is a banner displaying important information (permission request, page error etc),
* and provide actions for user to address. It requires a user action to be dismissed.
*/
public class BannerMessagePreference extends Preference {
public enum AttentionLevel {
HIGH(0, R.color.banner_background_attention_high, R.color.banner_accent_attention_high),
MEDIUM(1,
R.color.banner_background_attention_medium,
R.color.banner_accent_attention_medium),
LOW(2, R.color.banner_background_attention_low, R.color.banner_accent_attention_low);
// Corresponds to the enum valye of R.attr.attentionLevel
private final int mAttrValue;
@ColorRes private final int mBackgroundColorResId;
@ColorRes private final int mAccentColorResId;
AttentionLevel(int attrValue, @ColorRes int backgroundColorResId,
@ColorRes int accentColorResId) {
mAttrValue = attrValue;
mBackgroundColorResId = backgroundColorResId;
mAccentColorResId = accentColorResId;
}
static AttentionLevel fromAttr(int attrValue) {
for (AttentionLevel level : values()) {
if (level.mAttrValue == attrValue) {
return level;
}
}
throw new IllegalArgumentException();
}
public @ColorRes int getAccentColorResId() {
return mAccentColorResId;
}
public @ColorRes int getBackgroundColorResId() {
return mBackgroundColorResId;
}
}
private static final String TAG = "BannerPreference";
private static final boolean IS_AT_LEAST_S = BuildCompatUtils.isAtLeastS();
private final BannerMessagePreference.ButtonInfo mPositiveButtonInfo =
new BannerMessagePreference.ButtonInfo();
private final BannerMessagePreference.ButtonInfo mNegativeButtonInfo =
new BannerMessagePreference.ButtonInfo();
private final BannerMessagePreference.DismissButtonInfo mDismissButtonInfo =
new BannerMessagePreference.DismissButtonInfo();
// Default attention level is High.
private AttentionLevel mAttentionLevel = AttentionLevel.HIGH;
private String mSubtitle;
public BannerMessagePreference(Context context) {
super(context);
init(context, null /* attrs */);
}
public BannerMessagePreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setSelectable(false);
setLayoutResource(R.layout.settingslib_banner_message);
if (IS_AT_LEAST_S) {
if (attrs != null) {
// Get attention level and subtitle from layout XML
TypedArray a =
context.obtainStyledAttributes(attrs, R.styleable.BannerMessagePreference);
int mAttentionLevelValue =
a.getInt(R.styleable.BannerMessagePreference_attentionLevel, 0);
mAttentionLevel = AttentionLevel.fromAttr(mAttentionLevelValue);
mSubtitle = a.getString(R.styleable.BannerMessagePreference_subtitle);
a.recycle();
}
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final Context context = getContext();
final TextView titleView = (TextView) holder.findViewById(R.id.banner_title);
CharSequence title = getTitle();
titleView.setText(title);
titleView.setVisibility(title == null ? View.GONE : View.VISIBLE);
final TextView summaryView = (TextView) holder.findViewById(R.id.banner_summary);
summaryView.setText(getSummary());
mPositiveButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_positive_btn);
mNegativeButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_negative_btn);
final Resources.Theme theme = context.getTheme();
@ColorInt final int accentColor =
context.getResources().getColor(mAttentionLevel.getAccentColorResId(), theme);
final ImageView iconView = (ImageView) holder.findViewById(R.id.banner_icon);
if (iconView != null) {
Drawable icon = getIcon();
iconView.setImageDrawable(
icon == null
? getContext().getDrawable(R.drawable.ic_warning)
: icon);
iconView.setColorFilter(
new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN));
}
if (IS_AT_LEAST_S) {
@ColorInt final int backgroundColor =
context.getResources().getColor(
mAttentionLevel.getBackgroundColorResId(), theme);
holder.setDividerAllowedAbove(false);
holder.setDividerAllowedBelow(false);
holder.itemView.getBackground().setTint(backgroundColor);
mPositiveButtonInfo.mColor = accentColor;
mNegativeButtonInfo.mColor = accentColor;
mDismissButtonInfo.mButton = (ImageButton) holder.findViewById(R.id.banner_dismiss_btn);
mDismissButtonInfo.setUpButton();
final TextView subtitleView = (TextView) holder.findViewById(R.id.banner_subtitle);
subtitleView.setText(mSubtitle);
subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE);
} else {
holder.setDividerAllowedAbove(true);
holder.setDividerAllowedBelow(true);
}
mPositiveButtonInfo.setUpButton();
mNegativeButtonInfo.setUpButton();
}
/**
* Set the visibility state of positive button.
*/
public BannerMessagePreference setPositiveButtonVisible(boolean isVisible) {
if (isVisible != mPositiveButtonInfo.mIsVisible) {
mPositiveButtonInfo.mIsVisible = isVisible;
notifyChanged();
}
return this;
}
/**
* Set the visibility state of negative button.
*/
public BannerMessagePreference setNegativeButtonVisible(boolean isVisible) {
if (isVisible != mNegativeButtonInfo.mIsVisible) {
mNegativeButtonInfo.mIsVisible = isVisible;
notifyChanged();
}
return this;
}
/**
* Set the visibility state of dismiss button.
*/
@RequiresApi(Build.VERSION_CODES.S)
public BannerMessagePreference setDismissButtonVisible(boolean isVisible) {
if (isVisible != mDismissButtonInfo.mIsVisible) {
mDismissButtonInfo.mIsVisible = isVisible;
notifyChanged();
}
return this;
}
/**
* Register a callback to be invoked when positive button is clicked.
*/
public BannerMessagePreference setPositiveButtonOnClickListener(
View.OnClickListener listener) {
if (listener != mPositiveButtonInfo.mListener) {
mPositiveButtonInfo.mListener = listener;
notifyChanged();
}
return this;
}
/**
* Register a callback to be invoked when negative button is clicked.
*/
public BannerMessagePreference setNegativeButtonOnClickListener(
View.OnClickListener listener) {
if (listener != mNegativeButtonInfo.mListener) {
mNegativeButtonInfo.mListener = listener;
notifyChanged();
}
return this;
}
/**
* Register a callback to be invoked when the dismiss button is clicked.
*/
@RequiresApi(Build.VERSION_CODES.S)
public BannerMessagePreference setDismissButtonOnClickListener(
View.OnClickListener listener) {
if (listener != mDismissButtonInfo.mListener) {
mDismissButtonInfo.mListener = listener;
notifyChanged();
}
return this;
}
/**
* Sets the text to be displayed in positive button.
*/
public BannerMessagePreference setPositiveButtonText(@StringRes int textResId) {
return setPositiveButtonText(getContext().getString(textResId));
}
/**
* Sets the text to be displayed in positive button.
*/
public BannerMessagePreference setPositiveButtonText(String positiveButtonText) {
if (!TextUtils.equals(positiveButtonText, mPositiveButtonInfo.mText)) {
mPositiveButtonInfo.mText = positiveButtonText;
notifyChanged();
}
return this;
}
/**
* Sets the text to be displayed in negative button.
*/
public BannerMessagePreference setNegativeButtonText(@StringRes int textResId) {
return setNegativeButtonText(getContext().getString(textResId));
}
/**
* Sets the text to be displayed in negative button.
*/
public BannerMessagePreference setNegativeButtonText(String negativeButtonText) {
if (!TextUtils.equals(negativeButtonText, mNegativeButtonInfo.mText)) {
mNegativeButtonInfo.mText = negativeButtonText;
notifyChanged();
}
return this;
}
/**
* Sets the subtitle.
*/
@RequiresApi(Build.VERSION_CODES.S)
public BannerMessagePreference setSubtitle(@StringRes int textResId) {
return setSubtitle(getContext().getString(textResId));
}
/**
* Sets the subtitle.
*/
@RequiresApi(Build.VERSION_CODES.S)
public BannerMessagePreference setSubtitle(String subtitle) {
if (!TextUtils.equals(subtitle, mSubtitle)) {
mSubtitle = subtitle;
notifyChanged();
}
return this;
}
/**
* Sets the attention level. This will update the color theme of the preference.
*/
public BannerMessagePreference setAttentionLevel(AttentionLevel attentionLevel) {
if (attentionLevel == mAttentionLevel) {
return this;
}
if (attentionLevel != null) {
mAttentionLevel = attentionLevel;
notifyChanged();
}
return this;
}
static class ButtonInfo {
private Button mButton;
private CharSequence mText;
private View.OnClickListener mListener;
private boolean mIsVisible = true;
@ColorInt private int mColor;
void setUpButton() {
mButton.setText(mText);
mButton.setOnClickListener(mListener);
if (IS_AT_LEAST_S) {
mButton.setTextColor(mColor);
}
if (shouldBeVisible()) {
mButton.setVisibility(View.VISIBLE);
} else {
mButton.setVisibility(View.GONE);
}
}
/**
* By default, two buttons are visible.
* If user didn't set a text for a button, then it should not be shown.
*/
private boolean shouldBeVisible() {
return mIsVisible && (!TextUtils.isEmpty(mText));
}
}
static class DismissButtonInfo {
private ImageButton mButton;
private View.OnClickListener mListener;
private boolean mIsVisible = true;
void setUpButton() {
mButton.setOnClickListener(mListener);
if (shouldBeVisible()) {
mButton.setVisibility(View.VISIBLE);
} else {
mButton.setVisibility(View.GONE);
}
}
/**
* By default, dismiss button is visible if it has a click listener.
*/
private boolean shouldBeVisible() {
return mIsVisible && (mListener != null);
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.Rect;
import android.util.AttributeSet;
import android.view.TouchDelegate;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.settingslib.widget.preference.banner.R;
/**
* The view providing {@link BannerMessagePreference}.
*
* <p>Callers should not instantiate this view directly but rather through adding a
* {@link BannerMessagePreference} to a {@code PreferenceScreen}.
*/
public class BannerMessageView extends LinearLayout {
private Rect mTouchTargetForDismissButton;
public BannerMessageView(Context context) {
super(context);
}
public BannerMessageView(Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
}
public BannerMessageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public BannerMessageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setupIncreaseTouchTargetForDismissButton();
}
private void setupIncreaseTouchTargetForDismissButton() {
if (mTouchTargetForDismissButton != null) {
// Already set up
return;
}
// The dismiss button is in the 'top row' RelativeLayout for positioning, but this element
// does not have enough space to provide large touch targets. We therefore set the top
// target on this view.
View topRow = findViewById(R.id.top_row);
View dismissButton = findViewById(R.id.banner_dismiss_btn);
if (topRow == null || dismissButton == null || dismissButton.getVisibility() != VISIBLE) {
return;
}
int minimum =
getResources()
.getDimensionPixelSize(com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target);
int width = dismissButton.getWidth();
int height = dismissButton.getHeight();
int widthIncrease = width < minimum ? minimum - width : 0;
int heightIncrease = height < minimum ? minimum - height : 0;
// Compute the hit rect of dismissButton within the local co-orindate reference of this view
// (rather than it's direct parent topRow).
Rect hitRectWithinTopRow = new Rect();
dismissButton.getHitRect(hitRectWithinTopRow);
Rect hitRectOfTopRowWithinThis = new Rect();
topRow.getHitRect(hitRectOfTopRowWithinThis);
mTouchTargetForDismissButton = new Rect();
mTouchTargetForDismissButton.left =
hitRectOfTopRowWithinThis.left + hitRectWithinTopRow.left;
mTouchTargetForDismissButton.right =
hitRectOfTopRowWithinThis.left + hitRectWithinTopRow.right;
mTouchTargetForDismissButton.top =
hitRectOfTopRowWithinThis.top + hitRectWithinTopRow.top;
mTouchTargetForDismissButton.bottom =
hitRectOfTopRowWithinThis.top + hitRectWithinTopRow.bottom;
// Adjust the touch target rect to apply the necessary increase in width and height.
mTouchTargetForDismissButton.left -=
widthIncrease % 2 == 1 ? (widthIncrease / 2) + 1 : widthIncrease / 2;
mTouchTargetForDismissButton.top -=
heightIncrease % 2 == 1 ? (heightIncrease / 2) + 1 : heightIncrease / 2;
mTouchTargetForDismissButton.right += widthIncrease / 2;
mTouchTargetForDismissButton.bottom += heightIncrease / 2;
setTouchDelegate(new TouchDelegate(mTouchTargetForDismissButton, dismissButton));
}
}