Test: build Change-Id: I2f5e7f85b5a7358c707cf3897f354ead42980956gugelfrei
parent
9df8cfa0a6
commit
080b934e6d
After Width: | Height: | Size: 268 B |
After Width: | Height: | Size: 619 B |
After Width: | Height: | Size: 268 B |
After Width: | Height: | Size: 619 B |
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<group>
|
||||
<clip-path android:pathData="M24,24H0V0h24v24z M 0,0" />
|
||||
<path
|
||||
android:pathData="M9.6 13.5h.4c.2 0 .4,-.1.5,-.2s.2,-.2.2,-.4v-.2s-.1,-.1,-.1,-.2,-.1,-.1,-.2,-.1h-.5s-.1.1,-.2.1,-.1.1,-.1.2v.2h-1c0,-.2 0,-.3.1,-.5s.2,-.3.3,-.4.3,-.2.4,-.2.4,-.1.5,-.1c.2 0 .4 0 .6.1s.3.1.5.2.2.2.3.4.1.3.1.5v.3s-.1.2,-.1.3,-.1.2,-.2.2,-.2.1,-.3.2c.2.1.4.2.5.4s.2.4.2.6c0 .2 0 .4,-.1.5s-.2.3,-.3.4,-.3.2,-.5.2,-.4.1,-.6.1c-.2 0,-.4 0,-.5,-.1s-.3,-.1,-.5,-.2,-.2,-.2,-.3,-.4,-.1,-.4,-.1,-.6h.8v.2s.1.1.1.2.1.1.2.1h.5s.1,-.1.2,-.1.1,-.1.1,-.2v-.5s-.1,-.1,-.1,-.2,-.1,-.1,-.2,-.1h-.6v-.7zm5.7.7c0 .3 0 .6,-.1.8l-.3.6s-.3.3,-.5.3,-.4.1,-.6.1,-.4 0,-.6,-.1,-.3,-.2,-.5,-.3,-.2,-.3,-.3,-.6,-.1,-.5,-.1,-.8v-.7c0,-.3 0,-.6.1,-.8l.3,-.6s.3,-.3.5,-.3.4,-.1.6,-.1.4 0 .6.1.3.2.5.3.2.3.3.6.1.5.1.8v.7zm-.9,-.8v-.5s-.1,-.2,-.1,-.3,-.1,-.1,-.2,-.2,-.2,-.1,-.3,-.1,-.2 0,-.3.1l-.2.2s-.1.2,-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3,-.1l.2,-.2s.1,-.2.1,-.3v-1.5zM4 13c0 4.4 3.6 8 8 8s8,-3.6 8,-8h-2c0 3.3,-2.7 6,-6 6s-6,-2.7,-6,-6 2.7,-6 6,-6v4l5,-5,-5,-5v4c-4.4 0,-8 3.6,-8 8z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</group>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,16L9,16L9,8h2v8zM15,16h-2L13,8h2v8z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5 -6,4.5z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<group>
|
||||
<clip-path android:pathData="M0,0h24v24H0V0z M 0,0" />
|
||||
<path
|
||||
android:pathData="M12 5V1L7 6l5 5V7c3.3 0 6 2.7 6 6s-2.7 6,-6 6,-6,-2.7,-6,-6H4c0 4.4 3.6 8 8 8s8,-3.6 8,-8,-3.6,-8,-8,-8zm-1.1 11H10v-3.3L9 13v-.7l1.8,-.6h.1V16zm4.3,-1.8c0 .3 0 .6,-.1.8l-.3.6s-.3.3,-.5.3,-.4.1,-.6.1,-.4 0,-.6,-.1,-.3,-.2,-.5,-.3,-.2,-.3,-.3,-.6,-.1,-.5,-.1,-.8v-.7c0,-.3 0,-.6.1,-.8l.3,-.6s.3,-.3.5,-.3.4,-.1.6,-.1.4 0 .6.1c.2.1.3.2.5.3s.2.3.3.6.1.5.1.8v.7zm-.9,-.8v-.5s-.1,-.2,-.1,-.3,-.1,-.1,-.2,-.2,-.2,-.1,-.3,-.1,-.2 0,-.3.1l-.2.2s-.1.2,-.1.3v2s.1.2.1.3.1.1.2.2.2.1.3.1.2 0 .3,-.1l.2,-.2s.1,-.2.1,-.3v-1.5z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</group>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 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:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#55000000"
|
||||
android:orientation="vertical"
|
||||
android:layoutDirection="ltr">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/title_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:checked="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/back"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:textSize="20sp"
|
||||
android:text="North by Northwest"
|
||||
android:textColor="#FFFFFFFF" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/cast"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/TitleBarButton.MediaRouteButton"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:paddingTop="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton android:id="@+id/prev" style="@style/TransportControlsButton.Previous" />
|
||||
<ImageButton android:id="@+id/rew" style="@style/TransportControlsButton.Rew" />
|
||||
<ImageButton android:id="@+id/pause" style="@style/TransportControlsButton.Pause" />
|
||||
<ImageButton android:id="@+id/ffwd" style="@style/TransportControlsButton.Ffwd" />
|
||||
<ImageButton android:id="@+id/next" style="@style/TransportControlsButton.Next" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/mediacontroller_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:padding="0dp"
|
||||
android:progressTint="#FFFFFFFF"
|
||||
android:thumbTint="#FFFFFFFF"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingRight="15dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_current"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@id/time_current"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#BBBBBB" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/overflow"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/BottomBarButton.Overflow"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/fullscreen"
|
||||
android:layout_toLeftOf="@id/overflow"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/BottomBarButton.FullScreen"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/cc"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_toLeftOf="@id/fullscreen"
|
||||
android:layout_centerVertical="true"
|
||||
style="@style/BottomBarButton.CC" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="TransportControlsButton">
|
||||
<item name="android:background">@null</item>
|
||||
<item name="android:layout_width">70dp</item>
|
||||
<item name="android:layout_height">40dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TransportControlsButton.Previous">
|
||||
<item name="android:src">@drawable/ic_skip_previous</item>
|
||||
</style>
|
||||
|
||||
<style name="TransportControlsButton.Next">
|
||||
<item name="android:src">@drawable/ic_skip_next</item>
|
||||
</style>
|
||||
|
||||
<style name="TransportControlsButton.Pause">
|
||||
<item name="android:src">@drawable/ic_pause_circle_filled</item>
|
||||
</style>
|
||||
|
||||
<style name="TransportControlsButton.Ffwd">
|
||||
<item name="android:src">@drawable/ic_forward_30</item>
|
||||
</style>
|
||||
|
||||
<style name="TransportControlsButton.Rew">
|
||||
<item name="android:src">@drawable/ic_rewind_10</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="TitleBarButton">
|
||||
<item name="android:background">@null</item>
|
||||
<item name="android:layout_width">36dp</item>
|
||||
<item name="android:layout_height">36dp</item>
|
||||
<item name="android:layout_margin">10dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TitleBarButton.MediaRouteButton">
|
||||
<item name="android:src">@drawable/ic_cast</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="BottomBarButton">
|
||||
<item name="android:background">@null</item>
|
||||
<item name="android:layout_width">24dp</item>
|
||||
<item name="android:layout_height">24dp</item>
|
||||
<item name="android:layout_margin">10dp</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomBarButton.CC">
|
||||
<item name="android:src">@drawable/ic_media_cc_disabled</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomBarButton.FullScreen">
|
||||
<item name="android:src">@drawable/ic_fullscreen</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomBarButton.Overflow">
|
||||
<item name="android:src">@drawable/ic_chevron_right</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/* Copyright 2017, 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.
|
||||
*/
|
||||
-->
|
||||
<resources>
|
||||
<!--java-symbol type="id" name="cc" />
|
||||
<java-symbol type="id" name="ffwd" />
|
||||
<java-symbol type="id" name="mediacontroller_progress" />
|
||||
<java-symbol type="id" name="next" />
|
||||
<java-symbol type="id" name="pause" />
|
||||
<java-symbol type="id" name="prev" />
|
||||
<java-symbol type="id" name="rew" />
|
||||
<java-symbol type="id" name="time" />
|
||||
<java-symbol type="id" name="time_current" /-->
|
||||
</resources>
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2018 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.media.SubtitleController.Anchor;
|
||||
import android.media.SubtitleTrack.RenderingWidget;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
class SubtitleView extends FrameLayout implements Anchor {
|
||||
private static final String TAG = "SubtitleView";
|
||||
|
||||
private RenderingWidget mSubtitleWidget;
|
||||
private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
|
||||
|
||||
public SubtitleView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SubtitleView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SubtitleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public SubtitleView(
|
||||
Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitleWidget(RenderingWidget subtitleWidget) {
|
||||
if (mSubtitleWidget == subtitleWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean attachedToWindow = isAttachedToWindow();
|
||||
if (mSubtitleWidget != null) {
|
||||
if (attachedToWindow) {
|
||||
mSubtitleWidget.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
mSubtitleWidget.setOnChangedListener(null);
|
||||
}
|
||||
mSubtitleWidget = subtitleWidget;
|
||||
|
||||
if (subtitleWidget != null) {
|
||||
if (mSubtitlesChangedListener == null) {
|
||||
mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
|
||||
@Override
|
||||
public void onChanged(RenderingWidget renderingWidget) {
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
setWillNotDraw(false);
|
||||
subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
|
||||
|
||||
if (attachedToWindow) {
|
||||
subtitleWidget.onAttachedToWindow();
|
||||
requestLayout();
|
||||
}
|
||||
} else {
|
||||
setWillNotDraw(true);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Looper getSubtitleLooper() {
|
||||
return Looper.getMainLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
if (mSubtitleWidget != null) {
|
||||
mSubtitleWidget.onAttachedToWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
if (mSubtitleWidget != null) {
|
||||
mSubtitleWidget.onDetachedFromWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
if (mSubtitleWidget != null) {
|
||||
final int width = getWidth() - getPaddingLeft() - getPaddingRight();
|
||||
final int height = getHeight() - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
mSubtitleWidget.setSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
|
||||
if (mSubtitleWidget != null) {
|
||||
final int saveCount = canvas.save();
|
||||
canvas.translate(getPaddingLeft(), getPaddingTop());
|
||||
mSubtitleWidget.draw(canvas);
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return SubtitleView.class.getName();
|
||||
}
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2018 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.media.MediaPlayer;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
|
||||
import static android.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
|
||||
|
||||
class VideoSurfaceView extends SurfaceView implements VideoViewInterface, SurfaceHolder.Callback {
|
||||
private static final String TAG = "VideoSurfaceView";
|
||||
private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
|
||||
private SurfaceHolder mSurfaceHolder = null;
|
||||
private SurfaceListener mSurfaceListener = null;
|
||||
private MediaPlayer mMediaPlayer;
|
||||
// A flag to indicate taking over other view should be proceed.
|
||||
private boolean mIsTakingOverOldView;
|
||||
private VideoViewInterface mOldView;
|
||||
|
||||
|
||||
public VideoSurfaceView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public VideoSurfaceView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// implements VideoViewInterface
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean assignSurfaceToMediaPlayer(MediaPlayer mp) {
|
||||
Log.d(TAG, "assignSurfaceToMediaPlayer(): mSurfaceHolder: " + mSurfaceHolder);
|
||||
if (mp == null || !hasAvailableSurface()) {
|
||||
return false;
|
||||
}
|
||||
mp.setDisplay(mSurfaceHolder);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSurfaceListener(SurfaceListener l) {
|
||||
mSurfaceListener = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return VIEW_TYPE_SURFACEVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaPlayer(MediaPlayer mp) {
|
||||
mMediaPlayer = mp;
|
||||
if (mIsTakingOverOldView) {
|
||||
takeOver(mOldView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeOver(@NonNull VideoViewInterface oldView) {
|
||||
if (assignSurfaceToMediaPlayer(mMediaPlayer)) {
|
||||
((View) oldView).setVisibility(GONE);
|
||||
mIsTakingOverOldView = false;
|
||||
mOldView = null;
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceTakeOverDone(this);
|
||||
}
|
||||
} else {
|
||||
mIsTakingOverOldView = true;
|
||||
mOldView = oldView;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAvailableSurface() {
|
||||
return (mSurfaceHolder != null && mSurfaceHolder.getSurface() != null);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// implements SurfaceHolder.Callback
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.d(TAG, "surfaceCreated: mSurfaceHolder: " + mSurfaceHolder + ", new holder: " + holder);
|
||||
mSurfaceHolder = holder;
|
||||
if (mIsTakingOverOldView) {
|
||||
takeOver(mOldView);
|
||||
} else {
|
||||
assignSurfaceToMediaPlayer(mMediaPlayer);
|
||||
}
|
||||
|
||||
if (mSurfaceListener != null) {
|
||||
Rect rect = mSurfaceHolder.getSurfaceFrame();
|
||||
mSurfaceListener.onSurfaceCreated(this, rect.width(), rect.height());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceChanged(this, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
// After we return from this we can't use the surface any more
|
||||
mSurfaceHolder = null;
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Investigate the way to move onMeasure() code into FrameLayout.
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int videoWidth = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoWidth();
|
||||
int videoHeight = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoHeight();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
|
||||
+ MeasureSpec.toString(heightMeasureSpec) + ")");
|
||||
Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
|
||||
Log.i(TAG, " viewSize: " + getWidth() + "/" + getHeight());
|
||||
Log.i(TAG, " mVideoWidth/height: " + videoWidth + ", " + videoHeight);
|
||||
}
|
||||
|
||||
int width = getDefaultSize(videoWidth, widthMeasureSpec);
|
||||
int height = getDefaultSize(videoHeight, heightMeasureSpec);
|
||||
|
||||
if (videoWidth > 0 && videoHeight > 0) {
|
||||
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
|
||||
// the size is fixed
|
||||
width = widthSpecSize;
|
||||
height = heightSpecSize;
|
||||
|
||||
// for compatibility, we adjust size based on aspect ratio
|
||||
if (videoWidth * height < width * videoHeight) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "image too wide, correcting");
|
||||
}
|
||||
width = height * videoWidth / videoHeight;
|
||||
} else if (videoWidth * height > width * videoHeight) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "image too tall, correcting");
|
||||
}
|
||||
height = width * videoHeight / videoWidth;
|
||||
}
|
||||
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
|
||||
// only the width is fixed, adjust the height to match aspect ratio if possible
|
||||
width = widthSpecSize;
|
||||
height = width * videoHeight / videoWidth;
|
||||
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
|
||||
// couldn't match aspect ratio within the constraints
|
||||
height = heightSpecSize;
|
||||
}
|
||||
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
|
||||
// only the height is fixed, adjust the width to match aspect ratio if possible
|
||||
height = heightSpecSize;
|
||||
width = height * videoWidth / videoHeight;
|
||||
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
|
||||
// couldn't match aspect ratio within the constraints
|
||||
width = widthSpecSize;
|
||||
}
|
||||
} else {
|
||||
// neither the width nor the height are fixed, try to use actual video size
|
||||
width = videoWidth;
|
||||
height = videoHeight;
|
||||
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
|
||||
// too tall, decrease both width and height
|
||||
height = heightSpecSize;
|
||||
width = height * videoWidth / videoHeight;
|
||||
}
|
||||
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
|
||||
// too wide, decrease both width and height
|
||||
width = widthSpecSize;
|
||||
height = width * videoHeight / videoWidth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no size yet, just adopt the given spec sizes
|
||||
}
|
||||
setMeasuredDimension(width, height);
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "end of onMeasure()");
|
||||
Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ViewType: SurfaceView / Visibility: " + getVisibility()
|
||||
+ " / surfaceHolder: " + mSurfaceHolder;
|
||||
}
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2018 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.MediaPlayer;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
import android.view.View;
|
||||
|
||||
import static android.widget.VideoView2.VIEW_TYPE_TEXTUREVIEW;
|
||||
|
||||
@RequiresApi(26)
|
||||
class VideoTextureView extends TextureView
|
||||
implements VideoViewInterface, TextureView.SurfaceTextureListener {
|
||||
private static final String TAG = "VideoTextureView";
|
||||
private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private SurfaceTexture mSurfaceTexture;
|
||||
private Surface mSurface;
|
||||
private SurfaceListener mSurfaceListener;
|
||||
private MediaPlayer mMediaPlayer;
|
||||
// A flag to indicate taking over other view should be proceed.
|
||||
private boolean mIsTakingOverOldView;
|
||||
private VideoViewInterface mOldView;
|
||||
|
||||
public VideoTextureView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public VideoTextureView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public VideoTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public VideoTextureView(
|
||||
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setSurfaceTextureListener(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// implements VideoViewInterface
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean assignSurfaceToMediaPlayer(MediaPlayer mp) {
|
||||
Log.d(TAG, "assignSurfaceToMediaPlayer(): mSurfaceTexture: " + mSurfaceTexture);
|
||||
if (mp == null || !hasAvailableSurface()) {
|
||||
// Surface is not ready.
|
||||
return false;
|
||||
}
|
||||
mp.setSurface(mSurface);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSurfaceListener(SurfaceListener l) {
|
||||
mSurfaceListener = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewType() {
|
||||
return VIEW_TYPE_TEXTUREVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaPlayer(MediaPlayer mp) {
|
||||
mMediaPlayer = mp;
|
||||
if (mIsTakingOverOldView) {
|
||||
takeOver(mOldView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeOver(@NonNull VideoViewInterface oldView) {
|
||||
if (assignSurfaceToMediaPlayer(mMediaPlayer)) {
|
||||
((View) oldView).setVisibility(GONE);
|
||||
mIsTakingOverOldView = false;
|
||||
mOldView = null;
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceTakeOverDone(this);
|
||||
}
|
||||
} else {
|
||||
mIsTakingOverOldView = true;
|
||||
mOldView = oldView;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAvailableSurface() {
|
||||
return (mSurfaceTexture != null && !mSurfaceTexture.isReleased() && mSurface != null);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// implements TextureView.SurfaceTextureListener
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
|
||||
Log.d(TAG, "onSurfaceTextureAvailable: mSurfaceTexture: " + mSurfaceTexture
|
||||
+ ", new surface: " + surfaceTexture);
|
||||
mSurfaceTexture = surfaceTexture;
|
||||
mSurface = new Surface(mSurfaceTexture);
|
||||
if (mIsTakingOverOldView) {
|
||||
takeOver(mOldView);
|
||||
} else {
|
||||
assignSurfaceToMediaPlayer(mMediaPlayer);
|
||||
}
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceCreated(this, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceChanged(this, width, height);
|
||||
}
|
||||
// requestLayout(); // TODO: figure out if it should be called here?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
|
||||
if (mSurfaceListener != null) {
|
||||
mSurfaceListener.onSurfaceDestroyed(this);
|
||||
}
|
||||
mSurfaceTexture = null;
|
||||
mSurface = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int videoWidth = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoWidth();
|
||||
int videoHeight = (mMediaPlayer == null) ? 0 : mMediaPlayer.getVideoHeight();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
|
||||
+ MeasureSpec.toString(heightMeasureSpec) + ")");
|
||||
Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
|
||||
Log.i(TAG, " viewSize: " + getWidth() + "/" + getHeight());
|
||||
Log.i(TAG, " mVideoWidth/height: " + videoWidth + ", " + videoHeight);
|
||||
}
|
||||
|
||||
int width = getDefaultSize(videoWidth, widthMeasureSpec);
|
||||
int height = getDefaultSize(videoHeight, heightMeasureSpec);
|
||||
|
||||
if (videoWidth > 0 && videoHeight > 0) {
|
||||
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
|
||||
// the size is fixed
|
||||
width = widthSpecSize;
|
||||
height = heightSpecSize;
|
||||
|
||||
// for compatibility, we adjust size based on aspect ratio
|
||||
if (videoWidth * height < width * videoHeight) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "image too wide, correcting");
|
||||
}
|
||||
width = height * videoWidth / videoHeight;
|
||||
} else if (videoWidth * height > width * videoHeight) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "image too tall, correcting");
|
||||
}
|
||||
height = width * videoHeight / videoWidth;
|
||||
}
|
||||
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
|
||||
// only the width is fixed, adjust the height to match aspect ratio if possible
|
||||
width = widthSpecSize;
|
||||
height = width * videoHeight / videoWidth;
|
||||
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
|
||||
// couldn't match aspect ratio within the constraints
|
||||
height = heightSpecSize;
|
||||
}
|
||||
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
|
||||
// only the height is fixed, adjust the width to match aspect ratio if possible
|
||||
height = heightSpecSize;
|
||||
width = height * videoWidth / videoHeight;
|
||||
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
|
||||
// couldn't match aspect ratio within the constraints
|
||||
width = widthSpecSize;
|
||||
}
|
||||
} else {
|
||||
// neither the width nor the height are fixed, try to use actual video size
|
||||
width = videoWidth;
|
||||
height = videoHeight;
|
||||
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
|
||||
// too tall, decrease both width and height
|
||||
height = heightSpecSize;
|
||||
width = height * videoWidth / videoHeight;
|
||||
}
|
||||
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
|
||||
// too wide, decrease both width and height
|
||||
width = widthSpecSize;
|
||||
height = width * videoHeight / videoWidth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no size yet, just adopt the given spec sizes
|
||||
}
|
||||
setMeasuredDimension(width, height);
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "end of onMeasure()");
|
||||
Log.i(TAG, " measuredSize: " + getMeasuredWidth() + "/" + getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ViewType: TextureView / Visibility: " + getVisibility()
|
||||
+ " / surfaceTexture: " + mSurfaceTexture;
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue