Merge "docs: more ics overview changes... reorg a few sections, revise intro paragraph also update API levels doc with ICS version add info about system themes and using an options menu button" into ics-mr0
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 5f38eb4..c3c9d16 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -72,7 +72,7 @@
      * This is passed as the requiredFeatures parameter in AccountManager.addAccount()
      * if it is called.
      */
-    public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY = 
+    public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY =
             "addAccountRequiredFeatures";
 
     /**
@@ -110,7 +110,6 @@
     private ArrayList<AccountInfo> mAccountInfos;
     private int mPendingRequest = REQUEST_NULL;
     private Parcelable[] mExistingAccounts = null;
-    private Parcelable[] mSavedAccounts = null;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -124,12 +123,10 @@
 
         if (savedInstanceState != null) {
             mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
-            mSavedAccounts =
+            mExistingAccounts =
                     savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
-            mExistingAccounts = null;
         } else {
             mPendingRequest = REQUEST_NULL;
-            mSavedAccounts = null;
             mExistingAccounts = null;
         }
 
@@ -246,7 +243,9 @@
     protected void onSaveInstanceState(final Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);
-        outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
+        if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
+            outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
+        }
     }
 
     // Called when the choose account type activity (for adding an account) returns.
@@ -264,7 +263,6 @@
 
         // we got our result, so clear the fact that we had a pending request
         mPendingRequest = REQUEST_NULL;
-        mExistingAccounts = null;
 
         if (resultCode == RESULT_CANCELED) {
             return;
@@ -293,7 +291,7 @@
                 if (accountName == null || accountType == null) {
                     Account[] currentAccounts = AccountManager.get(this).getAccounts();
                     Set<Account> preExistingAccounts = new HashSet<Account>();
-                    for (Parcelable accountParcel : mSavedAccounts) {
+                    for (Parcelable accountParcel : mExistingAccounts) {
                         preExistingAccounts.add((Account) accountParcel);
                     }
                     for (Account account : currentAccounts) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index d338764..caad6fd 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -116,6 +116,12 @@
  * auto-focus capabilities. In order for your application to be compatible with
  * more devices, you should not make assumptions about the device camera
  * specifications.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using cameras, read the
+ * <a href="{@docRoot}guide/topics/media/camera.html">Camera</a> developer guide.</p>
+ * </div>
  */
 public class Camera {
     private static final String TAG = "Camera";
diff --git a/core/java/android/service/textservice/package.html b/core/java/android/service/textservice/package.html
new file mode 100644
index 0000000..89c6dbc
--- /dev/null
+++ b/core/java/android/service/textservice/package.html
@@ -0,0 +1,38 @@
+<HTML>
+<BODY>
+<p>Provides classes that allow you to create spell checkers in a manner similar to the
+input method framework (for IMEs).</p>
+
+<p>To create a new spell checker, you must implement a service that extends {@link
+android.service.textservice.SpellCheckerService} and extend the {@link
+android.service.textservice.SpellCheckerService.Session} class to provide spelling suggestions based
+on text provided by the interface's callback methods. In the {@link
+android.service.textservice.SpellCheckerService.Session} callback methods, you must return the
+spelling suggestions as {@link android.view.textservice.SuggestionsInfo} objects. </p>
+
+<p>Applications with a spell checker service must declare the {@link
+android.Manifest.permission#BIND_TEXT_SERVICE} permission as required by the service. The service
+must also declare an intent filter with {@code &lt;action
+android:name="android.service.textservice.SpellCheckerService" />} as the intent’s action and should
+include a {@code &lt;meta-data&gt;} element that declares configuration information for the spell
+checker. For example:</p>
+
+<pre>
+&lt;service
+    android:label="&#064;string/app_name"
+    android:name=".SampleSpellCheckerService"
+    android:permission="android.permission.BIND_TEXT_SERVICE" >
+    &lt;intent-filter >
+        &lt;action android:name="android.service.textservice.SpellCheckerService" />
+    &lt;/intent-filter>
+    &lt;meta-data
+        android:name="android.view.textservice.scs"
+        android:resource="&#064;xml/spellchecker" />
+&lt;/service>
+</pre>
+
+<p>For example code, see the <a
+href="{@docRoot}resources/samples/SampleSpellCheckerService/index.html">Spell
+Checker</a> sample app.</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7eae739..081e267 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -108,6 +108,7 @@
     private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
+    private static final boolean DEBUG_FPS = false;
     private static final boolean WATCH_POINTER = false;
 
     /**
@@ -274,6 +275,11 @@
     private Thread mRenderProfiler;
     private volatile boolean mRenderProfilingEnabled;
 
+    // Variables to track frames per second, enabled via DEBUG_FPS flag
+    private long mFpsStartTime = -1;
+    private long mFpsPrevTime = -1;
+    private int mFpsNumFrames;
+
     /**
      * see {@link #playSoundEffect(int)}
      */
@@ -1766,12 +1772,42 @@
         }
     }
 
