From 18f41969a12e4b6d0e441f37c4d798fc24e0365d Mon Sep 17 00:00:00 2001 From: fujunwei Date: Fri, 13 May 2016 08:31:13 +0800 Subject: [PATCH] [Android] Support third part media player on Crosswalk A requirement from an important customer who want to forward web resources with proxy on Crosswalk, but android system MediaPlayer can't set a proxy with a standard API. The ExoMediaPlayer is playing videos and music is a popular activity on Android devices, and it can be configured with proxy. https://developer.android.com/guide/topics/media/exoplayer.html BUG=XWALK-6770 --- .../org/xwalk/core/internal/XWalkContent.java | 7 +- .../internal/XWalkContentsClientBridge.java | 8 + .../internal/XWalkMediaPlayerInternal.java | 254 ++++++++++++++++++ ...XWalkMediaPlayerResourceLoadingFilter.java | 16 +- .../core/internal/XWalkViewInternal.java | 13 + .../reflection_generator.py | 1 + 6 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerInternal.java diff --git a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContent.java b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContent.java index 28e031c463..15a7753c20 100644 --- a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContent.java +++ b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContent.java @@ -132,7 +132,7 @@ public XWalkContent(Context context, String animatable, XWalkViewInternal xwView mGeolocationPermissions = new XWalkGeolocationPermissions(sharedPreferences); MediaPlayerBridge.setResourceLoadingFilter( - new XWalkMediaPlayerResourceLoadingFilter()); + new XWalkMediaPlayerResourceLoadingFilter(mContentsClientBridge)); setNativeContent(nativeInit(), animatable); @@ -379,6 +379,11 @@ public void setXWalkWebChromeClient(XWalkWebChromeClient client) { mContentsClientBridge.setXWalkWebChromeClient(client); } + public void setXWalkMediaPlayer(XWalkMediaPlayerInternal mediaPlayer) { + if (mNativeContent == 0) return; + mContentsClientBridge.setXWalkMediaPlayer(mediaPlayer); + } + public XWalkWebChromeClient getXWalkWebChromeClient() { if (mNativeContent == 0) return null; return mContentsClientBridge.getXWalkWebChromeClient(); diff --git a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java index 03e76cadee..dfdbb8a3ce 100644 --- a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java +++ b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkContentsClientBridge.java @@ -70,6 +70,7 @@ class XWalkContentsClientBridge extends XWalkContentsClient private XWalkNavigationHandler mNavigationHandler; private XWalkNotificationService mNotificationService; private Handler mUiThreadHandler; + private XWalkMediaPlayerInternal mXWalkMediaPlayerInternal; /** State recording variables */ // For fullscreen state. @@ -163,6 +164,13 @@ public void setResourceClient(XWalkResourceClientInternal client) { mXWalkResourceClient = new XWalkResourceClientInternal(mXWalkView); } + public void setXWalkMediaPlayer(XWalkMediaPlayerInternal mediaPlayer) { + mXWalkMediaPlayerInternal = mediaPlayer; + } + + public XWalkMediaPlayerInternal getExternalMediaPlayer() { + return mXWalkMediaPlayerInternal; + } public void setXWalkWebChromeClient(XWalkWebChromeClient client) { // If it's null, use Crosswalk implementation. diff --git a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerInternal.java b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerInternal.java new file mode 100644 index 0000000000..65e26e8282 --- /dev/null +++ b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerInternal.java @@ -0,0 +1,254 @@ +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.xwalk.core.internal; + +import android.content.Context; +import android.media.MediaPlayer.OnBufferingUpdateListener; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.media.MediaPlayer.OnPreparedListener; +import android.media.MediaPlayer.OnSeekCompleteListener; +import android.media.MediaPlayer.OnVideoSizeChangedListener; +import android.media.MediaPlayer.TrackInfo; +import android.net.Uri; +import android.util.Log; +import android.view.Surface; + +import java.io.FileDescriptor; +import java.util.HashMap; +import java.util.Map; + +import org.chromium.media.ExternalMediaPlayer; + +@XWalkAPI(createExternally = true) +public class XWalkMediaPlayerInternal extends ExternalMediaPlayer { + private final static String TAG = "XWalkMediaPlayerInternal"; + + private void unsupported() { + Log.e(TAG, "ERROR: The function must be implemented"); + throw new UnsupportedOperationException(); + } + + /** + * Sets the Surface to be used as the sink for the video portion of the media. + * @param surface the Surface to be used for the video portion of the media. + * @since 7.0 + */ + @XWalkAPI + public void setSurface(Surface surface) { + unsupported(); + } + + /** + * Sets the data source as a content Uri. + * @param context the Context to use when resolving the Uri. + * @param uri the Content URI of the data you want to play. + * @param headers the headers to be sent together with the request for the data. + * @since 7.0 + */ + @XWalkAPI + public void setDataSource(Context context, Uri uri, Map headers) { + unsupported(); + } + + /** + * Sets the data source (FileDescriptor) to use. + * @param fd the FileDescriptor for the file you want to play. + * @param offset the offset into the file where the data to be played starts, in bytes. + * @param length the length in bytes of the data to be played. + * @since 7.0 + */ + @XWalkAPI + public void setDataSource(FileDescriptor fd, long offset, long length) { + unsupported(); + } + + /** + * Sets the data source as a content Uri. + * @param context the Context to use when resolving the Uri. + * @param uri the Content URI of the data you want to play. + * @since 7.0 + */ + @XWalkAPI + public void setDataSource(Context context, Uri uri) { + unsupported(); + } + + /** + * Prepares the player for playback, asynchronously. + * @since 7.0 + */ + @XWalkAPI + public void prepareAsync() { + unsupported(); + } + + /** + * Checks whether the MediaPlayer is playing. + * @since 7.0 + */ + @XWalkAPI + public boolean isPlaying() { + unsupported(); + return false; + } + + /** + * Returns the width of the video. + * @since 7.0 + */ + @XWalkAPI + public int getVideoWidth() { + unsupported(); + return 0; + } + + /** + * Returns the height of the video. + * @since 7.0 + */ + @XWalkAPI + public int getVideoHeight() { + unsupported(); + return 0; + } + + /** + * Gets the current playback position. + * @since 7.0 + */ + @XWalkAPI + public int getCurrentPosition() { + unsupported(); + return 0; + } + + /** + * Gets the duration of the file. + * @since 7.0 + */ + @XWalkAPI + public int getDuration() { + unsupported(); + return 0; + } + + /** + * Releases resources associated with this MediaPlayer object. + * @since 7.0 + */ + @XWalkAPI + public void release() { + unsupported(); + } + + /** + * Sets the volume on this player. + * @since 7.0 + */ + @XWalkAPI + public void setVolume(float volume1, float volume2) { + unsupported(); + } + + /** + * Starts or resumes playback. If playback had previously been paused, + * playback will continue from where it was paused. If playback had been stopped, + * or never started before, playback will start at the beginning. + * @since 7.0 + */ + @XWalkAPI + public void start() { + unsupported(); + } + + /** + * Pauses playback. Call {@link XWalkMediaPlayerInternal#start()} to resume. + * @since 7.0 + */ + @XWalkAPI + public void pause() { + unsupported(); + } + + /** + * Seeks to specified time position. + * @since 7.0 + */ + @XWalkAPI + public void seekTo(int msec) { + unsupported(); + } + + /** + * Returns an array of track information. + * @since 7.0 + */ + @XWalkAPI + public TrackInfo[] getTrackInfo() { + unsupported(); + return null; + } + + /** + * Register a callback to be invoked when the status of a network stream's buffer has changed. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { + unsupported(); + } + + /** + * Register a callback to be invoked when the end of a media source has been reached during playback. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnCompletionListener(OnCompletionListener listener) { + unsupported(); + } + + /** + * Register a callback to be invoked when an error has happened during an asynchronous operation. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnErrorListener(OnErrorListener listener) { + unsupported(); + } + + /** + * Register a callback to be invoked when the media source is ready for playback. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnPreparedListener(OnPreparedListener listener) { + unsupported(); + } + + /** + * Register a callback to be invoked when a seek operation has been completed. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { + unsupported(); + } + + /** + * Register a callback to be invoked when the video size is known or updated. + * @param listener the callback that will be run. + * @since 7.0 + */ + @XWalkAPI + public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) { + unsupported(); + } +} diff --git a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerResourceLoadingFilter.java b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerResourceLoadingFilter.java index 2ad2d07591..7d0b3fd46f 100644 --- a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerResourceLoadingFilter.java +++ b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkMediaPlayerResourceLoadingFilter.java @@ -6,9 +6,9 @@ import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.MediaPlayer; import android.net.Uri; +import org.chromium.media.ExternalMediaPlayer; import org.chromium.media.MediaPlayerBridge; import java.io.File; @@ -22,8 +22,14 @@ class XWalkMediaPlayerResourceLoadingFilter extends MediaPlayerBridge.ResourceLoadingFilter { + private XWalkContentsClientBridge mContentsClientBridge; + + XWalkMediaPlayerResourceLoadingFilter(XWalkContentsClientBridge clientBridge) { + mContentsClientBridge = clientBridge; + } + @Override - public boolean shouldOverrideResourceLoading(MediaPlayer mediaPlayer, + public boolean shouldOverrideResourceLoading(ExternalMediaPlayer mediaPlayer, Context context, Uri uri) { String scheme = uri.getScheme(); if (scheme == null) return false; @@ -39,10 +45,14 @@ public boolean shouldOverrideResourceLoading(MediaPlayer mediaPlayer, context.getAssets().openFd(AndroidProtocolHandler.getAssetPath(uri)); mediaPlayer.setDataSource( afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); - return true; } catch (Exception e) { return false; } } + + @Override + public ExternalMediaPlayer getExternalMediaPlayer() { + return mContentsClientBridge.getExternalMediaPlayer(); + } } diff --git a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewInternal.java b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewInternal.java index 6034a055f7..81c28752f6 100644 --- a/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewInternal.java +++ b/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewInternal.java @@ -954,6 +954,19 @@ public void setResourceClient(XWalkResourceClientInternal client) { mContent.setResourceClient(client); } + /** + * Support third party MediaPlayer in Crosswalk with implementing the api + * from XWalkMediaPlayerInternal. + * @param mediaPlayer the XWalkMediaPlayerInternal implemented by customers. + * @since 7.0 + */ + @XWalkAPI(reservable = true) + public void setXWalkMediaPlayer(XWalkMediaPlayerInternal mediaPlayer) { + if (mContent == null) return; + checkThreadSafety(); + mContent.setXWalkMediaPlayer(mediaPlayer); + } + /** * Set Background color of the view */ diff --git a/tools/reflection_generator/reflection_generator.py b/tools/reflection_generator/reflection_generator.py index a08c8bfe91..190c7b4dec 100755 --- a/tools/reflection_generator/reflection_generator.py +++ b/tools/reflection_generator/reflection_generator.py @@ -39,6 +39,7 @@ 'XWalkHttpAuthInternal', 'XWalkJavascriptResultHandlerInternal', 'XWalkJavascriptResultInternal', + 'XWalkMediaPlayerInternal', 'XWalkNativeExtensionLoaderInternal', 'XWalkNavigationHistoryInternal', 'XWalkNavigationItemInternal',