Merge "Fix issue #17671802: "content" command always prints..." into lmp-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 005baed..3d14c58 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -635,14 +635,7 @@
             if (mIcon != null) {
                 return mIcon;
             }
-            if (mIconFilename != null) {
-                try {
-                    return ActivityManagerNative.getDefault().
-                            getTaskDescriptionIcon(mIconFilename);
-                } catch (RemoteException e) {
-                }
-            }
-            return null;
+            return loadTaskDescriptionIcon(mIconFilename);
         }
 
         /** @hide */
@@ -650,6 +643,23 @@
             return mIconFilename;
         }
 
+        /** @hide */
+        public Bitmap getInMemoryIcon() {
+            return mIcon;
+        }
+
+        /** @hide */
+        public static Bitmap loadTaskDescriptionIcon(String iconFilename) {
+            if (iconFilename != null) {
+                try {
+                    return ActivityManagerNative.getDefault().
+                            getTaskDescriptionIcon(iconFilename);
+                } catch (RemoteException e) {
+                }
+            }
+            return null;
+        }
+
         /**
          * @return The color override on the theme's primary color.
          */
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 300301b..b492deb 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -702,6 +702,20 @@
     }
 
     /**
+     * Disable NFC hardware.
+     * @hide
+    */
+    @SystemApi
+    public boolean disable(boolean persist) {
+        try {
+            return sService.disable(persist);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
      * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
      * use {@link #resumePolling()}.
      * @hide
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 6796134..8ea28ec 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -478,7 +478,7 @@
 
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
-    int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
@@ -486,22 +486,16 @@
         return nullObjectReturn("fstat return -1");
     }
 
-    // Duplicate the descriptor here to prevent leaking memory. A leak occurs
-    // if we only close the file descriptor and not the file object it is used to
-    // create.  If we don't explicitly clean up the file (which in turn closes the
-    // descriptor) the buffers allocated internally by fseek will be leaked.
-    int dupDescriptor = dup(descriptor);
+    // Restore the descriptor's offset on exiting this function.
+    AutoFDSeek autoRestore(descriptor);
 
-    FILE* file = fdopen(dupDescriptor, "r");
+    FILE* file = fdopen(descriptor, "r");
     if (file == NULL) {
-        // cleanup the duplicated descriptor since it will not be closed when the
-        // file is cleaned up (fclose).
-        close(dupDescriptor);
         return nullObjectReturn("Could not open file");
     }
 
     SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
-                         SkFILEStream::kCallerPasses_Ownership));
+                         SkFILEStream::kCallerRetains_Ownership));
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 14aa570..f7584d8 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -492,7 +492,7 @@
 
     @Override
     public Drawable mutate() {
-        if (!mMutated) {
+        if (!mMutated && super.mutate() == this) {
             final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
             setConstantState(newState);
             mMutated = true;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index df1b126..ad0b415 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -151,7 +151,7 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
+            mAnimatedVectorState.mVectorDrawable.mutate();
             mMutated = true;
         }
         return this;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 4fd98b7..c7aa98e 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -114,7 +114,8 @@
     /** Current dirty bounds, union of current and previous drawing bounds. */
     private final Rect mDirtyBounds = new Rect();
 
-    private final RippleState mState;
+    /** Mirrors mLayerState with some extra information. */
+    private RippleState mState;
 
     /** The masking layer, e.g. the layer with id R.id.mask. */
     private Drawable mMask;
@@ -885,18 +886,34 @@
         return mState;
     }
 
+    @Override
+    public Drawable mutate() {
+        super.mutate();
+
+        // LayerDrawable creates a new state using createConstantState, so
+        // this should always be a safe cast.
+        mState = (RippleState) mLayerState;
+        return this;
+    }
+
+    @Override
+    RippleState createConstantState(LayerState state, Resources res) {
+        return new RippleState(state, this, res);
+    }
+
     static class RippleState extends LayerState {
         int[] mTouchThemeAttrs;
         ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA);
         int mMaxRadius = RADIUS_AUTO;
 
-        public RippleState(RippleState orig, RippleDrawable owner, Resources res) {
+        public RippleState(LayerState orig, RippleDrawable owner, Resources res) {
             super(orig, owner, res);
 
-            if (orig != null) {
-                mTouchThemeAttrs = orig.mTouchThemeAttrs;
-                mColor = orig.mColor;
-                mMaxRadius = orig.mMaxRadius;
+            if (orig != null && orig instanceof RippleState) {
+                final RippleState origs = (RippleState) orig;
+                mTouchThemeAttrs = origs.mTouchThemeAttrs;
+                mColor = origs.mColor;
+                mMaxRadius = origs.mMaxRadius;
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index bbb0b50..8014837 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -507,9 +507,10 @@
                 pathRenderer.getAlpha());
         pathRenderer.setAlpha(alphaInFloat);
 
-        pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
-        if (pathRenderer.mRootName != null) {
-            pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
+        final String name = a.getString(R.styleable.VectorDrawable_name);
+        if (name != null) {
+            pathRenderer.mRootName = name;
+            pathRenderer.mVGTargetsMap.put(name, pathRenderer);
         }
     }
 
@@ -1313,9 +1314,15 @@
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
 
-            mPathName = a.getString(R.styleable.VectorDrawableClipPath_name);
-            mNodes = PathParser.createNodesFromPathData(a.getString(
-                    R.styleable.VectorDrawableClipPath_pathData));
+            final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+            if (pathName != null) {
+                mPathName = pathName;
+            }
+
+            final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+            if (pathData != null) {
+                mNodes = PathParser.createNodesFromPathData(pathData);
+            }
         }
 
         @Override
@@ -1415,9 +1422,15 @@
             // Extract the theme attributes, if any.
             mThemeAttrs = a.extractThemeAttrs();
 
-            mPathName = a.getString(R.styleable.VectorDrawablePath_name);
-            mNodes = PathParser.createNodesFromPathData(a.getString(
-                    R.styleable.VectorDrawablePath_pathData));
+            final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+            if (pathName != null) {
+                mPathName = pathName;
+            }
+
+            final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+            if (pathData != null) {
+                mNodes = PathParser.createNodesFromPathData(pathData);
+            }
 
             mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
                     mFillColor);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 48450dd..1a44c8c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -908,4 +908,7 @@
 
     <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
     <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
+
+    <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
+    <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index d4b403d..9d4fe66 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -177,16 +177,24 @@
                 if (t != null) {
                     Drawable cachedIcon = mApplicationIconCache.get(t.key);
                     Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
+
                     // Load the application icon if it is stale or we haven't cached one yet
                     if (cachedIcon == null) {
-                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
-                                t.key.userId);
-                        if (info != null) {
-                            cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                        cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
+                                mContext.getResources());
+
+                        if (cachedIcon == null) {
+                            ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
+                                    t.key.userId);
+                            if (info != null) {
+                                cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                            }
                         }
+
                         if (cachedIcon == null) {
                             cachedIcon = mDefaultApplicationIcon;
                         }
+
                         // At this point, even if we can't load the icon, we will set the default
                         // icon.
                         mApplicationIconCache.put(t.key, cachedIcon);
@@ -230,6 +238,17 @@
             }
         }
     }
