Decorating People Tile background

Change-Id: Ie88ad8482e0dcd6b5f1640827fe71b9d9137cf0c
Test: manual and PeopleTileViewHelperTest
Bug: 184741504
This commit is contained in:
Flavio Fiszman
2021-04-29 10:38:47 +01:00
parent 30de424ddf
commit b331ca659b
8 changed files with 695 additions and 196 deletions

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/emojis"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp">
<TextView
android:id="@+id/emoji1"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:paddingStart="40dp"
android:maxLines="1"
android:alpha="0.2"/>
<TextView
android:id="@+id/emoji2"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:paddingTop="5dp"
android:paddingStart="27dp"
android:maxLines="1"
android:alpha="0.2"/>
<TextView
android:id="@+id/emoji3"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:paddingEnd="25dp"
android:maxLines="1"
android:alpha="0.2"/>
</RelativeLayout>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/emojis"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/emoji1"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:paddingTop="-2dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="end"
android:maxLines="1"
android:alpha="0.2"/>
<TextView
android:id="@+id/emoji2"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:paddingTop="20dp"
android:maxLines="1"
android:alpha="0.2"/>
<TextView
android:id="@+id/emoji3"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="top"
android:paddingTop="10dp"
android:maxLines="1"
android:alpha="0.2"/>
</LinearLayout>

View File

