Merge "docs: revisions to api overview" into ics-mr0
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index cdf1f8d..83df8a5 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -134,6 +134,11 @@
                 R.drawable.ic_audio_phone,
                 R.drawable.ic_audio_phone,
                 false),
+        AlarmStream(AudioManager.STREAM_ALARM,
+                R.string.volume_alarm,
+                R.drawable.ic_audio_alarm,
+                R.drawable.ic_audio_alarm_mute,
+                false),
         MediaStream(AudioManager.STREAM_MUSIC,
                 R.string.volume_icon_description_media,
                 R.drawable.ic_audio_vol,
@@ -167,7 +172,8 @@
         StreamResources.RingerStream,
         StreamResources.VoiceStream,
         StreamResources.MediaStream,
-        StreamResources.NotificationStream
+        StreamResources.NotificationStream,
+        StreamResources.AlarmStream
     };
 
     /** Object that contains data for each slider */
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index a5d6c9a..b24dd69 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -147,6 +147,11 @@
             setColorFilter(tint);
         }
         
+        int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+        if (alpha != 255) {
+            setAlpha(alpha);
+        }
+
         mCropToPadding = a.getBoolean(
                 com.android.internal.R.styleable.ImageView_cropToPadding, false);
         
diff --git a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
index f3f1957..6e8c921 100644
--- a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
+++ b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
@@ -25,14 +25,12 @@
         android:fadingEdge="horizontal"
         android:ellipsize="marquee"
         android:visibility="gone"
-        android:alpha="0.7"
         />
     <LinearLayout
         android:id="@+id/line3"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:alpha="0.7"
         >
         <TextView android:id="@+id/text"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
@@ -62,6 +60,7 @@
             android:scaleType="center"
             android:paddingLeft="8dp"
             android:visibility="gone"
+            android:drawableAlpha="180"
             />
     </LinearLayout>
     <ProgressBar
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6c7a981..d7691f7 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2639,6 +2639,9 @@
         <!-- The offset of the baseline within this view. See {see android.view.View#getBaseline}
              for details -->
         <attr name="baseline" format="dimension" />
+        <!-- @hide The alpha value (0-255) set on the ImageView's drawable. Equivalent
+             to calling ImageView.setAlpha(int), not the same as View.setAlpha(float). -->
+        <attr name="drawableAlpha" format="integer" />
     </declare-styleable>
     <declare-styleable name="ToggleButton">
         <!-- The text for the button when it is checked. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 20af731..e60e8b2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -230,10 +230,11 @@
     <style name="TextAppearance.StatusBar.Icon">
     </style>
     <style name="TextAppearance.StatusBar.EventContent">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">13sp</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Title">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">16sp</item>
         <item name="android:textStyle">bold</item>
     </style>
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index babd2c0..d2e5627 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -58,13 +58,16 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(bufferIdx);
-        remote()->transact(REQUEST_BUFFER, data, &reply);
+        status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
         bool nonNull = reply.readInt32();
         if (nonNull) {
             *buf = new GraphicBuffer();
             reply.read(**buf);
         }
-        status_t result = reply.readInt32();
+        result = reply.readInt32();
         return result;
     }
 
@@ -73,9 +76,12 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(bufferCount);
-        remote()->transact(SET_BUFFER_COUNT, data, &reply);
-        status_t err = reply.readInt32();
-        return err;
+        status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
     }
 
     virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
@@ -86,9 +92,12 @@
         data.writeInt32(h);
         data.writeInt32(format);
         data.writeInt32(usage);
-        remote()->transact(DEQUEUE_BUFFER, data, &reply);
+        status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
         *buf = reply.readInt32();
-        int result = reply.readInt32();
+        result = reply.readInt32();
         return result;
     }
 
@@ -98,11 +107,14 @@
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(buf);
         data.writeInt64(timestamp);
-        remote()->transact(QUEUE_BUFFER, data, &reply);
+        status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
         *outWidth = reply.readInt32();
         *outHeight = reply.readInt32();
         *outTransform = reply.readInt32();
-        status_t result = reply.readInt32();
+        result = reply.readInt32();
         return result;
     }
 
@@ -120,8 +132,11 @@
         data.writeFloat(reg.top);
         data.writeFloat(reg.right);
         data.writeFloat(reg.bottom);
-        remote()->transact(SET_CROP, data, &reply);
-        status_t result = reply.readInt32();
+        status_t result = remote()->transact(SET_CROP, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
         return result;
     }
 
@@ -129,8 +144,11 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(transform);
-        remote()->transact(SET_TRANSFORM, data, &reply);
-        status_t result = reply.readInt32();
+        status_t result = remote()->transact(SET_TRANSFORM, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
         return result;
     }
 
@@ -138,8 +156,11 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(mode);
-        remote()->transact(SET_SCALING_MODE, data, &reply);
-        status_t result = reply.readInt32();
+        status_t result = remote()->transact(SET_SCALING_MODE, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
         return result;
     }
 
@@ -147,9 +168,12 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(what);
-        remote()->transact(QUERY, data, &reply);
+        status_t result = remote()->transact(QUERY, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
         value[0] = reply.readInt32();
-        status_t result = reply.readInt32();
+        result = reply.readInt32();
         return result;
     }
 
@@ -157,8 +181,11 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(enabled);
-        remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply);
-        status_t result = reply.readInt32();
+        status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
         return result;
     }
 
@@ -167,11 +194,14 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(api);
-        remote()->transact(CONNECT, data, &reply);
+        status_t result = remote()->transact(CONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
         *outWidth = reply.readInt32();
         *outHeight = reply.readInt32();
         *outTransform = reply.readInt32();
-        status_t result = reply.readInt32();
+        result = reply.readInt32();
         return result;
     }
 
@@ -179,8 +209,11 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(api);
-        remote()->transact(DISCONNECT, data, &reply);
-        status_t result = reply.readInt32();
+        status_t result =remote()->transact(DISCONNECT, data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
         return result;
     }
 };
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 6cb8799..6d70135 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -25,6 +25,7 @@
         android:id="@+id/global_screenshot_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center"
         android:background="@drawable/global_screenshot_background"
         android:visibility="gone">
         <ImageView android:id="@+id/global_screenshot"
@@ -32,9 +33,4 @@
             android:layout_height="wrap_content"
             android:adjustViewBounds="true" />
     </FrameLayout>
-    <ImageView android:id="@+id/global_screenshot_flash"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="#FFFFFFFF"
-        android:visibility="gone" />
 </FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 65d5138..a717b57 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -168,10 +168,20 @@
     <!-- Compatibility mode help screen: body text. [CHAR LIMIT=150] -->
     <string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
 
-    <!-- toast message displayed when a screenshot is saved to the Gallery. -->
-    <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
-    <!-- toast message displayed when we fail to take a screenshot. -->
-    <string name="screenshot_failed_toast">Could not save screenshot. External storage may be in use.</string>
+    <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
+    <string name="screenshot_saving_ticker">Saving...</string>
+    <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] -->
+    <string name="screenshot_saving_title">Saving screenshot...</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>
+    <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
+    <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>
+    <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
+    <string name="screenshot_failed_title">Screenshot failed</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>
 
     <!-- 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/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 3fa3078..cf073c4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -19,27 +19,27 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
-import android.media.MediaScannerConnection;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Binder;
 import android.os.Environment;
 import android.os.ServiceManager;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
@@ -50,16 +50,11 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.systemui.R;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.OutputStream;
-import java.lang.Thread;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
@@ -83,6 +78,46 @@
     private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
     private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/%s";
 
+    private int mNotificationId;
+    private NotificationManager mNotificationManager;
+    private Notification.Builder mNotificationBuilder;
+    private Intent mLaunchIntent;
+    private String mImageDir;
+    private String mImageFileName;
+    private String mImageFilePath;
+    private String mImageDate;
+    private long mImageTime;
+
+    SaveImageInBackgroundTask(Context context, NotificationManager nManager, int nId) {
+        Resources r = context.getResources();
+
+        // Prepare all the output metadata
+        mImageTime = System.currentTimeMillis();
+        mImageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));
+        mImageDir = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES).getAbsolutePath();
+        mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, mImageDate);
+        mImageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, mImageDir,
+                SCREENSHOTS_DIR_NAME, mImageFileName);
+
+        // 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);
+        mNotificationId = nId;
+        mNotificationBuilder = new Notification.Builder(context)
+            .setTicker(r.getString(R.string.screenshot_saving_ticker))
+            .setContentTitle(r.getString(R.string.screenshot_saving_title))
+            .setContentText(r.getString(R.string.screenshot_saving_text))
+            .setSmallIcon(android.R.drawable.ic_menu_gallery)
+            .setWhen(System.currentTimeMillis());
+        Notification n = mNotificationBuilder.getNotification();
+        n.flags |= Notification.FLAG_NO_CLEAR;
+
+        mNotificationManager = nManager;
+        mNotificationManager.notify(nId, n);
+    }
+
     @Override
     protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
         if (params.length != 1) return null;
@@ -91,23 +126,15 @@
         Bitmap image = params[0].image;
 
         try {
-            long currentTime = System.currentTimeMillis();
-            String date = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(currentTime));
-            String imageDir = Environment.getExternalStoragePublicDirectory(
-                    Environment.DIRECTORY_PICTURES).getAbsolutePath();
-            String imageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, date);
-            String imageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, imageDir,
-                    SCREENSHOTS_DIR_NAME, imageFileName);
-
             // Save the screenshot to the MediaStore
             ContentValues values = new ContentValues();
             ContentResolver resolver = context.getContentResolver();
-            values.put(MediaStore.Images.ImageColumns.DATA, imageFilePath);
-            values.put(MediaStore.Images.ImageColumns.TITLE, imageFileName);
-            values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, imageFileName);
-            values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, currentTime);
-            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, currentTime);
-            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, currentTime);
+            values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);
+            values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
+            values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
+            values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime);
+            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, mImageTime);
+            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, mImageTime);
             values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
             Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
 
@@ -118,7 +145,7 @@
 
             // update file size in the database
             values.clear();
-            values.put(MediaStore.Images.ImageColumns.SIZE, new File(imageFilePath).length());
+            values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
             resolver.update(uri, values, null, null);
 
             params[0].result = 0;
@@ -135,12 +162,22 @@
     protected void onPostExecute(SaveImageInBackgroundData params) {
         if (params.result > 0) {
             // Show a message that we've failed to save the image to disk
-            Toast.makeText(params.context, R.string.screenshot_failed_toast,
-                    Toast.LENGTH_SHORT).show();
+            GlobalScreenshot.notifyScreenshotError(params.context, mNotificationManager);
         } else {
-            // Show a message that we've saved the screenshot to disk
-            Toast.makeText(params.context, R.string.screenshot_saving_toast,
-                    Toast.LENGTH_SHORT).show();
+            // Show the final notification to indicate screenshot saved
+            Resources r = params.context.getResources();
+
+            mNotificationBuilder
+                .setTicker(r.getString(R.string.screenshot_saved_title))
+                .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                .setContentText(r.getString(R.string.screenshot_saved_text))
+                .setContentIntent(PendingIntent.getActivity(params.context, 0, mLaunchIntent, 0))
+                .setWhen(System.currentTimeMillis())
+                .setAutoCancel(true);
+
+            Notification n = mNotificationBuilder.getNotification();
+            n.flags &= ~Notification.FLAG_NO_CLEAR;
+            mNotificationManager.notify(mNotificationId, n);
         }
         params.finisher.run();
     };
@@ -154,22 +191,21 @@
  */
 class GlobalScreenshot {
     private static final String TAG = "GlobalScreenshot";
-    private static final int SCREENSHOT_FADE_IN_DURATION = 900;
+    private static final int SCREENSHOT_NOTIFICATION_ID = 789;
+    private static final int SCREENSHOT_FADE_IN_DURATION = 500;
     private static final int SCREENSHOT_FADE_OUT_DELAY = 1000;
-    private static final int SCREENSHOT_FADE_OUT_DURATION = 450;
-    private static final int TOAST_FADE_IN_DURATION = 500;
-    private static final int TOAST_FADE_OUT_DELAY = 1000;
-    private static final int TOAST_FADE_OUT_DURATION = 500;
+    private static final int SCREENSHOT_FADE_OUT_DURATION = 300;
     private static final float BACKGROUND_ALPHA = 0.65f;
-    private static final float SCREENSHOT_SCALE = 0.85f;
-    private static final float SCREENSHOT_MIN_SCALE = 0.7f;
-    private static final float SCREENSHOT_ROTATION = -6.75f; // -12.5f;
+    private static final float SCREENSHOT_SCALE_FUDGE = 0.075f; // To account for the border padding
+    private static final float SCREENSHOT_SCALE = 0.8f;
+    private static final float SCREENSHOT_MIN_SCALE = 0.775f;
 
     private Context mContext;
     private LayoutInflater mLayoutInflater;
     private IWindowManager mIWindowManager;
     private WindowManager mWindowManager;
     private WindowManager.LayoutParams mWindowLayoutParams;
+    private NotificationManager mNotificationManager;
     private Display mDisplay;
     private DisplayMetrics mDisplayMetrics;
     private Matrix mDisplayMatrix;
@@ -182,10 +218,15 @@
 
     private AnimatorSet mScreenshotAnimation;
 
-    // General use cubic interpolator
-    final TimeInterpolator mCubicInterpolator = new TimeInterpolator() {
+    // Fade interpolators
+    final TimeInterpolator mFadeInInterpolator = new TimeInterpolator() {
         public float getInterpolation(float t) {
-            return t*t*t;
+            return (float) Math.pow(t, 1.5f);
+        }
+    };
+    final TimeInterpolator mFadeOutInterpolator = new TimeInterpolator() {
+        public float getInterpolation(float t) {
+            return (float) t;
         }
     };
     // The interpolator used to control the background alpha at the start of the animation
@@ -237,6 +278,8 @@
                 PixelFormat.TRANSLUCENT);
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mNotificationManager =
+            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         mDisplay = mWindowManager.getDefaultDisplay();
     }
 
@@ -248,7 +291,8 @@
         data.context = mContext;
         data.image = mScreenBitmap;
         data.finisher = finisher;
