Create palette preview for color correction.
Bug: 145968068 Test: make RunSettingsRoboTests ROBOTEST_FILTER=PaletteListViewTest Test: make RunSettingsRoboTests2 Change-Id: If624c8ab5b6c212b5a3ad97ceac57404d34b9deb
This commit is contained in:
292
src/com/android/settings/accessibility/PaletteListView.java
Normal file
292
src/com/android/settings/accessibility/PaletteListView.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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.settings.accessibility;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.GradientDrawable.Orientation;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settingslib.widget.R;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Custom ListView {@link ListView} which displays palette to deploy the color code preview.
|
||||
*
|
||||
* <p>The preview shows gradient from color white to specific color code on each list view item, in
|
||||
* addition, text view adjusts the attribute of width for adapting the text length.
|
||||
*
|
||||
* <p>The text cannot fills the whole view for ensuring the gradient color preview can purely
|
||||
* display also the view background shows the color beside the text variable end point.
|
||||
*/
|
||||
public class PaletteListView extends ListView {
|
||||
private static final float VIEW_PITCH = 0.05f;
|
||||
private final Context mContext;
|
||||
private final DisplayAdapter mDisplayAdapter;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final String mDefaultGradientColorCodeString;
|
||||
private final int mDefaultGradientColor;
|
||||
private float mTextBound;
|
||||
|
||||
public PaletteListView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PaletteListView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public PaletteListView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContext = context;
|
||||
mDisplayAdapter = new DisplayAdapter();
|
||||
mLayoutInflater = LayoutInflater.from(context);
|
||||
mDefaultGradientColorCodeString =
|
||||
getResources().getString(R.color.palette_list_gradient_background);
|
||||
mDefaultGradientColor =
|
||||
getResources().getColor(R.color.palette_list_gradient_background, null);
|
||||
mTextBound = 0.0f;
|
||||
init();
|
||||
}
|
||||
|
||||
private static int getScreenWidth(WindowManager windowManager) {
|
||||
final Display display = windowManager.getDefaultDisplay();
|
||||
final DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
display.getMetrics(displayMetrics);
|
||||
return displayMetrics.widthPixels;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
final TypedArray colorNameArray = getResources().obtainTypedArray(
|
||||
R.array.setting_palette_colors);
|
||||
final TypedArray colorCodeArray = getResources().obtainTypedArray(
|
||||
R.array.setting_palette_data);
|
||||
final int colorNameArrayLength = colorNameArray.length();
|
||||
final List<ColorAttributes> colorList = new ArrayList<>();
|
||||
computeTextWidthBounds(colorNameArray);
|
||||
|
||||
for (int index = 0; index < colorNameArrayLength; index++) {
|
||||
colorList.add(
|
||||
new ColorAttributes(
|
||||
/* colorName= */ colorNameArray.getString(index),
|
||||
/* colorCode= */ colorCodeArray.getColor(index, mDefaultGradientColor),
|
||||
/* textBound= */ mTextBound,
|
||||
/* gradientDrawable= */
|
||||
new GradientDrawable(Orientation.LEFT_RIGHT, null)));
|
||||
}
|
||||
|
||||
mDisplayAdapter.setColorList(colorList);
|
||||
setAdapter(mDisplayAdapter);
|
||||
setDividerHeight(/* height= */ 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets string array that required the color name and color code for deploy the new color
|
||||
* preview.
|
||||
*
|
||||
* <p>The parameters not allow null define but two array length inconsistent are acceptable, in
|
||||
* addition, to prevent IndexOutOfBoundsException the algorithm will check array data, and base
|
||||
* on the array size to display data, or fills color code array if length less than other.
|
||||
*
|
||||
* @param colorNames a string array of color name
|
||||
* @param colorCodes a string array of color code
|
||||
* @return true if new array data apply successful
|
||||
*/
|
||||
@VisibleForTesting
|
||||
boolean setPaletteListColors(@NonNull String[] colorNames, @NonNull String[] colorCodes) {
|
||||
if (colorNames == null || colorCodes == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int colorNameArrayLength = colorNames.length;
|
||||
final int colorCodeArrayLength = colorCodes.length;
|
||||
final List<ColorAttributes> colorList = new ArrayList<>();
|
||||
final String[] colorCodeArray = fillColorCodeArray(colorCodes, colorNameArrayLength,
|
||||
colorCodeArrayLength);
|
||||
computeTextWidthBounds(colorNames);
|
||||
|
||||
for (int index = 0; index < colorNameArrayLength; index++) {
|
||||
colorList.add(
|
||||
new ColorAttributes(
|
||||
/* colorName= */ colorNames[index],
|
||||
/* colorCode= */ Color.parseColor(colorCodeArray[index]),
|
||||
/* textBound= */ mTextBound,
|
||||
/* gradientDrawable= */
|
||||
new GradientDrawable(Orientation.LEFT_RIGHT, null)));
|
||||
}
|
||||
|
||||
mDisplayAdapter.setColorList(colorList);
|
||||
mDisplayAdapter.notifyDataSetChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
private String[] fillColorCodeArray(String[] colorCodes, int colorNameArrayLength,
|
||||
int colorCodeArrayLength) {
|
||||
if (colorNameArrayLength == colorCodeArrayLength
|
||||
|| colorNameArrayLength < colorCodeArrayLength) {
|
||||
return colorCodes;
|
||||
}
|
||||
|
||||
final String[] colorCodeArray = new String[colorNameArrayLength];
|
||||
for (int index = 0; index < colorNameArrayLength; index++) {
|
||||
if (index < colorCodeArrayLength) {
|
||||
colorCodeArray[index] = colorCodes[index];
|
||||
} else {
|
||||
colorCodeArray[index] = mDefaultGradientColorCodeString;
|
||||
}
|
||||
}
|
||||
return colorCodeArray;
|
||||
}
|
||||
|
||||
private void computeTextWidthBounds(TypedArray colorNameTypedArray) {
|
||||
final int colorNameArrayLength = colorNameTypedArray.length();
|
||||
final String[] colorNames = new String[colorNameArrayLength];
|
||||
for (int index = 0; index < colorNameArrayLength; index++) {
|
||||
colorNames[index] = colorNameTypedArray.getString(index);
|
||||
}
|
||||
|
||||
measureBound(colorNames);
|
||||
}
|
||||
|
||||
private void computeTextWidthBounds(String[] colorNameArray) {
|
||||
final int colorNameArrayLength = colorNameArray.length;
|
||||
final String[] colorNames = new String[colorNameArrayLength];
|
||||
for (int index = 0; index < colorNameArrayLength; index++) {
|
||||
colorNames[index] = colorNameArray[index];
|
||||
}
|
||||
|
||||
measureBound(colorNames);
|
||||
}
|
||||
|
||||
private void measureBound(String[] dataArray) {
|
||||
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
|
||||
Context.WINDOW_SERVICE);
|
||||
final View view = mLayoutInflater.inflate(R.layout.palette_listview_item, null);
|
||||
final TextView textView = view.findViewById(R.id.item_textview);
|
||||
final List<String> colorNameList = new ArrayList<>(Arrays.asList(dataArray));
|
||||
Collections.sort(colorNameList, Comparator.comparing(String::length));
|
||||
// Gets the last index of list which sort by text length.
|
||||
textView.setText(Iterables.getLast(colorNameList));
|
||||
|
||||
final float textWidth = textView.getPaint().measureText(textView.getText().toString());
|
||||
// Computes rate of text width compare to screen width, and measures the round the double
|
||||
// to two decimal places manually.
|
||||
final float textBound = Math.round(textWidth / getScreenWidth(windowManager) * 100) / 100f;
|
||||
mTextBound = textBound + VIEW_PITCH;
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
public TextView textView;
|
||||
}
|
||||
|
||||
/** An adapter that converts color text title and color code to text views. */
|
||||
private final class DisplayAdapter extends BaseAdapter {
|
||||
|
||||
private List<ColorAttributes> mColorList;
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mColorList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mColorList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final ViewHolder viewHolder;
|
||||
final ColorAttributes paletteAttribute = mColorList.get(position);
|
||||
final String colorName = paletteAttribute.getColorName();
|
||||
final GradientDrawable gradientDrawable = paletteAttribute.getGradientDrawable();
|
||||
|
||||
if (convertView == null) {
|
||||
convertView = mLayoutInflater.inflate(R.layout.palette_listview_item, null);
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.textView = convertView.findViewById(R.id.item_textview);
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
viewHolder.textView.setText(colorName);
|
||||
viewHolder.textView.setBackground(gradientDrawable);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
protected void setColorList(List<ColorAttributes> colorList) {
|
||||
mColorList = colorList;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ColorAttributes {
|
||||
private final int mColorIndex = 2; // index for inject color.
|
||||
private final int mColorOffsetIndex = 1; // index for offset effect.
|
||||
private final String mColorName;
|
||||
private final GradientDrawable mGradientDrawable;
|
||||
private final int[] mGradientColors =
|
||||
{/* startColor=*/ mDefaultGradientColor, /* centerColor=*/ mDefaultGradientColor,
|
||||
/* endCode= */ 0};
|
||||
private final float[] mGradientOffsets =
|
||||
{/* starOffset= */ 0.0f, /* centerOffset= */ 0.5f, /* endOffset= */ 1.0f};
|
||||
|
||||
ColorAttributes(
|
||||
String colorName, int colorCode, float textBound,
|
||||
GradientDrawable gradientDrawable) {
|
||||
mGradientColors[mColorIndex] = colorCode;
|
||||
mGradientOffsets[mColorOffsetIndex] = textBound;
|
||||
gradientDrawable.setColors(mGradientColors, mGradientOffsets);
|
||||
mColorName = colorName;
|
||||
mGradientDrawable = gradientDrawable;
|
||||
}
|
||||
|
||||
public String getColorName() {
|
||||
return mColorName;
|
||||
}
|
||||
|
||||
public GradientDrawable getGradientDrawable() {
|
||||
return mGradientDrawable;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user