Merge change Ic0e32f12 into eclair-mr2

* changes:
  Add a callback for the ConnectSink Call.
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index a52b86a..b74564a 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.accounts.Account;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.ContentResolver;
@@ -30,6 +31,7 @@
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.net.Uri;
+import android.os.RemoteException;
 import android.pim.ICalendar;
 import android.pim.RecurrenceSet;
 import android.text.TextUtils;
@@ -37,8 +39,6 @@
 import android.text.format.Time;
 import android.util.Config;
 import android.util.Log;
-import android.accounts.Account;
-import android.os.RemoteException;
 
 /**
  * The Calendar provider contains all calendar events.
@@ -1223,7 +1223,7 @@
         /**
          * The default sort order for this table
          */
-        public static final String DEFAULT_SORT_ORDER = "alarmTime ASC,begin ASC,title ASC";
+        public static final String DEFAULT_SORT_ORDER = "begin ASC,title ASC";
     }
 
     public static final class CalendarAlerts implements BaseColumns,
@@ -1240,6 +1240,8 @@
         public static final Uri CONTENT_URI_BY_INSTANCE =
             Uri.parse("content://calendar/calendar_alerts/by_instance");
 
+        private static final boolean DEBUG = true;
+
         public static final Uri insert(ContentResolver cr, long eventId,
                 long begin, long end, long alarmTime, int minutes) {
             ContentValues values = new ContentValues();
@@ -1257,9 +1259,9 @@
         }
 
         public static final Cursor query(ContentResolver cr, String[] projection,
-                String selection, String[] selectionArgs) {
+                String selection, String[] selectionArgs, String sortOrder) {
             return cr.query(CONTENT_URI, projection, selection, selectionArgs,
-                    DEFAULT_SORT_ORDER);
+                    sortOrder);
         }
 
         /**
@@ -1276,7 +1278,7 @@
             // TODO: construct an explicit SQL query so that we can add
             // "LIMIT 1" to the end and get just one result.
             String[] projection = new String[] { ALARM_TIME };
-            Cursor cursor = query(cr, projection, selection, null);
+            Cursor cursor = query(cr, projection, selection, null, ALARM_TIME + " ASC");
             long alarmTime = -1;
             try {
                 if (cursor != null && cursor.moveToFirst()) {
@@ -1305,46 +1307,61 @@
             // Get all the alerts that have been scheduled but have not fired
             // and should have fired by now and are not too old.
             long now = System.currentTimeMillis();
-            long ancient = now - 24 * DateUtils.HOUR_IN_MILLIS;
+            long ancient = now - DateUtils.DAY_IN_MILLIS;
             String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.SCHEDULED
                     + " AND " + CalendarAlerts.ALARM_TIME + "<" + now
                     + " AND " + CalendarAlerts.ALARM_TIME + ">" + ancient
                     + " AND " + CalendarAlerts.END + ">=" + now;
             String[] projection = new String[] {
-                    _ID,
-                    BEGIN,
-                    END,
                     ALARM_TIME,
             };
-            Cursor cursor = CalendarAlerts.query(cr, projection, selection, null);
+
+            // TODO: construct an explicit SQL query so that we can add
+            // "GROUPBY" instead of doing a sort and de-dup
+            Cursor cursor = CalendarAlerts.query(cr, projection, selection, null, "alarmTime ASC");
             if (cursor == null) {
                 return;
             }
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+
+            if (DEBUG) {
                 Log.d(TAG, "missed alarms found: " + cursor.getCount());
             }
 
             try {
+                long alarmTime = -1;
+
                 while (cursor.moveToNext()) {
-                    long id = cursor.getLong(0);
-                    long begin = cursor.getLong(1);
-                    long end = cursor.getLong(2);
-                    long alarmTime = cursor.getLong(3);
-                    Uri uri = ContentUris.withAppendedId(CONTENT_URI, id);
-                    Intent intent = new Intent(android.provider.Calendar.EVENT_REMINDER_ACTION);
-                    intent.setData(uri);
-                    intent.putExtra(android.provider.Calendar.EVENT_BEGIN_TIME, begin);
-                    intent.putExtra(android.provider.Calendar.EVENT_END_TIME, end);
-                    PendingIntent sender = PendingIntent.getBroadcast(context,
-                            0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-                    Log.w(TAG, "rescheduling missed alarm, id: " + id + " begin: " + begin
-                            + " end: " + end + " alarmTime: " + alarmTime);
-                    manager.set(AlarmManager.RTC_WAKEUP, alarmTime, sender);
+                    long newAlarmTime = cursor.getLong(0);
+                    if (alarmTime != newAlarmTime) {
+                        if (DEBUG) {
+                            Log.w(TAG, "rescheduling missed alarm. alarmTime: " + newAlarmTime);
+                        }
+                        scheduleAlarm(context, manager, newAlarmTime);
+                        alarmTime = newAlarmTime;
+                    }
                 }
             } finally {
                 cursor.close();
             }
+        }
 
+        public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
+            if (DEBUG) {
+                Time time = new Time();
+                time.set(alarmTime);
+                String schedTime = time.format(" %a, %b %d, %Y %I:%M%P");
+                Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
+            }
+
+            if (manager == null) {
+                manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+            }
+
+            Intent intent = new Intent(android.provider.Calendar.EVENT_REMINDER_ACTION);
+            intent.putExtra(android.provider.Calendar.CalendarAlerts.ALARM_TIME, alarmTime);
+            PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
+                    PendingIntent.FLAG_CANCEL_CURRENT);
+            manager.set(AlarmManager.RTC_WAKEUP, alarmTime, pi);
         }
 
         /**
@@ -1367,7 +1384,7 @@
             // TODO: construct an explicit SQL query so that we can add
             // "LIMIT 1" to the end and get just one result.
             String[] projection = new String[] { CalendarAlerts.ALARM_TIME };
-            Cursor cursor = query(cr, projection, selection, null);
+            Cursor cursor = query(cr, projection, selection, null, null);
             boolean found = false;
             try {
                 if (cursor != null && cursor.getCount() > 0) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index fe5f830..e98d8ee 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -448,7 +448,7 @@
 
         /**
          * The kind of data that is used as the display name for the contact, see
-         * {@link DisplayNameSources}.
+         * DisplayNameSources.
          */
         public static final String DISPLAY_NAME_SOURCE = "display_name_source";
 