+
+    Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
+            SystemServicesProxy ssp, Resources res) {
+        Bitmap tdIcon = iconBitmap != null
+                ? iconBitmap
+                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
+        if (tdIcon != null) {
+            return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
+        }
+        return null;
+    }
 }
 
 /* Recents task loader
@@ -321,15 +340,20 @@
         if (icon != null) {
             return icon;
         }
-        // Return the task description icon if it exists
-        if (td != null && td.getIcon() != null) {
-            icon = ssp.getBadgedIcon(new BitmapDrawable(res, td.getIcon()), taskKey.userId);
-            mApplicationIconCache.put(taskKey, icon);
-            return icon;
-        }
-        // If we are preloading this task, continue to load the activity icon
+
+        // If we are preloading this task, continue to load the task description icon or the
+        // activity icon
         if (preloadTask) {
-            // All short paths failed, load the icon from the activity info and cache it
+
+            // Return and cache the task description icon if it exists
+            Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
+                    td.getIconFilename(), ssp, res);
+            if (tdDrawable != null) {
+                mApplicationIconCache.put(taskKey, tdDrawable);
+                return tdDrawable;
+            }
+
+            // Load the icon from the activity info and cache it
             if (infoHandle.info == null) {
                 infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
                         taskKey.userId);
@@ -453,10 +477,17 @@
                 activityInfoCache.put(cnKey, infoHandle);
             }
 
+            Bitmap icon = t.taskDescription != null
+                    ? t.taskDescription.getInMemoryIcon()
+                    : null;
+            String iconFilename = t.taskDescription != null
+                    ? t.taskDescription.getIconFilename()
+                    : null;
+
             // Add the task to the stack
             Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
                     activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
-                    config.lockToAppEnabled);
+                    config.lockToAppEnabled, icon, iconFilename);
 
             if (preloadTask && loadTaskThumbnails) {
                 // Load the thumbnail from the cache if possible
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 406e03f..a7e2b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -124,7 +124,8 @@
     public boolean isActive;
     public boolean lockToThisTask;
     public boolean lockToTaskEnabled;
-
+    public Bitmap icon;
+    public String iconFilename;
     TaskCallbacks mCb;
 
     public Task() {
@@ -133,7 +134,8 @@
 
     public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
                 String activityTitle, Drawable activityIcon, int colorPrimary,
-                boolean lockToThisTask, boolean lockToTaskEnabled) {
+                boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
+                String iconFilename) {
         boolean isInAffiliationGroup = (taskAffiliation != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
         this.key = key;
@@ -147,6 +149,8 @@
         this.isActive = isActive;
         this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
         this.lockToTaskEnabled = lockToTaskEnabled;
+        this.icon = icon;
+        this.iconFilename = iconFilename;
     }
 
     /** Copies the other task. */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Interaction.java b/packages/SystemUI/src/com/android/systemui/volume/Interaction.java
