Merge "Media scanner support for FL(Forward Lock) DRM file types"
diff --git a/api/current.xml b/api/current.xml
index 35fb3ef..ff4942e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26658,6 +26658,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;extra_click_download_ids&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="PAUSED_QUEUED_FOR_WIFI"
  type="int"
  transient="false"
@@ -27617,6 +27628,17 @@
  visibility="public"
 >
 </method>
+<method name="onDestroyOptionsMenu"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onDestroyView"
  return="void"
  abstract="false"
@@ -83600,6 +83622,17 @@
  visibility="public"
 >
 </method>
+<method name="getColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOpacity"
  return="int"
  abstract="false"
@@ -83624,6 +83657,19 @@
 <parameter name="alpha" type="int">
 </parameter>
 </method>
+<method name="setColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="color" type="int">
+</parameter>
+</method>
 <method name="setColorFilter"
  return="void"
  abstract="false"
@@ -145048,6 +145094,23 @@
 <parameter name="key" type="java.lang.CharSequence">
 </parameter>
 </method>
+<method name="finishPreferencePanel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="caller" type="android.app.Fragment">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="android.content.Intent">
+</parameter>
+</method>
 <method name="getPreferenceManager"
  return="android.preference.PreferenceManager"
  abstract="false"
@@ -145276,7 +145339,7 @@
 <parameter name="push" type="boolean">
 </parameter>
 </method>
-<method name="startPreferenceFragment"
+<method name="startPreferencePanel"
  return="void"
  abstract="false"
  native="false"
@@ -145286,9 +145349,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="fragment" type="android.app.Fragment">
+<parameter name="fragmentClass" type="java.lang.String">
 </parameter>
-<parameter name="ft" type="android.app.FragmentTransaction">
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="titleRes" type="int">
+</parameter>
+<parameter name="titleText" type="java.lang.CharSequence">
+</parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
 </parameter>
 </method>
 <method name="startWithFragment"
@@ -145305,6 +145376,10 @@
 </parameter>
 <parameter name="args" type="android.os.Bundle">
 </parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
+</parameter>
 </method>
 <method name="switchToHeader"
  return="void"
@@ -347567,7 +347642,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="toCopyIn" type="E[]">
+<parameter name="array" type="E[]">
 </parameter>
 </constructor>
 <method name="add"
@@ -347595,7 +347670,7 @@
 >
 <parameter name="index" type="int">
 </parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
 </parameter>
 </method>
 <method name="addAll"
@@ -347723,7 +347798,9 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
 </parameter>
 </method>
 <method name="indexOf"
@@ -347736,9 +347813,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
 </parameter>
 </method>
 <method name="isEmpty"
@@ -347773,7 +347848,9 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
 </parameter>
 </method>
 <method name="lastIndexOf"
@@ -347786,9 +347863,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
 </parameter>
 </method>
 <method name="listIterator"
@@ -347879,7 +347954,7 @@
 >
 <parameter name="index" type="int">
 </parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
 </parameter>
 </method>
 <method name="size"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 37c8ad0..b5fddfa 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -389,11 +389,13 @@
             if (err == 0) {
                 observer.waitForCompletion();
                 sets = observer.sets;
-                for (RestoreSet s : sets) {
-                    if (s.token == token) {
-                        System.out.println("Scheduling restore: " + s.name);
-                        didRestore = (mRestore.restoreAll(token, observer) == 0);
-                        break;
+                if (sets != null) {
+                    for (RestoreSet s : sets) {
+                        if (s.token == token) {
+                            System.out.println("Scheduling restore: " + s.name);
+                            didRestore = (mRestore.restoreAll(token, observer) == 0);
+                            break;
+                        }
                     }
                 }
             }
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 1741e60..2242462 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -28,12 +28,18 @@
 
     private int mNumKeyframes;
 
-    ArrayList<Keyframe> mKeyframes;
+    Keyframe mFirstKeyframe;
+    Keyframe mLastKeyframe;
+    TimeInterpolator mInterpolator; // only used in the 2-keyframe case
+    ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
 
     public KeyframeSet(Keyframe... keyframes) {
+        mNumKeyframes = keyframes.length;
         mKeyframes = new ArrayList<Keyframe>();
         mKeyframes.addAll(Arrays.asList(keyframes));
-        mNumKeyframes = mKeyframes.size();
+        mFirstKeyframe = mKeyframes.get(0);
+        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+        mInterpolator = mLastKeyframe.getInterpolator();
     }
 
     public static KeyframeSet ofInt(int... values) {
@@ -125,32 +131,40 @@
      * @return The animated value.
      */
     public Object getValue(float fraction, TypeEvaluator evaluator) {
-        // TODO: special-case 2-keyframe common case
+
+        // Special-case optimization for the common case of only two keyframes
+        if (mNumKeyframes == 2) {
+            if (mInterpolator != null) {
+                fraction = mInterpolator.getInterpolation(fraction);
+            }
+            return evaluator.evaluate(fraction, mFirstKeyframe.getValue(),
+                    mLastKeyframe.getValue());
+        }
 
         if (fraction <= 0f) {
-            final Keyframe prevKeyframe = mKeyframes.get(0);
             final Keyframe nextKeyframe = mKeyframes.get(1);
             final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
             if (interpolator != null) {
                 fraction = interpolator.getInterpolation(fraction);
             }
-            float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                (nextKeyframe.getFraction() - prevKeyframe.getFraction());
-            return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
+            final float prevFraction = mFirstKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (nextKeyframe.getFraction() - prevFraction);
+            return evaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
                     nextKeyframe.getValue());
         } else if (fraction >= 1f) {
             final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
-            final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1);
-            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
+            final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
             if (interpolator != null) {
                 fraction = interpolator.getInterpolation(fraction);
             }
-            float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+            final float prevFraction = prevKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (mLastKeyframe.getFraction() - prevFraction);
             return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
-                    nextKeyframe.getValue());
+                    mLastKeyframe.getValue());
         }
-        Keyframe prevKeyframe = mKeyframes.get(0);
+        Keyframe prevKeyframe = mFirstKeyframe;
         for (int i = 1; i < mNumKeyframes; ++i) {
             Keyframe nextKeyframe = mKeyframes.get(i);
             if (fraction < nextKeyframe.getFraction()) {
@@ -158,14 +172,15 @@
                 if (interpolator != null) {
                     fraction = interpolator.getInterpolation(fraction);
                 }
-                float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                    (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+                final float prevFraction = prevKeyframe.getFraction();
+                float intervalFraction = (fraction - prevFraction) /
+                    (nextKeyframe.getFraction() - prevFraction);
                 return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                         nextKeyframe.getValue());
             }
             prevKeyframe = nextKeyframe;
         }
-        // shouldn't get here
-        return mKeyframes.get(mNumKeyframes - 1).getValue();
+        // shouldn't reach here
+        return mLastKeyframe.getValue();
     }
 }
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 7427651..5b8c91d 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -376,9 +376,14 @@
      */
     @Override
     public void setTarget(Object target) {
-        mTarget = target;
-        // New property/values/target should cause re-initialization prior to starting
-        mInitialized = false;
+        if (mTarget != target) {
+            mTarget = target;
+            if (mTarget  != null && target != null && mTarget.getClass() == target.getClass()) {
+                return;
+            }
+            // New target type should cause re-initialization prior to starting
+            mInitialized = false;
+        }
     }
 
     @Override
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ad8c971..a0b70b5 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1142,7 +1142,7 @@
         switch (mPlayingState) {
         case RUNNING:
         case SEEKED:
-            float fraction = (float)(currentTime - mStartTime) / mDuration;
+            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
             if (fraction >= 1f) {
                 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
                     // Time to repeat
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 66038d8..b359ce6 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -299,7 +299,7 @@
      * 
      * <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
      * {@link #DISPLAY_SHOW_HOME} option.
-     * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
+     * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)
      * will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
      * 
      * @param options A combination of the bits defined by the DISPLAY_ constants
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 45ce860..b9ac848 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -27,6 +27,14 @@
  * AndroidManifest.xml's &lt;application&gt; tag, which will cause that class
  * to be instantiated for you when the process for your application/package is
  * created.
+ * 
+ * <p class="note">There is normally no need to subclass Application.  In
+ * most situation, static singletons can provide the same functionality in a
+ * more modular way.  If your singleton needs a global context (for example
+ * to register broadcast receivers), the function to retrieve it can be
+ * given a {@link android.content.Context} which internally uses
+ * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
+ * when first constructing the singleton.</p>
  */
 public class Application extends ContextWrapper implements ComponentCallbacks {
     
@@ -46,12 +54,10 @@
     }
 
     /**
-     * Called when the application is stopping.  There are no more application
-     * objects running and the process will exit.  <em>Note: never depend on
-     * this method being called; in many cases an unneeded application process
-     * will simply be killed by the kernel without executing any application
-     * code.</em>
-     * If you override this method, be sure to call super.onTerminate().
+     * This method is for use in emulated process environments.  It will
+     * never be called on a production Android device, where processes are
+     * removed by simply killing them; no user code (including this callback)
+     * is executed when doing so.
      */
     public void onTerminate() {
     }
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 570e494..592a63b 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -272,6 +272,14 @@
      */
     public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
 
+    /**
+     * When clicks on multiple notifications are received, the following
+     * provides an array of download ids corresponding to the download notification that was
+     * clicked. It can be retrieved by the receiver of this
+     * Intent using {@link android.content.Intent#getLongArrayExtra(String)}.
+     */
+    public static final String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
+
     // this array must contain all public columns
     private static final String[] COLUMNS = new String[] {
         COLUMN_ID,
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f27a15e..eaf1aee 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1027,6 +1027,16 @@
     }
 
     /**
+     * Called when this fragment's option menu items are no longer being
+     * included in the overall options menu.  Receiving this call means that
+     * the menu needed to be rebuilt, but this fragment's items were not
+     * included in the newly built menu (its {@link #onCreateOptionsMenu(Menu, MenuInflater)}
+     * was not called).
+     */
+    public void onDestroyOptionsMenu() {
+    }
+    
+    /**
      * This hook is called whenever an item in your options menu is selected.
      * The default implementation simply returns false to have the normal
      * processing happen (calling the item's Runnable or sending a message to
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index 22e0747..e924c1c 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.animation.LayoutTransition;
 import android.app.FragmentManager.BackStackEntry;
 import android.content.Context;
 import android.util.AttributeSet;
@@ -69,6 +70,7 @@
         addView(mContainer);
         a.getFragmentManager().addOnBackStackChangedListener(this);
         updateCrumbs();
+        setLayoutTransition(new LayoutTransition());
     }
 
     /**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 45f9325..512ca16 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -268,6 +268,7 @@
     ArrayList<Fragment> mAdded;
     ArrayList<Integer> mAvailIndices;
     ArrayList<BackStackRecord> mBackStack;
+    ArrayList<Fragment> mCreatedMenus;
     
     // Must be accessed while locked.
     ArrayList<BackStackRecord> mBackStackIndices;
@@ -1325,15 +1326,32 @@
     
     public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         boolean show = false;
+        ArrayList<Fragment> newMenus = null;
         if (mActive != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu) {
                     show = true;
                     f.onCreateOptionsMenu(menu, inflater);
+                    if (newMenus == null) {
+                        newMenus = new ArrayList<Fragment>();
+                    }
+                    newMenus.add(f);
                 }
             }
         }
+        
+        if (mCreatedMenus != null) {
+            for (int i=0; i<mCreatedMenus.size(); i++) {
+                Fragment f = mCreatedMenus.get(i);
+                if (newMenus == null || !newMenus.contains(f)) {
+                    f.onDestroyOptionsMenu();
+                }
+            }
+        }
+        
+        mCreatedMenus = newMenus;
+        
         return show;
     }
     
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 0c8e4d9..138e7f2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -773,6 +773,7 @@
 
                 case CONNECT_HFP_INCOMING:
                     transitionTo(mIncomingHandsfree);
+                    break;
                 case CONNECT_A2DP_INCOMING:
                     transitionTo(mIncomingA2dp);
 
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0c6a237..97c957d 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -825,7 +825,7 @@
 
     /**
      * Called when the user selects an item in the header list.  The default
-     * implementation will call either {@link #startWithFragment(String, Bundle)}
+     * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)}
      * or {@link #switchToHeader(Header)} as appropriate.
      *
      * @param header The header that was selected.
@@ -834,7 +834,7 @@
     public void onHeaderClick(Header header, int position) {
         if (header.fragment != null) {
             if (mSinglePane) {
-                startWithFragment(header.fragment, header.fragmentArguments);
+                startWithFragment(header.fragment, header.fragmentArguments, null, 0);
             } else {
                 switchToHeader(header);
             }
@@ -852,13 +852,18 @@
      * @param fragmentName The name of the fragment to display.
      * @param args Optional arguments to supply to the fragment.
      */
-    public void startWithFragment(String fragmentName, Bundle args) {
+    public void startWithFragment(String fragmentName, Bundle args,
+            Fragment resultTo, int resultRequestCode) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClass(this, getClass());
         intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
         intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
         intent.putExtra(EXTRA_NO_HEADERS, true);
-        startActivity(intent);
+        if (resultTo == null) {
+            startActivity(intent);
+        } else {
+            resultTo.startActivityForResult(intent, resultRequestCode);
+        }
     }
 
     /**
@@ -923,9 +928,15 @@
      * @param header The new header to display.
      */
     public void switchToHeader(Header header) {
-        int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
-        switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
-        setSelectedHeader(header);
+        if (mCurHeader == header) {
+            // This is the header we are currently displaying.  Just make sure
+            // to pop the stack up to its root state.
+            getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+        } else {
+            int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
+            switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
+            setSelectedHeader(header);
+        }
     }
 
     Header findBestMatchingHeader(Header cur, ArrayList<Header> from) {
@@ -982,7 +993,7 @@
      */
     public void startPreferenceFragment(Fragment fragment, boolean push) {
         FragmentTransaction transaction = getFragmentManager().openTransaction();
-        startPreferenceFragment(fragment, transaction);
+        transaction.replace(com.android.internal.R.id.prefs, fragment);
         if (push) {
             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
             transaction.addToBackStack(BACK_STACK_PREFS);
@@ -993,25 +1004,74 @@
     }
 
     /**
-     * Start a new fragment.
-     *
-     * @param fragment The fragment to start
-     * @param ft The FragmentTransaction in which to perform this operation.
-     * Will not be added to the back stack or committed for you; you use do that.
+     * Start a new fragment containing a preference panel.  If the prefences
+     * are being displayed in multi-pane mode, the given fragment class will
+     * be instantiated and placed in the appropriate pane.  If running in
+     * single-pane mode, a new activity will be launched in which to show the
+     * fragment.
+     * 
+     * @param fragmentClass Full name of the class implementing the fragment.
+     * @param args Any desired arguments to supply to the fragment.
+     * @param titleRes Optional resource identifier of the title of this
+     * fragment.
+     * @param titleText Optional text of the title of this fragment.
+     * @param resultTo Optional fragment that result data should be sent to.
+     * If non-null, resultTo.onActivityResult() will be called when this
+     * preference panel is done.  The launched panel must use
+     * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
+     * @param resultRequestCode If resultTo is non-null, this is the caller's
+     * request code to be received with the resut.
      */
-    public void startPreferenceFragment(Fragment fragment, FragmentTransaction ft) {
-        ft.replace(com.android.internal.R.id.prefs, fragment);
+    public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
+            CharSequence titleText, Fragment resultTo, int resultRequestCode) {
+        if (mSinglePane) {
+            startWithFragment(fragmentClass, args, resultTo, resultRequestCode);
+        } else {
+            Fragment f = Fragment.instantiate(this, fragmentClass, args);
+            if (resultTo != null) {
+                f.setTargetFragment(resultTo, resultRequestCode);
+            }
+            FragmentTransaction transaction = getFragmentManager().openTransaction();
+            transaction.replace(com.android.internal.R.id.prefs, f);
+            if (titleRes != 0) {
+                transaction.setBreadCrumbTitle(titleRes);
+            } else if (titleText != null) {
+                transaction.setBreadCrumbTitle(titleText);
+            }
+            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+            transaction.addToBackStack(BACK_STACK_PREFS);
+            transaction.commit();
+        }
     }
-
+    
+    /**
+     * Called by a preference panel fragment to finish itself.
+     * 
+     * @param caller The fragment that is asking to be finished.
+     * @param resultCode Optional result code to send back to the original
+     * launching fragment.
+     * @param resultData Optional result data to send back to the original
+     * launching fragment.
+     */
+    public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
+        if (mSinglePane) {
+            setResult(resultCode, resultData);
+            finish();
+        } else {
+            if (caller != null) {
+                if (caller.getTargetFragment() != null) {
+                    caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
+                            resultCode, resultData);
+                }
+            }
+            // XXX be smarter about popping the stack.
+            onBackPressed();
+        }
+    }
+    
     @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
-        Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
-        FragmentTransaction transaction = getFragmentManager().openTransaction();
-        startPreferenceFragment(f, transaction);
-        transaction.setBreadCrumbTitle(pref.getTitle());
-        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
-        transaction.addToBackStack(BACK_STACK_PREFS);
-        transaction.commit();
+        startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0);
         return true;
     }
 
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 7289012..ec8f031 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -385,11 +385,23 @@
         // Allow 3 seconds for profiles to gracefully disconnect
         // TODO: Introduce a callback mechanism so that each profile can notify
         // BluetoothService when it is done shutting down
