Merge "Require that persistable Uri permissions be taken." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 5362fdf..c2dfa92 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,6 +71,7 @@
     field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+    field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
     field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
@@ -132,6 +133,7 @@
     field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
+    field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index dd2e006..45a38be 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -42,4 +42,5 @@
     oneway void setCurrentUser(int userId);
     oneway void showAssistant();
     oneway void dispatch(in MotionEvent event);
+    oneway void launchCamera();
 }
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 356401c..e30c1ff 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -31,7 +31,6 @@
 import android.text.Layout.Alignment;
 import android.text.StaticLayout;
 import android.text.TextPaint;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
@@ -52,14 +51,12 @@
     /** Temporary rectangle used for computing line bounds. */
     private final RectF mLineBounds = new RectF();
 
-    /** Temporary array used for computing line wrapping. */
-    private float[] mTextWidths;
-
     /** Reusable string builder used for holding text. */
     private final StringBuilder mText = new StringBuilder();
-    private final StringBuilder mBreakText = new StringBuilder();
 
-    private TextPaint mPaint;
+    private Alignment mAlignment;
+    private TextPaint mTextPaint;
+    private Paint mPaint;
 
     private int mForegroundColor;
     private int mBackgroundColor;
@@ -122,11 +119,12 @@
         mShadowOffsetX = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_offset);
         mShadowOffsetY = mShadowOffsetX;
 
-        final TextPaint paint = new TextPaint();
-        paint.setAntiAlias(true);
-        paint.setSubpixelText(true);
+        mTextPaint = new TextPaint();
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setSubpixelText(true);
 
-        mPaint = paint;
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
 
         setText(text);
         setTextSize(textSize);
@@ -174,21 +172,30 @@
     public void setTextSize(float size) {
         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
         final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics);
-        if (mPaint.getTextSize() != size) {
-            mHasMeasurements = false;
+        if (mTextPaint.getTextSize() != size) {
+            mTextPaint.setTextSize(size);
             mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
-            mPaint.setTextSize(size);
 
-            requestLayout();
+            mHasMeasurements = false;
+            forceLayout();
         }
     }
 
     public void setTypeface(Typeface typeface) {
-        if (mPaint.getTypeface() != typeface) {
-            mHasMeasurements = false;
-            mPaint.setTypeface(typeface);
+        if (mTextPaint.getTypeface() != typeface) {
+            mTextPaint.setTypeface(typeface);
 
-            requestLayout();
+            mHasMeasurements = false;
+            forceLayout();
+        }
+    }
+
+    public void setAlignment(Alignment textAlignment) {
+        if (mAlignment != textAlignment) {
+            mAlignment = textAlignment;
+
+            mHasMeasurements = false;
+            forceLayout();
         }
     }
 
@@ -222,63 +229,19 @@
         }
 
         // Account for padding.
-        final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX;
+        final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
         maxWidth -= paddingX;
-
         if (maxWidth <= 0) {
             return false;
         }
 
-        final TextPaint paint = mPaint;
-        final CharSequence text = mText;
-        final int textLength = text.length();
-        if (mTextWidths == null || mTextWidths.length < textLength) {
-            mTextWidths = new float[textLength];
-        }
-
-        final float[] textWidths = mTextWidths;
-        paint.getTextWidths(text, 0, textLength, textWidths);
-
-        // Compute total length.
-        float runLength = 0;
-        for (int i = 0; i < textLength; i++) {
-            runLength += textWidths[i];
-        }
-
-        final int lineCount = (int) (runLength / maxWidth) + 1;
-        final int lineLength = (int) (runLength / lineCount);
-
-        // Build line break buffer.
-        final StringBuilder breakText = mBreakText;
-        breakText.setLength(0);
-
-        int line = 0;
-        int lastBreak = 0;
-        int maxRunLength = 0;
-        runLength = 0;
-        for (int i = 0; i < textLength; i++) {
-            if (runLength > lineLength) {
-                final CharSequence sequence = text.subSequence(lastBreak, i);
-                final int trimmedLength = TextUtils.getTrimmedLength(sequence);
-                breakText.append(sequence, 0, trimmedLength);
-                breakText.append('\n');
-                lastBreak = i;
-                runLength = 0;
-            }
-
-            runLength += textWidths[i];
-
-            if (runLength > maxRunLength) {
-                maxRunLength = (int) Math.ceil(runLength);
-            }
-        }
-        breakText.append(text.subSequence(lastBreak, textLength));
-
+        // TODO: Implement minimum-difference line wrapping. Adding the results
+        // of Paint.getTextWidths() seems to return different values than
+        // StaticLayout.getWidth(), so this is non-trivial.
         mHasMeasurements = true;
         mLastMeasuredWidth = maxWidth;
-
-        mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT,
-                mSpacingMult, mSpacingAdd, true);
+        mLayout = new StaticLayout(
+                mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true);
 
         return true;
     }
@@ -316,54 +279,50 @@
         final int innerPaddingX = mInnerPaddingX;
         c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
 
-        final RectF bounds = mLineBounds;
         final int lineCount = layout.getLineCount();
-        final Paint paint = layout.getPaint();
-        paint.setShadowLayer(0, 0, 0, 0);
+        final Paint textPaint = mTextPaint;
+        final Paint paint = mPaint;
+        final RectF bounds = mLineBounds;
 
-        final int backgroundColor = mBackgroundColor;
-        if (Color.alpha(backgroundColor) > 0) {
-            paint.setColor(backgroundColor);
-            paint.setStyle(Style.FILL);
-
+        if (Color.alpha(mBackgroundColor) > 0) {
             final float cornerRadius = mCornerRadius;
             float previousBottom = layout.getLineTop(0);
 
+            paint.setColor(mBackgroundColor);
+            paint.setStyle(Style.FILL);
+
             for (int i = 0; i < lineCount; i++) {
-                bounds.left = layout.getLineLeft(i) - innerPaddingX;
+                bounds.left = layout.getLineLeft(i) -innerPaddingX;
                 bounds.right = layout.getLineRight(i) + innerPaddingX;
                 bounds.top = previousBottom;
                 bounds.bottom = layout.getLineBottom(i);
-
                 previousBottom = bounds.bottom;
 
                 c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
             }
         }
 
-        final int edgeType = mEdgeType;
-        if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
-            paint.setColor(mEdgeColor);
-            paint.setStyle(Style.FILL_AND_STROKE);
-            paint.setStrokeJoin(Join.ROUND);
-            paint.setStrokeWidth(mOutlineWidth);
+        if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+            textPaint.setStrokeJoin(Join.ROUND);
+            textPaint.setStrokeWidth(mOutlineWidth);
+            textPaint.setColor(mEdgeColor);
+            textPaint.setStyle(Style.FILL_AND_STROKE);
 
             for (int i = 0; i < lineCount; i++) {
                 layout.drawText(c, i, i);
             }
+        } else if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+            textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
         }
 
-        if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
-            paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
-        }
-
-        paint.setColor(mForegroundColor);
-        paint.setStyle(Style.FILL);
+        textPaint.setColor(mForegroundColor);
+        textPaint.setStyle(Style.FILL);
 
         for (int i = 0; i < lineCount; i++) {
             layout.drawText(c, i, i);
         }
 
+        textPaint.setShadowLayer(0, 0, 0, 0);
         c.restoreToCount(saveCount);
     }
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4c15e18..b41b5b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1403,6 +1403,27 @@
         android:label="@string/permlab_expandStatusBar"
         android:description="@string/permdesc_expandStatusBar" />
 
+    <!-- ============================================================== -->
+    <!-- Permissions related to adding/removing shortcuts from Launcher -->
+    <!-- ============================================================== -->
+    <eat-comment />
+
+    <!-- Allows an application to install a shortcut in Launcher -->
+    <permission
+        android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_install_shortcut"
+        android:description="@string/permdesc_install_shortcut" />
+
+        <!-- Allows an application to uninstall a shortcut in Launcher -->
+    <permission
+        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_uninstall_shortcut"
+        android:description="@string/permdesc_uninstall_shortcut"/>
+
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
     <!-- ==================================================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84a0d37..b3cb2a1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1255,4 +1255,8 @@
     <!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
          transient navigation confirmation prompt.-->
     <integer name="config_transient_navigation_confirmation_panic">5000</integer>