new file mode 100644
index 0000000..46eab36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/Interaction.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.systemui.volume;
+
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnGenericMotionListener;
+import android.view.View.OnTouchListener;
+
+public class Interaction {
+
+    public static void register(View v, final Callback callback) {
+        v.setOnTouchListener(new OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                callback.onInteraction();
+                return false;
+            }
+        });
+        v.setOnGenericMotionListener(new OnGenericMotionListener() {
+            @Override
+            public boolean onGenericMotion(View v, MotionEvent event) {
+                callback.onInteraction();
+                return false;
+            }
+        });
+    }
+
+    public interface Callback {
+        void onInteraction();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index 66e1e15..f7f5047 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -80,6 +80,12 @@
         addView(b);
         b.setTag(value);
         b.setOnClickListener(mClick);
+        Interaction.register(b, new Interaction.Callback() {
+            @Override
+            public void onInteraction() {
+                fireInteraction();
+            }
+        });
     }
 
     public void updateLocale() {
@@ -96,6 +102,12 @@
         }
     }
 
+    private void fireInteraction() {
+        if (mCallback != null) {
+            mCallback.onInteraction();
+        }
+    }
+
     private final View.OnClickListener mClick = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -103,7 +115,7 @@
         }
     };
 
-    public interface Callback {
+    public interface Callback extends Interaction.Callback {
         void onSelected(Object value);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index fa43f32..40bdea2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -42,6 +42,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
 import android.net.Uri;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
@@ -400,11 +401,10 @@
                 | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                 | LayoutParams.FLAG_HARDWARE_ACCELERATED);
         mView = window.findViewById(R.id.content);
-        mView.setOnTouchListener(new View.OnTouchListener() {
+        Interaction.register(mView, new Interaction.Callback() {
             @Override
-            public boolean onTouch(View v, MotionEvent event) {
+            public void onInteraction() {
                 resetTimeout();
-                return false;
             }
         });
 
@@ -1382,9 +1382,10 @@
     }
 
     private void resetTimeout() {
+        final boolean touchExploration = mAccessibilityManager.isTouchExplorationEnabled();
         if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis()
-                + " delay=" + mTimeoutDelay);
-        if (sSafetyWarning == null || !mAccessibilityManager.isTouchExplorationEnabled()) {
+                + " delay=" + mTimeoutDelay + " touchExploration=" + touchExploration);
+        if (sSafetyWarning == null || !touchExploration) {
             removeMessages(MSG_TIMEOUT);
             sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay);
             removeMessages(MSG_USER_ACTIVITY);
@@ -1393,6 +1394,7 @@
     }
 
     private void forceTimeout(long delay) {
+        if (LOGD) Log.d(mTag, "forceTimeout delay=" + delay + " callers=" + Debug.getCallers(3));
         removeMessages(MSG_TIMEOUT);
         sendEmptyMessageDelayed(MSG_TIMEOUT, delay);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index c1681c7..ea431ae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -135,20 +135,21 @@
             @Override
             public void onClick(View v) {
                 setExpanded(true);
-                fireInteraction();
             }
         });
+        Interaction.register(mZenSubheadCollapsed, mInteractionCallback);
 
         mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded);
+        Interaction.register(mZenSubheadExpanded, mInteractionCallback);
 
         mMoreSettings = findViewById(R.id.zen_more_settings);
         mMoreSettings.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 fireMoreSettings();
-                fireInteraction();
             }
         });
+        Interaction.register(mMoreSettings, mInteractionCallback);
 
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
     }
@@ -444,18 +445,22 @@
                         childTag.rb.setChecked(false);
                     }
                     select(tag.condition);
-                    fireInteraction();
+                    announceConditionSelection(tag);
                 }
             }
         });
