Merge "Add Settings for vector-specific PointerIcon fill colors." into main

This commit is contained in:
Treehugger Robot
2024-06-07 16:31:59 +00:00
committed by Android (Google) Code Review
7 changed files with 376 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2024 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.settings.inputmethod;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_GREEN;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_PINK;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_YELLOW;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.BlendMode;
import android.graphics.BlendModeColorFilter;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.StateSet;
import android.view.Gravity;
import android.view.PointerIcon;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settingslib.Utils;
public class PointerFillStylePreference extends Preference {
@Nullable private LinearLayout mButtonHolder;
public PointerFillStylePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.pointer_icon_fill_style_layout);
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mButtonHolder = (LinearLayout) holder.findViewById(R.id.button_holder);
// Intercept hover events so setting row does not highlight when hovering buttons.
if (mButtonHolder != null) {
mButtonHolder.setOnHoverListener((v, e) -> true);
}
int currentStyle = getPreferenceDataStore().getInt(Settings.System.POINTER_FILL_STYLE,
POINTER_ICON_VECTOR_STYLE_FILL_BLACK);
initStyleButton(holder, R.id.button_black, POINTER_ICON_VECTOR_STYLE_FILL_BLACK,
currentStyle);
initStyleButton(holder, R.id.button_green, POINTER_ICON_VECTOR_STYLE_FILL_GREEN,
currentStyle);
initStyleButton(holder, R.id.button_yellow, POINTER_ICON_VECTOR_STYLE_FILL_YELLOW,
currentStyle);
initStyleButton(holder, R.id.button_pink, POINTER_ICON_VECTOR_STYLE_FILL_PINK,
currentStyle);
initStyleButton(holder, R.id.button_blue, POINTER_ICON_VECTOR_STYLE_FILL_BLUE,
currentStyle);
}
private void initStyleButton(@NonNull PreferenceViewHolder holder, int id, int style,
int currentStyle) {
ImageView button = (ImageView) holder.findViewById(id);
if (button == null) {
return;
}
int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill};
try (TypedArray ta = getContext().obtainStyledAttributes(
PointerIcon.vectorFillStyleToResource(style), attrs)) {
button.setBackground(getBackgroundSelector(ta.getColor(0, Color.BLACK)));
}
button.setForeground(getForegroundDrawable(style, currentStyle));
button.setForegroundGravity(Gravity.CENTER);
button.setOnClickListener(
(v) -> {
getPreferenceDataStore().putInt(Settings.System.POINTER_FILL_STYLE, style);
setButtonChecked(id);
});
button.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW));
}
// Generate background instead of defining in XML so we can use res color from the platform.
private StateListDrawable getBackgroundSelector(int color) {
StateListDrawable background = new StateListDrawable();
Resources res = getContext().getResources();
int ovalSize = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_diameter);
background.setBounds(0, 0, ovalSize, ovalSize);
// Add hovered state first! The order states are added matters for a StateListDrawable.
GradientDrawable hoveredOval = new GradientDrawable();
hoveredOval.setColor(color);
int textColor = Utils.getColorAttr(getContext(),
com.android.internal.R.attr.materialColorOutline).getDefaultColor();
hoveredOval.setStroke(
res.getDimensionPixelSize(R.dimen.pointer_fill_style_shape_hovered_stroke),
textColor);
hoveredOval.setSize(ovalSize, ovalSize);
hoveredOval.setBounds(0, 0, ovalSize, ovalSize);
hoveredOval.setCornerRadius(ovalSize / 2f);
background.addState(new int[]{android.R.attr.state_hovered}, hoveredOval);
GradientDrawable defaultOval = new GradientDrawable();
defaultOval.setColor(color);
defaultOval.setStroke(
res.getDimensionPixelSize(R.dimen.pointer_fill_style_shape_default_stroke),
textColor);
defaultOval.setSize(ovalSize, ovalSize);
defaultOval.setBounds(0, 0, ovalSize, ovalSize);
defaultOval.setCornerRadius(ovalSize / 2f);
background.addState(StateSet.WILD_CARD, defaultOval);
return background;
}
private Drawable getForegroundDrawable(int style, int currentStyle) {
Resources res = getContext().getResources();
int ovalSize = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_diameter);
Drawable checkMark = getContext().getDrawable(R.drawable.ic_check_24dp);
int padding = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_padding) / 2;
checkMark.setBounds(padding, padding, ovalSize - padding, ovalSize - padding);
checkMark.setColorFilter(new BlendModeColorFilter(Color.WHITE, BlendMode.SRC_IN));
checkMark.setAlpha(style == currentStyle ? 255 : 0);
return checkMark;
}
private void setButtonChecked(int id) {
if (mButtonHolder == null) {
return;
}
for (int i = 0; i < mButtonHolder.getChildCount(); i++) {
View child = mButtonHolder.getChildAt(i);
if (child != null) {
child.getForeground().setAlpha(child.getId() == id ? 255 : 0);
}
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2024 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.settings.inputmethod;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
public class PointerFillStylePreferenceController extends BasePreferenceController {
@VisibleForTesting
static final String KEY_POINTER_FILL_STYLE = "pointer_fill_style";
public PointerFillStylePreferenceController(@NonNull Context context) {
super(context, KEY_POINTER_FILL_STYLE);
}
@AvailabilityStatus
public int getAvailabilityStatus() {
return android.view.flags.Flags.enableVectorCursorA11ySettings() ? AVAILABLE
: CONDITIONALLY_UNAVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
Preference pointerFillStylePreference = screen.findPreference(KEY_POINTER_FILL_STYLE);
if (pointerFillStylePreference == null) {
return;
}
pointerFillStylePreference.setPreferenceDataStore(new PreferenceDataStore() {
@Override
public void putInt(@NonNull String key, int value) {
Settings.System.putIntForUser(mContext.getContentResolver(), key, value,
UserHandle.USER_CURRENT);
}
@Override
public int getInt(@NonNull String key, int defValue) {
return Settings.System.getIntForUser(mContext.getContentResolver(), key, defValue,
UserHandle.USER_CURRENT);
}
});
}
}