Initial commit for VideoView2Impl

Test: build
Change-Id: I2f5e7f85b5a7358c707cf3897f354ead42980956
gugelfrei
Insun Kang 7 years ago
parent 9df8cfa0a6
commit 080b934e6d

@ -32,6 +32,8 @@ LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
LOCAL_MULTILIB := first
LOCAL_JAVA_LIBRARIES += android-support-annotations
# Embed native libraries in package, rather than installing to /system/lib*.
# TODO: Find a right way to include libs in the apk. b/72066556
LOCAL_MODULE_TAGS := samples

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

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>

@ -41,4 +41,5 @@
<attr name="mediaRouteControlPanelThemeOverlay" format="reference" />
<attr name="mediaRouteTheme" format="reference" />
<attr name="enableControlView" format="boolean" />
</resources>

@ -81,4 +81,14 @@
<!-- Placeholder text indicating that the user is currently casting screen. [CHAR LIMIT=50] -->
<string name="mr_controller_casting_screen">Casting screen</string>
<string name="lockscreen_pause_button_content_description">Pause</string>
<string name="lockscreen_play_button_content_description">Play</string>
<!-- Text for error alert when a video container is not valid for progressive download/playback. -->
<string name="VideoView2_error_text_invalid_progressive_playback">This video isn\'t valid for streaming to this device.</string>
<!-- Text for error alert when a video cannot be played. It can be used by any app. -->
<string name="VideoView2_error_text_unknown">Can\'t play this video.</string>
<!-- Button to close error alert when a video cannot be played. -->
<string name="VideoView2_error_button">OK</string>
</resources>

@ -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>

@ -18,14 +18,16 @@ package com.android.media.update;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.media.update.MediaController2Provider;
import android.media.update.MediaControlView2Provider;
import android.media.update.VideoView2Provider;
import android.media.update.StaticProvider;
import android.media.update.ViewProvider;
import android.widget.MediaController2;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
import com.android.widget.MediaController2Impl;
import com.android.widget.MediaControlView2Impl;
import com.android.widget.VideoView2Impl;
public class ApiFactory implements StaticProvider {
@ -36,13 +38,15 @@ public class ApiFactory implements StaticProvider {
}
@Override
public MediaController2Provider createMediaController2(
MediaController2 instance, ViewProvider superProvider) {
return new MediaController2Impl(instance, superProvider);
public MediaControlView2Provider createMediaControlView2(
MediaControlView2 instance, ViewProvider superProvider) {
return new MediaControlView2Impl(instance, superProvider);
}
@Override
public VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider) {
return new VideoView2Impl(instance, superProvider);
public VideoView2Provider createVideoView2(
VideoView2 instance, ViewProvider superProvider,
@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
return new VideoView2Impl(instance, superProvider, attrs, defStyleAttr, defStyleRes);
}
}

@ -39,11 +39,11 @@ public class ApiHelper {
mLibTheme = libTheme;
}
public Resources getLibResources() {
return mLibResources;
public static Resources getLibResources() {
return sInstance.mLibResources;
}
public Resources.Theme getLibTheme() {
return mLibTheme;
public static Resources.Theme getLibTheme() {
return sInstance.mLibTheme;
}
}

@ -16,21 +16,22 @@
package com.android.widget;
import android.graphics.Canvas;
import android.media.session.MediaController;
import android.media.update.MediaController2Provider;
import android.media.update.MediaControlView2Provider;
import android.media.update.ViewProvider;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.MediaController2;
import android.widget.MediaControlView2;
public class MediaController2Impl implements MediaController2Provider {
private final MediaController2 mInstance;
public class MediaControlView2Impl implements MediaControlView2Provider {
private final MediaControlView2 mInstance;
private final ViewProvider mSuperProvider;
public MediaController2Impl(MediaController2 instance, ViewProvider superProvider) {
static final String ACTION_SHOW_SUBTITLE = "showSubtitle";
static final String ACTION_HIDE_SUBTITLE = "hideSubtitle";
public MediaControlView2Impl(MediaControlView2 instance, ViewProvider superProvider) {
mInstance = instance;
mSuperProvider = superProvider;
@ -42,11 +43,6 @@ public class MediaController2Impl implements MediaController2Provider {
// TODO: Implement
}
@Override
public void setAnchorView_impl(View view) {
// TODO: Implement
}
@Override
public void show_impl() {
// TODO: Implement
@ -68,11 +64,6 @@ public class MediaController2Impl implements MediaController2Provider {
// TODO: Implement
}
@Override
public void setPrevNextListeners_impl(OnClickListener next, OnClickListener prev) {
// TODO: Implement
}
@Override
public void showCCButton_impl() {
// TODO: Implement
@ -124,34 +115,10 @@ public class MediaController2Impl implements MediaController2Provider {
// TODO: Implement
}
@Override
public void onAttachedToWindow_impl() {
mSuperProvider.onAttachedToWindow_impl();
// TODO: Implement
}
@Override
public void onDetachedFromWindow_impl() {
mSuperProvider.onDetachedFromWindow_impl();
// TODO: Implement
}
@Override
public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
// TODO: Implement
}
@Override
public void draw_impl(Canvas canvas) {
mSuperProvider.draw_impl(canvas);
// TODO: Implement
}
@Override
public CharSequence getAccessibilityClassName_impl() {
// TODO: Implement
return MediaController2.class.getName();
return MediaControlView2.class.getName();
}
@Override

@ -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;
}
}
Loading…
Cancel
Save