-        final TextView title = (TextView) row.findViewById(android.R.id.title);
-        if (condition == null) {
-            title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
-        } else {
-            title.setText(condition.summary);
+
+        if (tag.title == null) {
+            tag.title = (TextView) row.findViewById(android.R.id.title);
         }
-        title.setEnabled(enabled);
-        title.setAlpha(enabled ? 1 : .4f);
+        if (condition == null) {
+            tag.title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
+        } else {
+            tag.title.setText(condition.summary);
+        }
+        tag.title.setEnabled(enabled);
+        tag.title.setAlpha(enabled ? 1 : .4f);
+
         final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
         button1.setOnClickListener(new OnClickListener() {
             @Override
@@ -471,11 +476,10 @@
                 onClickTimeButton(row, tag, true /*up*/);
             }
         });
-        title.setOnClickListener(new OnClickListener() {
+        tag.title.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
                 tag.rb.setChecked(true);
-                fireInteraction();
             }
         });
 
@@ -497,6 +501,30 @@
             button1.setVisibility(View.GONE);
             button2.setVisibility(View.GONE);
         }
+        // wire up interaction callbacks for newly-added condition rows
+        if (convertView == null) {
+            Interaction.register(tag.rb, mInteractionCallback);
+            Interaction.register(tag.title, mInteractionCallback);
+            Interaction.register(button1, mInteractionCallback);
+            Interaction.register(button2, mInteractionCallback);
+        }
+    }
+
+    private void announceConditionSelection(ConditionTag tag) {
+        final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
+        String modeText;
+        switch(zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                modeText = mContext.getString(R.string.zen_important_interruptions);
+                break;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                modeText = mContext.getString(R.string.zen_no_interruptions);
+                break;
+             default:
+                return;
+        }
+        announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
+                tag.title.getText()));
     }
 
     private void onClickTimeButton(View row, ConditionTag tag, boolean up) {
@@ -530,7 +558,7 @@
         bind(mTimeCondition, row);
         tag.rb.setChecked(true);
         select(mTimeCondition);
-        fireInteraction();
+        announceConditionSelection(tag);
     }
 
     private void select(Condition condition) {
@@ -611,6 +639,7 @@
     // used as the view tag on condition rows
     private static class ConditionTag {
         RadioButton rb;
+        TextView title;
         Condition condition;
     }
 
@@ -691,5 +720,17 @@
                 mController.setZen((Integer) value);
             }
         }
+
+        @Override
+        public void onInteraction() {
+            fireInteraction();
+        }
+    };
+
+    private final Interaction.Callback mInteractionCallback = new Interaction.Callback() {
+        @Override
+        public void onInteraction() {
+            fireInteraction();
+        }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java b/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
index 96e2a8e..d887712 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
@@ -31,6 +31,7 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -110,6 +111,17 @@
         message.setText(text);
         final ImageView icon = (ImageView) mZenToast.findViewById(android.R.id.icon);
         icon.setImageResource(iconRes);
+        mZenToast.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                // noop
+            }
+
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                mZenToast.announceForAccessibility(message.getText());
+            }
+        });
         mWindowManager.addView(mZenToast, params);
         final int animDuration = res.getInteger(R.integer.zen_toast_animation_duration);
         final int visibleDuration = res.getInteger(R.integer.zen_toast_visible_duration);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 006f5db..6ea4497 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4093,6 +4093,7 @@
             } else {
                 intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
             }
+            mPowerManager.wakeUp(whenNanos / 1000000);
             mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
         }
         mCameraLensCoverState = lensCoverState;
@@ -5268,6 +5269,7 @@
     @Override
     public void systemBooted() {
         if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.bindService(mContext);
             mKeyguardDelegate.onBootCompleted();
         }
         synchronized (mLock) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index e9ca5c9..50fe7c7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -102,9 +102,12 @@
     };
 
     public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
+        mScrim = createScrim(context);
+    }
+
+    public void bindService(Context context) {
         Intent intent = new Intent();
         intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
-        mScrim = createScrim(context);
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
             if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
@@ -250,7 +253,6 @@
         if (mKeyguardService != null) {
             mKeyguardService.onSystemReady();
         } else {
-            if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
             mKeyguardState.systemIsReady = true;
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 74841ba..a30775b 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6316,7 +6316,12 @@
                 mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
-                SystemProperties.set("dev.bootcomplete", "1");
+
+                // And trigger dev.bootcomplete if we are not showing encryption progress
+                if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
+                    || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
+                    SystemProperties.set("dev.bootcomplete", "1");
+                }
                 for (int i=0; i<mStartedUsers.size(); i++) {
                     UserStartedState uss = mStartedUsers.valueAt(i);
                     if (uss.mState == UserStartedState.STATE_BOOTING) {