+
+    <!-- For some operators, PDU has garbages. To fix it, need to use valid index -->
+    <integer name="config_valid_wappush_index">-1</integer>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c57873e..c20c427 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -599,6 +599,22 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_expandStatusBar">Allows the app to expand or collapse the status bar.</string>
 
+    <!-- Title of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permlab_install_shortcut">install shortcuts</string>
+    <!-- Description of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permdesc_install_shortcut">Allows an application to add
+        Homescreen shortcuts without user intervention.</string>
+
+    <!-- Title of an application permission, listed so the user can uninstall application shortcuts
+    in their Launcher -->
+    <string name="permlab_uninstall_shortcut">uninstall shortcuts</string>
+    <!-- Description of an application permission, listed so the user can install application shortcuts
+    in their Launcher -->
+    <string name="permdesc_uninstall_shortcut">Allows the application to remove
+        Homescreen shortcuts without user intervention.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_processOutgoingCalls">reroute outgoing calls</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 14b319f..57a4bb7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -316,6 +316,7 @@
   <java-symbol type="integer" name="config_safe_media_volume_index" />
   <java-symbol type="integer" name="config_mobile_mtu" />
   <java-symbol type="integer" name="config_volte_replacement_rat"/>
+  <java-symbol type="integer" name="config_valid_wappush_index" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index c8ace44..a7c5b20 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -553,6 +553,11 @@
      * @return The decoded bitmap, or null if the image data could not be
      *         decoded, or, if opts is non-null, if opts requested only the
      *         size be returned (in opts.outWidth and opts.outHeight)
+     *
+     * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+     * if {@link InputStream#markSupported is.markSupported()} returns true,
+     * <code>is.mark(1024)</code> would be called. As of
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
     public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
         // we don't throw in this case, thus allowing the caller to only check
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 3524b25..3a99977 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -104,6 +104,11 @@
      *                    allowing sharing may degrade the decoding speed.
      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
      * @throws IOException if the image format is not supported or can not be decoded.
+     *
+     * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
+     * if {@link InputStream#markSupported is.markSupported()} returns true,
+     * <code>is.mark(1024)</code> would be called. As of
+     * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
     public static BitmapRegionDecoder newInstance(InputStream is,
             boolean isShareable) throws IOException {
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 5e574a6..25d4c5e 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -41,7 +41,7 @@
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
     inline bool hasNvSystemTime() const { return mHasNvSystemTime; }
-
+    inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; }
     inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
     inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
     inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index a63cac6..ed0a79a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -240,20 +240,20 @@
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
-                GL_UNSIGNED_BYTE, bitmap->getPixels());
+        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+                texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
         break;
     case SkBitmap::kRGB_565_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), texture->height,
-                GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
+        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+                texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
         texture->blend = false;
         break;
     case SkBitmap::kARGB_8888_Config:
         glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height,
-                GL_UNSIGNED_BYTE, bitmap->getPixels());
+        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+                texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         // Do this after calling getPixels() to make sure Skia's deferred
         // decoding happened
         texture->blend = !bitmap->isOpaque();
@@ -293,17 +293,28 @@
     SkCanvas canvas(rgbaBitmap);
     canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
 
-    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), height,
+    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
             GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
 }
 
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
-        GLenum type, const GLvoid * data) {
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+        GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
+    // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+    //       if the stride doesn't match the width
+    const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
+    if (useStride) {
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+    }
+
     if (resize) {
         glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
     } else {
         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
     }
+
+    if (useStride) {
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 80bb22e..57fc19a 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -125,8 +125,8 @@
     void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
 
     void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
-    void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
-            GLenum type, const GLvoid * data);
+    void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+            GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
 
     void init();
 
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index cbed3e4..d5f38b5 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -119,7 +119,7 @@
     // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
     // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
     // With OpenGL ES 2.0 we have to upload entire stripes instead.
-    mHasES3 = Extensions::getInstance().getMajorGlVersion() >= 3;
+    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
 }
 
 CacheTexture::~CacheTexture() {
@@ -206,21 +206,21 @@
 bool CacheTexture::upload() {
     const Rect& dirtyRect = mDirtyRect;
 
-    uint32_t x = mHasES3 ? dirtyRect.left : 0;
+    uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
     uint32_t y = dirtyRect.top;
-    uint32_t width = mHasES3 ? dirtyRect.getWidth() : mWidth;
+    uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth;
     uint32_t height = dirtyRect.getHeight();
 
     // The unpack row length only needs to be specified when a new
     // texture is bound
-    if (mHasES3) {
+    if (mHasUnpackRowLength) {
         glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
     }
 
     mTexture->upload(x, y, width, height);
     setDirty(false);
 
-    return mHasES3;
+    return mHasUnpackRowLength;
 }
 
 void CacheTexture::setDirty(bool dirty) {
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 028b611..61b38f8 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -190,7 +190,7 @@
     uint32_t mMaxQuadCount;
     Caches& mCaches;
     CacheBlock* mCacheBlocks;
-    bool mHasES3;
+    bool mHasUnpackRowLength;
     Rect mDirtyRect;
 };
 
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index edde68d..4dec081 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.content.Context;
+import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
@@ -1583,6 +1584,7 @@
             }
 
             final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize);