+    /**
+     * Called from draw() when DEBUG_FPS is enabled
+     */
+    private void trackFPS() {
+        // Tracks frames per second drawn. First value in a series of draws may be bogus
+        // because it down not account for the intervening idle time
+        long nowTime = System.currentTimeMillis();
+        if (mFpsStartTime < 0) {
+            mFpsStartTime = mFpsPrevTime = nowTime;
+            mFpsNumFrames = 0;
+        } else {
+            ++mFpsNumFrames;
+            String thisHash = Integer.toHexString(System.identityHashCode(this));
+            long frameTime = nowTime - mFpsPrevTime;
+            long totalTime = nowTime - mFpsStartTime;
+            Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
+            mFpsPrevTime = nowTime;
+            if (totalTime > 1000) {
+                float fps = (float) mFpsNumFrames * 1000 / totalTime;
+                Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
+                mFpsStartTime = nowTime;
+                mFpsNumFrames = 0;
+            }
+        }
+    }
+
     private void draw(boolean fullRedrawNeeded) {
         Surface surface = mSurface;
         if (surface == null || !surface.isValid()) {
             return;
         }
 
+        if (DEBUG_FPS) {
+            trackFPS();
+        }
+
         if (!sFirstDrawComplete) {
             synchronized (sFirstDrawHandlers) {
                 sFirstDrawComplete = true;
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index ac0dc35..18a4794 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -22,8 +22,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Typeface;
 import android.os.Handler;
@@ -61,6 +59,14 @@
     private final Handler mHandler = new Handler();
     private BroadcastReceiver mIntentReceiver;
 
+    private static final Typeface sBackgroundFont;
+    private static final Typeface sForegroundFont;
+
+    static {
+        sBackgroundFont = Typeface.createFromFile(SYSTEM_FONT_TIME_BACKGROUND);
+        sForegroundFont = Typeface.createFromFile(SYSTEM_FONT_TIME_FOREGROUND);
+    }
+
     private static class TimeChangedReceiver extends BroadcastReceiver {
         private WeakReference<DigitalClock> mClock;
         private Context mContext;
@@ -159,13 +165,11 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        AssetManager assets = mContext.getAssets();
-
         /* The time display consists of two tones. That's why we have two overlapping text views. */
         mTimeDisplayBackground = (TextView) findViewById(R.id.timeDisplayBackground);
-        mTimeDisplayBackground.setTypeface(Typeface.createFromFile(SYSTEM_FONT_TIME_BACKGROUND));
+        mTimeDisplayBackground.setTypeface(sBackgroundFont);
         mTimeDisplayForeground = (TextView) findViewById(R.id.timeDisplayForeground);
-        mTimeDisplayForeground.setTypeface(Typeface.createFromFile(SYSTEM_FONT_TIME_FOREGROUND));
+        mTimeDisplayForeground.setTypeface(sForegroundFont);
         mAmPm = new AmPm(this, null);
         mCalendar = Calendar.getInstance();
 
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index e34822d..803047e 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -206,7 +206,7 @@
 
     <!-- Area to overlay FaceLock -->
     <TextView android:id="@+id/faceLockAreaView"
-        android:visibility="gone"
+        android:visibility="invisible"
         android:layout_row="0"
         android:layout_column="2"
         android:layout_rowSpan="8"
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index e1280ba..6b03359 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -195,7 +195,7 @@
 
     <!-- Area to overlay FaceLock -->
     <TextView android:id="@+id/faceLockAreaView"
-        android:visibility="gone"
+        android:visibility="invisible"
         android:layout_row="3"
         android:layout_column="0"
         android:layout_rowSpan="2"
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 2778f4e..1038657 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -162,7 +162,7 @@
 
     <!-- Area to overlay FaceLock -->
     <TextView android:id="@+id/faceLockAreaView"
-        android:visibility="gone"
+        android:visibility="invisible"
         android:layout_row="0"
         android:layout_column="1"
         android:layout_rowSpan="7"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 03fc79e..f286ccd 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -174,7 +174,7 @@
 
     <!-- Area to overlay FaceLock -->
     <TextView android:id="@+id/faceLockAreaView"
-        android:visibility="gone"
+        android:visibility="invisible"
         android:layout_row="4"
         android:layout_column="0"
         android:layout_rowSpan="1"
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..d000f7e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..f19dc93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..80fc849
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_bg.xml
deleted file mode 100644
index 320ed40..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/recents_thumbnail_bg_dragging" android:state_activated="true" />
-    <item android:drawable="@*android:color/transparent"/>
-</selector>
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
index d683af9..7033077 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
@@ -16,5 +16,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_selected="true" />
     <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+    <item android:drawable="@drawable/recents_thumbnail_bg_dragging" android:state_activated="true" />
     <item android:drawable="@*android:color/transparent"/>
 </selector>
diff --git a/packages/SystemUI/res/drawable/status_bar_recents_background.xml b/packages/SystemUI/res/drawable/status_bar_recents_background.xml
new file mode 100644
index 0000000..8b22bf1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/status_bar_recents_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <gradient name="status_bar_recents_background"
+            android:startColor="#cc000000"
+            android:endColor="#66000000"
+            android:angle="@integer/status_bar_recents_bg_gradient_degrees"
+	    />
+</shape>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
new file mode 100644
index 0000000..bbae18d
--- /dev/null
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Whether we're using the tablet-optimized recents interface (we use this
+     value at runtime for some things) -->
+    <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
+</resources>
+
diff --git a/packages/SystemUI/res/values-port/config.xml b/packages/SystemUI/res/values-port/config.xml
new file mode 100644
index 0000000..bbae18d
--- /dev/null
+++ b/packages/SystemUI/res/values-port/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Whether we're using the tablet-optimized recents interface (we use this
+     value at runtime for some things) -->
+    <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
+</resources>
+
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 555baa2..bce0bc4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,7 +22,7 @@
     <drawable name="notification_item_background_color_pressed">#ff257390</drawable>
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
     <drawable name="status_bar_background">#ff000000</drawable>
-    <drawable name="status_bar_recents_background">#b3000000</drawable>
+    <drawable name="status_bar_recents_background_solid">#b3000000</drawable>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <color name="status_bar_recents_app_label_color">#ffffffff</color>
     <drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a717b57..b26709d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -169,19 +169,19 @@
     <string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
 
     <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
-    <string name="screenshot_saving_ticker">Saving...</string>
+    <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
     <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
-    <string name="screenshot_saving_title">Saving screenshot...</string>
+    <string name="screenshot_saving_title">Saving screenshot\u2026</string>
     <!-- Notification text displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=100] -->
-    <string name="screenshot_saving_text">Please wait for screenshot to be saved</string>
+    <string name="screenshot_saving_text">Screenshot is being saved.</string>
     <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
-    <string name="screenshot_saved_title">Screenshot captured</string>
+    <string name="screenshot_saved_title">Screenshot captured.</string>
     <!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] -->