@@ -468,12 +468,12 @@
 
         /**
          * The type of alphabet used to capture the phonetic name.  See
-         * {@link PhoneticNameStyle}.
+         * PhoneticNameStyle.
          */
         public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
 
         /**
-         * Pronunciation of the full name. See {@link PhoneticNameStyle}.
+         * Pronunciation of the full name. See PhoneticNameStyle.
          */
         public static final String PHONETIC_NAME = "phonetic_name";
 
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 7eb42f2..fb369d3 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -108,8 +108,6 @@
     private static final int RECEIVED_TOUCH_ICON_URL             = 132;
     private static final int GET_VISITED_HISTORY                 = 133;
     private static final int OPEN_FILE_CHOOSER                   = 134;
-    private static final int SHOW_CUSTOM_VIEW                    = 135;
-    private static final int HIDE_CUSTOM_VIEW                    = 136;
 
     // Message triggered by the client to resume execution
     private static final int NOTIFY                              = 200;
@@ -681,23 +679,6 @@
                     mWebChromeClient.openFileChooser((UploadFile) msg.obj);
                 }
                 break;
-
-            case SHOW_CUSTOM_VIEW:
-                if (mWebChromeClient != null) {
-                    HashMap<String, Object> map =
-                            (HashMap<String, Object>) msg.obj;
-                    View view = (View) map.get("view");
-                    WebChromeClient.CustomViewCallback callback =
-                            (WebChromeClient.CustomViewCallback) map.get("callback");
-                    mWebChromeClient.onShowCustomView(view, callback);
-                }
-                break;
-
-            case HIDE_CUSTOM_VIEW:
-                if (mWebChromeClient != null) {
-                    mWebChromeClient.onHideCustomView();
-                }
-                break;
         }
     }
 
@@ -1404,24 +1385,4 @@
         }
         return uploadFile.getResult();
     }
-
-    /* package */ void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
-        if (mWebChromeClient == null) {
-            return;
-        }
-        Message msg = obtainMessage(SHOW_CUSTOM_VIEW);
-        HashMap<String, Object> map = new HashMap<String, Object>();
-        map.put("view", view);
-        map.put("callback", callback);
-        msg.obj = map;
-        sendMessage(msg);
-    }
-
-    /* package */ void hideCustomView() {
-        if (mWebChromeClient == null) {
-            return;
-        }
-        Message msg = obtainMessage(HIDE_CUSTOM_VIEW);
-        sendMessage(msg);
-    }
 }