+            mRegionCueBoxes.add(cueBox);
             addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 
             if (getChildCount() > mRegion.mLines) {
@@ -1696,12 +1698,27 @@
 
             removeAllViews();
 
+            final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment);
+            final Alignment alignment;
+            switch (cueAlignment) {
+                case TextTrackCue.ALIGNMENT_LEFT:
+                    alignment = Alignment.ALIGN_LEFT;
+                    break;
+                case TextTrackCue.ALIGNMENT_RIGHT:
+                    alignment = Alignment.ALIGN_RIGHT;
+                    break;
+                case TextTrackCue.ALIGNMENT_MIDDLE:
+                default:
+                    alignment = Alignment.ALIGN_CENTER;
+            }
+
             final CaptionStyle captionStyle = mCaptionStyle;
             final float fontSize = mFontSize;
             final TextTrackCueSpan[][] lines = mCue.mLines;
             final int lineCount = lines.length;
             for (int i = 0; i < lineCount; i++) {
                 final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]);
+                lineBox.setAlignment(alignment);
                 lineBox.setCaptionStyle(captionStyle, fontSize);
 
                 addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 5cf05f8..ba6685a 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -149,6 +149,14 @@
     <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
     <string name="keyguard_accessibility_transport_stop_description">Stop button</string>
 
+    <!-- Accessibility description for when the device prompts the user to dismiss keyguard
+         in order to complete an action. This will be followed by a message about the current
+         security option (e.g. "Pattern unlock."). [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_show_bouncer">Unlock to continue</string>
+
+    <!-- Accessibility description for when the bouncer prompt is dismissed. [CHAR LIMIT=NONE] -->
+    <string name="keyguard_accessibility_hide_bouncer">Launch canceled</string>
+
     <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
     <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
     <string name="password_keyboard_label_symbol_key">\?123</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index aa43711..a9e9d3a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -24,7 +24,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AlertDialog;
-import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetHost;
@@ -41,7 +40,6 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.media.RemoteControlClient;
-import android.os.Bundle;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -49,11 +47,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -206,6 +202,13 @@
         }
     }
 
+    public void announceCurrentSecurityMethod() {
+        View v = (View) getSecurityView(mCurrentSecuritySelection);
+        if (v != null) {
+            v.announceForAccessibility(v.getContentDescription());
+        }
+    }
+
     private void getInitialTransportState() {
         DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
                 .getCachedDisplayClientState();
@@ -1663,4 +1666,8 @@
         mAppWidgetContainer.handleExternalCameraEvent(event);
     }
 
+    public void launchCamera() {
+        mActivityLauncher.launchCamera(getHandler(), null);
+    }
+
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
index 77006c5..d7c5fe2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -137,6 +137,10 @@
             checkPermission();
             mKeyguardViewMediator.dispatch(event);
         }
+        public void launchCamera() {
+            checkPermission();
+            mKeyguardViewMediator.launchCamera();
+        }
     };
 
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index 177e0f8..a0e44d7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -506,4 +506,10 @@
             mKeyguardView.dispatch(event);
         }
     }
