• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.accessibility;
18 
19 import static android.graphics.drawable.GradientDrawable.Orientation;
20 
21 import static com.android.settings.accessibility.AccessibilityUtil.getScreenHeightPixels;
22 import static com.android.settings.accessibility.AccessibilityUtil.getScreenWidthPixels;
23 
24 import static com.google.common.primitives.Ints.max;
25 
26 import android.content.Context;
27 import android.content.res.ColorStateList;
28 import android.graphics.Paint.FontMetrics;
29 import android.graphics.drawable.GradientDrawable;
30 import android.util.AttributeSet;
31 import android.view.Gravity;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.TextView;
35 
36 import androidx.annotation.ColorInt;
37 import androidx.annotation.IntDef;
38 import androidx.core.text.TextUtilsCompat;
39 import androidx.preference.Preference;
40 import androidx.preference.PreferenceViewHolder;
41 
42 import com.android.settings.R;
43 import com.android.settingslib.Utils;
44 
45 import com.google.common.primitives.Floats;
46 import com.google.common.primitives.Ints;
47 
48 import java.lang.annotation.Retention;
49 import java.lang.annotation.RetentionPolicy;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collections;
53 import java.util.Comparator;
54 import java.util.List;
55 import java.util.Locale;
56 import java.util.stream.Collectors;
57 
58 /** Preference that easier preview by matching name to color. */
59 public final class PaletteListPreference extends Preference {
60 
61     private final List<Integer> mGradientColors = new ArrayList<>();
62     private final List<Float> mGradientOffsets = new ArrayList<>();
63 
64     @IntDef({
65             Position.START,
66             Position.CENTER,
67             Position.END,
68     })
69     @Retention(RetentionPolicy.SOURCE)
70     @interface Position {
71         int START = 0;
72         int CENTER = 1;
73         int END = 2;
74     }
75 
76     /**
77      * Constructs a new PaletteListPreference with the given context's theme and the supplied
78      * attribute set.
79      *
80      * @param context The Context this is associated with, through which it can access the current
81      *                theme, resources, etc.
82      * @param attrs The attributes of the XML tag that is inflating the view.
83      */
PaletteListPreference(Context context, AttributeSet attrs)84     public PaletteListPreference(Context context, AttributeSet attrs) {
85         this(context, attrs, 0);
86     }
87 
88     /**
89      * Constructs a new PaletteListPreference with the given context's theme, the supplied
90      * attribute set, and default style attribute.
91      *
92      * @param context The Context this is associated with, through which it can access the
93      *                current theme, resources, etc.
94      * @param attrs The attributes of the XML tag that is inflating the view.
95      * @param defStyleAttr An attribute in the current theme that contains a reference to a style
96      *                     resource that supplies default
97      *                     values for the view. Can be 0 to not look for
98      *                     defaults.
99      */
PaletteListPreference(Context context, AttributeSet attrs, int defStyleAttr)100     public PaletteListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
101         super(context, attrs, defStyleAttr);
102         setLayoutResource(R.layout.daltonizer_preview);
103     }
104 
105     @Override
onBindViewHolder(PreferenceViewHolder holder)106     public void onBindViewHolder(PreferenceViewHolder holder) {
107         super.onBindViewHolder(holder);
108 
109         final ViewGroup paletteView = holder.itemView.findViewById(R.id.palette_view);
110         initPaletteAttributes(getContext());
111         initPaletteView(getContext(), paletteView);
112     }
113 
initPaletteAttributes(Context context)114     private void initPaletteAttributes(Context context) {
115         final int defaultColor = context.getColor(R.color.palette_list_gradient_background);
116         mGradientColors.add(Position.START, defaultColor);
117         mGradientColors.add(Position.CENTER, defaultColor);
118         mGradientColors.add(Position.END, defaultColor);
119 
120         mGradientOffsets.add(Position.START, /* element= */ 0.0f);
121         mGradientOffsets.add(Position.CENTER, /* element= */ 0.5f);
122         mGradientOffsets.add(Position.END, /* element= */ 1.0f);
123     }
124 
initPaletteView(Context context, ViewGroup rootView)125     private void initPaletteView(Context context, ViewGroup rootView) {
126         if (rootView.getChildCount() > 0) {
127             rootView.removeAllViews();
128         }
129 
130         final List<Integer> paletteColors = getPaletteColors(context);
131         final List<String> paletteData = getPaletteData(context);
132 
133         final ColorStateList textColor =
134                 Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
135         final float textPadding =
136                 context.getResources().getDimension(R.dimen.accessibility_layout_margin_start_end);
137         final String maxLengthData =
138                 Collections.max(paletteData, Comparator.comparing(String::length));
139         final int textWidth = getTextWidth(context, maxLengthData);
140         final float textBound = (textWidth + textPadding) / getScreenWidthPixels(context);
141         mGradientOffsets.set(Position.CENTER, textBound);
142 
143         final int screenHalfHeight = getScreenHeightPixels(context) / 2;
144         final int paletteItemHeight =
145                 max(screenHalfHeight / paletteData.size(), getTextLineHeight(context));
146 
147         for (int i = 0; i < paletteData.size(); ++i) {
148             final TextView textView = new TextView(context);
149             textView.setText(paletteData.get(i));
150             textView.setTextColor(textColor);
151             textView.setHeight(paletteItemHeight);
152             textView.setPaddingRelative(Math.round(textPadding), 0, 0, 0);
153             textView.setGravity(Gravity.CENTER_VERTICAL);
154             textView.setBackground(createGradientDrawable(rootView, paletteColors.get(i)));
155 
156             rootView.addView(textView);
157         }
158 
159         updateFirstAndLastItemsBackground(context, rootView, paletteData.size());
160     }
161 
createGradientDrawable(ViewGroup rootView, @ColorInt int color)162     private GradientDrawable createGradientDrawable(ViewGroup rootView, @ColorInt int color) {
163         mGradientColors.set(Position.END, color);
164 
165         final GradientDrawable gradientDrawable = new GradientDrawable();
166         final Locale locale = Locale.getDefault();
167         final Orientation orientation =
168                 TextUtilsCompat.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL
169                     ? Orientation.RIGHT_LEFT
170                     : Orientation.LEFT_RIGHT;
171         gradientDrawable.setOrientation(orientation);
172         gradientDrawable.setColors(Ints.toArray(mGradientColors), Floats.toArray(mGradientOffsets));
173 
174         return gradientDrawable;
175     }
176 
updateFirstAndLastItemsBackground(Context context, ViewGroup rootView, int size)177     private void updateFirstAndLastItemsBackground(Context context, ViewGroup rootView, int size) {
178         final int radius =
179                 context.getResources().getDimensionPixelSize(
180                         R.dimen.accessibility_illustration_view_radius);
181         final int lastIndex = size - 1;
182         final GradientDrawable firstItem =
183                 (GradientDrawable) rootView.getChildAt(0).getBackground();
184         final GradientDrawable lastItem =
185                 (GradientDrawable) rootView.getChildAt(lastIndex).getBackground();
186         firstItem.setCornerRadii(new float[]{radius, radius, radius, radius, 0, 0, 0, 0});
187         lastItem.setCornerRadii(new float[]{0, 0, 0, 0, radius, radius, radius, radius});
188     }
189 
getPaletteColors(Context context)190     private List<Integer> getPaletteColors(Context context) {
191         final int[] paletteResources =
192                 context.getResources().getIntArray(R.array.setting_palette_colors);
193         return Arrays.stream(paletteResources).boxed().collect(Collectors.toList());
194     }
195 
getPaletteData(Context context)196     private List<String> getPaletteData(Context context) {
197         final String[] paletteResources =
198                 context.getResources().getStringArray(R.array.setting_palette_data);
199         return Arrays.asList(paletteResources);
200     }
201 
getTextWidth(Context context, String text)202     private int getTextWidth(Context context, String text) {
203         final TextView tempView = new TextView(context);
204         return Math.round(tempView.getPaint().measureText(text));
205     }
206 
getTextLineHeight(Context context)207     private int getTextLineHeight(Context context) {
208         final TextView tempView = new TextView(context);
209         final FontMetrics fontMetrics = tempView.getPaint().getFontMetrics();
210         return Math.round(fontMetrics.bottom - fontMetrics.top);
211     }
212 }
213