bug 705572 - Kindle Fire: YouTube videos do not open in unavailable YouTube App r=dougt,mfinkle a=akeybl
authorBrad Lassey <blassey@mozilla.com>
Mon, 05 Dec 2011 16:57:33 -0500
changeset 79278 2bbfe14f8b8d929ba6803ba74a9188bfa3fabc0c
parent 79277 4952c336f367bf949e911a1186831220b346e9aa
child 79279 fb1fa0a1fa7ccef1c8ccc1a8497fc0379893ab2b
child 79282 dea4e14dc88aa30d2af4aefbe408ff79f9575551
child 79287 fcec1cc2c18fc76fb9f316cd768cbdb7801550c4
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt, mfinkle, akeybl
bugs705572
milestone9.0
bug 705572 - Kindle Fire: YouTube videos do not open in unavailable YouTube App r=dougt,mfinkle a=akeybl
embedding/android/AndroidManifest.xml.in
embedding/android/GeckoAppShell.java
embedding/android/Makefile.in
embedding/android/VideoPlayer.java
embedding/android/resources/layout/videoplayer.xml
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -116,10 +116,18 @@
         <activity android:name="LauncherShortcuts"
                   android:label="@string/launcher_shortcuts_title">
             <!--  This intent-filter allows your shortcuts to be created in the launcher. -->
             <intent-filter>
                 <action android:name="android.intent.action.CREATE_SHORTCUT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name="org.mozilla.gecko.VideoPlayer"
+                  android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation" 
+                  android:theme="@android:style/Theme.NoTitleBar" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest> 
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -799,16 +799,28 @@ public class GeckoAppShell
             intent.putExtra(Intent.EXTRA_TEXT, aUriSpec);
             intent.putExtra(Intent.EXTRA_SUBJECT, aTitle);
             if (aMimeType != null && aMimeType.length() > 0)
                 intent.setType(aMimeType);
         } else if (aMimeType.length() > 0) {
             intent.setDataAndType(Uri.parse(aUriSpec), aMimeType);
         } else {
             Uri uri = Uri.parse(aUriSpec);
+            if ("vnd.youtube".equals(uri.getScheme())) {
+                // Special case youtube to fallback to our own player
+                String[] handlers = getHandlersForURL(aUriSpec, aAction);
+                if (handlers.length == 0) {
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.setClassName(GeckoApp.mAppContext.getPackageName(),
+                                        "org.mozilla.gecko.VideoPlayer");
+                    intent.setData(uri);
+                    GeckoApp.mAppContext.startActivity(intent);
+                    return true;
+                }
+            }
             if ("sms".equals(uri.getScheme())) {
                 // Have a apecial handling for the SMS, as the message body
                 // is not extracted from the URI automatically
                 final String query = uri.getEncodedQuery();
                 if (query != null && query.length() > 0) {
                     final String[] fields = query.split("&");
                     boolean foundBody = false;
                     String resultQuery = "";
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -49,16 +49,17 @@ JAVAFILES = \
   GeckoApp.java \
   GeckoAppShell.java \
   GeckoConnectivityReceiver.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceLockInfo.java \
+  VideoPlayer.java \
   $(NULL)
 
 PROCESSEDJAVAFILES = \
   App.java \
   Restarter.java \
   NotificationHandler.java \
   LauncherShortcuts.java \
   $(NULL)
@@ -120,16 +121,17 @@ DEFINES += -DMOZ_ANDROID_SHARED_ID="$(AN
 endif
 
 RES_LAYOUT = \
   res/layout/notification_progress.xml \
   res/layout/notification_progress_text.xml \
   res/layout/notification_icon_text.xml \
   res/layout/launch_app_list.xml \
   res/layout/launch_app_listitem.xml \
+  res/layout/videoplayer.xml \
   $(NULL)
 
 RES_VALUES = res/values/colors.xml res/values/themes.xml
 
 AB_rCD = $(shell echo $(AB_CD) | sed -e s/-/-r/)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
new file mode 100644
--- /dev/null
+++ b/embedding/android/VideoPlayer.java
@@ -0,0 +1,113 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brad Lassey <blassey@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import android.app.Activity;
+import android.os.Bundle;
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import android.util.*;
+import android.widget.*;
+import android.net.*;
+import android.content.Intent;
+
+public class VideoPlayer extends Activity
+{
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.videoplayer);
+        mVideoView = (VideoView) findViewById(R.id.VideoView);
+        MediaController mediaController = new MediaController(this);
+        mediaController.setAnchorView(mVideoView);
+        Intent intent = getIntent();
+        Uri data = intent.getData();
+        String spec = null;
+        if ("vnd.youtube".equals(data.getScheme())) {
+            String ssp = data.getSchemeSpecificPart();
+            String id = ssp.substring(0, ssp.indexOf('?'));
+            spec = getSpecFromYouTubeVideoID(id);
+        }
+        if (spec == null)
+            return;
+        Uri video = Uri.parse(spec);
+        mVideoView.setMediaController(mediaController);
+        mVideoView.setVideoURI(video);
+        mVideoView.start();
+    }
+
+    VideoView mVideoView;
+
+    String getSpecFromYouTubeVideoID(String id) {
+        String spec = null;
+        try {
+            String info_uri = "http://www.youtube.com/get_video_info?&video_id=" + id;
+            URL info_url = new URL(info_uri);
+            URLConnection urlConnection = info_url.openConnection();
+            BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
+            try {
+                StringBuilder sb = new StringBuilder();
+                String line;
+                while ((line = br.readLine()) != null)
+                    sb.append(line);
+                android.net.Uri fakeUri = android.net.Uri.parse("fake:/fake?" + sb);
+                String stream_map = fakeUri.getQueryParameter("url_encoded_fmt_stream_map");
+                if (stream_map == null)
+                    return null;
+                String[] streams = stream_map.split(",");
+                for (int i = 0; i < streams.length; i++) {
+                    fakeUri = android.net.Uri.parse("fake:/fake?" + streams[i]);
+                    String url = fakeUri.getQueryParameter("url");
+                    String type = fakeUri.getQueryParameter("type");
+                    if (type != null && url != null &&
+                        (type.startsWith("video/mp4") || type.startsWith("video/webm"))) {
+                        spec = url;
+                    }
+                }
+            } finally {
+                br.close();
+            }
+        } catch (Exception e) {
+            Log.e("VideoPlayer", "exception", e);
+        }
+        return spec;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/embedding/android/resources/layout/videoplayer.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+  <VideoView
+      android:layout_height="fill_parent"
+      android:layout_width="fill_parent"
+      android:layout_gravity="center"
+      android:id="@+id/VideoView" />
+</LinearLayout>