+        disconnectDevices();
+
         mHandler.sendMessageDelayed(
                 mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
         return true;
     }
 
+    private synchronized void disconnectDevices() {
+        // Disconnect devices handled by BluetoothService.
+        for (BluetoothDevice device: getConnectedInputDevices()) {
+            disconnectInputDevice(device);
+        }
+
+        for (BluetoothDevice device: getConnectedPanDevices()) {
+            disconnectPanDevice(device);
+        }
+    }
 
     private synchronized void finishDisable(boolean saveSetting) {
         if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 87e03cf..ab97569 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6296,8 +6296,14 @@
             if (invalidateCache) {
                 mPrivateFlags &= ~DRAWING_CACHE_VALID;
             }
-            final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
+            final ViewParent p = mParent;
+            if (ai != null && ai.mHardwareAccelerated) {
+                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+                // with a null dirty rect, which tells the ViewRoot to redraw everything
+                p.invalidateChild(this, null);
+                return;
+            }
             if (p != null && ai != null) {
                 final Rect r = ai.mTmpInvalRect;
                 r.set(0, 0, mRight - mLeft, mBottom - mTop);
@@ -6321,7 +6327,8 @@
      */
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
-        return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK;
+        return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
+                (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
     }
 
     private void computeOpaqueFlags() {
@@ -8618,7 +8625,11 @@
      */
     @RemotableViewMethod
     public void setBackgroundColor(int color) {
-        setBackgroundDrawable(new ColorDrawable(color));
+        if (mBGDrawable instanceof ColorDrawable) {
+            ((ColorDrawable) mBGDrawable).setColor(color);
+        } else {
+            setBackgroundDrawable(new ColorDrawable(color));
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b881bdd..aef13ad 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2101,6 +2101,8 @@
         final int cr = child.mRight;
         final int cb = child.mBottom;
 
+        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
+
         final int flags = mGroupFlags;
 
         if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
@@ -2182,7 +2184,7 @@
             }
         }
 
-        concatMatrix |= !child.hasIdentityMatrix();
+        concatMatrix |= !childHasIdentityMatrix;
 
         // Sets the flag as early as possible to allow draw() implementations
         // to call invalidate() successfully when doing animations
@@ -2231,40 +2233,41 @@
         }
 
         if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
-            int transX = 0;
-            int transY = 0;
+            if (transformToApply != null || !childHasIdentityMatrix) {
+                int transX = 0;
+                int transY = 0;
 
-            if (hasNoCache) {
-                transX = -sx;
-                transY = -sy;
-            }
+                if (hasNoCache) {
+                    transX = -sx;
+                    transY = -sy;
+                }
 
-            if (transformToApply != null) {
-                if (concatMatrix) {
-                    // Undo the scroll translation, apply the transformation matrix,
-                    // then redo the scroll translate to get the correct result.
+                if (transformToApply != null) {
+                    if (concatMatrix) {
+                        // Undo the scroll translation, apply the transformation matrix,
+                        // then redo the scroll translate to get the correct result.
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(transformToApply.getMatrix());
+                        canvas.translate(transX, transY);
+                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+                    }
+
+                    float transformAlpha = transformToApply.getAlpha();
+                    if (transformAlpha < 1.0f) {
+                        alpha *= transformToApply.getAlpha();
+                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+                    }
+                }
+
+                if (!childHasIdentityMatrix) {
                     canvas.translate(-transX, -transY);
-                    canvas.concat(transformToApply.getMatrix());
+                    canvas.concat(child.getMatrix());
                     canvas.translate(transX, transY);
-                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
                 }
-
-                float transformAlpha = transformToApply.getAlpha();
-                if (transformAlpha < 1.0f) {
-                    alpha *= transformToApply.getAlpha();
-                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-                }
-            }
-
-            if (!child.hasIdentityMatrix()) {
-                canvas.translate(-transX, -transY);
-                canvas.concat(child.getMatrix());
-                canvas.translate(transX, transY);
             }
 
             if (alpha < 1.0f) {
                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-
                 if (hasNoCache) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (!child.onSetAlpha(multipliedAlpha)) {
@@ -3209,19 +3212,6 @@
 
         final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            final int[] location = attachInfo.mInvalidateChildLocation;
-            location[CHILD_LEFT_INDEX] = child.mLeft;
-            location[CHILD_TOP_INDEX] = child.mTop;
-            Matrix childMatrix = child.getMatrix();
-            if (!childMatrix.isIdentity()) {
-                RectF boundingRect = attachInfo.mTmpTransformRect;
-                boundingRect.set(dirty);
-                childMatrix.mapRect(boundingRect);
-                dirty.set((int) boundingRect.left, (int) boundingRect.top,
-                        (int) (boundingRect.right + 0.5f),
-                        (int) (boundingRect.bottom + 0.5f));
-            }
-
             // If the child is drawing an animation, we want to copy this flag onto
             // ourselves and the parent to make sure the invalidate request goes
             // through
@@ -3229,45 +3219,95 @@
 
             // Check whether the child that requests the invalidate is fully opaque
             final boolean isOpaque = child.isOpaque() && !drawAnimation &&
-                    child.getAnimation() != null;
+                    child.getAnimation() == null;
             // Mark the child as dirty, using the appropriate flag
             // Make sure we do not set both flags at the same time
             final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
 
-            do {
-                View view = null;
-                if (parent instanceof View) {
-                    view = (View) parent;
+            if (dirty == null) {
+                do {
+                    View view = null;
+                    if (parent instanceof View) {
+                        view = (View) parent;
+                        if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
+                            // already marked dirty - we're done
+                            break;
+                        }
+                    }
+
+                    if (drawAnimation) {
+                        if (view != null) {
+                            view.mPrivateFlags |= DRAW_ANIMATION;
+                        } else if (parent instanceof ViewRoot) {
+                            ((ViewRoot) parent).mIsAnimating = true;
+                        }
+                    }
+
+                    if (parent instanceof ViewRoot) {
+                        ((ViewRoot) parent).invalidate();
+                        parent = null;
+                    } else if (view != null) {
+                        if ((mPrivateFlags & DRAWN) == DRAWN) {
+                            view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                            if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+                                view.mPrivateFlags =
+                                        (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+                            }
+                            parent = view.mParent;
+                        } else {
+                            parent = null;
+                        }
+                    }
+                } while (parent != null);
+            } else {
+                final int[] location = attachInfo.mInvalidateChildLocation;
+                location[CHILD_LEFT_INDEX] = child.mLeft;
+                location[CHILD_TOP_INDEX] = child.mTop;
+                Matrix childMatrix = child.getMatrix();
+                if (!childMatrix.isIdentity()) {
+                    RectF boundingRect = attachInfo.mTmpTransformRect;
+                    boundingRect.set(dirty);
+                    childMatrix.mapRect(boundingRect);
+                    dirty.set((int) boundingRect.left, (int) boundingRect.top,
+                            (int) (boundingRect.right + 0.5f),
+                            (int) (boundingRect.bottom + 0.5f));
                 }
 
-                if (drawAnimation) {
+                do {
+                    View view = null;
+                    if (parent instanceof View) {
+                        view = (View) parent;
+                    }
+
+                    if (drawAnimation) {
+                        if (view != null) {
+                            view.mPrivateFlags |= DRAW_ANIMATION;
+                        } else if (parent instanceof ViewRoot) {
+                            ((ViewRoot) parent).mIsAnimating = true;
+                        }
+                    }
+
+                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
+                    // flag coming from the child that initiated the invalidate
+                    if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+                        view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+                    }
+
+                    parent = parent.invalidateChildInParent(location, dirty);
                     if (view != null) {
-                        view.mPrivateFlags |= DRAW_ANIMATION;
-                    } else if (parent instanceof ViewRoot) {
-                        ((ViewRoot) parent).mIsAnimating = true;
+                        // Account for transform on current parent
+                        Matrix m = view.getMatrix();
+                        if (!m.isIdentity()) {
+                            RectF boundingRect = attachInfo.mTmpTransformRect;
+                            boundingRect.set(dirty);
+                            m.mapRect(boundingRect);
+                            dirty.set((int) boundingRect.left, (int) boundingRect.top,
+                                    (int) (boundingRect.right + 0.5f),
+                                    (int) (boundingRect.bottom + 0.5f));
+                        }
                     }
-                }
-
-                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
-                // flag coming from the child that initiated the invalidate
-                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
-                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
-                }
-
-                parent = parent.invalidateChildInParent(location, dirty);
-                if (view != null) {
-                    // Account for transform on current parent
-                    Matrix m = view.getMatrix();
-                    if (!m.isIdentity()) {
-                        RectF boundingRect = attachInfo.mTmpTransformRect;
-                        boundingRect.set(dirty);
-                        m.mapRect(boundingRect);
-                        dirty.set((int) boundingRect.left, (int) boundingRect.top,
-                                (int) (boundingRect.right + 0.5f),
-                                (int) (boundingRect.bottom + 0.5f));
-                    }
-                }
-            } while (parent != null);
+                } while (parent != null);
+            }
         }
     }
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 06261bb..22a7773 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -543,6 +543,11 @@
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+        if (dirty == null) {
+            // Fast invalidation for GL-enabled applications; GL must redraw everything
+            invalidate();
+            return;
+        }
         if (mCurScrollY != 0 || mTranslator != null) {
             mTempRect.set(dirty);
             dirty = mTempRect;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e5f4b08..c657a1c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -794,7 +794,17 @@
         public int softInputMode;
         
         /**
-         * Placement of window within the screen as per {@link Gravity}
+         * Placement of window within the screen as per {@link Gravity}.  Both
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} and
+         * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+         * Gravity.applyDisplay} are used during window layout, with this value
+         * given as the desired gravity.  For example you can specify
+         * {@link Gravity#DISPLAY_CLIP_HORIZONTAL Gravity.DISPLAY_CLIP_HORIZONTAL} and
+         * {@link Gravity#DISPLAY_CLIP_VERTICAL Gravity.DISPLAY_CLIP_VERTICAL} here
+         * to control the behavior of
+         * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+         * Gravity.applyDisplay}.
          *
          * @see Gravity
          */
@@ -802,13 +812,19 @@
     
         /**
          * The horizontal margin, as a percentage of the container's width,
-         * between the container and the widget.
+         * between the container and the widget.  See
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} for how this is used.  This
+         * field is added with {@link #x} to supply the <var>xAdj</var> parameter.
          */
         public float horizontalMargin;
     
         /**
          * The vertical margin, as a percentage of the container's height,
-         * between the container and the widget.
+         * between the container and the widget.  See
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} for how this is used.  This
+         * field is added with {@link #y} to supply the <var>yAdj</var> parameter.
          */
         public float verticalMargin;
     
@@ -1168,14 +1184,22 @@
             sb.append('x');
             sb.append((height== MATCH_PARENT ?"fill":(height==WRAP_CONTENT?"wrap":height)));
             sb.append(")");
-            if (softInputMode != 0) {
-                sb.append(" sim=#");
-                sb.append(Integer.toHexString(softInputMode));
+            if (horizontalMargin != 0) {
+                sb.append(" hm=");
+                sb.append(horizontalMargin);
+            }
+            if (verticalMargin != 0) {
+                sb.append(" vm=");
+                sb.append(verticalMargin);
             }
             if (gravity != 0) {
                 sb.append(" gr=#");
                 sb.append(Integer.toHexString(gravity));
             }
+            if (softInputMode != 0) {
+                sb.append(" sim=#");
+                sb.append(Integer.toHexString(softInputMode));
+            }
             sb.append(" ty=");
             sb.append(type);
             sb.append(" fl=#");
@@ -1190,6 +1214,18 @@
                 sb.append(" or=");
                 sb.append(screenOrientation);
             }
+            if (alpha != 1.0f) {
+                sb.append(" alpha=");
+                sb.append(alpha);
+            }
+            if (screenBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+                sb.append(" sbrt=");
+                sb.append(screenBrightness);
+            }
+            if (buttonBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+                sb.append(" bbrt=");
+                sb.append(buttonBrightness);
+            }
             if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 sb.append(" compatible=true");
             }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1fd31a3..1a341e1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -544,16 +544,18 @@
      * Generally, it's best to keep as little as possible in the queue thread
      * because it's the most fragile.
      * @param whenNanos The event time in uptime nanoseconds.
+     * @param action The key event action.
+     * @param flags The key event flags.
      * @param keyCode The key code.
-     * @param down True if the key is down.
+     * @param scanCode The key's scan code.
      * @param policyFlags The policy flags associated with the key.
      * @param isScreenOn True if the screen is already on
      *
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
      *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
-    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
-            boolean isScreenOn);
+    public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+            int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
     
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
@@ -571,6 +573,7 @@
      * @param action The key event action.
      * @param flags The key event flags.
      * @param keyCode The key code.
+     * @param scanCode The key's scan code.
      * @param metaState bit mask of meta keys that are held.
      * @param repeatCount Number of times a key down has repeated.
      * @param policyFlags The policy flags associated with the key.
@@ -578,7 +581,7 @@
      * not be further dispatched.
      */
     public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
-            int keyCode, int metaState, int repeatCount, int policyFlags);
+            int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
 
     /**
      * Called when layout of the windows is about to start.
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 3bcd483a4..14dc61d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -370,6 +370,7 @@
             int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
             imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
         }
+        updateCursorControllerPositions();
     }
 
     @Override
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 72b4e36..f5affe5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3477,7 +3477,9 @@
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
             invalidate();
         }
-        if (inEditingMode()) mWebTextView.onDrawSubstitute();
+        if (inEditingMode()) {
+            mWebTextView.onDrawSubstitute();
+        }
         mWebViewCore.signalRepaintDone();
 
         // paint the highlight in the end
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 39b1377..be1234d 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -413,33 +413,46 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         int keyCode = event.getKeyCode();
-        if (event.getRepeatCount() == 0 && event.isDown() && (
-                keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK ||
-                keyCode ==  KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                keyCode ==  KeyEvent.KEYCODE_SPACE)) {
-            doPauseResume();
-            show(sDefaultTimeout);
-            if (mPauseButton != null) {
-                mPauseButton.requestFocus();
+        final boolean uniqueDown = event.getRepeatCount() == 0
+                && event.getAction() == KeyEvent.ACTION_DOWN;
+        if (keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+                || keyCode == KeyEvent.KEYCODE_SPACE) {
+            if (uniqueDown) {
+                doPauseResume();
+                show(sDefaultTimeout);
+                if (mPauseButton != null) {
+                    mPauseButton.requestFocus();
+                }
             }
             return true;
-        } else if (keyCode ==  KeyEvent.KEYCODE_MEDIA_STOP) {
-            if (mPlayer.isPlaying()) {
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+            if (uniqueDown && !mPlayer.isPlaying()) {
+                mPlayer.start();
+                updatePausePlay();
+                show(sDefaultTimeout);
+            }
+            return true;
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+            if (uniqueDown && mPlayer.isPlaying()) {
                 mPlayer.pause();
                 updatePausePlay();
+                show(sDefaultTimeout);
             }
             return true;
-        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-                keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
             // don't show the controls for volume adjustment
             return super.dispatchKeyEvent(event);
         } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
-            hide();
-
+            if (uniqueDown) {
+                hide();
+            }
             return true;
-        } else {
-            show(sDefaultTimeout);
         }
+
+        show(sDefaultTimeout);
         return super.dispatchKeyEvent(event);
     }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 35c50fd..6ba7b44 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -132,6 +132,25 @@
             // here
             return;
         }
+
+        protected boolean startIntentSafely(Context context, PendingIntent pendingIntent,
+                Intent fillInIntent) {
+            try {
+                // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+                context.startIntentSender(
+                        pendingIntent.getIntentSender(), fillInIntent,
+                        Intent.FLAG_ACTIVITY_NEW_TASK,
+                        Intent.FLAG_ACTIVITY_NEW_TASK, 0);
+            } catch (IntentSender.SendIntentException e) {
+                android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
+                return false;
+            } catch (Exception e) {
+                android.util.Log.e(LOG_TAG, "Cannot send pending intent due to " +
+                        "unknown exception: ", e);
+                return false;
+            }
+            return true;
+        }
     }
 
     private class SetEmptyView extends Action {
@@ -236,15 +255,7 @@
                         rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
 
                         fillInIntent.setSourceBounds(rect);
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), fillInIntent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
+                        startIntentSafely(v.getContext(), pendingIntent, fillInIntent);
                     }
 
                 };
@@ -326,16 +337,7 @@
                         final Intent intent = new Intent();
                         intent.setSourceBounds(rect);
                         intent.putExtras(extras);
-
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), intent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
+                        startIntentSafely(v.getContext(), pendingIntent, intent);
                     }
 
                 };
@@ -441,15 +443,7 @@
 
                         final Intent intent = new Intent();
                         intent.setSourceBounds(rect);
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), intent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
+                        startIntentSafely(v.getContext(), pendingIntent, intent);
                     }
                 };
                 target.setOnClickListener(listener);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 36adacd..ce4e8e5 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -115,7 +115,6 @@
     }
 
     private void initTabWidget() {
-        setOrientation(LinearLayout.HORIZONTAL);
         mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
 
         final Context context = mContext;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9855d6e..2fcae1c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4277,6 +4277,15 @@
 
         canvas.restore();
 
+        updateCursorControllerPositions();
+    }
+
+    /**
+     * Update the positions of the CursorControllers.  Needed by WebTextView,
+     * which does not draw.
+     * @hide
+     */
+    protected void updateCursorControllerPositions() {
         if (mInsertionPointCursorController != null &&
                 mInsertionPointCursorController.isShowing()) {
             mInsertionPointCursorController.updatePosition();
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 3d9cde4..2be7bca 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -529,10 +529,19 @@
                     mMediaController.hide();
                 }
                 return true;
+            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+                if (mMediaPlayer.isPlaying()) {
+                    start();
+                    mMediaController.hide();
+                }
+                return true;
             } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
