From d5f9fa574da2ee210ac86154ab0aea9fee5e8278 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 28 May 2013 14:39:39 -0700 Subject: [PATCH] Listen for HTTP proxy changes and propagate the information to the media framework. related-to-bug: 8873723 Change-Id: I2a34343f8006fa1b1448a1f047458fd58fe14fda (cherry picked from commit bfe9154142428aa8abecaf943dfeffc55f411ea7) --- media/java/android/media/MediaPlayer.java | 78 ++++++++++++++++++++++++++++++- media/jni/android_media_MediaPlayer.cpp | 64 ++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index f74516366b09..b729640a7f65 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -16,9 +16,14 @@ package android.media; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.AssetFileDescriptor; +import android.net.Proxy; +import android.net.ProxyProperties; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -864,6 +869,7 @@ public class MediaPlayer */ public void setDataSource(Context context, Uri uri, Map headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + disableProxyListener(); String scheme = uri.getScheme(); if(scheme == null || scheme.equals("file")) { @@ -896,8 +902,13 @@ public class MediaPlayer } Log.d(TAG, "Couldn't open file on client side, trying server side"); + setDataSource(uri.toString(), headers); - return; + + if (scheme.equalsIgnoreCase("http") + || scheme.equalsIgnoreCase("https")) { + setupProxyListener(context); + } } /** @@ -948,6 +959,8 @@ public class MediaPlayer private void setDataSource(String path, String[] keys, String[] values) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + disableProxyListener(); + final Uri uri = Uri.parse(path); if ("file".equals(uri.getScheme())) { path = uri.getPath(); @@ -991,7 +1004,13 @@ public class MediaPlayer * @param length the length in bytes of the data to be played * @throws IllegalStateException if it is called in an invalid state */ - public native void setDataSource(FileDescriptor fd, long offset, long length) + public void setDataSource(FileDescriptor fd, long offset, long length) + throws IOException, IllegalArgumentException, IllegalStateException { + disableProxyListener(); + _setDataSource(fd, offset, length); + } + + private native void _setDataSource(FileDescriptor fd, long offset, long length) throws IOException, IllegalArgumentException, IllegalStateException; /** @@ -1332,6 +1351,8 @@ public class MediaPlayer _reset(); // make sure none of the listeners get called anymore mEventHandler.removeCallbacksAndMessages(null); + + disableProxyListener(); } private native void _reset(); @@ -2449,4 +2470,57 @@ public class MediaPlayer return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT || mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); } + + private Context mProxyContext = null; + private ProxyReceiver mProxyReceiver = null; + + private void setupProxyListener(Context context) { + IntentFilter filter = new IntentFilter(); + filter.addAction(Proxy.PROXY_CHANGE_ACTION); + mProxyReceiver = new ProxyReceiver(); + mProxyContext = context; + + Intent currentProxy = + context.getApplicationContext().registerReceiver(mProxyReceiver, filter); + + if (currentProxy != null) { + handleProxyBroadcast(currentProxy); + } + } + + private void disableProxyListener() { + if (mProxyReceiver == null) { + return; + } + + Context appContext = mProxyContext.getApplicationContext(); + if (appContext != null) { + appContext.unregisterReceiver(mProxyReceiver); + } + + mProxyReceiver = null; + mProxyContext = null; + } + + private void handleProxyBroadcast(Intent intent) { + ProxyProperties props = + (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO); + + if (props == null || props.getHost() == null) { + updateProxyConfig(null); + } else { + updateProxyConfig(props); + } + } + + private class ProxyReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) { + handleProxyBroadcast(intent); + } + } + } + + private native void updateProxyConfig(ProxyProperties props); } diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index c5098ce1c7f2..7c607ea36718 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -55,6 +55,10 @@ struct fields_t { jfieldID surface_texture; jmethodID post_event; + + jmethodID proxyConfigGetHost; + jmethodID proxyConfigGetPort; + jmethodID proxyConfigGetExclusionList; }; static fields_t fields; @@ -622,6 +626,20 @@ android_media_MediaPlayer_native_init(JNIEnv *env) if (fields.surface_texture == NULL) { return; } + + clazz = env->FindClass("android/net/ProxyProperties"); + if (clazz == NULL) { + return; + } + + fields.proxyConfigGetHost = + env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;"); + + fields.proxyConfigGetPort = + env->GetMethodID(clazz, "getPort", "()I"); + + fields.proxyConfigGetExclusionList = + env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;"); } static void @@ -823,6 +841,49 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject ; } +static void +android_media_MediaPlayer_updateProxyConfig( + JNIEnv *env, jobject thiz, jobject proxyProps) +{ + ALOGV("updateProxyConfig"); + sp thisplayer = getMediaPlayer(env, thiz); + if (thisplayer == NULL) { + return; + } + + if (proxyProps == NULL) { + thisplayer->updateProxyConfig( + NULL /* host */, 0 /* port */, NULL /* exclusionList */); + } else { + jstring hostObj = (jstring)env->CallObjectMethod( + proxyProps, fields.proxyConfigGetHost); + + const char *host = env->GetStringUTFChars(hostObj, NULL); + + int port = env->CallIntMethod(proxyProps, fields.proxyConfigGetPort); + + jstring exclusionListObj = (jstring)env->CallObjectMethod( + proxyProps, fields.proxyConfigGetExclusionList); + + const char *exclusionList = + env->GetStringUTFChars(exclusionListObj, NULL); + + if (host != NULL && exclusionListObj != NULL) { + thisplayer->updateProxyConfig(host, port, exclusionList); + } + + if (exclusionList != NULL) { + env->ReleaseStringUTFChars(exclusionListObj, exclusionList); + exclusionList = NULL; + } + + if (host != NULL) { + env->ReleaseStringUTFChars(hostObj, host); + host = NULL; + } + } +} + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -832,7 +893,7 @@ static JNINativeMethod gMethods[] = { (void *)android_media_MediaPlayer_setDataSourceAndHeaders }, - {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, + {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, @@ -867,6 +928,7 @@ static JNINativeMethod gMethods[] = { {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, + {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig}, }; static const char* const kClassPathName = "android/media/MediaPlayer"; -- 2.11.0