diff --git a/core/java/android/webkit/PluginFullScreenHolder.java b/core/java/android/webkit/PluginFullScreenHolder.java
new file mode 100644
index 0000000..6a0b145
--- /dev/null
+++ b/core/java/android/webkit/PluginFullScreenHolder.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package android.webkit;
+
+import android.app.Dialog;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+
+class PluginFullScreenHolder extends Dialog {
+
+    private static final String LOGTAG = "FullScreenHolder";
+
+    private final WebView mWebView;
+    private final int mNpp;
+    private int mX;
+    private int mY;
+    private int mWidth;
+    private int mHeight;
+
+    PluginFullScreenHolder(WebView webView, int npp) {
+        super(webView.getContext(), android.R.style.Theme_NoTitleBar_Fullscreen);
+        mWebView = webView;
+        mNpp = npp;
+    }
+
+    Rect getBound() {
+        return new Rect(mX, mY, mWidth, mHeight);
+    }
+
+    /*
+     * x, y, width, height are in the caller's view coordinate system. (x, y) is
+     * relative to the top left corner of the caller's view.
+     */
+    void updateBound(int x, int y, int width, int height) {
+        mX = x;
+        mY = y;
+        mWidth = width;
+        mHeight = height;
+    }
+
+    @Override
+    public void onBackPressed() {
+        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
+                .sendToTarget();
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (event.isSystem()) {
+            return super.onKeyDown(keyCode, event);
+        }
+        mWebView.onKeyDown(keyCode, event);
+        // always return true as we are the handler
+        return true;
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (event.isSystem()) {
+            return super.onKeyUp(keyCode, event);
+        }
+        mWebView.onKeyUp(keyCode, event);
+        // always return true as we are the handler
+        return true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final float x = event.getX();
+        final float y = event.getY();
+        // TODO: find a way to know when the dialog size changed so that we can
+        // cache the ratio
+        final View decorView = getWindow().getDecorView();
+        event.setLocation(mX + x * mWidth / decorView.getWidth(),
+                mY + y * mHeight / decorView.getHeight());
+        mWebView.onTouchEvent(event);
+        // always return true as we are the handler
+        return true;
+    }
+
+    @Override
+    public boolean onTrackballEvent(MotionEvent event) {
+        mWebView.onTrackballEvent(event);
+        // always return true as we are the handler
+        return true;
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        mWebView.getWebViewCore().sendMessage(
+                WebViewCore.EventHub.HIDE_FULLSCREEN, mNpp, 0);
+    }
+
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7d49cb6a..d99f9f2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -301,6 +301,9 @@
     // Used by WebViewCore to create child views.
     /* package */ final ViewManager mViewManager;
 
+    // Used to display in full screen mode
+    PluginFullScreenHolder mFullScreenHolder;
+
     /**
      * Position of the last touch event.
      */
@@ -487,6 +490,8 @@
     static final int INVAL_RECT_MSG_ID                  = 26;
     static final int REQUEST_KEYBOARD                   = 27;
     static final int DO_MOTION_UP                       = 28;
+    static final int SHOW_FULLSCREEN                    = 29;
+    static final int HIDE_FULLSCREEN                    = 30;
 
     static final String[] HandlerDebugString = {
         "REMEMBER_PASSWORD", //              = 1;
@@ -516,7 +521,9 @@
         "WEBCORE_NEED_TOUCH_EVENTS", //      = 25;
         "INVAL_RECT_MSG_ID", //              = 26;
         "REQUEST_KEYBOARD", //               = 27;
-        "DO_MOTION_UP" //                    = 28;
+        "DO_MOTION_UP", //                   = 28;
+        "SHOW_FULLSCREEN", //                = 29;
+        "HIDE_FULLSCREEN" //                 = 30;
     };
 
     // If the site doesn't use the viewport meta tag to specify the viewport,
@@ -3993,6 +4000,11 @@
                             || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                     }
+                    if (mFullScreenHolder != null) {
+                        // in full screen mode, the WebView can't be panned.
+                        mTouchMode = TOUCH_DONE_MODE;
+                        break;
+                    }
 
                     // if it starts nearly horizontal or vertical, enforce it
                     int ax = Math.abs(deltaX);
@@ -4147,7 +4159,7 @@
                             ted.mX = viewToContentX((int) x + mScrollX);
                             ted.mY = viewToContentY((int) y + mScrollY);
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
-                        } else {
+                        } else if (mFullScreenHolder == null) {
                             doDoubleTap();
                         }
                         break;