+
+    public void launchCamera() {
+        if (mKeyguardView != null) {
+            mKeyguardView.launchCamera();
+        }
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 478096c..0606d83 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -122,6 +122,7 @@
     private static final int KEYGUARD_TIMEOUT = 13;
     private static final int SHOW_ASSISTANT = 14;
     private static final int DISPATCH_EVENT = 15;
+    private static final int LAUNCH_CAMERA = 16;
 
     /**
      * The default amount of time we stay awake (used for all key input)
@@ -1071,6 +1072,9 @@
                 case DISPATCH_EVENT:
                     handleDispatchEvent((MotionEvent) msg.obj);
                     break;
+                case LAUNCH_CAMERA:
+                    handleLaunchCamera();
+                    break;
             }
         }
     };
@@ -1107,6 +1111,10 @@
         sendUserPresentBroadcast();
     }
 
+    protected void handleLaunchCamera() {
+        mKeyguardViewManager.launchCamera();
+    }
+
     protected void handleDispatchEvent(MotionEvent event) {
         mKeyguardViewManager.dispatch(event);
     }
@@ -1341,4 +1349,9 @@
         Message msg = mHandler.obtainMessage(DISPATCH_EVENT, event);
         mHandler.sendMessage(msg);
     }
+
+    public void launchCamera() {
+        Message msg = mHandler.obtainMessage(LAUNCH_CAMERA);
+        mHandler.sendMessage(msg);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index d9f9471..d1862cd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -87,6 +87,11 @@
     }
 
     public void showBouncer(boolean show) {
+        CharSequence what = mKeyguardHostView.getContext().getResources().getText(
+                show ? R.string.keyguard_accessibility_show_bouncer
+                        : R.string.keyguard_accessibility_hide_bouncer);
+        mKeyguardHostView.announceForAccessibility(what);
+        mKeyguardHostView.announceCurrentSecurityMethod();
         mChallengeLayout.showBouncer();
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
index f7dc058..f8857ab 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -90,6 +90,7 @@
     // Background worker thread: used here for persistence, also made available to widget frames
     private final HandlerThread mBackgroundWorkerThread;
     private final Handler mBackgroundWorkerHandler;
+    private boolean mCameraEventInProgress;
 
     public KeyguardWidgetPager(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -941,14 +942,18 @@
         beginCameraEvent();
         int cameraPage = getPageCount() - 1;
         boolean endWarp = false;
-        if (isCameraPage(cameraPage)) {
+        if (isCameraPage(cameraPage) || mCameraEventInProgress) {
             switch (event.getAction()) {
                 case MotionEvent.ACTION_DOWN:
+                    // Once we start dispatching camera events, we must continue to do so
+                    // to keep event dispatch happy.
+                    mCameraEventInProgress = true;
                     userActivity();
                     startWarp(cameraPage);
                     break;
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
+                    mCameraEventInProgress = false;
                     endWarp = true;
                     break;
             }
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index 765b274..aa7256b 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -153,6 +153,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
@@ -297,6 +298,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 9592b18..b9ad799 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -149,6 +149,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
@@ -290,6 +291,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 11cbbc7..aa365ae 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -157,6 +157,7 @@
                 android:src="@drawable/search_light"
                 android:scaleType="center"
                 android:visibility="gone"
+                android:contentDescription="@string/accessibility_search_light"
                 />
 
             <com.android.systemui.statusbar.policy.KeyButtonView
@@ -167,6 +168,7 @@
                 android:src="@drawable/ic_sysbar_camera"
                 android:scaleType="center"
                 android:visibility="gone"
+                android:contentDescription="@string/accessibility_camera_button"
                 />
         </FrameLayout>
 
@@ -312,6 +314,7 @@
             android:src="@drawable/search_light"
             android:scaleType="center"
             android:visibility="gone"
+            android:contentDescription="@string/accessibility_search_light"
             />
 
         <!-- No camera button in landscape mode -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index eb425e6..58865ab 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -192,6 +192,10 @@
     <string name="accessibility_menu">Menu</string>
     <!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_recent">Recent apps</string>
+    <!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_search_light">Search</string>
+    <!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_camera_button">Camera</string>
 
     <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ime_switch_button">Switch input method button.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 3a5524d..3a82753 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -50,8 +50,7 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mSourceView == null || mDelegateView == null || mDisabled
-                || mBar.shouldDisableNavbarGestures()) {
+        if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
             return false;
         }
 
@@ -73,7 +72,7 @@
             return false;
         }
 
-        if (!mPanelShowing && action == MotionEvent.ACTION_MOVE) {
+        if (!mDisabled && !mPanelShowing && action == MotionEvent.ACTION_MOVE) {
             final int historySize = event.getHistorySize();
             for (int k = 0; k < historySize + 1; k++) {
                 float x = k < historySize ? event.getHistoricalX(k) : event.getX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
index a6e2347..1221a55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -103,4 +103,30 @@
         return false;
     }
 
+    public void showAssistant() {
+        if (mService != null) {
+            try {
+                mService.showAssistant();
+            } catch (RemoteException e) {
+                // What to do?
+                Log.e(TAG, "RemoteException launching assistant!", e);
+            }
+        } else {
+            Log.w(TAG, "dispatch(event): NO SERVICE!");
+        }
+    }
+
+    public void launchCamera() {
+        if (mService != null) {
+            try {
+                mService.launchCamera();
+            } catch (RemoteException e) {
+                // What to do?
+                Log.e(TAG, "RemoteException launching camera!", e);
+            }
+        } else {
+            Log.w(TAG, "dispatch(event): NO SERVICE!");
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 24e27b1..596fac6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -37,8 +37,10 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -86,7 +88,7 @@
 
     // used to disable the camera icon in navbar when disabled by DPM
     private boolean mCameraDisabledByDpm;
-    KeyguardTouchDelegate mTouchDelegate;
+    KeyguardTouchDelegate mKeyguardTouchDelegate;
 
     private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
         @Override
@@ -110,7 +112,7 @@
                     }
                     break;
             }
-            return mTouchDelegate.dispatch(event);
+            return mKeyguardTouchDelegate.dispatch(event);
         }
     };
 
@@ -153,7 +155,7 @@
 
         mBarTransitions = new NavigationBarTransitions(this);
 
-        mTouchDelegate = new KeyguardTouchDelegate(mContext);
+        mKeyguardTouchDelegate = new KeyguardTouchDelegate(mContext);
 
         mCameraDisabledByDpm = isCameraDisabledByDpm();
         watchForDevicePolicyChanges();
@@ -339,7 +341,7 @@
                 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
                 final  boolean disabledBecauseKeyguardSecure =
                         (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
-                        && mTouchDelegate.isSecure();
+                        && mKeyguardTouchDelegate.isSecure();
                 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
             } catch (RemoteException e) {
                 Log.e(TAG, "Can't get userId", e);
@@ -389,12 +391,44 @@
 
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
 
-        // Add a touch handler for camera icon for all view orientations.
-        for (int i = 0; i < mRotatedViews.length; i++) {
-            View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
-            if (cameraButton != null) {
-                cameraButton.setOnTouchListener(mCameraTouchListener);
+
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (accessibilityManager.isEnabled()) {
+            // In accessibility mode, we add a simple click handler since swipe is tough to
+            // trigger near screen edges.
+            View camera = getCameraButton();
+            View searchLight = getSearchLight();
+            if (camera != null || searchLight != null) {
+                OnClickListener listener = new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        launchForAccessibilityClick(v);
+                    }
+                };
+                if (camera != null) {
+                    camera.setOnClickListener(listener);
+                }
+                if (searchLight != null) {
+                    searchLight.setOnClickListener(listener);
+                }
             }
+        } else {
+            // Add a touch handler for camera icon for all view orientations.
+            for (int i = 0; i < mRotatedViews.length; i++) {
+                View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
+                if (cameraButton != null) {
+                    cameraButton.setOnTouchListener(mCameraTouchListener);
+                }
+            }
+        }
+    }
+
+    protected void launchForAccessibilityClick(View v) {
+        if (v == getCameraButton()) {
+            mKeyguardTouchDelegate.launchCamera();
+        } else if (v == getSearchLight()) {
+            mKeyguardTouchDelegate.showAssistant();
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index b27584d..5e299ee 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -192,6 +192,10 @@
         // Not used by PhoneWindowManager.  See code in {@link NavigationBarView}
     }
 
+    public void launchCamera() {
+        // Not used by PhoneWindowManager.  See code in {@link NavigationBarView}
+    }
+
     @Override
     public IBinder asBinder() {
         return mService.asBinder();