-    <string name="screenshot_saved_text">Touch to view your screenshot</string>
+    <string name="screenshot_saved_text">Touch to view your screenshot.</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
-    <string name="screenshot_failed_title">Screenshot failed</string>
+    <string name="screenshot_failed_title">Couldn\'t capture screenshot.</string>
     <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
-    <string name="screenshot_failed_text">Failed to save screenshot. External storage may be in use.</string>
+    <string name="screenshot_failed_text">Couldn\'t save screenshot. Storage may be in use.</string>
 
     <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
     <string name="usb_preference_title">USB file transfer options</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 07281d4..14ce266 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -17,6 +17,7 @@
 package com.android.systemui;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.ValueAnimator;
@@ -40,6 +41,8 @@
     public static final int X = 0;
     public static final int Y = 1;
 
+    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
     private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
@@ -199,6 +202,10 @@
         return mDragging;
     }
 
+    /**
+     * @param view The view to be dismissed
+     * @param velocity The desired pixels/second speed at which the view should move
+     */
     public void dismissChild(final View view, float velocity) {
         final View animView = mCallback.getChildContentView(view);
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
@@ -221,22 +228,14 @@
             duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
         }
 
+        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
-        anim.setInterpolator(new LinearInterpolator());
+        anim.setInterpolator(sLinearInterpolator);
         anim.setDuration(duration);
-        anim.addListener(new AnimatorListener() {
-            public void onAnimationStart(Animator animation) {
-            }
-
-            public void onAnimationRepeat(Animator animation) {
-            }
-
+        anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animation) {
                 mCallback.onChildDismissed(view);
-            }
-
-            public void onAnimationCancel(Animator animation) {
-                mCallback.onChildDismissed(view);
+                animView.setLayerType(View.LAYER_TYPE_NONE, null);
             }
         });
         anim.addUpdateListener(new AnimatorUpdateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 8d5c33f..bd1fcfc 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -230,7 +230,7 @@
 
     public void handleShowBackground(boolean show) {
         if (show) {
-            mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background);
+            mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background_solid);
         } else {
             mRecentsScrim.setBackgroundDrawable(null);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
index b7e656e..813099a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -83,7 +83,7 @@
             mLinearLayout = layout;
             mAttachedToWindow = true;
             mBackgroundDrawable = mContext.getResources()
-                .getDrawable(R.drawable.status_bar_recents_background).getConstantState();
+                .getDrawable(R.drawable.status_bar_recents_background_solid).getConstantState();
             updateShowBackground();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 181cc98..301ae73 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -38,6 +38,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Environment;
+import android.os.Process;
 import android.os.ServiceManager;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
@@ -54,7 +55,6 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
-import com.android.server.wm.WindowManagerService;
 import com.android.systemui.R;
 
 import java.io.File;
@@ -68,6 +68,7 @@
 class SaveImageInBackgroundData {
     Context context;
     Bitmap image;
+    Uri imageUri;
     Runnable finisher;
     int iconSize;
     int result;
@@ -128,9 +129,6 @@
                 (iconHeight - data.iconSize) / 2, data.iconSize, data.iconSize);
 
         // Show the intermediate notification
-        mLaunchIntent = new Intent(Intent.ACTION_VIEW);
-        mLaunchIntent.setDataAndType(Uri.fromFile(new File(mImageFilePath)), "image/png");
-        mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mTickerAddSpace = !mTickerAddSpace;
         mNotificationId = nId;
         mNotificationBuilder = new Notification.Builder(context)
@@ -152,6 +150,10 @@
     protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
         if (params.length != 1) return null;
 
+        // By default, AsyncTask sets the worker thread to have background thread priority, so bump
+        // it back up so that we save a little quicker.
+        Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+
         Context context = params[0].context;
         Bitmap image = params[0].image;
 
@@ -178,6 +180,7 @@
             values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
             resolver.update(uri, values, null, null);
 
+            params[0].imageUri = uri;
             params[0].result = 0;
         } catch (Exception e) {
             // IOException/UnsupportedOperationException may be thrown if external storage is not
@@ -197,6 +200,11 @@
             // Show the final notification to indicate screenshot saved
             Resources r = params.context.getResources();
 
+            // Create the intent to show the screenshot in gallery
+            mLaunchIntent = new Intent(Intent.ACTION_VIEW);
+            mLaunchIntent.setDataAndType(params.imageUri, "image/png");
+            mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
             mNotificationBuilder
                 .setContentTitle(r.getString(R.string.screenshot_saved_title))
                 .setContentText(r.getString(R.string.screenshot_saved_text))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4e9b411..b724552 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -50,7 +50,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
@@ -213,6 +212,8 @@
     boolean mAnimatingReveal = false;
     int mViewDelta;
     int[] mAbsPos = new int[2];
+    Runnable mPostCollapseCleanup = null;
+
 
     // for disabling the status bar
     int mDisabled = 0;
@@ -1238,6 +1239,10 @@
             return;
         }
         mExpanded = false;