@@ -67,68 +67,79 @@
android:visibility="gone"
/>
</RelativeLayout>
<TextView
android:layout_gravity="center"
android:id="@+id/name"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="12dp"
android:gravity="start"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" />
android:layout_height="match_parent">
<include layout="@layout/people_tile_punctuation_background_large" />
<include layout="@layout/people_tile_emoji_background_large" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_gravity="center"
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="12dp"
android:gravity="start"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/predefined_icon"
android:tint="?android:attr/colorAccent"
android:gravity="start|center_vertical"
android:paddingEnd="6dp"
android:layout_width="24dp"
android:layout_height="18dp" />
<TextView
android:layout_gravity="center"
android:id="@+id/subtext"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/predefined_icon"
android:tint="?android:attr/colorAccent"
android:gravity="start|center_vertical"
android:paddingEnd="6dp"
android:layout_width="24dp"
android:layout_height="18dp" />
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/people_space_content_background"
android:gravity="center"
android:scaleType="centerCrop" />
<TextView
android:layout_gravity="center"
android:id="@+id/subtext"
android:gravity="center_vertical"
android:id="@+id/text_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/empty_user_name"
android:maxLines="2"
android:singleLine="false"
android:text="@string/empty_status"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorSecondary"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/people_space_content_background"
android:gravity="center"
android:scaleType="centerCrop" />
<TextView
android:layout_gravity="center"
android:id="@+id/text_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:singleLine="false"
android:text="@string/empty_status"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -21,121 +21,127 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
<RelativeLayout
android:background="@drawable/people_space_tile_view_card"
android:id="@+id/item"
android:orientation="vertical"
android:layout_gravity="center"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/people_tile_punctuation_background_medium" />
<include layout="@layout/people_tile_emoji_background_medium" />
<LinearLayout
android:orientation="horizontal"
android:gravity="top"
android:layout_weight="1"
android:id="@+id/item"
android:orientation="vertical"
android:layout_gravity="center"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="0dp">
<ImageView
android:gravity="start"
android:id="@+id/person_icon"
android:layout_marginStart="-2dp"
android:layout_marginTop="-2dp"
android:layout_width="52dp"
android:layout_height="52dp" />
<ImageView
android:id="@+id/availability"
android:layout_marginStart="-2dp"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/circle_green_10dp" />
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:gravity="top|start"
android:paddingStart="12dp"
android:orientation="horizontal"
android:gravity="top"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/subtext"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp"
android:paddingBottom="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end" />
android:layout_height="0dp">
<ImageView
android:id="@+id/image"
android:gravity="center"
android:background="@drawable/people_space_content_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
android:gravity="start"
android:id="@+id/person_icon"
android:layout_marginStart="-2dp"
android:layout_marginTop="-2dp"
android:layout_width="52dp"
android:layout_height="52dp" />
<ImageView
android:id="@+id/availability"
android:layout_marginStart="-2dp"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/circle_green_10dp" />
<LinearLayout
android:orientation="vertical"
android:gravity="top|start"
android:paddingStart="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/subtext"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp"
android:paddingBottom="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end" />
<ImageView
android:id="@+id/image"
android:gravity="center"
android:background="@drawable/people_space_content_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/text_content"
android:text="@string/empty_status"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="false"
android:ellipsize="end" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:gravity="bottom"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToOutline="true">
<TextView
android:id="@+id/text_content"
android:text="@string/empty_status"
android:id="@+id/name"
android:gravity="center_vertical"
android:layout_weight="1"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="12sp"
android:layout_width="match_parent"
android:textSize="14sp"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/messages_count"
android:gravity="end"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="false"
android:ellipsize="end" />
android:visibility="gone"
/>
<ImageView
android:id="@+id/predefined_icon"
android:tint="?android:attr/colorAccent"
android:gravity="end|center_vertical"
android:paddingStart="6dp"
android:layout_width="24dp"
android:layout_height="18dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:gravity="bottom"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToOutline="true">
<TextView
android:id="@+id/name"
android:gravity="center_vertical"
android:layout_weight="1"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/messages_count"
android:gravity="end"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<ImageView
android:id="@+id/predefined_icon"
android:tint="?android:attr/colorAccent"
android:gravity="end|center_vertical"
android:paddingStart="6dp"
android:layout_width="24dp"
android:layout_height="18dp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:id="@+id/punctuations"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="10dp">
<TextView
android:id="@+id/punctuation1"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:paddingTop="-2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:maxLines="1"
android:rotation="5"/>
<TextView
android:id="@+id/punctuation2"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:paddingTop="5dp"
android:paddingStart="27dp"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="350"/>
<TextView
android:id="@+id/punctuation3"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:paddingEnd="25dp"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="350"/>
<TextView
android:id="@+id/punctuation4"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:paddingStart="15dp"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="10"/>
<TextView
android:id="@+id/punctuation5"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:paddingTop="15dp"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="5"/>
<TextView
android:id="@+id/punctuation6"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="34sp"
android:textStyle="bold"
android:paddingStart="20dp"
android:paddingTop="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:maxLines="1"
android:rotation="350"/>
</RelativeLayout>

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:id="@+id/punctuations"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/punctuation1"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:textStyle="bold"
android:paddingTop="-2dp"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:gravity="center_vertical|end"
android:maxLines="1"
android:rotation="5"/>
<TextView
android:id="@+id/punctuation2"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="top"
android:gravity="top|end"
android:includeFontPadding="false"
android:paddingTop="25dp"
android:maxLines="1"
android:rotation="350"/>
<TextView
android:id="@+id/punctuation3"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center|end"
android:includeFontPadding="false"
android:paddingTop="10dp"
android:maxLines="1"
android:rotation="350"/>
<TextView
android:id="@+id/punctuation4"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingTop="10dp"
android:gravity="start|top"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="10"/>
<TextView
android:id="@+id/punctuation5"
android:textColor="?androidprv:attr/colorSurfaceVariant"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="27sp"
android:textStyle="bold"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingTop="15dp"
android:gravity="start|center_vertical"
android:includeFontPadding="false"
android:maxLines="1"
android:rotation="350"/>
</LinearLayout>

View File