-                    && mMediaPlayer.isPlaying()) {
-                pause();
-                mMediaController.show();
+                    || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+                if (!mMediaPlayer.isPlaying()) {
+                    pause();
+                    mMediaController.show();
+                }
+                return true;
             } else {
                 toggleMediaControlsVisiblity();
             }
diff --git a/core/res/res/anim/fragment_close_enter.xml b/core/res/res/anim/fragment_close_enter.xml
index 7a9a3b9..edf1948 100644
--- a/core/res/res/anim/fragment_close_enter.xml
+++ b/core/res/res/anim/fragment_close_enter.xml
@@ -26,7 +26,7 @@
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
         android:interpolator="@anim/decelerate_interpolator"
-        android:valueFrom="-400"
+        android:valueFrom="-100"
         android:valueTo="0"
         android:valueType="floatType"
         android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_close_exit.xml b/core/res/res/anim/fragment_close_exit.xml
index 0743577..fbba476 100644
--- a/core/res/res/anim/fragment_close_exit.xml
+++ b/core/res/res/anim/fragment_close_exit.xml
@@ -27,7 +27,7 @@
     <objectAnimator
         android:interpolator="@anim/accelerate_interpolator"
         android:valueFrom="0"
-        android:valueTo="400"
+        android:valueTo="100"
         android:valueType="floatType"
         android:propertyName="translationX"
         android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/anim/fragment_open_enter.xml b/core/res/res/anim/fragment_open_enter.xml
index ac60494..334f4ef 100644
--- a/core/res/res/anim/fragment_open_enter.xml
+++ b/core/res/res/anim/fragment_open_enter.xml
@@ -24,7 +24,7 @@
         android:propertyName="alpha"
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
-        android:valueFrom="400"
+        android:valueFrom="100"
         android:valueTo="0"
         android:valueType="floatType"
         android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_open_exit.xml b/core/res/res/anim/fragment_open_exit.xml
index 3bf1ad4..764fc39 100644
--- a/core/res/res/anim/fragment_open_exit.xml
+++ b/core/res/res/anim/fragment_open_exit.xml
@@ -25,7 +25,7 @@
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
         android:valueFrom="0"
-        android:valueTo="-400"
+        android:valueTo="-100"
         android:valueType="floatType"
         android:propertyName="translationX"
         android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/layout/tab_content.xml b/core/res/res/layout/tab_content.xml
index 0ee87ce..79147fb 100644
--- a/core/res/res/layout/tab_content.xml
+++ b/core/res/res/layout/tab_content.xml
@@ -22,8 +22,9 @@
 	android:layout_width="match_parent" android:layout_height="match_parent">
 	<LinearLayout android:orientation="vertical"
     	android:layout_width="match_parent" android:layout_height="match_parent">
-        <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent"
-        	android:layout_height="wrap_content" android:layout_weight="0" />
+    <TabWidget android:id="@android:id/tabs"
+        android:orientation="horizontal" android:layout_width="match_parent"
+        android:layout_height="wrap_content" android:layout_weight="0" />
         <FrameLayout android:id="@android:id/tabcontent"
         	android:layout_width="match_parent" android:layout_height="0dip"
             android:layout_weight="1"/>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 077ce26..80072f4 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -572,7 +572,7 @@
     <style name="Theme.IconMenu">
         <!-- Menu/item attributes -->
         <item name="android:itemTextAppearance">@android:style/TextAppearance.Widget.IconMenu.Item</item>
-        <item name="android:selectableItemBackground">@android:drawable/menu_selector</item>
+        <item name="android:itemBackground">@android:drawable/menu_selector</item>
         <item name="android:itemIconDisabledAlpha">?android:attr/disabledAlpha</item>
         <item name="android:horizontalDivider">@android:drawable/divider_horizontal_dark</item>
         <item name="android:verticalDivider">@android:drawable/divider_vertical_dark</item>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 1d6ab25..d868599 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -129,9 +129,8 @@
 
   <tr>
     <td><code>raw/</code></td>
-    <td><p>Arbitrary files to save in their raw form. Files in here are not compressed by the
-system. To open these resources with a raw {@link java.io.InputStream}, call {@link
-android.content.res.Resources#openRawResource(int)
+    <td><p>Arbitrary files to save in their raw form. To open these resources with a raw
+{@link java.io.InputStream}, call {@link android.content.res.Resources#openRawResource(int)
 Resources.openRawResource()} with the resource ID, which is {@code R.raw.<em>filename</em>}.</p>
       <p>However, if you need access to original file names and file hierarchy, you might consider
 saving some resources in the {@code
diff --git a/docs/html/resources/faq/framework.jd b/docs/html/resources/faq/framework.jd
index f4b8db0..4a7a3fc 100644
--- a/docs/html/resources/faq/framework.jd
+++ b/docs/html/resources/faq/framework.jd
@@ -68,12 +68,17 @@
 <p>For sharing complex non-persistent user-defined objects for short
 duration, the following approaches are recommended:
 </p>
-  <h4>The android.app.Application class</h4>
-  <p>The android.app.Application is a base class for those who need to
-maintain global application state. It can be accessed via
-getApplication() from any Activity or Service. It has a couple of
-life-cycle methods and will be instantiated by Android automatically if
-your register it in AndroidManifest.xml.</p>
+  <h4>Singleton class</h4>
+  <p>You can take advantage of the fact that your application
+components run in the same process through the use of a singleton.
+This is a class that is designed to have only one instance.  It
+has a static method with a name such as <code>getInstance()</code>
+that returns the instance; the first time this method is called,
+it creates the global instance.  Because all callers get the same
+instance, they can use this as a point of interaction.  For
+example activity A may retrieve the instance and call setValue(3);
+later activity B may retrieve the instance and call getValue() to
+retrieve the last set value.</p>
 
   <h4>A public static field/method</h4>
   <p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
@@ -90,18 +95,6 @@
 intent extras. The recipient activity retrieves the object using this
 key.</p>
 
-  <h4>A Singleton class</h4>
-  <p>There are advantages to using a static Singleton, such as you can
-refer to them without casting getApplication() to an
-application-specific class, or going to the trouble of hanging an
-interface on all your Application subclasses so that your various
-modules can refer to that interface instead. </p>
-<p>But, the life cycle of a static is not well under your control; so
-to abide by the life-cycle model, the application class should initiate and
-tear down these static objects in the onCreate() and onTerminate() methods
-of the Application Class</p>
-</p>
-
 <h3>Persistent Objects</h3>
 
 <p>Even while an application appears to continue running, the system
@@ -146,15 +139,11 @@
 <h2>If an Activity starts a remote service, is there any way for the
 Service to pass a message back to the Activity?</h2>
 
-<p>The remote service can define a callback interface and register it with the
-clients to callback into the clients. The 
-{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to
-register and unregister clients with the service, and send and receive
-messages.</p>
-
-<p>The sample code for remote service callbacks is given in <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">ApiDemos/RemoteService</a></p>
-
+<p>See the {@link android.app.Service} documentation's for examples of
+how clients can interact with a service.  You can take advantage of the
+fact that your components run in the same process to greatly simplify
+service interaction from the generic remote case, as shown by the "Local
+Service Sample".  In some cases techniques like singletons may also make sense.
 
 
 <a name="6" id="6"></a>
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index a25fad4..289348a 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -51,7 +51,7 @@
      */
     public ColorDrawable(int color) {
         this(null);
-        mState.mBaseColor = mState.mUseColor = color;
+        setColor(color);
     }
 
     private ColorDrawable(ColorState state) {
@@ -72,6 +72,25 @@
     }
 
     /**
+     * Gets the drawable's color value.
+     *
+     * @return int The color to draw.
+     */
+    public int getColor() {
+        return mState.mUseColor;
+    }
+
+    /**
+     * Sets the drawable's color value. This action will clobber the results of prior calls to
+     * {@link #setAlpha(int)} on this object, which side-affected the underlying color.
+     *
+     * @param color The color to draw.
+     */
+    public void setColor(int color) {
+        mState.mBaseColor = mState.mUseColor = color;
+    }
+
+    /**
      * Returns the alpha value of this drawable's color.
      *
      * @return A value between 0 and 255.
@@ -131,7 +150,7 @@
     }
 
     final static class ColorState extends ConstantState {
-        int mBaseColor; // initial color. never changes
+        int mBaseColor; // base color, independent of setAlpha()
         int mUseColor;  // basecolor modulated by setAlpha()
         int mChangingConfigurations;
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 1f5ed7c..c692bc1 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -78,10 +78,6 @@
 
         if (dest) {
             *dest = ptr;
-        } else {
-            if (rsc->props.mLogScripts) {
-                LOGV("ScriptC::setupScript, NULL var binding address.");
-            }
         }
     }
 }
@@ -404,16 +400,14 @@
     const ScriptCState::SymbolTable_t *sym;
     ScriptC *s = (ScriptC *)pContext;
     sym = ScriptCState::lookupSymbol(name);
-    if (sym) {
-        return sym->mPtr;
+    if (!sym) {
+        sym = ScriptCState::lookupSymbolCL(name);
     }
-    sym = ScriptCState::lookupSymbolCL(name);
-    if (sym) {
-        return sym->mPtr;
+    if (!sym) {
+        sym = ScriptCState::lookupSymbolGL(name);
     }
-    s->mEnviroment.mIsThreadable = false;
-    sym = ScriptCState::lookupSymbolGL(name);
     if (sym) {
+        s->mEnviroment.mIsThreadable &= sym->threadable;
         return sym->mPtr;
     }
     LOGE("ScriptC sym lookup failed for %s", name);
@@ -425,7 +419,6 @@
 
 void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
 {
-    LOGV("%p ScriptCState::runCompiler ", rsc);
     {
         StopWatch compileTimer("RenderScript compile time");
         s->mBccScript = bccCreateScript();
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index e5b5ba9..86a7ad3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -89,6 +89,7 @@
     struct SymbolTable_t {
         const char * mName;
         void * mPtr;
+        bool threadable;
     };
     //static SymbolTable_t gSyms[];
     static const SymbolTable_t * lookupSymbol(const char *);
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 9fadee0..ecae306 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -436,120 +436,120 @@
 //                 ::= d  # double
 
 static ScriptCState::SymbolTable_t gSyms[] = {
-    { "__divsi3", (void *)&SC_divsi3 },
+    { "__divsi3", (void *)&SC_divsi3, true },
 
     // allocation
-    { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX },
-    { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY },
-    { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ },
-    { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD },
-    { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces },
-    { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation },
+    { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
+    { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true },
+    { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true },
+    { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true },
+    { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true },
+    { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true },
 
-    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX },
-    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
-    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
+    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true },
+    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true },
+    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true },
 
-    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject },
-    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject },
-    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject },
-    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject },
-    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject },
-    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject },
-    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject },
-    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject },
-    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true },
 
 
-    { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty },
+    { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true },
 
 
     // Debug
-    { "_Z7rsDebugPKcf", (void *)&SC_debugF },
-    { "_Z7rsDebugPKcff", (void *)&SC_debugFv2 },
-    { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3 },
-    { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4 },
-    { "_Z7rsDebugPKcd", (void *)&SC_debugD },
-    { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4 },
-    { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3 },
-    { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2 },
-    { "_Z7rsDebugPKci", (void *)&SC_debugI32 },
-    { "_Z7rsDebugPKcj", (void *)&SC_debugU32 },
+    { "_Z7rsDebugPKcf", (void *)&SC_debugF, true },
+    { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true },
+    { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true },
+    { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true },
+    { "_Z7rsDebugPKcd", (void *)&SC_debugD, true },
+    { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true },
+    { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true },
+    { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true },
+    { "_Z7rsDebugPKci", (void *)&SC_debugI32, true },
+    { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true },
     // Both "long" and "unsigned long" need to be redirected to their
     // 64-bit counterparts, since we have hacked Slang to use 64-bit
     // for "long" on Arm (to be similar to Java).
-    { "_Z7rsDebugPKcl", (void *)&SC_debugLL64 },
-    { "_Z7rsDebugPKcm", (void *)&SC_debugULL64 },
-    { "_Z7rsDebugPKcx", (void *)&SC_debugLL64 },
-    { "_Z7rsDebugPKcy", (void *)&SC_debugULL64 },
-    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP },
+    { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true },
+    { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true },
+    { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true },
+    { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true },
+    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true },
 
     // RS Math
-    { "_Z6rsRandi", (void *)&SC_randi },
-    { "_Z6rsRandii", (void *)&SC_randi2 },
-    { "_Z6rsRandf", (void *)&SC_randf },
-    { "_Z6rsRandff", (void *)&SC_randf2 },
-    { "_Z6rsFracf", (void *)&SC_frac },
+    { "_Z6rsRandi", (void *)&SC_randi, true },
+    { "_Z6rsRandii", (void *)&SC_randi2, true },
+    { "_Z6rsRandf", (void *)&SC_randf, true },
+    { "_Z6rsRandff", (void *)&SC_randf2, true },
+    { "_Z6rsFracf", (void *)&SC_frac, true },
 
     // time
-    { "_Z8rsSecondv", (void *)&SC_second },
-    { "_Z8rsMinutev", (void *)&SC_minute },
-    { "_Z6rsHourv", (void *)&SC_hour },
-    { "_Z5rsDayv", (void *)&SC_day },
-    { "_Z7rsMonthv", (void *)&SC_month },
-    { "_Z6rsYearv", (void *)&SC_year },
-    { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis },
-    { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos },
-    { "_Z7rsGetDtv", (void*)&SC_getDt },
+    { "_Z8rsSecondv", (void *)&SC_second, true },
+    { "_Z8rsMinutev", (void *)&SC_minute, true },
+    { "_Z6rsHourv", (void *)&SC_hour, true },
+    { "_Z5rsDayv", (void *)&SC_day, true },
+    { "_Z7rsMonthv", (void *)&SC_month, true },
+    { "_Z6rsYearv", (void *)&SC_year, true },
+    { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
+    { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
+    { "_Z7rsGetDtv", (void*)&SC_getDt, false },
 
-    { "_Z14rsSendToClienti", (void *)&SC_toClient },
-    { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2 },
-    { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking },
-    { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2 },
+    { "_Z14rsSendToClienti", (void *)&SC_toClient, false },
+    { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2, false },
+    { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false },
+    { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false },
 
-    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach },
-    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2 },
+    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false },
+    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true },
 
 ////////////////////////////////////////////////////////////////////
 
-    //{ "sinf_fast", (void *)&SC_sinf_fast },
-    //{ "cosf_fast", (void *)&SC_cosf_fast },
+    //{ "sinf_fast", (void *)&SC_sinf_fast, true },
+    //{ "cosf_fast", (void *)&SC_cosf_fast, true },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 1b1a752..7031f84 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -88,11 +88,6 @@
     return tanf(v * M_PI);
 }
 
-    //{ "logb", (void *)& },
-    //{ "mad", (void *)& },
-    //{ "nan", (void *)& },
-    //{ "tgamma", (void *)& },
-
 //////////////////////////////////////////////////////////////////////////////
 // Integer
 //////////////////////////////////////////////////////////////////////////////
@@ -198,105 +193,105 @@
 
 static ScriptCState::SymbolTable_t gSyms[] = {
     // OpenCL math
-    { "_Z4acosf", (void *)&acosf },
-    { "_Z5acoshf", (void *)&acoshf },
-    { "_Z6acospif", (void *)&SC_acospi },
-    { "_Z4asinf", (void *)&asinf },
-    { "_Z5asinhf", (void *)&asinhf },
-    { "_Z6asinpif", (void *)&SC_asinpi },
-    { "_Z4atanf", (void *)&atanf },
-    { "_Z5atan2ff", (void *)&atan2f },
-    { "_Z6atanpif", (void *)&SC_atanpi },
-    { "_Z7atan2piff", (void *)&SC_atan2pi },
-    { "_Z4cbrtf", (void *)&cbrtf },
-    { "_Z4ceilf", (void *)&ceilf },
-    { "_Z8copysignff", (void *)&copysignf },
-    { "_Z3cosf", (void *)&cosf },
-    { "_Z4coshf", (void *)&coshf },
-    { "_Z5cospif", (void *)&SC_cospi },
-    { "_Z4erfcf", (void *)&erfcf },
-    { "_Z3erff", (void *)&erff },
-    { "_Z3expf", (void *)&expf },
-    { "_Z4exp2f", (void *)&exp2f },
-    { "_Z5exp10f", (void *)&SC_exp10 },
-    { "_Z5expm1f", (void *)&expm1f },
-    { "_Z4fabsf", (void *)&fabsf },
-    { "_Z4fdimff", (void *)&fdimf },
-    { "_Z5floorf", (void *)&floorf },
-    { "_Z3fmafff", (void *)&fmaf },
-    { "_Z4fmaxff", (void *)&fmaxf },
-    { "_Z4fminff", (void *)&fminf },  // float fmin(float, float)
-    { "_Z4fmodff", (void *)&fmodf },
-    { "_Z5fractfPf", (void *)&SC_fract },
-    { "_Z5frexpfPi", (void *)&frexpf },
-    { "_Z5hypotff", (void *)&hypotf },
-    { "_Z5ilogbf", (void *)&ilogbf },
-    { "_Z5ldexpfi", (void *)&ldexpf },
-    { "_Z6lgammaf", (void *)&lgammaf },
-    { "_Z3logf", (void *)&logf },
-    { "_Z4log2f", (void *)&SC_log2 },
-    { "_Z5log10f", (void *)&log10f },
-    { "_Z5log1pf", (void *)&log1pf },
-    //{ "logb", (void *)& },
-    //{ "mad", (void *)& },
-    { "modf", (void *)&modff },
-    //{ "nan", (void *)& },
-    { "_Z9nextafterff", (void *)&nextafterf },
-    { "_Z3powff", (void *)&powf },
-    { "_Z4pownfi", (void *)&SC_pown },
-    { "_Z4powrff", (void *)&SC_powr },
-    { "_Z9remainderff", (void *)&remainderf },
-    { "remquo", (void *)&remquof },
-    { "_Z4rintf", (void *)&rintf },
-    { "_Z5rootnfi", (void *)&SC_rootn },
-    { "_Z5roundf", (void *)&roundf },
-    { "_Z5rsqrtf", (void *)&SC_rsqrt },
-    { "_Z3sinf", (void *)&sinf },
-    { "sincos", (void *)&SC_sincos },
-    { "_Z4sinhf", (void *)&sinhf },
-    { "_Z5sinpif", (void *)&SC_sinpi },
-    { "_Z4sqrtf", (void *)&sqrtf },
-    { "_Z3tanf", (void *)&tanf },
-    { "_Z4tanhf", (void *)&tanhf },
-    { "_Z5tanpif", (void *)&SC_tanpi },
-    //{ "tgamma", (void *)& },
-    { "_Z5truncf", (void *)&truncf },
+    { "_Z4acosf", (void *)&acosf, true },
+    { "_Z5acoshf", (void *)&acoshf, true },
+    { "_Z6acospif", (void *)&SC_acospi, true },
+    { "_Z4asinf", (void *)&asinf, true },
+    { "_Z5asinhf", (void *)&asinhf, true },
+    { "_Z6asinpif", (void *)&SC_asinpi, true },
+    { "_Z4atanf", (void *)&atanf, true },
+    { "_Z5atan2ff", (void *)&atan2f, true },
+    { "_Z6atanpif", (void *)&SC_atanpi, true },
+    { "_Z7atan2piff", (void *)&SC_atan2pi, true },
+    { "_Z4cbrtf", (void *)&cbrtf, true },
+    { "_Z4ceilf", (void *)&ceilf, true },
+    { "_Z8copysignff", (void *)&copysignf, true },
+    { "_Z3cosf", (void *)&cosf, true },
+    { "_Z4coshf", (void *)&coshf, true },
+    { "_Z5cospif", (void *)&SC_cospi, true },
+    { "_Z4erfcf", (void *)&erfcf, true },
+    { "_Z3erff", (void *)&erff, true },
+    { "_Z3expf", (void *)&expf, true },
+    { "_Z4exp2f", (void *)&exp2f, true },
+    { "_Z5exp10f", (void *)&SC_exp10, true },
+    { "_Z5expm1f", (void *)&expm1f, true },
+    { "_Z4fabsf", (void *)&fabsf, true },
+    { "_Z4fdimff", (void *)&fdimf, true },
+    { "_Z5floorf", (void *)&floorf, true },
+    { "_Z3fmafff", (void *)&fmaf, true },
+    { "_Z4fmaxff", (void *)&fmaxf, true },
+    { "_Z4fminff", (void *)&fminf, true },  // float fmin(float, float)
+    { "_Z4fmodff", (void *)&fmodf, true },
+    { "_Z5fractfPf", (void *)&SC_fract, true },
+    { "_Z5frexpfPi", (void *)&frexpf, true },
+    { "_Z5hypotff", (void *)&hypotf, true },
+    { "_Z5ilogbf", (void *)&ilogbf, true },
+    { "_Z5ldexpfi", (void *)&ldexpf, true },
+    { "_Z6lgammaf", (void *)&lgammaf, true },
+    { "_Z3logf", (void *)&logf, true },
+    { "_Z4log2f", (void *)&SC_log2, true },
+    { "_Z5log10f", (void *)&log10f, true },
+    { "_Z5log1pf", (void *)&log1pf, true },
+    //{ "logb", (void *)&, true },
+    //{ "mad", (void *)&, true },
+    { "modf", (void *)&modff, true },
+    //{ "nan", (void *)&, true },
+    { "_Z9nextafterff", (void *)&nextafterf, true },
+    { "_Z3powff", (void *)&powf, true },
+    { "_Z4pownfi", (void *)&SC_pown, true },
+    { "_Z4powrff", (void *)&SC_powr, true },
+    { "_Z9remainderff", (void *)&remainderf, true },
+    { "remquo", (void *)&remquof, true },
+    { "_Z4rintf", (void *)&rintf, true },
+    { "_Z5rootnfi", (void *)&SC_rootn, true },
+    { "_Z5roundf", (void *)&roundf, true },
+    { "_Z5rsqrtf", (void *)&SC_rsqrt, true },
+    { "_Z3sinf", (void *)&sinf, true },
+    { "sincos", (void *)&SC_sincos, true },
+    { "_Z4sinhf", (void *)&sinhf, true },
+    { "_Z5sinpif", (void *)&SC_sinpi, true },
+    { "_Z4sqrtf", (void *)&sqrtf, true },
+    { "_Z3tanf", (void *)&tanf, true },
+    { "_Z4tanhf", (void *)&tanhf, true },
+    { "_Z5tanpif", (void *)&SC_tanpi, true },
+    //{ "tgamma", (void *)&, true },
+    { "_Z5truncf", (void *)&truncf, true },
 
     // OpenCL Int
-    { "_Z3absi", (void *)&SC_abs_i32 },
-    { "_Z3abss", (void *)&SC_abs_i16 },
-    { "_Z3absc", (void *)&SC_abs_i8 },
-    { "_Z3clzj", (void *)&SC_clz_u32 },
-    { "_Z3clzt", (void *)&SC_clz_u16 },
-    { "_Z3clzh", (void *)&SC_clz_u8 },
-    { "_Z3clzi", (void *)&SC_clz_i32 },
-    { "_Z3clzs", (void *)&SC_clz_i16 },
-    { "_Z3clzc", (void *)&SC_clz_i8 },
-    { "_Z3maxjj", (void *)&SC_max_u32 },
-    { "_Z3maxtt", (void *)&SC_max_u16 },
-    { "_Z3maxhh", (void *)&SC_max_u8 },
-    { "_Z3maxii", (void *)&SC_max_i32 },
-    { "_Z3maxss", (void *)&SC_max_i16 },
-    { "_Z3maxcc", (void *)&SC_max_i8 },
-    { "_Z3minjj", (void *)&SC_min_u32 },
-    { "_Z3mintt", (void *)&SC_min_u16 },
-    { "_Z3minhh", (void *)&SC_min_u8 },
-    { "_Z3minii", (void *)&SC_min_i32 },
-    { "_Z3minss", (void *)&SC_min_i16 },
-    { "_Z3mincc", (void *)&SC_min_i8 },
+    { "_Z3absi", (void *)&SC_abs_i32, true },
+    { "_Z3abss", (void *)&SC_abs_i16, true },
+    { "_Z3absc", (void *)&SC_abs_i8, true },
+    { "_Z3clzj", (void *)&SC_clz_u32, true },
+    { "_Z3clzt", (void *)&SC_clz_u16, true },
+    { "_Z3clzh", (void *)&SC_clz_u8, true },
+    { "_Z3clzi", (void *)&SC_clz_i32, true },
+    { "_Z3clzs", (void *)&SC_clz_i16, true },
+    { "_Z3clzc", (void *)&SC_clz_i8, true },
+    { "_Z3maxjj", (void *)&SC_max_u32, true },
+    { "_Z3maxtt", (void *)&SC_max_u16, true },
+    { "_Z3maxhh", (void *)&SC_max_u8, true },
+    { "_Z3maxii", (void *)&SC_max_i32, true },
+    { "_Z3maxss", (void *)&SC_max_i16, true },
+    { "_Z3maxcc", (void *)&SC_max_i8, true },
+    { "_Z3minjj", (void *)&SC_min_u32, true },
+    { "_Z3mintt", (void *)&SC_min_u16, true },
+    { "_Z3minhh", (void *)&SC_min_u8, true },
+    { "_Z3minii", (void *)&SC_min_i32, true },
+    { "_Z3minss", (void *)&SC_min_i16, true },
+    { "_Z3mincc", (void *)&SC_min_i8, true },
 
     // OpenCL 6.11.4
-    { "_Z5clampfff", (void *)&SC_clamp_f32 },
-    { "_Z7degreesf", (void *)&SC_degrees },
-    { "_Z3maxff", (void *)&SC_max_f32 },
-    { "_Z3minff", (void *)&SC_min_f32 },
-    { "_Z3mixfff", (void *)&SC_mix_f32 },
-    { "_Z7radiansf", (void *)&SC_radians },
-    { "_Z4stepff", (void *)&SC_step_f32 },
-    //{ "smoothstep", (void *)& },
-    { "_Z4signf", (void *)&SC_sign_f32 },
+    { "_Z5clampfff", (void *)&SC_clamp_f32, true },
+    { "_Z7degreesf", (void *)&SC_degrees, true },
+    { "_Z3maxff", (void *)&SC_max_f32, true },
+    { "_Z3minff", (void *)&SC_min_f32, true },
+    { "_Z3mixfff", (void *)&SC_mix_f32, true },
+    { "_Z7radiansf", (void *)&SC_radians, true },
+    { "_Z4stepff", (void *)&SC_step_f32, true },
+    //{ "smoothstep", (void *)&, true },
+    { "_Z4signf", (void *)&SC_sign_f32, true },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(const char *sym)
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index b991cab..5b07e7b 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -441,53 +441,53 @@
 //                 ::= d  # double
 
 static ScriptCState::SymbolTable_t gSyms[] = {
-    { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment },
-    { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore },
-    { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex },
-    { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster },
-    { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler },
-    { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture },
+    { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment, false },
+    { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore, false },
+    { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex, false },
+    { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster, false },
+    { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler, false },
+    { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture, false },
 
-    { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix },
-    { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix },
-    { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix },
+    { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix, false },
+    { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix, false },
+    { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix, false },
 
-    { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix },
+    { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix, false },
 
-    { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor },
+    { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor, false },
 
-    { "_Z11rsgGetWidthv", (void *)&SC_getWidth },
-    { "_Z12rsgGetHeightv", (void *)&SC_getHeight },
+    { "_Z11rsgGetWidthv", (void *)&SC_getWidth, false },
+    { "_Z12rsgGetHeightv", (void *)&SC_getHeight, false },
 
-    { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2 },
-    { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture },
-    { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject },
+    { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2, false },
+    { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture, false },
+    { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject, false },
 
-    { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect },
-    { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad },
-    { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords },
-    { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace },
+    { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect, false },
+    { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad, false },
+    { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords, false },
+    { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace, false },
 
-    { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh },
-    { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive },
-    { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange },
-    { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox },
+    { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh, false },
+    { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive, false },
+    { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange, false },
+    { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox, false },
 
-    { "_Z13rsgClearColorffff", (void *)&SC_ClearColor },
-    { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth },
+    { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
+    { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
 
-    { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText },
-    { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc },
-    { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText },
-    { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc },
+    { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false },
+    { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false },
+    { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false },
+    { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false },
 
-    { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont },
-    { "_Z12rsgFontColorffff", (void *)&SC_FontColor },
+    { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false },
+    { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false },
 
     // misc
-    { "_Z5colorffff", (void *)&SC_color },
+    { "_Z5colorffff", (void *)&SC_color, false },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolGL(const char *sym)
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b936c4d..58d4c56 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -1408,8 +1408,13 @@
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
     int32_t eventType = POWER_MANAGER_BUTTON_EVENT;
-    if (eventEntry->type == EventEntry::TYPE_MOTION) {
+    switch (eventEntry->type) {
+    case EventEntry::TYPE_MOTION: {
         const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
+        if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+            return;
+        }
+
         if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
             switch (motionEntry->action) {
             case AMOTION_EVENT_ACTION_DOWN:
@@ -1427,6 +1432,15 @@
                 break;
             }
         }
+        break;
+    }
+    case EventEntry::TYPE_KEY: {
+        const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
+        if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
+            return;
+        }
+        break;
+    }
     }
 
     CommandEntry* commandEntry = postCommandLocked(
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 91dc2b2..0f1aa4e 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -145,7 +145,7 @@
                 case KeyEvent.KEYCODE_MEDIA_PLAY:
                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                    /* Suppress PLAYPAUSE toggle when phone is ringing or
+                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
                      * in-call to avoid music playback */
                     if (mTelephonyManager == null) {
                         mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -155,11 +155,13 @@
                             mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
                         return true;  // suppress key event
                     }
-                case KeyEvent.KEYCODE_HEADSETHOOK: 
-                case KeyEvent.KEYCODE_MEDIA_STOP: 
-                case KeyEvent.KEYCODE_MEDIA_NEXT: 
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 
-                case KeyEvent.KEYCODE_MEDIA_REWIND: 
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                     Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                     intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -191,12 +193,15 @@
         } else if (event.getAction() == KeyEvent.ACTION_UP) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK: 
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 
-                case KeyEvent.KEYCODE_MEDIA_STOP: 
-                case KeyEvent.KEYCODE_MEDIA_NEXT: 
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 
-                case KeyEvent.KEYCODE_MEDIA_REWIND: 
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                     Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                     intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c034ec9..c870503 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -795,6 +795,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
             case KeyEvent.KEYCODE_CAMERA:
                 return false;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 1383354..4644a7c 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -209,7 +209,12 @@
                 mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
                         : R.string.lockscreen_sound_off_label);
             }
-            mCallback.pokeWakelock();
+            // Don't poke the wake lock when returning to a state where the handle is
+            // not grabbed since that can happen when the system (instead of the user)
+            // cancels the grab.
+            if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) {
+                mCallback.pokeWakelock();
+            }
         }
     }
 
@@ -231,10 +236,11 @@
 
         /** {@inheritDoc} */
         public void onGrabbedStateChange(View v, int grabbedState) {
+            // Don't poke the wake lock when returning to a state where the handle is
+            // not grabbed since that can happen when the system (instead of the user)
+            // cancels the grab.
             if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) {
                 mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
-            } else {
-                mCallback.pokeWakelock();
             }
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 3691d97..e944f9d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -627,13 +627,6 @@
             // should be executed...  do it!
             mPanelChordingKey = 0;
             mPanelMayLongPress = false;
-            InputMethodManager imm = (InputMethodManager)
-                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-            if (imm != null) {
-                mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
-            }
-            
         }
 
         return false;
@@ -1259,7 +1252,7 @@
             case KeyEvent.KEYCODE_MEDIA_PLAY:
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                /* Suppress PLAYPAUSE toggle when phone is ringing or in-call
+                /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
                  * to avoid music playback */
                 if (mTelephonyManager == null) {
                     mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -1275,6 +1268,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                 intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -1455,6 +1449,7 @@
             }
 
             case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
             case KeyEvent.KEYCODE_MEDIA_PLAY:
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -1462,6 +1457,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                 intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7f49da9..e950ae5 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -54,6 +54,7 @@
 import com.android.internal.view.BaseInputHandler;
 import com.android.internal.widget.PointerLocationView;
 
+import android.telephony.TelephonyManager;
 import android.util.Config;
 import android.util.EventLog;
 import android.util.Log;
@@ -63,6 +64,7 @@
 import android.view.HapticFeedbackConstants;
 import android.view.IWindowManager;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.InputHandler;
 import android.view.KeyEvent;
@@ -217,7 +219,7 @@
     WindowState mKeyguard = null;
     KeyguardViewMediator mKeyguardMediator;
     GlobalActions mGlobalActions;
-    boolean mShouldTurnOffOnKeyUp;
+    volatile boolean mPowerKeyHandled;
     RecentApplicationsDialog mRecentAppsDialog;
     Handler mHandler;
     
@@ -477,28 +479,47 @@
         }
     }
 
-    Runnable mPowerLongPress = new Runnable() {
+    private void interceptPowerKeyDown(boolean handled) {
+        mPowerKeyHandled = handled;
+        if (!handled) {
+            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+        }
+    }
+
+    private boolean interceptPowerKeyUp(boolean canceled) {
+        if (!mPowerKeyHandled) {
+            mHandler.removeCallbacks(mPowerLongPress);
+            return !canceled;
+        } else {
+            mPowerKeyHandled = true;
+            return false;
+        }
+    }
+
+    private final Runnable mPowerLongPress = new Runnable() {
         public void run() {
-            // The context isn't read
-            if (mLongPressOnPowerBehavior < 0) {
-                mLongPressOnPowerBehavior = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
-            }
-            switch (mLongPressOnPowerBehavior) {
-            case LONG_PRESS_POWER_NOTHING:
-                break;
-            case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-                mShouldTurnOffOnKeyUp = false;
-                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                showGlobalActionsDialog();
-                break;
-            case LONG_PRESS_POWER_SHUT_OFF:
-                mShouldTurnOffOnKeyUp = false;
-                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                ShutdownThread.shutdown(mContext, true);
-                break;
+            if (!mPowerKeyHandled) {
+                // The context isn't read
+                if (mLongPressOnPowerBehavior < 0) {
+                    mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
+                }
+                switch (mLongPressOnPowerBehavior) {
+                case LONG_PRESS_POWER_NOTHING:
+                    break;
+                case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+                    mPowerKeyHandled = true;
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+                    showGlobalActionsDialog();
+                    break;
+                case LONG_PRESS_POWER_SHUT_OFF:
+                    mPowerKeyHandled = true;
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+                    ShutdownThread.shutdown(mContext, true);
+                    break;
+                }
             }
         }
     };
@@ -1111,12 +1132,22 @@
                 com.android.internal.R.anim.lock_screen_behind_enter);
     }
     