@@ -4163,8 +4175,9 @@
                         if ((deltaX * deltaX + deltaY * deltaY) > mTouchSlopSquare) {
                             Log.w(LOGTAG, "Miss a drag as we are waiting for" +
                                     " WebCore's response for touch down.");
-                            if (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
-                                    || computeVerticalScrollExtent() < computeVerticalScrollRange()) {
+                            if (mFullScreenHolder == null
+                                    && (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
+                                    || computeVerticalScrollExtent() < computeVerticalScrollRange())) {
                                 // we will not rewrite drag code here, but we
                                 // will try fling if it applies.
                                 WebViewCore.pauseUpdate(mWebViewCore);
@@ -5115,7 +5128,7 @@
             // exclude INVAL_RECT_MSG_ID since it is frequently output
             if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
                 Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
-                        > DO_MOTION_UP ? Integer.toString(msg.what)
+                        > HIDE_FULLSCREEN ? Integer.toString(msg.what)
                         : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
             }
             if (mWebViewCore == null) {
@@ -5146,7 +5159,9 @@
                         mPreventDoubleTap = false;
                     }
                     if (mTouchMode == TOUCH_INIT_MODE) {
-                        mTouchMode = TOUCH_SHORTPRESS_START_MODE;
+                        mTouchMode = mFullScreenHolder == null
+                                ? TOUCH_SHORTPRESS_START_MODE
+                                        : TOUCH_SHORTPRESS_MODE;
                         updateSelection();
                     } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                         mTouchMode = TOUCH_DONE_MODE;
@@ -5164,8 +5179,10 @@
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDrag == PREVENT_DRAG_NO) {
                         mTouchMode = TOUCH_DONE_MODE;
-                        performLongClick();
-                        rebuildWebTextView();
+                        if (mFullScreenHolder == null) {
+                            performLongClick();
+                            rebuildWebTextView();
+                        }
                     }
                     break;
                 }
@@ -5466,6 +5483,35 @@
                     doMotionUp(msg.arg1, msg.arg2, (Boolean) msg.obj);
                     break;
 
+                case SHOW_FULLSCREEN:
+                    WebViewCore.PluginFullScreenData data
+                            = (WebViewCore.PluginFullScreenData) msg.obj;
+                    if (data.mNpp != 0 && data.mView != null) {
+                        if (mFullScreenHolder != null) {
+                            Log.w(LOGTAG,
+                                    "Should not have another full screen.");
+                            mFullScreenHolder.dismiss();
+                        }
+                        mFullScreenHolder = new PluginFullScreenHolder(
+                                WebView.this, data.mNpp);
+                        mFullScreenHolder.setContentView(data.mView);
+                        mFullScreenHolder.setCancelable(false);
+                        mFullScreenHolder.setCanceledOnTouchOutside(false);
+                    }
+                    mFullScreenHolder.updateBound(contentToViewX(data.mDocX)
+                            - mScrollX, contentToViewY(data.mDocY) - mScrollY,
+                            contentToViewDimension(data.mDocWidth),
+                            contentToViewDimension(data.mDocHeight));
+                    mFullScreenHolder.show();
+                    break;
+
+                case HIDE_FULLSCREEN:
+                    if (mFullScreenHolder != null) {
+                        mFullScreenHolder.dismiss();
+                        mFullScreenHolder = null;
+                    }
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e198ee8..ce2637b 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -41,7 +41,6 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
-import android.webkit.plugin.FullScreenDrawingModel;
 import android.webkit.plugin.SurfaceDrawingModel;
 import android.webkit.plugin.WebkitPlugin;
 
@@ -737,6 +736,15 @@
         boolean mRemember;
     }
 
+    static class PluginFullScreenData {
+        View mView;
+        int mNpp;
+        int mDocX;
+        int mDocY;
+        int mDocWidth;
+        int mDocHeight;
+    }
+
         static final String[] HandlerDebugString = {
             "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
             "SCROLL_TEXT_INPUT", // = 99
@@ -870,6 +878,8 @@
 
         static final int POPULATE_VISITED_LINKS = 181;
 
+        static final int HIDE_FULLSCREEN = 182;
+
         // private message ids
         private static final int DESTROY =     200;
 
@@ -1313,6 +1323,10 @@
                                     message);
                             break;
                         }
+
+                        case HIDE_FULLSCREEN:
+                            nativeFullScreenPluginHidden(msg.arg1);
+                            break;
                     }
                 }
             };