+        if (mPostCollapseCleanup != null) {
+            mPostCollapseCleanup.run();
+            mPostCollapseCleanup = null;
+        }
     }
 
     void doAnimation() {
@@ -2066,49 +2071,67 @@
         }
         public void onClick(View v) {
             synchronized (mNotificationData) {
-                // let's also queue up 400ms worth of animated dismissals
-                final int N = mini(5, mPile.getChildCount());
+                // animate-swipe all dismissable notifications, then animate the shade closed
+                int numChildren = mPile.getChildCount();
 
-                final ArrayList<View> snapshot = new ArrayList<View>(N);
-                for (int i=0; i<N; i++) {
+                int scrollTop = mScrollView.getScrollY();
+                int scrollBottom = scrollTop + mScrollView.getHeight();
+                final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
+                for (int i=0; i<numChildren; i++) {
                     final View child = mPile.getChildAt(i);
-                    if (mPile.canChildBeDismissed(child)) snapshot.add(child);
+                    if (mPile.canChildBeDismissed(child) && child.getBottom() > scrollTop &&
+                            child.getTop() < scrollBottom) {
+                        snapshot.add(child);
+                    }
                 }
+                final int N = snapshot.size();
                 new Thread(new Runnable() {
                     @Override
                     public void run() {
-                        final int ROW_DELAY = 100;
+                        // Decrease the delay for every row we animate to give the sense of
+                        // accelerating the swipes
+                        final int ROW_DELAY_DECREMENT = 10;
+                        int currentDelay = 140;
+                        int totalDelay = 0;
 
-                        mHandler.postDelayed(new Runnable() {
-                            public void run() {
-                                animateCollapse(false, 0f);
-                            }
-                        }, (N-1) * ROW_DELAY);
+                        // Set the shade-animating state to avoid doing other work during
+                        // all of these animations. In particular, avoid layout and
+                        // redrawing when collapsing the shade.
+                        mPile.setViewRemoval(false);
 
-                        mHandler.postDelayed(new Runnable() {
+                        mPostCollapseCleanup = new Runnable() {
                             public void run() {
                                 try {
+                                    mPile.setViewRemoval(true);
                                     mBarService.onClearAllNotifications();
-                                } catch (RemoteException ex) { }
+                                } catch (Exception ex) { }
                             }
-                        }, N * ROW_DELAY + 500);
+                        };
 
-                        mPile.setAnimateBounds(false); // temporarily disable some re-layouts
-
+                        View sampleView = snapshot.get(0);
+                        int width = sampleView.getWidth();
+                        final int velocity = (int)(width * 8); // 1000/8 = 125 ms duration
                         for (View v : snapshot) {
                             final View _v = v;
-                            mHandler.post(new Runnable() {
+                            mHandler.postDelayed(new Runnable() {
                                 @Override
                                 public void run() {
-                                    mPile.dismissRowAnimated(_v, (int)(ROW_DELAY*0.25f));
+                                    mPile.dismissRowAnimated(_v, velocity);
                                 }
-                            });
-                            try {
-                                Thread.sleep(ROW_DELAY);
-                            } catch (InterruptedException ex) { }
+                            }, totalDelay);
+                            currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
+                            totalDelay += currentDelay;
                         }
-                        
-                        mPile.setAnimateBounds(true); // reenable layout animation
+                        // Delay the collapse animation until after all swipe animations have
+                        // finished. Provide some buffer because there may be some extra delay
+                        // before actually starting each swipe animation. Ideally, we'd
+                        // synchronize the end of those animations with the start of the collaps
+                        // exactly.
+                        mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                animateCollapse(false);
+                            }
+                        }, totalDelay + 225);
                     }
                 }).start();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index a7342dc..3649f75e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -29,7 +28,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
@@ -59,6 +57,10 @@
 
     private SwipeHelper mSwipeHelper;
 
