Add outline to tv pip menu arrows

In order to have an outline for the arrows, we draw them
programmatically instead of in xml with vector drawables.

This way, we can ensure that the Path for the drawable is
the same as the Path for the ViewOutlineProvider.

Bug: 220108601
Test: atest TvPipMenuController
Test: flash and check arrows are visible over white background

Change-Id: I965e9ac33f474012446b6f8096edf39d93a0c92e
This commit is contained in:
Galia Peycheva
2023-03-21 17:12:36 +00:00
parent 54f6fb6dc6
commit 741aef12d0
8 changed files with 76 additions and 122 deletions

View File

@@ -1,25 +0,0 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tv_pip_menu_focus_border"
android:pathData="M7,10l5,5 5,-5H7z"/>
</vector>

View File

@@ -1,25 +0,0 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tv_pip_menu_focus_border"
android:pathData="M14,7l-5,5 5,5V7z"/>
</vector>

View File

@@ -1,25 +0,0 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tv_pip_menu_focus_border"
android:pathData="M10,17l5,-5 -5,-5v10z"/>
</vector>

View File

@@ -1,25 +0,0 @@
<?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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tv_pip_menu_focus_border"
android:pathData="M7,14l5,-5 5,5H7z"/>
</vector>

View File

@@ -104,9 +104,7 @@
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:alpha="0"
android:contentDescription="@string/a11y_action_pip_move_up"
android:elevation="@dimen/pip_menu_arrow_elevation"
android:src="@drawable/pip_ic_move_up" />
android:contentDescription="@string/a11y_action_pip_move_up"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_right"
@@ -115,9 +113,7 @@
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:alpha="0"
android:contentDescription="@string/a11y_action_pip_move_right"
android:elevation="@dimen/pip_menu_arrow_elevation"
android:src="@drawable/pip_ic_move_right" />
android:contentDescription="@string/a11y_action_pip_move_right"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_down"
@@ -126,9 +122,7 @@
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:alpha="0"
android:contentDescription="@string/a11y_action_pip_move_down"
android:elevation="@dimen/pip_menu_arrow_elevation"
android:src="@drawable/pip_ic_move_down" />
android:contentDescription="@string/a11y_action_pip_move_down"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_left"
@@ -137,7 +131,5 @@
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:alpha="0"
android:contentDescription="@string/a11y_action_pip_move_left"
android:elevation="@dimen/pip_menu_arrow_elevation"
android:src="@drawable/pip_ic_move_left" />
android:contentDescription="@string/a11y_action_pip_move_left"/>
</RelativeLayout>

View File

@@ -33,8 +33,8 @@
<!-- outer space minus border width -->
<dimen name="pip_menu_outer_space_frame">20dp</dimen>
<dimen name="pip_menu_arrow_size">24dp</dimen>
<dimen name="pip_menu_arrow_elevation">5dp</dimen>
<dimen name="pip_menu_arrow_size">12dp</dimen>
<dimen name="pip_menu_arrow_elevation">1dp</dimen>
<dimen name="pip_menu_elevation_no_menu">1dp</dimen>
<dimen name="pip_menu_elevation_move_menu">7dp</dimen>

View File

@@ -27,6 +27,10 @@
<color name="tv_pip_menu_focus_border">#E8EAED</color>
<color name="tv_pip_menu_dim_layer">#990E0E0F</color>
<color name="tv_pip_menu_background">#1E232C</color>
<!-- Normally, the arrow color would be the same as the focus border color. But due to
optical illusion that looks too dark on the screen. That's why we define a separate
(lighter) arrow color. -->
<color name="tv_pip_menu_arrow_color">#F1F3F4</color>
<color name="tv_pip_edu_text">#99D2E3FC</color>
<color name="tv_pip_edu_text_home_icon">#D2E3FC</color>

View File

@@ -31,12 +31,19 @@ import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_MOVE_MENU;
import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_NO_MENU;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.os.Handler;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -89,6 +96,8 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
private final ImageView mArrowLeft;
private final TvWindowMenuActionButton mA11yDoneButton;
private final int mArrowElevation;
private @TvPipMenuController.TvPipMenuMode int mCurrentMenuMode = MODE_NO_MENU;
private final Rect mCurrentPipBounds = new Rect();
private int mCurrentPipGravity;
@@ -129,21 +138,70 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left);
mA11yDoneButton = findViewById(R.id.tv_pip_menu_done_button);
mResizeAnimationDuration = context.getResources().getInteger(
R.integer.config_pipResizeAnimationDuration);
mPipMenuFadeAnimationDuration = context.getResources()
.getInteger(R.integer.tv_window_menu_fade_animation_duration);
final Resources res = context.getResources();
mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
mPipMenuFadeAnimationDuration =
res.getInteger(R.integer.tv_window_menu_fade_animation_duration);
mPipMenuOuterSpace = res.getDimensionPixelSize(R.dimen.pip_menu_outer_space);
mPipMenuBorderWidth = res.getDimensionPixelSize(R.dimen.pip_menu_border_width);
mArrowElevation = res.getDimensionPixelSize(R.dimen.pip_menu_arrow_elevation);
mPipMenuOuterSpace = context.getResources()
.getDimensionPixelSize(R.dimen.pip_menu_outer_space);
mPipMenuBorderWidth = context.getResources()
.getDimensionPixelSize(R.dimen.pip_menu_border_width);
initMoveArrows();
mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, mListener);
((FrameLayout) findViewById(R.id.tv_pip_menu_edu_text_drawer_placeholder))
.addView(mEduTextDrawer);
}
private void initMoveArrows() {
final int arrowSize =
mContext.getResources().getDimensionPixelSize(R.dimen.pip_menu_arrow_size);
final Path arrowPath = createArrowPath(arrowSize);
final ShapeDrawable arrowDrawable = new ShapeDrawable();
arrowDrawable.setShape(new PathShape(arrowPath, arrowSize, arrowSize));
arrowDrawable.setTint(mContext.getResources().getColor(R.color.tv_pip_menu_arrow_color));
final ViewOutlineProvider arrowOutlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setPath(createArrowPath(view.getMeasuredHeight()));
}
};
initArrow(mArrowRight, arrowOutlineProvider, arrowDrawable, 0);
initArrow(mArrowDown, arrowOutlineProvider, arrowDrawable, 90);
initArrow(mArrowLeft, arrowOutlineProvider, arrowDrawable, 180);
initArrow(mArrowUp, arrowOutlineProvider, arrowDrawable, 270);
}
/**
* Creates a Path for a movement arrow in the MODE_MOVE_MENU. The resulting Path is a simple
* right-pointing triangle with its tip in the center of a size x size square:
* _ _ _ _ _
* |* |
* |* * |
* |* * |
* |* * |
* |* _ _ _ _|
*
*/
private Path createArrowPath(int size) {
final Path triangle = new Path();
triangle.lineTo(0, size);
triangle.lineTo(size / 2, size / 2);
triangle.close();
return triangle;
}
private void initArrow(View v, ViewOutlineProvider arrowOutlineProvider, Drawable arrowDrawable,
int rotation) {
v.setOutlineProvider(arrowOutlineProvider);
v.setBackground(arrowDrawable);
v.setRotation(rotation);
v.setElevation(mArrowElevation);
}
void onPipTransitionToTargetBoundsStarted(Rect targetBounds) {
if (targetBounds == null) {
return;