@@ -2236,35 +2250,53 @@
 
     // called by JNI. PluginWidget function to launch a full-screen view using a
     // View object provided by the plugin class.
-    private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp) {
+    private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp,
+            int x, int y, int width, int height) {
         if (mWebView == null) {
             return;
         }
 
-        final FullScreenDrawingModel surface = webkitPlugin.getFullScreenSurface();
+        final SurfaceDrawingModel surface = webkitPlugin.getFullScreenSurface();
         if(surface == null) {
-            Log.e(LOGTAG, "Attempted to create an full-screen surface with a null drawing model");
+            Log.e(LOGTAG, "Attempted to create an full-screen surface with a " +
+                    "null drawing model");
             return;
         }
 
-        WebChromeClient.CustomViewCallback callback = new WebChromeClient.CustomViewCallback() {
-            public void onCustomViewHidden() {
-                if (surface != null) {
-                    surface.onSurfaceRemoved();
-                    nativeFullScreenPluginHidden(npp);
-                }
-            }
-        };
-
-        mCallbackProxy.showCustomView(surface.getSurface(), callback);
+        PluginFullScreenData data = new PluginFullScreenData();
+        data.mView = surface.getSurface();
+        data.mNpp = npp;
+        data.mDocX = x;
+        data.mDocY = y;
+        data.mDocWidth = width;
+        data.mDocHeight = height;
+        mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
+                .sendToTarget();
     }
 
+    // called by JNI
     private void hideFullScreenPlugin() {
         if (mWebView == null) {
             return;
         }
+        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
+                .sendToTarget();
+    }
 
-        mCallbackProxy.hideCustomView();
+    // called by JNI
+    private void updateFullScreenPlugin(int x, int y, int width, int height) {
+        if (mWebView == null) {
+            return;
+        }
+
+        PluginFullScreenData data = new PluginFullScreenData();
+        data.mDocX = x;
+        data.mDocY = y;
+        data.mDocWidth = width;
+        data.mDocHeight = height;
+        // null mView and mNpp to indicate it is an update
+        mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
+                .sendToTarget();
     }
 
     // called by JNI.  PluginWidget functions for creating an embedded View for
diff --git a/core/java/android/webkit/plugin/FullScreenDrawingModel.java b/core/java/android/webkit/plugin/FullScreenDrawingModel.java
deleted file mode 100644
index fe9d197..0000000
--- a/core/java/android/webkit/plugin/FullScreenDrawingModel.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package android.webkit.plugin;
-
-/**
- *
- * @hide pending API solidification
- */
-public interface FullScreenDrawingModel extends SurfaceDrawingModel {
-
-    public void onSurfaceRemoved();
-
-}
diff --git a/core/java/android/webkit/plugin/WebkitPlugin.java b/core/java/android/webkit/plugin/WebkitPlugin.java
index af02cdc..3d13c1c 100644
--- a/core/java/android/webkit/plugin/WebkitPlugin.java
+++ b/core/java/android/webkit/plugin/WebkitPlugin.java
@@ -30,7 +30,7 @@
  */
 public interface WebkitPlugin {
 
-    SurfaceDrawingModel    getEmbeddedSurface();
-    FullScreenDrawingModel getFullScreenSurface();
+    SurfaceDrawingModel getEmbeddedSurface();
+    SurfaceDrawingModel getFullScreenSurface();
 
 }
diff --git a/include/media/stagefright/OMXPluginBase.h b/include/media/stagefright/OMXPluginBase.h
index 61cc50a..2fd8e12 100644
--- a/include/media/stagefright/OMXPluginBase.h
+++ b/include/media/stagefright/OMXPluginBase.h
@@ -22,6 +22,9 @@
 
 #include <OMX_Component.h>
 
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
 namespace android {
 
 struct OMXComponentBase;
@@ -44,6 +47,10 @@
             size_t size,
             OMX_U32 index) = 0;
 
+    virtual OMX_ERRORTYPE getRolesOfComponent(
+            const char *name,
+            Vector<String8> *roles) = 0;
+
 private:
     OMXPluginBase(const OMXPluginBase &);
     OMXPluginBase &operator=(const OMXPluginBase &);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 5a89b73..99c39f8 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -55,15 +55,68 @@
     const char *codec;
 };
 