+    // Flag set during notification removal animation to avoid causing too much work until
+    // animation is done
+    boolean mRemoveViews = true;
+
     public NotificationRowLayout(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -117,7 +119,7 @@
 
     public void onChildDismissed(View v) {
         final View veto = v.findViewById(R.id.veto);
-        if (veto != null && veto.getVisibility() != View.GONE) {
+        if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
             veto.performClick();
         }
     }
@@ -170,7 +172,6 @@
         final View childF = child;
 
         if (mAnimateBounds) {
-            child.setPivotY(0);
             final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
             alphaFade.setDuration(APPEAR_ANIM_LEN);
             alphaFade.addListener(new AnimatorListenerAdapter() {
@@ -189,6 +190,16 @@
         }
     }
 
+    /**
+     * Sets a flag to tell us whether to actually remove views. Removal is delayed by setting this
+     * to false during some animations to smooth out performance. Callers should restore the
+     * flag to true after the animation is done, and then they should make sure that the views
+     * get removed properly.
+     */
+    public void setViewRemoval(boolean removeViews) {
+        mRemoveViews = removeViews;
+    }
+
     public void dismissRowAnimated(View child) {
         dismissRowAnimated(child, 0);
     }
@@ -199,16 +210,34 @@
 
     @Override
     public void removeView(View child) {
-        final View childF = child;
+        if (!mRemoveViews) {
+            // This flag is cleared during an animation that removes all notifications. There
+            // should be a call to remove all notifications when the animation is done, at which
+            // time the view will be removed.
+            return;
+        }
         if (mAnimateBounds) {
             if (mAppearingViews.containsKey(child)) {
                 mAppearingViews.remove(child);
             }
-            child.setPivotY(0);
 
-            final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
-            alphaFade.setDuration(DISAPPEAR_ANIM_LEN);
-            alphaFade.addListener(new AnimatorListenerAdapter() {
+            // Don't fade it out if it already has a low alpha value, but run a non-visual
+            // animation which is used by onLayout() to animate shrinking the gap that it left
+            // in the list
+            ValueAnimator anim;
+            float currentAlpha = child.getAlpha();
+            if (currentAlpha > .1) {
+                anim = ObjectAnimator.ofFloat(child, "alpha", currentAlpha, 0);
+            } else {
+                if (currentAlpha > 0) {
+                    // Just make it go away - no need to render it anymore
+                    child.setAlpha(0);
+                }
+                anim = ValueAnimator.ofFloat(0, 1);
+            }
+            anim.setDuration(DISAPPEAR_ANIM_LEN);
+            final View childF = child;
+            anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
@@ -218,9 +247,8 @@
                 }
             });
 
-            alphaFade.start();
-
-            mDisappearingViews.put(child, alphaFade);
+            anim.start();
+            mDisappearingViews.put(child, anim);
 
             requestLayout(); // start the container animation
         } else {
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 96998af..2e63a60 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -421,16 +421,20 @@
                         Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
                         showWipeDialog(failedAttempts);
                     }
-                } else if (usingPattern && mEnableFallback) {
-                    if (failedAttempts == failedAttemptWarning) {
-                        showAlmostAtAccountLoginDialog();
-                    } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
-                        mLockPatternUtils.setPermanentlyLocked(true);
-                        updateScreen(mMode, false);
-                    }
                 } else {
-                    final boolean showTimeout =
+                    boolean showTimeout =
                         (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
+                    if (usingPattern && mEnableFallback) {
+                        if (failedAttempts == failedAttemptWarning) {
+                            showAlmostAtAccountLoginDialog();
+                            showTimeout = false; // don't show both dialogs
+                        } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
+                            mLockPatternUtils.setPermanentlyLocked(true);
+                            updateScreen(mMode, false);
+                            // don't show timeout dialog because we show account unlock screen next
+                            showTimeout = false;
+                        }
+                    }
                     if (showTimeout) {
                         showTimeoutDialog();
                     }
@@ -1136,14 +1140,25 @@
 
     // Everything below pertains to FaceLock - might want to separate this out
 
-    // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not
-    // uncommon for it to not exist.  But if it does exist, we need to make sure it's shown (hiding
-    // the fallback) if FaceLock is enabled, and make sure it's hidden (showing the unlock) if
-    // FaceLock is disabled
+    // Take care of FaceLock area when layout is created
     private void initializeFaceLockAreaView(View view) {
-        mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView);
-        if (mFaceLockAreaView == null) {
-            if (DEBUG) Log.d(TAG, "Layout does not have faceLockAreaView");
+        if (mLockPatternUtils.usingBiometricWeak() &&
+                mLockPatternUtils.isBiometricWeakInstalled()) {
+            mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView);
+            if (mFaceLockAreaView == null) {
+                Log.e(TAG, "Layout does not have faceLockAreaView and FaceLock is enabled");
+            } else {
+                if (mBoundToFaceLockService) {
+                    // If we are creating a layout when we are already bound to FaceLock, then we
+                    // are undergoing an orientation change.  Stop FaceLock and restart it in the
+                    // new location.
+                    if (DEBUG) Log.d(TAG, "Restarting FL - creating view while already bound");
+                    stopAndUnbindFromFaceLock();
+                    activateFaceLockIfAble();
+                }
+            }
+        } else {
+            mFaceLockAreaView = null; // Set to null if not using FaceLock
         }
     }
 
@@ -1160,7 +1175,7 @@
             break;
         case MSG_HIDE_FACELOCK_AREA_VIEW:
             if (mFaceLockAreaView != null) {
-                mFaceLockAreaView.setVisibility(View.GONE);
+                mFaceLockAreaView.setVisibility(View.INVISIBLE);
             }
             break;
         default:
@@ -1196,7 +1211,8 @@
         mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, timeoutMillis);
     }
 
-    // Binds to FaceLock service, but does not tell it to start
+    // Binds to FaceLock service.  This call does not tell it to start, but it causes the service
+    // to call the onServiceConnected callback, which then starts FaceLock.
     public void bindToFaceLock() {
         if (mLockPatternUtils.usingBiometricWeak() &&
                 mLockPatternUtils.isBiometricWeakInstalled()) {
@@ -1232,9 +1248,10 @@
                 if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
                 mBoundToFaceLockService = false;
             } else {
-                // This could probably happen after the session when someone activates FaceLock
-                // because it wasn't active when the phone was turned on
-                Log.w(TAG, "Attempt to unbind from FaceLock when not bound");
+                // This is usually not an error when this happens.  Sometimes we will tell it to
+                // unbind multiple times because it's called from both onWindowFocusChanged and
+                // onDetachedFromWindow.
+                if (DEBUG) Log.d(TAG, "Attempt to unbind from FaceLock when not bound");
             }
         }
     }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 3c6b416..41cf9a6 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -487,8 +487,16 @@
                 }
             } break;
             case MotionEvent.ACTION_POINTER_UP: {
-                // Send an event to the end of the drag gesture.
-                sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                final int activePointerCount = mPointerTracker.getActivePointerCount();
+                switch (activePointerCount) {
+                    case 1: {
+                        // Send an event to the end of the drag gesture.
+                        sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                    } break;
+                    default: {
+                        mCurrentState = STATE_TOUCH_EXPLORING;
+                    }
+                }
              } break;
             case MotionEvent.ACTION_UP: {
                 mCurrentState = STATE_TOUCH_EXPLORING;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 55fb371..0d6f405 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -165,7 +165,7 @@
     static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
     static final boolean DEBUG_USER_LEAVING = localLOGV || false;
     static final boolean DEBUG_RESULTS = localLOGV || false;
-    static final boolean DEBUG_BACKUP = localLOGV || true;
+    static final boolean DEBUG_BACKUP = localLOGV || false;
     static final boolean DEBUG_CONFIGURATION = localLOGV || false;
     static final boolean DEBUG_POWER = localLOGV || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
@@ -2607,9 +2607,18 @@
                 TAG, "Record #" + i + " " + r + ": app=" + r.app);
             if (r.app == app) {
                 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
-                    if (localLOGV) Slog.v(
-                        TAG, "Removing this entry!  frozen=" + r.haveState
-                        + " finishing=" + r.finishing);
+                    if (ActivityStack.DEBUG_ADD_REMOVE) {
+                        RuntimeException here = new RuntimeException("here");
+                        here.fillInStackTrace();
+                        Slog.i(TAG, "Removing activity " + r + " from stack at " + i
+                                + ": haveState=" + r.haveState
+                                + " stateNotNeeded=" + r.stateNotNeeded
+                                + " finishing=" + r.finishing
+                                + " state=" + r.state, here);
+                    }
+                    if (!r.finishing) {
+                        Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+                    }
                     r.makeFinishing();
                     mMainStack.mHistory.remove(i);
                     r.takeFromHistory();
@@ -2630,6 +2639,8 @@
                     r.app = null;
                     r.nowVisible = false;
                     if (!r.haveState) {
+                        if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG,
+                                "App died, clearing saved state of " + r);
                         r.icicle = null;
                     }
                 }
@@ -4479,7 +4490,7 @@
             }
         }
         if (pi == null) {
-            Slog.w(TAG, "No content provider found for: " + name);
+            Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString());
             return -1;
         }
 
@@ -4735,7 +4746,7 @@
             }
         }
         if (pi == null) {
-            Slog.w(TAG, "No content provider found for: " + authority);
+            Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString());
             return;
         }
 
@@ -4829,7 +4840,8 @@
                 }
             }
             if (pi == null) {
-                Slog.w(TAG, "No content provider found for: " + authority);
+                Slog.w(TAG, "No content provider found for permission revoke: "
+                        + uri.toSafeString());
                 return;
             }
 
@@ -13054,11 +13066,13 @@
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                app.hidden = false;
                 app.adjType = "foreground-service";
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                app.hidden = false;
                 app.adjType = "force-foreground";
                 app.adjSource = app.forcingToForeground;
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13069,6 +13083,7 @@
             // We don't want to kill the current heavy-weight process.
             adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.hidden = false;
             app.adjType = "heavy";
         }
 
@@ -13077,11 +13092,13 @@
             // home app, so we don't want to let it go into the background.
             adj = ProcessList.HOME_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.hidden = false;
             app.adjType = "home";
         }
-        
-        //Slog.i(TAG, "OOM " + app + ": initial adj=" + adj);
-        
+
+        if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+                + " reason=" + app.adjType);
+
         // By default, we use the computed adjustment.  It may be changed if
         // there are applications dependent on our services or providers, but
         // this gives us a baseline and makes sure we don't get into an