@@ -51,6 +51,7 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.TextView;
@@ -63,6 +64,7 @@ import com.android.systemui.people.widget.PeopleTileKey;
import java.text.NumberFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -102,6 +104,39 @@ public class PeopleTileViewHelper {
private static final Pattern ANY_DOUBLE_MARK_PATTERN = Pattern.compile("[!?][!?]+");
private static final Pattern MIXED_MARK_PATTERN = Pattern.compile("![?].*|.*[?]!");
// This regex can be used to match Unicode emoji characters and character sequences. It's from
// the official Unicode site (https://unicode.org/reports/tr51/#EBNF_and_Regex) with minor
// changes to fit our needs. It should be updated once new emoji categories are added.
//
// Emoji categories that can be matched by this regex:
// - Country flags. "\p{RI}\p{RI}" matches country flags since they always consist of 2 Unicode
// scalars.
// - Single-Character Emoji. "\p{Emoji}" matches Single-Character Emojis.
// - Emoji with modifiers. E.g. Emojis with different skin tones. "\p{Emoji}\p{EMod}" matches
// them.
// - Emoji Presentation. Those are characters which can normally be drawn as either text or as
// Emoji. "\p{Emoji}\x{FE0F}" matches them.
// - Emoji Keycap. E.g. Emojis for number 0 to 9. "\p{Emoji}\x{FE0F}\x{20E3}" matches them.
// - Emoji tag sequence. "\p{Emoji}[\x{E0020}-\x{E007E}]+\x{E007F}" matches them.
// - Emoji Zero-Width Joiner (ZWJ) Sequence. A ZWJ emoji is actually multiple emojis joined by
// the jointer "0x200D".
//
// Note: since "\p{Emoji}" also matches some ASCII characters like digits 0-9, we use
// "\p{Emoji}&&\p{So}" to exclude them. This is the change we made from the official emoji
// regex.
private static final String UNICODE_EMOJI_REGEX =
"\\p{RI}\\p{RI}|"
+ "("
+ "\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})"
+ "|[\\p{Emoji}&&\\p{So}]"
+ ")"
+ "("
+ "\\x{200D}"
+ "\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})"
+ "?)*";
private static final Pattern EMOJI_PATTERN = Pattern.compile(UNICODE_EMOJI_REGEX);
public static final String EMPTY_STRING = "";
private int mMediumVerticalPadding;
@@ -375,7 +410,7 @@ public class PeopleTileViewHelper {
} else {
setMaxLines(views, !TextUtils.isEmpty(sender));
CharSequence content = mTile.getNotificationContent();
views = setPunctuationRemoteViewsFields(views, content);
views = decorateBackground(views, content);
views.setColorAttr(R.id.text_content, "setTextColor", android.R.attr.textColorPrimary);
views.setTextViewText(R.id.text_content, mTile.getNotificationContent());
views.setViewVisibility(R.id.image, View.GONE);
@@ -506,33 +541,53 @@ public class PeopleTileViewHelper {
}
}
private RemoteViews setPunctuationRemoteViewsFields(
RemoteViews views, CharSequence content) {
String punctuation = getBackgroundTextFromMessage(content.toString());
private RemoteViews decorateBackground(RemoteViews views, CharSequence content) {
int visibility = View.GONE;
if (punctuation != null) {
visibility = View.VISIBLE;
CharSequence emoji = getDoubleEmoji(content);
if (!TextUtils.isEmpty(emoji)) {
setEmojiBackground(views, emoji);
setPunctuationBackground(views, null);
return views;
}
views.setTextViewText(R.id.punctuation1, punctuation);
views.setTextViewText(R.id.punctuation2, punctuation);
views.setTextViewText(R.id.punctuation3, punctuation);
views.setTextViewText(R.id.punctuation4, punctuation);
views.setTextViewText(R.id.punctuation5, punctuation);
views.setTextViewText(R.id.punctuation6, punctuation);
views.setViewVisibility(R.id.punctuation1, visibility);
views.setViewVisibility(R.id.punctuation2, visibility);
views.setViewVisibility(R.id.punctuation3, visibility);
views.setViewVisibility(R.id.punctuation4, visibility);
views.setViewVisibility(R.id.punctuation5, visibility);
views.setViewVisibility(R.id.punctuation6, visibility);
CharSequence punctuation = getDoublePunctuation(content);
setEmojiBackground(views, null);
setPunctuationBackground(views, punctuation);
return views;
}
/** Gets character for mTile background decoration based on notification content. */
private RemoteViews setEmojiBackground(RemoteViews views, CharSequence content) {
if (TextUtils.isEmpty(content)) {
views.setViewVisibility(R.id.emojis, View.GONE);
return views;
}
views.setTextViewText(R.id.emoji1, content);
views.setTextViewText(R.id.emoji2, content);
views.setTextViewText(R.id.emoji3, content);
views.setViewVisibility(R.id.emojis, View.VISIBLE);
return views;
}
private RemoteViews setPunctuationBackground(RemoteViews views, CharSequence content) {
if (TextUtils.isEmpty(content)) {
views.setViewVisibility(R.id.punctuations, View.GONE);
return views;
}
views.setTextViewText(R.id.punctuation1, content);
views.setTextViewText(R.id.punctuation2, content);
views.setTextViewText(R.id.punctuation3, content);
views.setTextViewText(R.id.punctuation4, content);
views.setTextViewText(R.id.punctuation5, content);
views.setTextViewText(R.id.punctuation6, content);
views.setViewVisibility(R.id.punctuations, View.VISIBLE);
return views;
}
/** Returns punctuation character(s) if {@code message} has double punctuation ("!" or "?"). */
@VisibleForTesting
String getBackgroundTextFromMessage(String message) {
CharSequence getDoublePunctuation(CharSequence message) {
if (!ANY_DOUBLE_MARK_PATTERN.matcher(message).find()) {
return null;
}
@@ -554,6 +609,48 @@ public class PeopleTileViewHelper {
return "!";
}
/** Returns emoji if {@code message} has two of the same emoji in sequence. */
@VisibleForTesting
CharSequence getDoubleEmoji(CharSequence message) {
Matcher unicodeEmojiMatcher = EMOJI_PATTERN.matcher(message);
// Stores the start and end indices of each matched emoji.
List<Pair<Integer, Integer>> emojiIndices = new ArrayList<>();
// Stores each emoji text.
List<CharSequence> emojiTexts = new ArrayList<>();
// Scan message for emojis
while (unicodeEmojiMatcher.find()) {
int start = unicodeEmojiMatcher.start();
int end = unicodeEmojiMatcher.end();
emojiIndices.add(new Pair(start, end));
emojiTexts.add(message.subSequence(start, end));
}
if (DEBUG) Log.d(TAG, "Number of emojis in the message: " + emojiIndices.size());
if (emojiIndices.size() < 2) {
return null;
}
for (int i = 1; i < emojiIndices.size(); ++i) {
Pair<Integer, Integer> second = emojiIndices.get(i);
Pair<Integer, Integer> first = emojiIndices.get(i - 1);
// Check if second emoji starts right after first starts
if (second.first == first.second) {
// Check if emojis in sequence are the same
if (Objects.equals(emojiTexts.get(i), emojiTexts.get(i - 1))) {
if (DEBUG) {
Log.d(TAG, "Two of the same emojis in sequence: " + emojiTexts.get(i));
}
return emojiTexts.get(i);
}
}
}
// No equal emojis in sequence.
return null;
}
private RemoteViews getViewForContentLayout() {
RemoteViews views = new RemoteViews(mContext.getPackageName(),
getLayoutForContent());

View File

@@ -76,6 +76,14 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {
private static final String NAME = "username";
private static final UserHandle USER = new UserHandle(0);
private static final String SENDER = "sender";
private static final CharSequence EMOJI_BR_FLAG = "\ud83c\udde7\ud83c\uddf7";
private static final CharSequence EMOJI_BEAR = "\ud83d\udc3b";
private static final CharSequence EMOJI_THUMBS_UP_BROWN_SKIN = "\uD83D\uDC4D\uD83C\uDFFD";
private static final CharSequence EMOJI_JOY = "\uD83D\uDE02";
private static final CharSequence EMOJI_FAMILY =
"\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67";
private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION =
new PeopleSpaceTile
.Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
@@ -701,94 +709,151 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {
@Test
public void testGetBackgroundTextFromMessageNoPunctuation() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test");
public void testGetDoublePunctuationNoPunctuation() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test");
assertThat(backgroundText).isNull();
}
@Test
public void testGetBackgroundTextFromMessageSingleExclamation() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test!");
public void testGetDoublePunctuationSingleExclamation() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test!");
assertThat(backgroundText).isNull();
}
@Test
public void testGetBackgroundTextFromMessageSingleQuestion() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("?test");
public void testGetDoublePunctuationSingleQuestion() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("?test");
assertThat(backgroundText).isNull();
}
@Test
public void testGetBackgroundTextFromMessageSeparatedMarks() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test! right!");
public void testGetDoublePunctuationSeparatedMarks() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test! right!");
assertThat(backgroundText).isNull();
}
@Test
public void testGetBackgroundTextFromMessageDoubleExclamation() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("!!test");
public void testGetDoublePunctuationDoubleExclamation() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("!!test");
assertThat(backgroundText).isEqualTo("!");
}
@Test
public void testGetBackgroundTextFromMessageDoubleQuestion() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test??");
public void testGetDoublePunctuationDoubleQuestion() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test??");
assertThat(backgroundText).isEqualTo("?");
}
@Test
public void testGetBackgroundTextFromMessageMixed() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test?!");
public void testGetDoublePunctuationMixed() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test?!");
assertThat(backgroundText).isEqualTo("!?");
}
@Test
public void testGetBackgroundTextFromMessageMixedInTheMiddle() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage(
public void testGetDoublePunctuationMixedInTheMiddle() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
"test!? in the middle");
assertThat(backgroundText).isEqualTo("!?");
}
@Test
public void testGetBackgroundTextFromMessageMixedDifferentOrder() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage(
public void testGetDoublePunctuationMixedDifferentOrder() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
"test!? in the middle");
assertThat(backgroundText).isEqualTo("!?");
}
@Test
public void testGetBackgroundTextFromMessageMultiple() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage(
public void testGetDoublePunctuationMultiple() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
"test!?!!? in the middle");
assertThat(backgroundText).isEqualTo("!?");
}
@Test
public void testGetBackgroundTextFromMessageQuestionFirst() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage(
public void testGetDoublePunctuationQuestionFirst() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
"test?? in the middle!!");
assertThat(backgroundText).isEqualTo("?");
}
@Test
public void testGetBackgroundTextFromMessageExclamationFirst() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage(
public void testGetDoublePunctuationExclamationFirst() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
"test!! in the middle??");
assertThat(backgroundText).isEqualTo("!");
}
@Test
public void testGetDoubleEmojisNoEmojis() {
CharSequence backgroundText = mPeopleTileViewHelper
.getDoubleEmoji("This string has no emojis.");
assertThat(backgroundText).isNull();
}
@Test
public void testGetDoubleEmojisSingleEmoji() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"This string has one emoji " + EMOJI_JOY + " in the middle.");
assertThat(backgroundText).isNull();
}
@Test
public void testGetDoubleEmojisSingleEmojiThenTwoEmojis() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"This string has one emoji " + EMOJI_JOY + " in the middle, then two "
+ EMOJI_BEAR + EMOJI_BEAR);
assertEquals(backgroundText, EMOJI_BEAR);
}
@Test
public void testGetDoubleEmojisTwoEmojisWithModifier() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"Yes! " + EMOJI_THUMBS_UP_BROWN_SKIN + EMOJI_THUMBS_UP_BROWN_SKIN + " Sure.");
assertEquals(backgroundText, EMOJI_THUMBS_UP_BROWN_SKIN);
}
@Test
public void testGetDoubleEmojisTwoFlagEmojis() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"Let's travel to " + EMOJI_BR_FLAG + EMOJI_BR_FLAG + " next year.");
assertEquals(backgroundText, EMOJI_BR_FLAG);
}
@Test
public void testGetDoubleEmojiTwoBears() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
EMOJI_BEAR.toString() + EMOJI_BEAR.toString() + "bears!");
assertEquals(backgroundText, EMOJI_BEAR);
}
@Test
public void testGetDoubleEmojiTwoEmojisTwice() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"Two sets of two emojis: " + EMOJI_FAMILY + EMOJI_FAMILY + EMOJI_BEAR + EMOJI_BEAR);
assertEquals(backgroundText, EMOJI_FAMILY);
}
@Test
public void testGetDoubleEmojiTwoEmojisSeparated() {
CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
"Two emojis " + EMOJI_BEAR + " separated " + EMOJI_BEAR + ".");
assertThat(backgroundText).isNull();
}
private int getSizeInDp(int dimenResourceId) {
return (int) (mContext.getResources().getDimension(dimenResourceId)
/ mContext.getResources().getDisplayMetrics().density);