+#if BUILD_WITH_FULL_STAGEFRIGHT
+#define OPTIONAL(x,y) { x, y },
+
+#define FACTORY_CREATE(name) \
+static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
+    return new name(source); \
+}
+
+#define FACTORY_REF(name) { #name, Make##name },
+
+FACTORY_CREATE(MP3Decoder)
+FACTORY_CREATE(AMRNBDecoder)
+FACTORY_CREATE(AMRWBDecoder)
+FACTORY_CREATE(AACDecoder)
+FACTORY_CREATE(AVCDecoder)
+FACTORY_CREATE(AMRNBEncoder)
+
+static sp<MediaSource> InstantiateSoftwareCodec(
+        const char *name, const sp<MediaSource> &source) {
+    struct FactoryInfo {
+        const char *name;
+        sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
+    };
+
+    static const FactoryInfo kFactoryInfo[] = {
+        FACTORY_REF(MP3Decoder)
+        FACTORY_REF(AMRNBDecoder)
+        FACTORY_REF(AMRWBDecoder)
+        FACTORY_REF(AACDecoder)
+        FACTORY_REF(AVCDecoder)
+        FACTORY_REF(AMRNBEncoder)
+    };
+    for (size_t i = 0;
+         i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
+        if (!strcmp(name, kFactoryInfo[i].name)) {
+            return (*kFactoryInfo[i].CreateFunc)(source);
+        }
+    }
+
+    return NULL;
+}
+
+#undef FACTORY_REF
+#undef FACTORY_CREATE
+
+#else
+#define OPTIONAL(x,y)
+#endif
+
 static const CodecInfo kDecoderInfo[] = {
     { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
+    OPTIONAL(MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder")
     { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
+    OPTIONAL(MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder")
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
+    OPTIONAL(MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder")
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
+    OPTIONAL(MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder")
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
@@ -73,11 +126,13 @@
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
+    OPTIONAL(MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder")
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
 };
 
 static const CodecInfo kEncoderInfo[] = {
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
+    OPTIONAL(MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBEncoder")
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
@@ -92,6 +147,8 @@
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
+#undef OPTIONAL
+
 #define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
 
@@ -188,8 +245,22 @@
     return false;
 }
 
+// A sort order in which non-OMX components are first,
+// followed by software codecs, i.e. OMX.PV.*, followed
+// by all the others.
 static int CompareSoftwareCodecsFirst(
         const String8 *elem1, const String8 *elem2) {
+    bool isNotOMX1 = strncmp(elem1->string(), "OMX.", 4);
+    bool isNotOMX2 = strncmp(elem2->string(), "OMX.", 4);
+
+    if (isNotOMX1) {
+        if (isNotOMX2) { return 0; }
+        return -1;
+    }
+    if (isNotOMX2) {
+        return 1;
+    }
+
     bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
     bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
 
@@ -293,27 +364,6 @@
     bool success = meta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
 
-#if BUILD_WITH_FULL_STAGEFRIGHT
-    if (!createEncoder) {
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
-            return new AACDecoder(source);
-        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
-            return new AMRNBDecoder(source);
-        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
-            return new AMRWBDecoder(source);
-        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-            return new MP3Decoder(source);
-        } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-                    && (flags & kPreferSoftwareCodecs)) {
-            return new AVCDecoder(source);
-        }
-    } else {
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
-            return new AMRNBEncoder(source);
-        }
-    }
-#endif
-
     Vector<String8> matchingCodecs;
     findMatchingCodecs(
             mime, createEncoder, matchComponentName, flags, &matchingCodecs);
@@ -330,6 +380,17 @@
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         componentName = matchingCodecs[i].string();
 
+#if BUILD_WITH_FULL_STAGEFRIGHT
+        sp<MediaSource> softwareCodec =
+            InstantiateSoftwareCodec(componentName, source);
+
+        if (softwareCodec != NULL) {
+            LOGV("Successfully allocated software codec '%s'", componentName);
+
+            return softwareCodec;
+        }
+#endif
+
         LOGV("Attempting to allocate OMX node '%s'", componentName);
 
         status_t err = omx->allocateNode(componentName, observer, &node);
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 965852b..4f88d99 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -12,8 +12,7 @@
 	OMX.cpp                       \
         OMXComponentBase.cpp          \
         OMXNodeInstance.cpp           \
-        OMXMaster.cpp                 \
-        OMXSoftwareCodecsPlugin.cpp   \
+        OMXMaster.cpp
 
 ifneq ($(BUILD_WITHOUT_PV),true)
 LOCAL_SRC_FILES += \
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 61be8f7..94dbb6d 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -208,6 +208,29 @@
     instance->onObserverDied(mMaster);
 }
 
+#if 0
+static void dumpRoles(OMXMaster *master, const char *name) {
+    Vector<String8> roles;
+    OMX_ERRORTYPE err = master->getRolesOfComponent(name, &roles);
+
+    if (err != OMX_ErrorNone) {
+        LOGE("Could not get roles for component '%s'.", name);
+        return;
+    }
+
+    if (roles.isEmpty()) {
+        LOGE("Component '%s' has NO roles!", name);
+        return;
+    }
+
+    LOGI("Component '%s' has the following roles:", name);
+
+    for (size_t i = 0; i < roles.size(); ++i) {
+        LOGI("%d) %s", i + 1, roles[i].string());
+    }
+}
+#endif
+
 status_t OMX::listNodes(List<String8> *list) {
     list->clear();
 
@@ -217,6 +240,8 @@
                 componentName, sizeof(componentName), index) == OMX_ErrorNone) {
         list->push_back(String8(componentName));
 
+        // dumpRoles(mMaster, componentName);
+
         ++index;
     }
 
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 12302f3..9a45bea 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -24,14 +24,10 @@
 #include "OMXPVCodecsPlugin.h"
 #endif
 
-#include "OMXSoftwareCodecsPlugin.h"
-
 namespace android {
 
 OMXMaster::OMXMaster()
     : mVendorLibHandle(NULL) {
-    addPlugin(new OMXSoftwareCodecsPlugin);
-
     addVendorPlugin();
 
 #ifndef NO_OPENCORE
@@ -168,4 +164,21 @@
     return OMX_ErrorNone;
 }
 
+OMX_ERRORTYPE OMXMaster::getRolesOfComponent(
+        const char *name,
+        Vector<String8> *roles) {
+    Mutex::Autolock autoLock(mLock);
+
+    roles->clear();
+
+    ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
+
+    if (index < 0) {
+        return OMX_ErrorInvalidComponentName;
+    }
+
+    OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
+    return plugin->getRolesOfComponent(name, roles);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h
index e944c4a..7ba8d18 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/OMXMaster.h
@@ -45,6 +45,10 @@
             size_t size,
             OMX_U32 index);
 
+    virtual OMX_ERRORTYPE getRolesOfComponent(
+            const char *name,
+            Vector<String8> *roles);
+
 private:
     Mutex mLock;
     List<OMXPluginBase *> mPlugins;
diff --git a/media/libstagefright/omx/OMXPVCodecsPlugin.cpp b/media/libstagefright/omx/OMXPVCodecsPlugin.cpp
index 2bd8094..d1f5be3 100644
--- a/media/libstagefright/omx/OMXPVCodecsPlugin.cpp
+++ b/media/libstagefright/omx/OMXPVCodecsPlugin.cpp
@@ -54,4 +54,48 @@
     return OMX_MasterComponentNameEnum(name, size, index);
 }
 
+OMX_ERRORTYPE OMXPVCodecsPlugin::getRolesOfComponent(
+        const char *name,
+        Vector<String8> *roles) {
+    roles->clear();
+
+    OMX_U32 numRoles;
+    OMX_ERRORTYPE err =
+        OMX_MasterGetRolesOfComponent(
+                const_cast<char *>(name),
+                &numRoles,
+                NULL);
+
+    if (err != OMX_ErrorNone) {
+        return err;
+    }
+
+    if (numRoles > 0) {
+        OMX_U8 **array = new OMX_U8 *[numRoles];
+        for (OMX_U32 i = 0; i < numRoles; ++i) {
+            array[i] = new OMX_U8[OMX_MAX_STRINGNAME_SIZE];
+        }
+
+        OMX_U32 numRoles2;
+        err = OMX_MasterGetRolesOfComponent(
+                const_cast<char *>(name), &numRoles2, array);
+
+        CHECK_EQ(err, OMX_ErrorNone);
+        CHECK_EQ(numRoles, numRoles2);
+
+        for (OMX_U32 i = 0; i < numRoles; ++i) {
+            String8 s((const char *)array[i]);
+            roles->push(s);
+
+            delete[] array[i];
+            array[i] = NULL;
+        }
+
+        delete[] array;
+        array = NULL;
+    }
+
+    return OMX_ErrorNone;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/omx/OMXPVCodecsPlugin.h b/media/libstagefright/omx/OMXPVCodecsPlugin.h
index f32eede..c133232 100644
--- a/media/libstagefright/omx/OMXPVCodecsPlugin.h
+++ b/media/libstagefright/omx/OMXPVCodecsPlugin.h
@@ -40,6 +40,10 @@
             size_t size,
             OMX_U32 index);
 
+    virtual OMX_ERRORTYPE getRolesOfComponent(
+            const char *name,
+            Vector<String8> *roles);
+
 private:
     OMXPVCodecsPlugin(const OMXPVCodecsPlugin &);
     OMXPVCodecsPlugin &operator=(const OMXPVCodecsPlugin &);
diff --git a/media/libstagefright/omx/OMXSoftwareCodecsPlugin.cpp b/media/libstagefright/omx/OMXSoftwareCodecsPlugin.cpp
deleted file mode 100644
index 51c7029..0000000
--- a/media/libstagefright/omx/OMXSoftwareCodecsPlugin.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include "OMXSoftwareCodecsPlugin.h"
-
-#include <string.h>
-
-namespace android {
-
-typedef OMX_ERRORTYPE (*ComponentFactory)(
-        const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
-        OMX_COMPONENTTYPE **component);
-
-static const struct ComponentInfo {
-    const char *mName;
-    ComponentFactory mFactory;
-} kComponentInfos[] = {
-};
-
-OMXSoftwareCodecsPlugin::OMXSoftwareCodecsPlugin() {
-}
-
-OMX_ERRORTYPE OMXSoftwareCodecsPlugin::makeComponentInstance(
-        const char *name,
-        const OMX_CALLBACKTYPE *callbacks,
-        OMX_PTR appData,
-        OMX_COMPONENTTYPE **component) {
-    *component = NULL;
-
-    const size_t kNumComponentInfos =
-        sizeof(kComponentInfos) / sizeof(kComponentInfos[0]);
-
-    for (size_t i = 0; i < kNumComponentInfos; ++i) {
-        if (!strcmp(kComponentInfos[i].mName, name)) {
-            return (*kComponentInfos[i].mFactory)(
-                    callbacks, appData, component);
-        }
-    }
-
-    return OMX_ErrorInvalidComponentName;
-}
-
-OMX_ERRORTYPE OMXSoftwareCodecsPlugin::destroyComponentInstance(
-        OMX_COMPONENTTYPE *component) {
-    return (*component->ComponentDeInit)(component);
-}
-
-OMX_ERRORTYPE OMXSoftwareCodecsPlugin::enumerateComponents(
-        OMX_STRING name,
-        size_t size,
-        OMX_U32 index) {
-    const size_t kNumComponentInfos =
-        sizeof(kComponentInfos) / sizeof(kComponentInfos[0]);
-
-    if (index >= kNumComponentInfos) {
-        return OMX_ErrorNoMore;
-    }
-
-    strncpy(name, kComponentInfos[index].mName, size - 1);
-    name[size - 1] = '\0';
-
-    return OMX_ErrorNone;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/omx/OMXSoftwareCodecsPlugin.h b/media/libstagefright/omx/OMXSoftwareCodecsPlugin.h
deleted file mode 100644
index 5beeb26..0000000
--- a/media/libstagefright/omx/OMXSoftwareCodecsPlugin.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#ifndef OMX_SOFTWARE_CODECS_PLUGIN_H_
-
-#define OMX_SOFTWARE_CODECS_PLUGIN_H_
-
-#include <media/stagefright/OMXPluginBase.h>
-
-namespace android {
-
-struct OMXSoftwareCodecsPlugin : public OMXPluginBase {
-    OMXSoftwareCodecsPlugin();
-
-    virtual OMX_ERRORTYPE makeComponentInstance(
-            const char *name,
-            const OMX_CALLBACKTYPE *callbacks,
-            OMX_PTR appData,
-            OMX_COMPONENTTYPE **component);
-
-    virtual OMX_ERRORTYPE destroyComponentInstance(
-            OMX_COMPONENTTYPE *component);
-
-    virtual OMX_ERRORTYPE enumerateComponents(
-            OMX_STRING name,
-            size_t size,
-            OMX_U32 index);
-
-private:
-    OMXSoftwareCodecsPlugin(const OMXSoftwareCodecsPlugin &);
-    OMXSoftwareCodecsPlugin &operator=(const OMXSoftwareCodecsPlugin &);
-};
-
-}  // namespace android
-
-#endif  // OMX_SOFTWARE_CODECS_PLUGIN_H_
-