@@ -13108,7 +13125,7 @@
             while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                 ServiceRecord s = jt.next();
                 if (s.startRequested) {
-                    if (app.hasShownUi) {
+                    if (app.hasShownUi && app != mHomeProcess) {
                         // If this process has shown some UI, let it immediately
                         // go to the LRU list because it may be pretty heavy with
                         // UI stuff.  We'll tag it with a label just to help
@@ -13169,7 +13186,7 @@
                                 if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                                     // Not doing bind OOM management, so treat
                                     // this guy more like a started service.
-                                    if (app.hasShownUi) {
+                                    if (app.hasShownUi && app != mHomeProcess) {
                                         // If this process has shown some UI, let it immediately
                                         // go to the LRU list because it may be pretty heavy with
                                         // UI stuff.  We'll tag it with a label just to help
@@ -13177,6 +13194,7 @@
                                         if (adj > clientAdj) {
                                             adjType = "bound-bg-ui-services";
                                         }
+                                        app.hidden = false;
                                         clientAdj = adj;
                                     } else {
                                         if (now >= (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
@@ -13200,7 +13218,8 @@
                                     // about letting this process get into the LRU
                                     // list to be killed and restarted if needed for
                                     // memory.
-                                    if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                    if (app.hasShownUi && app != mHomeProcess
+                                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                         adjType = "bound-bg-ui-services";
                                     } else {
                                         if ((cr.flags&(Context.BIND_ABOVE_CLIENT
@@ -13294,7 +13313,8 @@
                         int clientAdj = computeOomAdjLocked(
                             client, myHiddenAdj, TOP_APP, true);
                         if (adj > clientAdj) {
-                            if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                            if (app.hasShownUi && app != mHomeProcess
+                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 app.adjType = "bg-ui-provider";
                             } else {
                                 adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 1aed7fe0..28c3bae 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -87,6 +87,8 @@
     static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
     
     static final boolean DEBUG_STATES = false;
+    static final boolean DEBUG_ADD_REMOVE = false;
+    static final boolean DEBUG_SAVED_STATE = false;
 
     static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
     
@@ -653,6 +655,9 @@
             }
             completeResumeLocked(r);
             checkReadyForSleepLocked();
+            if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
+            r.icicle = null;
+            r.haveState = false;
         } else {
             // This activity is not starting in the resumed state... which
             // should look like we asked it to pause+stop (but remain visible),
@@ -664,9 +669,6 @@
             r.stopped = true;
         }
 
-        r.icicle = null;
-        r.haveState = false;
-
         // Launch the new version setup screen if needed.  We do this -after-
         // launching the initial activity (that is, home), so that it can have
         // a chance to initialize itself while in the background, making the
@@ -936,6 +938,7 @@
 
     final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
             CharSequence description) {
+        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
         r.icicle = icicle;
         r.haveState = true;
         r.updateThumbnail(thumbnail, description);
@@ -1544,6 +1547,7 @@
             }
 
             // Didn't need to use the icicle, and it is now out of date.
+            if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next);
             next.icicle = null;
             next.haveState = false;
             next.stopped = false;
@@ -1590,6 +1594,12 @@
                     // get started when the user navigates back to it.
                     addPos = i+1;
                     if (!startIt) {
+                        if (DEBUG_ADD_REMOVE) {
+                            RuntimeException here = new RuntimeException("here");
+                            here.fillInStackTrace();
+                            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
+                                    here);
+                        }
                         mHistory.add(addPos, r);
                         r.putInHistory();
                         mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
@@ -1622,6 +1632,11 @@
         }
         
         // Slot the activity into the history stack and proceed
+        if (DEBUG_ADD_REMOVE) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
+        }
         mHistory.add(addPos, r);
         r.putInHistory();
         r.frontOfTask = newTask;
@@ -1818,6 +1833,12 @@
                                     + " out to target's task " + target.task);
                             p.setTask(target.task, curThumbHolder, false);
                             curThumbHolder = p.thumbHolder;
+                            if (DEBUG_ADD_REMOVE) {
+                                RuntimeException here = new RuntimeException("here");
+                                here.fillInStackTrace();
+                                Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
+                                        + dstPos, here);
+                            }
                             mHistory.remove(srcPos);
                             mHistory.add(dstPos, p);
                             mService.mWindowManager.moveAppToken(dstPos, p);
@@ -1945,6 +1966,12 @@
                         } else {
                             lastReparentPos--;
                         }
+                        if (DEBUG_ADD_REMOVE) {
+                            RuntimeException here = new RuntimeException("here");
+                            here.fillInStackTrace();
+                            Slog.i(TAG, "Removing and adding activity " + p + " to stack at "
+                                    + lastReparentPos, here);
+                        }
                         mHistory.remove(srcPos);
                         p.setTask(task, null, false);
                         mHistory.add(lastReparentPos, p);
@@ -2143,6 +2170,12 @@
         ActivityRecord newTop = mHistory.remove(where);
         int top = mHistory.size();
         ActivityRecord oldTop = mHistory.get(top-1);
+        if (DEBUG_ADD_REMOVE) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.i(TAG, "Removing and adding activity " + newTop + " to stack at "
+                    + top, here);
+        }
         mHistory.add(top, newTop);
         oldTop.frontOfTask = false;
         newTop.frontOfTask = true;
@@ -2183,7 +2216,7 @@
         if (resultTo != null) {
             int index = indexOfTokenLocked(resultTo);
             if (DEBUG_RESULTS) Slog.v(
-                TAG, "Sending result to " + resultTo + " (index " + index + ")");
+                TAG, "Will send result to " + resultTo + " (index " + index + ")");
             if (index >= 0) {
                 sourceRecord = mHistory.get(index);
                 if (requestCode >= 0 && !sourceRecord.finishing) {
@@ -3279,34 +3312,15 @@
      */
     final boolean requestFinishActivityLocked(IBinder token, int resultCode,
             Intent resultData, String reason) {
-        if (DEBUG_RESULTS) Slog.v(
-            TAG, "Finishing activity: token=" + token
-            + ", result=" + resultCode + ", data=" + resultData);
-
         int index = indexOfTokenLocked(token);
+        if (DEBUG_RESULTS) Slog.v(
+                TAG, "Finishing activity @" + index + ": token=" + token
+                + ", result=" + resultCode + ", data=" + resultData);
         if (index < 0) {
             return false;
         }
         ActivityRecord r = mHistory.get(index);
 
-        // Is this the last activity left?
-        boolean lastActivity = true;
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord p = mHistory.get(i);
-            if (!p.finishing && p != r) {
-                lastActivity = false;
-                break;
-            }
-        }
-        
-        // If this is the last activity, but it is the home activity, then
-        // just don't finish it.
-        if (lastActivity) {
-            if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
-                return false;
-            }
-        }
-        
         finishActivityLocked(r, index, resultCode, resultData, reason);
         return true;
     }
@@ -3538,6 +3552,11 @@
     private final void removeActivityFromHistoryLocked(ActivityRecord r) {
         if (r.state != ActivityState.DESTROYED) {
             r.makeFinishing();
+            if (DEBUG_ADD_REMOVE) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.i(TAG, "Removing activity " + r + " from stack");
+            }
             mHistory.remove(r);
             r.takeFromHistory();
             if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
@@ -3769,6 +3788,11 @@
                 TAG, "At " + pos + " ckp " + r.task + ": " + r);
             if (r.task.taskId == task) {
                 if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
+                if (DEBUG_ADD_REMOVE) {
+                    RuntimeException here = new RuntimeException("here");
+                    here.fillInStackTrace();
+                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at " + top, here);
+                }
                 mHistory.remove(pos);
                 mHistory.add(top, r);
                 moved.add(0, r);
@@ -3858,6 +3882,12 @@
                 TAG, "At " + pos + " ckp " + r.task + ": " + r);
             if (r.task.taskId == task) {
                 if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
+                if (DEBUG_ADD_REMOVE) {
+                    RuntimeException here = new RuntimeException("here");
+                    here.fillInStackTrace();
+                    Slog.i(TAG, "Removing and adding activity " + r + " to stack at "
+                            + bottom, here);
+                }
                 mHistory.remove(pos);
                 mHistory.add(bottom, r);
                 moved.add(r);
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 759a84b..97e7aa3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -676,6 +676,15 @@
         return result;
     }
 
+    protected boolean isEmergency() {
+        final boolean result;
+        synchronized (mDataEnabledLock) {
+            result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
+        }
+        log("isEmergency: result=" + result);
+        return result;
+    }
+
     protected int apnTypeToId(String type) {
         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
             return APN_DEFAULT_ID;
@@ -981,17 +990,14 @@
 
     protected void onSetInternalDataEnabled(boolean enabled) {
         synchronized (mDataEnabledLock) {
-            final boolean prevEnabled = getAnyDataEnabled();
-            if (mInternalDataEnabled != enabled) {
-                mInternalDataEnabled = enabled;
-                if (prevEnabled != getAnyDataEnabled()) {
-                    if (!prevEnabled) {
-                        resetAllRetryCounts();
-                        onTrySetupData(Phone.REASON_DATA_ENABLED);
-                    } else {
-                        cleanUpAllConnections(null);
-                    }
-                }
+            mInternalDataEnabled = enabled;
+            if (enabled) {
+                log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
+                resetAllRetryCounts();
+                onTrySetupData(Phone.REASON_DATA_ENABLED);
+            } else {
+                log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
+                cleanUpAllConnections(null);
             }
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index a3f4f1f..2e99849 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -208,6 +208,24 @@
      * Converts a String into a byte array containing the 7-bit packed
      * GSM Alphabet representation of the string. If a header is provided,
      * this is included in the returned byte array and padded to a septet
+     * boundary. This method is used by OEM code.
+     *
+     * @param data The text string to encode.
+     * @param header Optional header (including length byte) that precedes
+     * the encoded data, padded to septet boundary.
+     * @return Byte array containing header and encoded data.
+     * @throws EncodeException if String is too large to encode
+     * @see #stringToGsm7BitPackedWithHeader(String, byte[], int, int)
+     */
+    public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header)
+            throws EncodeException {
+        return stringToGsm7BitPackedWithHeader(data, header, 0, 0);
+    }
+
+    /**
+     * Converts a String into a byte array containing the 7-bit packed
+     * GSM Alphabet representation of the string. If a header is provided,
+     * this is included in the returned byte array and padded to a septet
      * boundary.
      *
      * Unencodable chars are encoded as spaces
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index a7a4908..10121dd 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -832,6 +832,22 @@
         mNotifier.notifyOtaspChanged(this, otaspMode);
     }
 
+    /**
+     * @return true if a mobile originating emergency call is active
+     */
+    public boolean isInEmergencyCall() {
+        return false;
+    }
+
+    /**
+     * @return true if we are in the emergency call back mode. This is a period where
+     * the phone should be using as little power as possible and be ready to receive an
+     * incoming call from the emergency operator.
+     */
+    public boolean isInEcm() {
+        return false;
+    }
+
     public abstract String getPhoneName();
 
     public abstract int getPhoneType();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 09ee28c..58e3e5f 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -848,6 +848,14 @@
         mUnknownConnectionRegistrants.notifyResult(this);
     }
 
+    public boolean isInEmergencyCall() {
+        return mCT.isInEmergencyCall();
+    }
+
+    public boolean isInEcm() {
+        return mIsPhoneInEcmState;
+    }
+
     void sendEmergencyCallbackModeChange(){
         //Send an Intent
         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 3c7ff05..f5d05a1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -248,7 +248,7 @@
         boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
 
         if ((mState == State.IDLE || mState == State.SCANNING) &&
-                isDataAllowed() && getAnyDataEnabled()) {
+                isDataAllowed() && getAnyDataEnabled() && !isEmergency()) {
             boolean retValue = setupData(reason);
             notifyOffApnsOfAvailability(reason);
             return retValue;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 5497b7f..e166401 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -273,7 +273,14 @@
                 break;
             case ConnectivityManager.TYPE_MOBILE_HIPRI:
                 apnContext = addApnContext(Phone.APN_TYPE_HIPRI);
-                break;
+                ApnContext defaultContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
+                if (defaultContext != null) {
+                    applyNewState(apnContext, apnContext.isEnabled(),
+                            defaultContext.getDependencyMet());
+                } else {
+                    // the default will set the hipri dep-met when it is created
+                }
+                continue;
             case ConnectivityManager.TYPE_MOBILE_FOTA:
                 apnContext = addApnContext(Phone.APN_TYPE_FOTA);
                 break;
@@ -686,7 +693,7 @@
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
 
         if ((apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING) &&
-                isDataAllowed(apnContext) && getAnyDataEnabled()) {
+                isDataAllowed(apnContext) && getAnyDataEnabled() && !isEmergency()) {
 
             if (apnContext.getState() == State.IDLE) {
                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());