-    static ITelephony getPhoneInterface() {
-        return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+    static ITelephony getTelephonyService() {
+        ITelephony telephonyService = ITelephony.Stub.asInterface(
+                ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+        if (telephonyService == null) {
+            Log.w(TAG, "Unable to find ITelephony interface.");
+        }
+        return telephonyService;
     }
 
-    static IAudioService getAudioInterface() {
-        return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
+    static IAudioService getAudioService() {
+        IAudioService audioService = IAudioService.Stub.asInterface(
+                ServiceManager.checkService(Context.AUDIO_SERVICE));
+        if (audioService == null) {
+            Log.w(TAG, "Unable to find IAudioService interface.");
+        }
+        return audioService;
     }
 
     boolean keyguardOn() {
@@ -1131,7 +1162,7 @@
     /** {@inheritDoc} */
     @Override
     public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
-            int keyCode, int metaState, int repeatCount, int policyFlags) {
+            int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
         final boolean keyguardOn = keyguardOn();
         final boolean down = (action == KeyEvent.ACTION_DOWN);
         final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1164,11 +1195,9 @@
                         // and his ONLY options are to answer or reject the call.)
                         boolean incomingRinging = false;
                         try {
-                            ITelephony phoneServ = getPhoneInterface();
-                            if (phoneServ != null) {
-                                incomingRinging = phoneServ.isRinging();
-                            } else {
-                                Log.w(TAG, "Unable to find ITelephony interface");
+                            ITelephony telephonyService = getTelephonyService();
+                            if (telephonyService != null) {
+                                incomingRinging = telephonyService.isRinging();
                             }
                         } catch (RemoteException ex) {
                             Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
@@ -1824,23 +1853,6 @@
     }
 
     /**
-     * @return Whether a telephone call is in progress right now.
-     */
-    boolean isInCall() {
-        final ITelephony phone = getPhoneInterface();
-        if (phone == null) {
-            Log.w(TAG, "couldn't get ITelephony reference");
-            return false;
-        }
-        try {
-            return phone.isOffhook();
-        } catch (RemoteException e) {
-            Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
-            return false;
-        }
-    }
-
-    /**
      * @return Whether music is being played right now.
      */
     boolean isMusicActive() {
@@ -1857,9 +1869,8 @@
      * @param keycode
      */
     void handleVolumeKey(int stream, int keycode) {
-        final IAudioService audio = getAudioInterface();
-        if (audio == null) {
-            Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
+        IAudioService audioService = getAudioService();
+        if (audioService == null) {
             return;
         }
         try {
@@ -1867,7 +1878,7 @@
             // during the call, but we do it as a precaution for the rare possibility
             // that the music stops right before we call this
             mBroadcastWakeLock.acquire();
-            audio.adjustStreamVolume(stream,
+            audioService.adjustStreamVolume(stream,
                 keycode == KeyEvent.KEYCODE_VOLUME_UP
                             ? AudioManager.ADJUST_RAISE
                             : AudioManager.ADJUST_LOWER,
@@ -1878,41 +1889,15 @@
             mBroadcastWakeLock.release();
         }
     }
-    
-    static boolean isMediaKey(int code) {
-        if (code == KeyEvent.KEYCODE_HEADSETHOOK || 
-                code == KeyEvent.KEYCODE_MEDIA_PLAY ||
-                code == KeyEvent.KEYCODE_MEDIA_PAUSE ||
-                code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                code == KeyEvent.KEYCODE_MEDIA_STOP || 
-                code == KeyEvent.KEYCODE_MEDIA_NEXT ||
-                code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || 
-                code == KeyEvent.KEYCODE_MEDIA_REWIND ||
-                code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
-            return true;
-        }
-        return false;    
-    }
- 
+
     /** {@inheritDoc} */
     @Override
-    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-            int policyFlags, boolean isScreenOn) {
-        int result = ACTION_PASS_TO_USER;
+    public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+            int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+        final boolean down = action == KeyEvent.ACTION_DOWN;
+        final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
 
-        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-
-        final boolean isWakeKey = (policyFlags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
-        // If the key is injected, pretend that the screen is on and don't let the
-        // device go to sleep.  This feature is mainly used for testing purposes.
         final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
-        if (isInjected) {
-            isScreenOn = true;
-        }
 
         // If screen is off then we treat the case where the keyguard is open but hidden
         // the same as if it were open and in front.
@@ -1927,202 +1912,210 @@
                   + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
 
-        if (keyguardActive) {
-            if (isScreenOn) {
-                // when the screen is on, always give the event to the keyguard
-                result |= ACTION_PASS_TO_USER;
-            } else {
-                // otherwise, don't pass it to the user
-                result &= ~ACTION_PASS_TO_USER;
+        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
 
-                if (isWakeKey && down) {
+        // Basic policy based on screen state and keyguard.
+        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
+        //        is on or off, really.  We should care about whether the device is in an
+        //        interactive state or is in suspend pretending to be "off".
+        //        The primary screen might be turned off due to proximity sensor or
+        //        because we are presenting media on an auxiliary screen or remotely controlling
+        //        the device some other way (which is why we have an exemption here for injected
+        //        events).
+        int result;
+        if (isScreenOn || isInjected) {
+            // When the screen is on or if the key is injected pass the key to the application.
+            result = ACTION_PASS_TO_USER;
+        } else {
+            // When the screen is off and the key is not injected, determine whether
+            // to wake the device but don't pass the key to the application.
+            result = 0;
 
-                    // tell the mediator about a wake key, it may decide to
-                    // turn on the screen depending on whether the key is
-                    // appropriate.
-                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
-                            && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
-                        // when keyguard is showing and screen off, we need
-                        // to handle the volume key for calls and  music here
-                        if (isInCall()) {
-                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
-                        } else if (isMusicActive()) {
-                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
-                        }
-                    }
+            final boolean isWakeKey = (policyFlags
+                    & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+            if (down && isWakeKey) {
+                if (keyguardActive) {
+                    // If the keyguard is showing, let it decide what to do with the wake key.
+                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+                } else {
+                    // Otherwise, wake the device ourselves.
+                    result |= ACTION_POKE_USER_ACTIVITY;
                 }
             }
-        } else if (!isScreenOn) {
-            // If we are in-call with screen off and keyguard is not showing,
-            // then handle the volume key ourselves.
-            // This is necessary because the phone app will disable the keyguard
-            // when the proximity sensor is in use.
-            if (isInCall() &&
-                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
-                result &= ~ACTION_PASS_TO_USER;
-                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
-            }
-            if (isWakeKey) {
-                // a wake key has a sole purpose of waking the device; don't pass
-                // it to the user
-                result |= ACTION_POKE_USER_ACTIVITY;
-                result &= ~ACTION_PASS_TO_USER;
-            }
         }
 
-        if (keyCode == KeyEvent.KEYCODE_ENDCALL
-                || keyCode == KeyEvent.KEYCODE_POWER) {
-            if (down) {
-                boolean handled = false;
-                boolean hungUp = false;
-                // key repeats are generated by the window manager, and we don't see them
-                // here, so unless the driver is doing something it shouldn't be, we know
-                // this is the real press event.
-                ITelephony phoneServ = getPhoneInterface();
-                if (phoneServ != null) {
-                    try {
-                        if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
-                            handled = hungUp = phoneServ.endCall();
-                        } else if (keyCode == KeyEvent.KEYCODE_POWER) {
-                            if (phoneServ.isRinging()) {
-                                // Pressing Power while there's a ringing incoming
-                                // call should silence the ringer.
-                                phoneServ.silenceRinger();
-                                handled = true;
-                            } else if (phoneServ.isOffhook() &&
-                                       ((mIncallPowerBehavior
-                                         & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
-                                        != 0)) {
-                                // Otherwise, if "Power button ends call" is enabled,
-                                // the Power button will hang up any current active call.
-                                handled = hungUp = phoneServ.endCall();
+        // Handle special keys.
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP: {
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                // If an incoming call is ringing, either VOLUME key means
+                                // "silence ringer".  We handle these keys here, rather than
+                                // in the InCallScreen, to make sure we'll respond to them
+                                // even if the InCallScreen hasn't come to the foreground yet.
+                                // Look for the DOWN event here, to agree with the "fallback"
+                                // behavior in the InCallScreen.
+                                Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                      + " VOLUME key-down while ringing: Silence ringer!");
+
+                                // Silence the ringer.  (It's safe to call this
+                                // even if the ringer has already been silenced.)
+                                telephonyService.silenceRinger();
+
+                                // And *don't* pass this key thru to the current activity
+                                // (which is probably the InCallScreen.)
+                                result &= ~ACTION_PASS_TO_USER;
+                                break;
+                            }
+                            if (telephonyService.isOffhook()
+                                    && (result & ACTION_PASS_TO_USER) == 0) {
+                                // If we are in call but we decided not to pass the key to
+                                // the application, handle the volume change here.
+                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+                                break;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+
+                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
+                        // If music is playing but we decided not to pass the key to the
+                        // application, handle the volume change here.
+                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_ENDCALL: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    boolean hungUp = false;
+                    if (telephonyService != null) {
+                        try {
+                            hungUp = telephonyService.endCall();
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                } else {
+                    if (interceptPowerKeyUp(canceled)) {
+                        if ((mEndcallBehavior
+                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+                            if (goHome()) {
+                                break;
                             }
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
+                        if ((mEndcallBehavior
+                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+                        }
                     }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_POWER: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    boolean hungUp = false;
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                // Pressing Power while there's a ringing incoming
+                                // call should silence the ringer.
+                                telephonyService.silenceRinger();
+                            } else if ((mIncallPowerBehavior
+                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+                                    && telephonyService.isOffhook()) {
+                                // Otherwise, if "Power button ends call" is enabled,
+                                // the Power button will hang up any current active call.
+                                hungUp = telephonyService.endCall();
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+                    interceptPowerKeyDown(!isScreenOn || hungUp);
                 } else {
-                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-                }
-
-                if (!isScreenOn
-                        || (handled && keyCode != KeyEvent.KEYCODE_POWER)
-                        || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
-                    mShouldTurnOffOnKeyUp = false;
-                } else {
-                    // Only try to turn off the screen if we didn't already hang up.
-                    mShouldTurnOffOnKeyUp = true;
-                    mHandler.postDelayed(mPowerLongPress,
-                            ViewConfiguration.getGlobalActionKeyTimeout());
-                    result &= ~ACTION_PASS_TO_USER;
-                }
-            } else {
-                mHandler.removeCallbacks(mPowerLongPress);
-                if (mShouldTurnOffOnKeyUp) {
-                    mShouldTurnOffOnKeyUp = false;
-                    boolean gohome, sleeps;
-                    if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
-                        gohome = (mEndcallBehavior
-                                  & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
-                        sleeps = (mEndcallBehavior
-                                  & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
-                    } else {
-                        gohome = false;
-                        sleeps = true;
+                    if (interceptPowerKeyUp(canceled)) {
+                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
                     }
-                    if (keyguardActive
-                            || (sleeps && !gohome)
-                            || (gohome && !goHome() && sleeps)) {
-                        // They must already be on the keyguard or home screen,
-                        // go to sleep instead unless the event was injected.
-                        if (!isInjected) {
-                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-                                    + Integer.toHexString(mEndcallBehavior));
-                            result &= ~ACTION_POKE_USER_ACTIVITY;
-                            result |= ACTION_GO_TO_SLEEP;
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (!telephonyService.isIdle()) {
+                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+                                // to avoid music playback.
+                                break;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    result &= ~ACTION_PASS_TO_USER;
                 }
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if ((result & ACTION_PASS_TO_USER) == 0) {
+                    // Only do this if we would otherwise not pass it to the user. In that
+                    // case, the PhoneWindow class will do the same thing, except it will
+                    // only do it if the showing app doesn't process the key on its own.
+                    long when = whenNanos / 1000000;
+                    KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
+                            0, scanCode, flags, InputDevice.SOURCE_KEYBOARD);
+                    mBroadcastWakeLock.acquire();
+                    mHandler.post(new PassHeadsetKey(keyEvent));
+                }
+                break;
             }
-        } else if (isMediaKey(keyCode)) {
-            // This key needs to be handled even if the screen is off.
-            // If others need to be handled while it's off, this is a reasonable
-            // pattern to follow.
-            if ((result & ACTION_PASS_TO_USER) == 0) {
-                // Only do this if we would otherwise not pass it to the user. In that
-                // case, the PhoneWindow class will do the same thing, except it will
-                // only do it if the showing app doesn't process the key on its own.
-                long when = whenNanos / 1000000;
-                KeyEvent keyEvent = new KeyEvent(when, when,
-                        down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                        keyCode, 0);
-                mBroadcastWakeLock.acquire();
-                mHandler.post(new PassHeadsetKey(keyEvent));
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_CALL) {
-            // If an incoming call is ringing, answer it!
-            // (We handle this key here, rather than in the InCallScreen, to make
-            // sure we'll respond to the key even if the InCallScreen hasn't come to
-            // the foreground yet.)
 
-            // We answer the call on the DOWN event, to agree with
-            // the "fallback" behavior in the InCallScreen.
-            if (down) {
-                try {
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        if (phoneServ.isRinging()) {
-                            Log.i(TAG, "interceptKeyTq:"
-                                  + " CALL key-down while ringing: Answer the call!");
-                            phoneServ.answerRingingCall();
+            case KeyEvent.KEYCODE_CALL: {
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                      + " CALL key-down while ringing: Answer the call!");
+                                telephonyService.answerRingingCall();
 
-                            // And *don't* pass this key thru to the current activity
-                            // (which is presumably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
+                                // And *don't* pass this key thru to the current activity
+                                // (which is presumably the InCallScreen.)
+                                result &= ~ACTION_PASS_TO_USER;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
-                    } else {
-                        Log.w(TAG, "CALL button: Unable to find ITelephony interface");
                     }
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
                 }
-            }
-        } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
-                   || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-            // If an incoming call is ringing, either VOLUME key means
-            // "silence ringer".  We handle these keys here, rather than
-            // in the InCallScreen, to make sure we'll respond to them
-            // even if the InCallScreen hasn't come to the foreground yet.
-
-            // Look for the DOWN event here, to agree with the "fallback"
-            // behavior in the InCallScreen.
-            if (down) {
-                try {
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        if (phoneServ.isRinging()) {
-                            Log.i(TAG, "interceptKeyTq:"
-                                  + " VOLUME key-down while ringing: Silence ringer!");
-                            // Silence the ringer.  (It's safe to call this
-                            // even if the ringer has already been silenced.)
-                            phoneServ.silenceRinger();
-
-                            // And *don't* pass this key thru to the current activity
-                            // (which is probably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
-                        }
-                    } else {
-                        Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
-                    }
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
-                }
+                break;
             }
         }
-
         return result;
     }
 
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index cb4071a..e7eb129 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -404,17 +404,18 @@
         }
         
         @SuppressWarnings("unused")
-        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-                int policyFlags, boolean isScreenOn) {
+        public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+                int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
-                    whenNanos, keyCode, down, policyFlags, isScreenOn);
+                    whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
         }
         
         @SuppressWarnings("unused")
         public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
-                int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
+                int flags, int keyCode, int scanCode, int metaState, int repeatCount,
+                int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
-                    action, flags, keyCode, metaState, repeatCount, policyFlags);
+                    action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
         }
         
         @SuppressWarnings("unused")
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 747af26..a7a0c68 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -103,6 +103,8 @@
 
     private int mDataConnectionNetworkType;
 
+    private int mOtaspMode;
+
     static final int PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
                 PhoneStateListener.LISTEN_CALL_STATE |
@@ -225,6 +227,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+                        try {
+                            r.callback.onOtaspChanged(mOtaspMode);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -467,6 +476,25 @@
         }
     }
 
+    public void notifyOtaspChanged(int otaspMode) {
+        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
+            return;
+        }
+        synchronized (mRecords) {
+            mOtaspMode = otaspMode;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+                    try {
+                        r.callback.onOtaspChanged(otaspMode);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c29e4a9..55ebded 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5706,20 +5706,20 @@
         
         /* Provides an opportunity for the window manager policy to intercept early key
          * processing as soon as the key has been read from the device. */
-        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-                int policyFlags, boolean isScreenOn) {
-            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
-                    keyCode, down, policyFlags, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+                int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+            return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
+                    keyCode, scanCode, policyFlags, isScreenOn);
         }
         
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
         public boolean interceptKeyBeforeDispatching(InputChannel focus,
-                int action, int flags, int keyCode, int metaState, int repeatCount,
+                int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
                 int policyFlags) {
             WindowState windowState = getWindowStateForInputChannel(focus);
             return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
-                    keyCode, metaState, repeatCount, policyFlags);
+                    keyCode, scanCode, metaState, repeatCount, policyFlags);
         }
         
         /* Called when the current input focus changes.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 599163b..d4c4ba4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -857,7 +857,7 @@
         JNIEnv* env = jniEnv();
         jint wmActions = env->CallIntMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeQueueing,
-                when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
+                when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
         if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
             wmActions = 0;
         }
@@ -926,7 +926,7 @@
         jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeDispatching,
                 inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
-                keyEvent->getKeyCode(), keyEvent->getMetaState(),
+                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), policyFlags);
         bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
@@ -1358,10 +1358,10 @@
             "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeQueueing", "(JIZIZ)I");
+            "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
+            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 38f44d8..eda9b71 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -148,6 +148,14 @@
      */
     public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;
 
+    /**
+     * Listen for changes to OTASP mode.
+     *
+     * @see #onOtaspChanged
+     * @hide
+     */
+    public static final int LISTEN_OTASP_CHANGED                            = 0x00000200;
+
     public PhoneStateListener() {
     }
 
@@ -252,6 +260,21 @@
         // default implementation empty
     }
 
+
+    /**
+     * The Over The Air Service Provisioning (OTASP) has changed. Requires
+     * the READ_PHONE_STATE permission.
+     * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
+     *   means the value is currently unknown and the system should wait until
+     *   <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
+     *   making the decisision to perform OTASP or not.
+     *
+     * @hide
+     */
+    public void onOtaspChanged(int otaspMode) {
+        // default implementation empty
+    }
+
     /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
@@ -292,9 +315,14 @@
         public void onDataActivity(int direction) {
             Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
         }
+
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
             Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
         }
+
+        public void onOtaspChanged(int otaspMode) {
+            Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
+        }
     };
 
     Handler mHandler = new Handler() {
@@ -329,6 +357,9 @@
                 case LISTEN_SIGNAL_STRENGTHS:
                     PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
                     break;
+                case LISTEN_OTASP_CHANGED:
+                    PhoneStateListener.this.onOtaspChanged(msg.arg1);
+                    break;
             }
         }
     };
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 6a163dd..14808b6 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -148,6 +148,14 @@
         }
     }
 
+    public void notifyOtaspChanged(Phone sender, int otaspMode) {
+        try {
+            mRegistry.notifyOtaspChanged(otaspMode);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
     private void log(String s) {
         Log.d(LOG_TAG, "[PhoneNotifier] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 856d663..082c097 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -32,5 +32,6 @@
     void onDataConnectionStateChanged(int state, int networkType);
     void onDataActivity(int direction);
     void onSignalStrengthsChanged(in SignalStrength signalStrength);
+    void onOtaspChanged(in int otaspMode);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7a1587b..3c4bb12 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -66,7 +66,7 @@
     boolean showCallScreenWithDialpad(boolean showDialpad);
 
     /**
-     * End call or go to the Home screen
+     * End call if there is a call in progress, otherwise does nothing.
      *
      * @return whether it hung up
      */
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 6407a4e..3c83e50 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -38,4 +38,5 @@
             in LinkCapabilities linkCapabilities, int networkType);
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
+    void notifyOtaspChanged(in int otaspMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74e8c1b..554a7ba 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -750,6 +750,10 @@
         mNotifier.notifyDataConnection(this, reason, apnType);
     }
 
+    public void notifyOtaspChanged(int otaspMode) {
+        mNotifier.notifyOtaspChanged(this, otaspMode);
+    }
+
     public abstract String getPhoneName();
 
     public abstract int getPhoneType();
diff --git a/telephony/java/com/android/internal/telephony/PhoneNotifier.java b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
index 691271f..b1cf953 100644
--- a/telephony/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
@@ -42,4 +42,5 @@
 
     public void notifyDataActivity(Phone sender);
 
+    public void notifyOtaspChanged(Phone sender, int otaspMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index e8bbe5e..3f9ffc3 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -53,6 +53,12 @@
 
     public SignalStrength mSignalStrength;
 
+    /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
+    static public final int OTASP_UNINITIALIZED = 0;
+    static public final int OTASP_UNKNOWN = 1;
+    static public final int OTASP_NEEDED = 2;
+    static public final int OTASP_NOT_NEEDED = 3;
+
     /**
      * A unique identifier to track requests associated with a poll
      * and ignore stale responses.  The value is a count-down of
@@ -268,9 +274,11 @@
 
     public abstract void handleMessage(Message msg);
 
+    protected abstract Phone getPhone();
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
     protected abstract void updateSpnDisplay();
     protected abstract void setPowerStateToDesired();
+    protected abstract void log(String s);
 
     /**
      * Clean up existing voice and data connection then turn off radio power.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 6e53ec5..b9d5673 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -61,6 +61,7 @@
 import com.android.internal.telephony.PhoneNotifier;
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.PhoneSubInfo;
+import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.UUSInfo;
@@ -83,10 +84,6 @@
     static final String LOG_TAG = "CDMA";
     private static final boolean DBG = true;
 
-    // Min values used to by needsActivation
-    private static final String UNACTIVATED_MIN2_VALUE = "000000";
-    private static final String UNACTIVATED_MIN_VALUE = "1111110111";
-
     // Default Emergency Callback Mode exit timer
     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
 
@@ -1170,19 +1167,7 @@
      */
     @Override
     public boolean needsOtaServiceProvisioning() {
-        String cdmaMin = getCdmaMin();
-        boolean needsProvisioning;
-        if (cdmaMin == null || (cdmaMin.length() < 6)) {
-            if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
-                                    + cdmaMin + "' assume provisioning needed.");
-            needsProvisioning = true;
-        } else {
-            needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
-                    || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
-                    || SystemProperties.getBoolean("test_cdma_setup", false);
-        }
-        if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
-        return needsProvisioning;
+        return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
     }
 
     private static final String IS683A_FEATURE_CODE = "*228";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 3669e60..325c2e1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -354,6 +354,24 @@
                     || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
                     || !backgroundCall.getState().isAlive());
 
+        if (!ret) {
+            log(String.format("canDial is false\n" +
+                              "((serviceState=%d) != ServiceState.STATE_POWER_OFF)::=%s\n" +
+                              "&& pendingMO == null::=%s\n" +
+                              "&& !ringingCall.isRinging()::=%s\n" +
+                              "&& !disableCall.equals(\"true\")::=%s\n" +
+                              "&& (!foregroundCall.getState().isAlive()::=%s\n" +
+                              "   || foregroundCall.getState() == CdmaCall.State.ACTIVE::=%s\n" +
+                              "   ||!backgroundCall.getState().isAlive())::=%s)",
+                    serviceState,
+                    serviceState != ServiceState.STATE_POWER_OFF,
+                    pendingMO == null,
+                    !ringingCall.isRinging(),
+                    !disableCall.equals("true"),
+                    !foregroundCall.getState().isAlive(),
+                    foregroundCall.getState() == CdmaCall.State.ACTIVE,
+                    !backgroundCall.getState().isAlive()));
+        }
         return ret;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 7d2013b..11e04d4 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
@@ -65,6 +66,13 @@
     CdmaCellLocation cellLoc;
     CdmaCellLocation newCellLoc;
 
+    // Min values used to by getOtasp()
+    private static final String UNACTIVATED_MIN2_VALUE = "000000";
+    private static final String UNACTIVATED_MIN_VALUE = "1111110111";
+
+    // Current Otasp value
+    int mCurrentOtaspMode = OTASP_UNINITIALIZED;
+
      /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
     private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
     private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
@@ -446,6 +454,13 @@
                     if (!mIsMinInfoReady) {
                         mIsMinInfoReady = true;
                     }
+                    int otaspMode = getOtasp();
+                    if (mCurrentOtaspMode != otaspMode) {
+                        Log.d(LOG_TAG, "call phone.notifyOtaspChanged old otaspMode=" +
+                                mCurrentOtaspMode + " new otaspMode=" + otaspMode);
+                        mCurrentOtaspMode = otaspMode;
+                        phone.notifyOtaspChanged(mCurrentOtaspMode);
+                    }
                     phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
                             null);
                 } else {
@@ -642,6 +657,11 @@
         curPlmn = plmn;
     }
 
+    @Override
+    protected Phone getPhone() {
+        return phone;
+    }
+
     /**
      * Handle the result of one of the pollState()-related requests
      */
@@ -1641,10 +1661,6 @@
         return false;
     }
 
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
-    }
-
     public String getMdnNumber() {
         return mMdn;
     }
@@ -1700,6 +1716,32 @@
         }
     }
 
+    /**
+     * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
+     */
+    int getOtasp() {
+        int provisioningState;
+        if (mMin == null || (mMin.length() < 6)) {
+            if (DBG) Log.d(LOG_TAG, "getOtasp: bad mMin='" + mMin + "'");
+            provisioningState = OTASP_UNKNOWN;
+        } else {
+            if ((mMin.equals(UNACTIVATED_MIN_VALUE)
+                    || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
+                    || SystemProperties.getBoolean("test_cdma_setup", false)) {
+                provisioningState = OTASP_NEEDED;
+            } else {
+                provisioningState = OTASP_NOT_NEEDED;
+            }
+        }
+        if (DBG) Log.d(LOG_TAG, "getOtasp: state=" + provisioningState);
+        return provisioningState;
+    }
+
+    @Override
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
+    }
+
     private void hangupAndPowerOff() {
         // hang up all active voice calls
         phone.mCT.ringingCall.hangupIfAlive();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 6332415..bc41b01 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
@@ -226,6 +227,9 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
         phone.getContext().registerReceiver(mIntentReceiver, filter);
+
+        // Gsm doesn't support OTASP so its not needed
+        phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
     }
 
     public void dispose() {
@@ -246,6 +250,11 @@
         if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized");
     }
 
+    @Override
+    public Phone getPhone() {
+        return phone;
+    }
+
     /**
      * Registration point for transition into GPRS attached.
      * @param h handler to notify
@@ -1676,7 +1685,8 @@
         }
     }
 
-    private void log(String s) {
+    @Override
+    protected void log(String s) {
         Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s);
     }
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
index 8cb05cc..7bbe696 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
@@ -56,4 +56,7 @@
 
     public void notifyDataActivity(Phone sender) {
     }
+
+    public void notifyOtaspChanged(Phone sender, int otaspMode) {
+    }
 }