diff --git a/res/layout/daltonizer_preview.xml b/res/layout/daltonizer_preview.xml new file mode 100644 index 00000000000..24c0f7662c9 --- /dev/null +++ b/res/layout/daltonizer_preview.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/res/layout/palette_listview_item.xml b/res/layout/palette_listview_item.xml new file mode 100644 index 00000000000..e8cc940d7f5 --- /dev/null +++ b/res/layout/palette_listview_item.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index b1f9dfbd675..c88158b081a 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -22,11 +22,21 @@ @*android:color/material_grey_900 @*android:color/material_grey_900 @*android:color/material_grey_800 - + @*android:color/material_grey_800 @*android:color/material_grey_800 #AECBFA #5F6368 ?android:attr/colorAccent + + @android:color/black + @color/palette_list_dark_mode_color_red + @color/palette_list_dark_mode_color_orange + @color/palette_list_dark_mode_color_yellow + @color/palette_list_dark_mode_color_green + @color/palette_list_dark_mode_color_cyan + @color/palette_list_dark_mode_color_blue + @color/palette_list_dark_mode_color_purple + @color/palette_list_dark_mode_color_pink diff --git a/res/values/arrays.xml b/res/values/arrays.xml index f1b26267872..e3029059ccc 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -23,19 +23,19 @@ strings. --> - + America - + Europe - + Africa - + Asia - + Australia - + Pacific - + All @@ -274,8 +274,8 @@ Require all non-trusted certificate statuses - - + + 1 2 @@ -301,8 +301,8 @@ @string/wifi_ap_choose_2G - - + + Push button @@ -320,7 +320,7 @@ Unsuccessful Available Out-of-range - + @@ -410,7 +410,7 @@ - + DHCP @@ -1432,15 +1432,15 @@ - @string/wifi_calling_mode_wifi_preferred_summary - @string/wifi_calling_mode_cellular_preferred_summary - @string/wifi_calling_mode_wifi_only_summary + @string/wifi_calling_mode_wifi_preferred_summary + @string/wifi_calling_mode_cellular_preferred_summary + @string/wifi_calling_mode_wifi_only_summary - @string/wifi_calling_mode_wifi_preferred_summary - @string/wifi_calling_mode_cellular_preferred_summary + @string/wifi_calling_mode_wifi_preferred_summary + @string/wifi_calling_mode_cellular_preferred_summary @@ -1469,4 +1469,27 @@ "com.google.android.googlequicksearchbox" - + + + @string/color_red + @string/color_orange + @string/color_yellow + @string/color_green + @string/color_cyan + @string/color_blue + @string/color_purple + @string/color_pink + + + + + @color/palette_list_color_red + @color/palette_list_color_orange + @color/palette_list_color_yellow + @color/palette_list_color_green + @color/palette_list_color_cyan + @color/palette_list_color_blue + @color/palette_list_color_purple + @color/palette_list_color_pink + + \ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index 3fd77e8837d..1c18c6ab39a 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -148,4 +148,26 @@ #ffdadce0 #4182ef + + + @android:color/white + #d93025 + #e8710a + #f9ab00 + #1e8e3e + #12b5cb + #1a73e8 + #9334e6 + #e52592 + + + #f28b82 + #fcad70 + #fdd663 + #81c995 + #78d9ec + #8AB4F8 + #c58af9 + #ff8bcb + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index cfd313c5e6b..1a480fe50c9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7232,6 +7232,8 @@ Orange Purple + + Pink No SIM cards inserted diff --git a/res/xml/accessibility_daltonizer_settings.xml b/res/xml/accessibility_daltonizer_settings.xml index 22e05101b0d..75386f58bad 100644 --- a/res/xml/accessibility_daltonizer_settings.xml +++ b/res/xml/accessibility_daltonizer_settings.xml @@ -21,6 +21,13 @@ android:persistent="false" android:title="@string/accessibility_display_daltonizer_preference_title"> + + 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. + * + *

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 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. + * + *

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 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 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 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 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; + } + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/PaletteListViewTest.java b/tests/robotests/src/com/android/settings/accessibility/PaletteListViewTest.java new file mode 100644 index 00000000000..13e76d71392 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/PaletteListViewTest.java @@ -0,0 +1,65 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link PaletteListView} */ +@RunWith(RobolectricTestRunner.class) +public class PaletteListViewTest { + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private PaletteListView mPaletteListView; + + @Before + public void setUp() { + mPaletteListView = new PaletteListView(mContext); + } + + @Test + public void setColors_applySameLengthArray_configureSuccessful() { + final String[] colorName = {"White", "Black", "Yellow"}; + final String[] colorCode = {"#ffffff", "#000000", "#f9ab00"}; + + assertThat(mPaletteListView.setPaletteListColors(colorName, colorCode)).isTrue(); + } + + @Test + public void setColors_applyDifferentLengthArray_configureSuccessful() { + final String[] colorName = {"White", "Black", "Yellow", "Orange", "Red"}; + final String[] colorCode = {"#ffffff", "#000000", "#f9ab00"}; + + assertThat(mPaletteListView.setPaletteListColors(colorName, colorCode)).isTrue(); + } + + @Test + public void setColors_configureFailed() { + final String[] colorName = null; + final String[] colorCode = null; + + assertThat(mPaletteListView.setPaletteListColors(colorName, colorCode)).isFalse(); + } +}