-        new SaveImageInBackgroundTask().execute(data);
+        new SaveImageInBackgroundTask(mContext, mNotificationManager, SCREENSHOT_NOTIFICATION_ID)
+                .execute(data);
     }
 
     /**
@@ -300,8 +344,7 @@
 
         // If we couldn't take the screenshot, notify the user
         if (mScreenBitmap == null) {
-            Toast.makeText(mContext, R.string.screenshot_failed_toast,
-                    Toast.LENGTH_SHORT).show();
+            notifyScreenshotError(mContext, mNotificationManager);
             finisher.run();
             return;
         }
@@ -341,12 +384,13 @@
     }
     private ValueAnimator createScreenshotFadeInAnimation() {
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.setInterpolator(mCubicInterpolator);
+        anim.setInterpolator(mFadeInInterpolator);
         anim.setDuration(SCREENSHOT_FADE_IN_DURATION);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 mBackgroundView.setVisibility(View.VISIBLE);
+                mScreenshotContainerView.setTranslationY(0f);
                 mScreenshotContainerView.setVisibility(View.VISIBLE);
             }
         });
@@ -356,18 +400,19 @@
                 float t = ((Float) animation.getAnimatedValue()).floatValue();
                 mBackgroundView.setAlpha(mBackgroundViewAlphaInterpolator.getInterpolation(t) *
                         BACKGROUND_ALPHA);
-                float scaleT = SCREENSHOT_SCALE + (1f - t) * SCREENSHOT_SCALE;
+                float scaleT = SCREENSHOT_SCALE
+                        + (1f - t) * (1f - SCREENSHOT_SCALE)
+                        + SCREENSHOT_SCALE_FUDGE;
                 mScreenshotContainerView.setAlpha(t*t*t*t);
                 mScreenshotContainerView.setScaleX(scaleT);
                 mScreenshotContainerView.setScaleY(scaleT);
-                mScreenshotContainerView.setRotation(t * SCREENSHOT_ROTATION);
             }
         });
         return anim;
     }
     private ValueAnimator createScreenshotFadeOutAnimation() {
         ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
-        anim.setInterpolator(mCubicInterpolator);
+        anim.setInterpolator(mFadeOutInterpolator);
         anim.setStartDelay(SCREENSHOT_FADE_OUT_DELAY);
         anim.setDuration(SCREENSHOT_FADE_OUT_DURATION);
         anim.addListener(new AnimatorListenerAdapter() {
@@ -381,8 +426,9 @@
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
                 float t = ((Float) animation.getAnimatedValue()).floatValue();
-                float scaleT = SCREENSHOT_MIN_SCALE +
-                        t*(SCREENSHOT_SCALE - SCREENSHOT_MIN_SCALE);
+                float scaleT = SCREENSHOT_MIN_SCALE
+                        + t * (SCREENSHOT_SCALE - SCREENSHOT_MIN_SCALE)
+                        + SCREENSHOT_SCALE_FUDGE;
                 mScreenshotContainerView.setAlpha(t);
                 mScreenshotContainerView.setScaleX(scaleT);
                 mScreenshotContainerView.setScaleY(scaleT);
@@ -391,4 +437,19 @@
         });
         return anim;
     }
+
+    static void notifyScreenshotError(Context context, NotificationManager nManager) {
+        Resources r = context.getResources();
+
+        // Clear all existing notification, compose the new notification and show it
+        Notification n = new Notification.Builder(context)
+            .setTicker(r.getString(R.string.screenshot_failed_title))
+            .setContentTitle(r.getString(R.string.screenshot_failed_title))
+            .setContentText(r.getString(R.string.screenshot_failed_text))
+            .setSmallIcon(android.R.drawable.ic_menu_report_image)
+            .setWhen(System.currentTimeMillis())
+            .setAutoCancel(true)
+            .getNotification();
+        nManager.notify(SCREENSHOT_NOTIFICATION_ID, n);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 05ff8be..d112b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -17,26 +17,12 @@
 package com.android.systemui.screenshot;
 
 import android.app.Service;
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.net.Uri;
-import android.hardware.usb.UsbAccessory;
-import android.hardware.usb.UsbManager;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-
-import com.android.systemui.R;
 
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 5959537..2e1803e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -146,4 +146,26 @@
 
         mDoNotDisturb = new DoNotDisturb(mContext);
     }
+
+    protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
+        View vetoButton = row.findViewById(R.id.veto);
+        if (n.isClearable()) {
+            final String _pkg = n.pkg;
+            final String _tag = n.tag;
+            final int _id = n.id;
+            vetoButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        try {
+                            mBarService.onNotificationClear(_pkg, _tag, _id);
+                        } catch (RemoteException ex) {
+                            // system process is dead if we're here.
+                        }
+                    }
+                });
+            vetoButton.setVisibility(View.VISIBLE);
+        } else {
+            vetoButton.setVisibility(View.GONE);
+        }
+        return vetoButton;
+    }
 }
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 9c8c229..4e9b411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -94,7 +94,7 @@
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
 
     // additional instrumentation for testing purposes; intended to be left on during development
-    public static final boolean CHATTY = DEBUG || true;
+    public static final boolean CHATTY = DEBUG;
 
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
@@ -618,6 +618,10 @@
         boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
                 && notification.priority == oldNotification.priority;
                 // priority now encompasses isOngoing()
+
+        boolean updateTicker = notification.notification.tickerText != null
+                && !TextUtils.equals(notification.notification.tickerText,
+                        oldEntry.notification.notification.tickerText);
         boolean isFirstAnyway = rowParent.indexOfChild(oldEntry.row) == 0;
         if (contentsUnchanged && (orderUnchanged || isFirstAnyway)) {
             if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
@@ -665,10 +669,13 @@
             addNotificationViews(key, notification);
         }
 
+        // Update the veto button accordingly (and as a result, whether this row is
+        // swipe-dismissable)
+        updateNotificationVetoButton(oldEntry.row, notification);
+
         // Restart the ticker if it's still running
-        if (notification.notification.tickerText != null
-                && !TextUtils.equals(notification.notification.tickerText,
-                    oldEntry.notification.notification.tickerText)) {
+        if (updateTicker) {
+            mTicker.halt();
             tick(notification);
         }
 
@@ -711,23 +718,7 @@
         View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
 
         // wire up the veto button
-        View vetoButton = row.findViewById(R.id.veto);
-        if (notification.isClearable()) {
-            final String _pkg = notification.pkg;
-            final String _tag = notification.tag;
-            final int _id = notification.id;
-            vetoButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        try {
-                            mBarService.onNotificationClear(_pkg, _tag, _id);
-                        } catch (RemoteException ex) {
-                            // system process is dead if we're here.
-                        }
-                    }
-                });
-        } else {
-            vetoButton.setVisibility(View.GONE);
-        }
+        View vetoButton = updateNotificationVetoButton(row, notification);
         vetoButton.setContentDescription(mContext.getString(
                 R.string.accessibility_remove_notification));
 
@@ -897,23 +888,7 @@
         LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
-        View vetoButton = row.findViewById(R.id.veto);
-        if (entry.notification.isClearable()) {
-            final String _pkg = sbn.pkg;
-            final String _tag = sbn.tag;
-            final int _id = sbn.id;
-            vetoButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        try {
-                            mBarService.onNotificationClear(_pkg, _tag, _id);
-                        } catch (RemoteException ex) {
-                            // system process is dead if we're here.
-                        }
-                    }
-                });
-        } else {
-            vetoButton.setVisibility(View.GONE);
-        }
+        View vetoButton = updateNotificationVetoButton(row, sbn);
         vetoButton.setContentDescription(mContext.getString(
                 R.string.accessibility_remove_notification));
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 8d964e3..4f9eb38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -61,7 +61,7 @@
     // debug
     static final String TAG = "StatusBar.NetworkController";
     static final boolean DEBUG = false;
-    static final boolean CHATTY = true; // additional diagnostics, but not logspew
+    static final boolean CHATTY = false; // additional diagnostics, but not logspew
 
     // telephony
     boolean mHspaDataDistinguishable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 415a9a4..f0a10f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -840,6 +840,9 @@
         boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
                 && notification.priority == oldNotification.priority;
                 // priority now encompasses isOngoing()
+        boolean updateTicker = notification.notification.tickerText != null
+                && !TextUtils.equals(notification.notification.tickerText,
+                        oldEntry.notification.notification.tickerText);
         boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount()-1;
         if (contentsUnchanged && (orderUnchanged || isLastAnyway)) {
             if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
@@ -896,9 +899,8 @@
         }
 
         // Restart the ticker if it's still running
-        if (notification.notification.tickerText != null
-                && !TextUtils.equals(notification.notification.tickerText,
-                    oldEntry.notification.notification.tickerText)) {
+        if (updateTicker) {
+            mTicker.halt();
             tick(key, notification, false);
         }
 
@@ -1736,23 +1738,7 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
         workAroundBadLayerDrawableOpacity(row);
-        View vetoButton = row.findViewById(R.id.veto);
-        if (entry.notification.isClearable()) {
-            final String _pkg = sbn.pkg;
-            final String _tag = sbn.tag;
-            final int _id = sbn.id;
-            vetoButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        try {
-                            mBarService.onNotificationClear(_pkg, _tag, _id);
-                        } catch (RemoteException ex) {
-                            // system process is dead if we're here.
-                        }
-                    }
-                });
-        } else {
-            vetoButton.setVisibility(View.GONE);
-        }
+        View vetoButton = updateNotificationVetoButton(row, entry.notification);
         vetoButton.setContentDescription(mContext.getString(
                 R.string.accessibility_remove_notification));
 
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index ef48b9e..788ecda 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -43,10 +43,13 @@
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.SpellCheckerSubtype;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class TextServicesManagerService extends ITextServicesManager.Stub {
     private static final String TAG = TextServicesManagerService.class.getSimpleName();
@@ -480,6 +483,66 @@
         }
     }
 
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+
+            pw.println("Permission Denial: can't dump TextServicesManagerService from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized(mSpellCheckerMap) {
+            pw.println("Current Text Services Manager state:");
+            pw.println("  Spell Checker Map:");
+            for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) {
+                pw.print("    "); pw.print(ent.getKey()); pw.println(":");
+                SpellCheckerInfo info = ent.getValue();
+                pw.print("      "); pw.print("id="); pw.println(info.getId());
+                pw.print("      "); pw.print("comp=");
+                        pw.println(info.getComponent().toShortString());
+                int NS = info.getSubtypeCount();
+                for (int i=0; i<NS; i++) {
+                    SpellCheckerSubtype st = info.getSubtypeAt(i);
+                    pw.print("      "); pw.print("Subtype #"); pw.print(i); pw.println(":");
+                    pw.print("        "); pw.print("locale="); pw.println(st.getLocale());
+                    pw.print("        "); pw.print("extraValue=");
+                            pw.println(st.getExtraValue());
+                }
+            }
+            pw.println("");
+            pw.println("  Spell Checker Bind Groups:");
+            for (Map.Entry<String, SpellCheckerBindGroup> ent
+                    : mSpellCheckerBindGroups.entrySet()) {
+                SpellCheckerBindGroup grp = ent.getValue();
+                pw.print("    "); pw.print(ent.getKey()); pw.print(" ");
+                        pw.print(grp); pw.println(":");
+                pw.print("      "); pw.print("mInternalConnection=");
+                        pw.println(grp.mInternalConnection);
+                pw.print("      "); pw.print("mSpellChecker=");
+                        pw.println(grp.mSpellChecker);
+                pw.print("      "); pw.print("mBound="); pw.print(grp.mBound);
+                        pw.print(" mConnected="); pw.println(grp.mConnected);
+                int NL = grp.mListeners.size();
+                for (int i=0; i<NL; i++) {
+                    InternalDeathRecipient listener = grp.mListeners.get(i);
+                    pw.print("      "); pw.print("Listener #"); pw.print(i); pw.println(":");
+                    pw.print("        "); pw.print("mTsListener=");
+                            pw.println(listener.mTsListener);
+                    pw.print("        "); pw.print("mScListener=");
+                            pw.println(listener.mScListener);
+                    pw.print("        "); pw.print("mGroup=");
+                            pw.println(listener.mGroup);
+                    pw.print("        "); pw.print("mScLocale=");
+                            pw.print(listener.mScLocale);
+                            pw.print(" mUid="); pw.println(listener.mUid);
+                }
+            }
+        }
+    }
+
     // SpellCheckerBindGroup contains active text service session listeners.
     // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
     // mSpellCheckerBindGroups
@@ -488,6 +551,7 @@
         private final InternalServiceConnection mInternalConnection;
         private final ArrayList<InternalDeathRecipient> mListeners =
                 new ArrayList<InternalDeathRecipient>();
+        public boolean mBound;
         public ISpellCheckerService mSpellChecker;
         public boolean mConnected;
 
@@ -495,6 +559,7 @@
                 ITextServicesSessionListener listener, String locale,
                 ISpellCheckerSessionListener scListener, int uid, Bundle bundle) {
             mInternalConnection = connection;
+            mBound = true;
             mConnected = false;
             addListener(listener, locale, scListener, uid, bundle);
         }
@@ -580,15 +645,18 @@
             if (DBG) {
                 Slog.d(TAG, "cleanLocked");
             }
-            if (mListeners.isEmpty()) {
+            // If there are no more active listeners, clean up.  Only do this
+            // once.
+            if (mBound && mListeners.isEmpty()) {
+                mBound = false;
                 final String sciId = mInternalConnection.mSciId;
-                if (mSpellCheckerBindGroups.containsKey(sciId)) {
+                SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId);
+                if (cur == this) {
                     if (DBG) {
                         Slog.d(TAG, "Remove bind group.");
                     }
                     mSpellCheckerBindGroups.remove(sciId);
                 }
-                // Unbind service when there is no active clients.
                 mContext.unbindService(mInternalConnection);
             }
         }
@@ -623,7 +691,7 @@
                 }
                 ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
                 final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
-                if (group != null) {
+                if (this == group.mInternalConnection) {
                     group.onServiceConnected(spellChecker);
                 }
             }
@@ -631,7 +699,12 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            mSpellCheckerBindGroups.remove(mSciId);
+            synchronized(mSpellCheckerMap) {
+                final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
+                if (this == group.mInternalConnection) {
+                    mSpellCheckerBindGroups.remove(mSciId);
+                }
+            }
         }
     }