Merge "Verfiy global apps with device owner" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 1de3625..121bc8e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -668,7 +668,8 @@
 # FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
 dirs_to_document := \
 	$(dirs_to_check_apis) \
-  $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS))
+  $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
+  $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) \
 
 # These are relative to frameworks/base
 html_dirs := \
diff --git a/api/current.txt b/api/current.txt
index df9ea35..ea33eaf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28785,11 +28785,13 @@
   public class VoiceInteractionService extends android.app.Service {
     ctor public VoiceInteractionService();
     method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+    method public int getDisabledShowContext();
     method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onLaunchVoiceAssistFromKeyguard();
     method public void onReady();
     method public void onShutdown();
+    method public void setDisabledShowContext(int);
     method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -28801,6 +28803,7 @@
     method public void closeSystemDialogs();
     method public void finish();
     method public android.content.Context getContext();
+    method public int getDisabledShowContext();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
     method public void hide();
@@ -28832,6 +28835,7 @@
     method public void onTaskStarted(android.content.Intent, int);
     method public void onTrimMemory(int);
     method public void setContentView(android.view.View);
+    method public void setDisabledShowContext(int);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
     method public void show(android.os.Bundle, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb1c431..cbb1bb2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30934,11 +30934,13 @@
   public class VoiceInteractionService extends android.app.Service {
     ctor public VoiceInteractionService();
     method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+    method public int getDisabledShowContext();
     method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onLaunchVoiceAssistFromKeyguard();
     method public void onReady();
     method public void onShutdown();
+    method public void setDisabledShowContext(int);
     method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -30950,6 +30952,7 @@
     method public void closeSystemDialogs();
     method public void finish();
     method public android.content.Context getContext();
+    method public int getDisabledShowContext();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
     method public void hide();
@@ -30981,6 +30984,7 @@
     method public void onTaskStarted(android.content.Intent, int);
     method public void onTrimMemory(int);
     method public void setContentView(android.view.View);
+    method public void setDisabledShowContext(int);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
     method public void show(android.os.Bundle, int);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 849253b..08e1696 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -773,7 +773,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
-            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ad104a4..7fbb99a 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -25,6 +25,7 @@
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -238,8 +239,12 @@
             if (decorView != null && decorView.getBackground() == null) {
                 getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
             }
+            final boolean targetsM = decorView == null || decorView.getContext()
+                    .getApplicationInfo().targetSdkVersion >= VERSION_CODES.MNC;
+            ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
+                    mAllSharedElementNames;
             ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
-                    mSharedElementNames, resultCode, data);
+                    sharedElementNames, resultCode, data);
             mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
                 @Override
                 public void onTranslucentConversionComplete(boolean drawComplete) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 9673c98..40126d6 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -812,7 +812,7 @@
          * Returns true if assist data has been blocked starting at this node in the hierarchy.
          */
         public boolean isAssistBlocked() {
-            return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
+            return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
         }
 
         /**
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2b75f31..b2cec60 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -860,8 +860,23 @@
         final IMountService mountService = IMountService.Stub.asInterface(
                 ServiceManager.getService("mount"));
         try {
-            final String packageName = ActivityThread.currentOpPackageName();
+            String packageName = ActivityThread.currentOpPackageName();
+            if (packageName == null) {
+                // Package name can be null if the activity thread is running but the app
+                // hasn't bound yet. In this case we fall back to the first package in the
+                // current UID. This works for runtime permissions as permission state is
+                // per UID and permission realted app ops are updated for all UID packages.
+                String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
+                        android.os.Process.myUid());
+                if (packageNames == null || packageNames.length <= 0) {
+                    return new StorageVolume[0];
+                }
+                packageName = packageNames[0];
+            }
             final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+            if (uid <= 0) {
+                return new StorageVolume[0];
+            }
             return mountService.getVolumeList(uid, packageName);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d743484..aa22041 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -2393,7 +2393,7 @@
             intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime));
             intent.putExtra(ALARM_TIME, alarmTime);
             PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
-            manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi);
+            manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pi);
         }
 
         /**
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 549c93e..479c9e2 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -37,7 +37,6 @@
 import java.io.PrintWriter;
 import java.util.Locale;
 
-
 /**
  * Top-level service of the current global voice interactor, which is providing
  * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -154,11 +153,39 @@
     }
 
     /**
+     * Set contextual options you would always like to have disabled when a session
+     * is shown.  The flags may be any combination of
+     * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+     * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+     * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}.
+     */
+    public void setDisabledShowContext(int flags) {
+        try {
+            mSystemService.setDisabledShowContext(flags);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Return the value set by {@link #setDisabledShowContext}.
+     */
+    public int getDisabledShowContext() {
+        try {
+            return mSystemService.getDisabledShowContext();
+        } catch (RemoteException e) {
+            return 0;
+        }
+    }
+
+    /**
      * Request that the associated {@link android.service.voice.VoiceInteractionSession} be
      * shown to the user, starting it if necessary.
      * @param args Arbitrary arguments that will be propagated to the session.
      * @param flags Indicates additional optional behavior that should be performed.  May
-     * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+     * be any combination of
+     * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+     * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+      * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
      * to request that the system generate and deliver assist data on the current foreground
      * app as part of showing the session UI.
      */
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e408b36..95f96e8 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -650,7 +650,7 @@
     class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
         @Override
         public void executeMessage(Message msg) {
-            SomeArgs args;
+            SomeArgs args = null;
             switch (msg.what) {
                 case MSG_START_CONFIRMATION:
                     if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
@@ -676,6 +676,8 @@
                     args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
                     args.arg1 = onGetSupportedCommands((String[]) args.arg1);
+                    args.complete();
+                    args = null;
                     break;
                 case MSG_CANCEL:
                     if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
@@ -723,6 +725,9 @@
                     doHide();
                     break;
             }
+            if (args != null) {
+                args.recycle();
+            }
         }
 
         @Override
@@ -908,12 +913,38 @@
     }
 
     /**
+     * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
+     * VoiceInteractionService.setDisabledShowContext(int)}.
+     */
+    public void setDisabledShowContext(int flags) {
+        try {
+            mSystemService.setDisabledShowContext(flags);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
+     * VoiceInteractionService.getDisabledShowContext}.
+     */
+    public int getDisabledShowContext() {
+        try {
+            return mSystemService.getDisabledShowContext();
+        } catch (RemoteException e) {
+            return 0;
+        }
+    }
+
+    /**
      * Show the UI for this session.  This asks the system to go through the process of showing
      * your UI, which will eventually culminate in {@link #onShow}.  This is similar to calling
      * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
      * @param args Arbitrary arguments that will be propagated {@link #onShow}.
      * @param flags Indicates additional optional behavior that should be performed.  May
-     * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+     * be any combination of
+     * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+     * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+     * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
      * to request that the system generate and deliver assist data on the current foreground
      * app as part of showing the session UI.
      */
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 7f54f50..73ad981 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -37,6 +37,8 @@
     void setKeepAwake(IBinder token, boolean keepAwake);
     void closeSystemDialogs(IBinder token);
     void finish(IBinder token);
+    void setDisabledShowContext(int flags);
+    int getDisabledShowContext();
 
     /**
      * Gets the registered Sound model for keyphrase detection for the current user.
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index b0d24fd..c05e0d8 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -73,6 +73,16 @@
         }
     }
 
+    public void complete() {
+        synchronized (this) {
+            if (mWaitState != WAIT_WAITING) {
+                throw new IllegalStateException("Not waiting");
+            }
+            mWaitState = WAIT_FINISHED;
+            notifyAll();
+        }
+    }
+
     public void recycle() {
         if (mInPool) {
             throw new IllegalStateException("Already recycled.");
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index b3f688b..ca6fe61 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -285,7 +285,6 @@
 
         private final Context mContext;
         private final View mParent;
-        private final int[] mParentPositionOnScreen = new int[2];
         private final PopupWindow mPopupWindow;
         private final ViewGroup mContentContainer;
         private final int mMarginHorizontal;
@@ -339,7 +338,8 @@
         };
 
         private final Rect mViewPortOnScreen = new Rect();
-        private final Point mCoordsOnScreen = new Point();
+        private final Point mCoordsOnWindow = new Point();
+        private final int[] mTmpCoords = new int[2];
         private final Rect mTmpRect = new Rect();
 
         private final Region mTouchableRegion = new Region();
@@ -450,13 +450,11 @@
             }
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
-            // We need to specify the offset relative to mParent.
+            // We need to specify the position in window coordinates.
             // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
             // specify the popup poision in screen coordinates.
-            mParent.getLocationOnScreen(mParentPositionOnScreen);
-            final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
-            final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
-            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, relativeX, relativeY);
+            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x,
+                    mCoordsOnWindow.y);
             setTouchableSurfaceInsetsComputer();
             runShowAnimation();
         }
@@ -519,13 +517,10 @@
             cancelOverflowAnimations();
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
-            // We need to specify the offset relative to mParent.
+            // We need to specify the position in window coordinates.
             // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
             // specify the popup poision in screen coordinates.
-            mParent.getLocationOnScreen(mParentPositionOnScreen);
-            final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
-            final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
-            mPopupWindow.update(relativeX, relativeY, getWidth(), getHeight());
+            mPopupWindow.update(mCoordsOnWindow.x, mCoordsOnWindow.y, getWidth(), getHeight());
         }
 
         /**
@@ -624,7 +619,22 @@
                 mOverflowPanel.setOverflowDirection(mOverflowDirection);
             }
 
-            mCoordsOnScreen.set(x, y);
+            // We later specify the location of PopupWindow relative to the attached window.
+            // The idea here is that 1) we can get the location of a View in both window coordinates
+            // and screen coordiantes, where the offset between them should be equal to the window
+            // origin, and 2) we can use an arbitrary for this calculation while calculating the
+            // location of the rootview is supposed to be least expensive.
+            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid
+            // the following calculation.
+            mParent.getRootView().getLocationOnScreen(mTmpCoords);
+            int rootViewLeftOnScreen = mTmpCoords[0];
+            int rootViewTopOnScreen = mTmpCoords[1];
+            mParent.getRootView().getLocationInWindow(mTmpCoords);
+            int rootViewLeftOnWindow = mTmpCoords[0];
+            int rootViewTopOnWindow = mTmpCoords[1];
+            int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow;
+            int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow;
+            mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen);
         }
 
         private int getToolbarHeightWithVerticalMargin() {
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
index 7eb2aef..7294124 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -19,7 +19,7 @@
 import android.os.IBinder;
 
 /** {@hide} */
-interface IRemoteViewsAdapterConnection {
+oneway interface IRemoteViewsAdapterConnection {
     void onServiceConnected(IBinder service);
     void onServiceDisconnected();
 }
diff --git a/core/res/res/layout/common_tab_settings.xml b/core/res/res/layout/common_tab_settings.xml
new file mode 100644
index 0000000..d2a4acc
--- /dev/null
+++ b/core/res/res/layout/common_tab_settings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/tabhost"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/tabs_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="none"
+            android:fillViewport="true">
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                style="?android:attr/tabWidgetStyle" />
+
+        </HorizontalScrollView>
+
+        <!-- give an empty content area to make tabhost happy -->
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="0dip"
+            android:layout_height="0dip" />
+
+        <ListView
+            android:id="@android:id/list"
+            android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:layout_weight="1"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:smoothScrollbar="false" />
+
+    </LinearLayout>
+
+</TabHost>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d41031c..b330423 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1360,6 +1360,7 @@
   <java-symbol type="layout" name="restrictions_pin_setup" />
   <java-symbol type="layout" name="immersive_mode_cling" />
   <java-symbol type="layout" name="user_switching_dialog" />
+  <java-symbol type="layout" name="common_tab_settings" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd
index 20018c3..c7f6fcb 100644
--- a/docs/html/distribute/essentials/quality/tv.jd
+++ b/docs/html/distribute/essentials/quality/tv.jd
@@ -418,9 +418,9 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      If the app continues to play sound after the user has left, the app provides a <em>Now
-      Playing</em> card on the home screen recommendation row so users can return to the app to
-      control playback.
+      If the app continues to play sound or video after the user has left, the
+      app provides a <em>Now Playing</em> card on the home screen recommendation
+      row so users can return to the app to control playback.
       (<a href="{@docRoot}training/tv/playback/now-playing.html">Learn how</a>)
     </p>
   </td>
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 260fb6f..09f93b8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -145,7 +145,11 @@
 void CanvasContext::makeCurrent() {
     // TODO: Figure out why this workaround is needed, see b/13913604
     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
-    mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
+    EGLint error = 0;
+    mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
+    if (error) {
+        setSurface(nullptr);
+    }
 }
 
 void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index cb34e00..eb332d5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -217,7 +217,7 @@
     mCurrentSurface = EGL_NO_SURFACE;
 }
 
-bool EglManager::makeCurrent(EGLSurface surface) {
+bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
     if (isCurrent(surface)) return false;
 
     if (surface == EGL_NO_SURFACE) {
@@ -225,8 +225,14 @@
         surface = mPBufferSurface;
     }
     if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
-        LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
-                (void*)surface, egl_error_str());
+        if (errOut) {
+            *errOut = eglGetError();
+            ALOGW("Failed to make current on surface %p, error=%s",
+                    (void*)surface, egl_error_str(*errOut));
+        } else {
+            LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
+                    (void*)surface, egl_error_str());
+        }
     }
     mCurrentSurface = surface;
     return true;
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 8881de6..0a8cfd3 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -44,7 +44,7 @@
 
     bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
     // Returns true if the current surface changed, false if it was already current
-    bool makeCurrent(EGLSurface surface);
+    bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr);
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
     bool swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height);
 
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index a519d3f..6facb71 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -20,6 +20,7 @@
     android:minHeight="@dimen/qs_detail_item_height"
     android:background="@drawable/btn_borderless_rect"
     android:clickable="true"
+    android:focusable="true"
     android:gravity="center_vertical"
     android:orientation="horizontal" >
 
@@ -57,6 +58,7 @@
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:clickable="true"
+        android:focusable="true"
         android:scaleType="center"
         android:src="@drawable/ic_qs_cancel" />
 
diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
index 6a000fd..dc7577a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
@@ -27,6 +27,7 @@
             android:layout_width="48dp"
             android:layout_height="48dp"
             android:layout_gravity="end"
+            android:focusable="true"
             android:background="@drawable/ripple_drawable"
             android:contentDescription="@string/accessibility_clear_all"/>
 </com.android.systemui.statusbar.DismissView>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index da1f03e..f7c3c67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -478,7 +478,6 @@
     }
 
     private void setTint(ImageView v, int tint) {
-        v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
         v.setImageTintList(ColorStateList.valueOf(tint));
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37aa408..1582037 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10801,6 +10801,8 @@
         }
 
         // We are now ready to launch the assist activity.
+        IResultReceiver sendReceiver = null;
+        Bundle sendBundle = null;
         synchronized (this) {
             buildAssistBundleLocked(pae, extras);
             boolean exists = mPendingAssistExtras.remove(pae);
@@ -10809,19 +10811,21 @@
                 // Timed out.
                 return;
             }
-            if (pae.receiver != null) {
+            if ((sendReceiver=pae.receiver) != null) {
                 // Caller wants result sent back to them.
-                Bundle topBundle = new Bundle();
-                topBundle.putBundle("data", pae.extras);
-                topBundle.putParcelable("structure", pae.structure);
-                topBundle.putParcelable("content", pae.content);
-                try {
-                    pae.receiver.send(0, topBundle);
-                } catch (RemoteException e) {
-                }
-                return;
+                sendBundle = new Bundle();
+                sendBundle.putBundle("data", pae.extras);
+                sendBundle.putParcelable("structure", pae.structure);
+                sendBundle.putParcelable("content", pae.content);
             }
         }
+        if (sendReceiver != null) {
+            try {
+                sendReceiver.send(0, sendBundle);
+            } catch (RemoteException e) {
+            }
+            return;
+        }
 
         long ident = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index a71dfcd..8871e64 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -86,6 +86,7 @@
     private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
 
     Handler mHandler = new Handler() {
+        @Override
         public void handleMessage(android.os.Message msg) {
             switch (msg.what) {
                 case MSG_USER_SWITCHING:
@@ -274,7 +275,7 @@
             Slog.w(TAG, "enroll: no fingeprintd!");
             return;
         }
-        stopPendingOperations();
+        stopPendingOperations(true);
         mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
         final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
         try {
@@ -315,17 +316,23 @@
         return 0;
     }
 
-    private void stopPendingOperations() {
+    private void stopPendingOperations(boolean initiatedByClient) {
         if (mEnrollClient != null) {
-            stopEnrollment(mEnrollClient.token, true);
+            stopEnrollment(mEnrollClient.token, initiatedByClient);
         }
         if (mAuthClient != null) {
-            stopAuthentication(mAuthClient.token, true);
+            stopAuthentication(mAuthClient.token, initiatedByClient);
         }
         // mRemoveClient is allowed to continue
     }
 
-    void stopEnrollment(IBinder token, boolean notify) {
+    /**
+     * Stop enrollment in progress and inform client if they initiated it.
+     *
+     * @param token token for client
+     * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+     */
+    void stopEnrollment(IBinder token, boolean initiatedByClient) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopEnrollment: no fingeprintd!");
@@ -333,15 +340,15 @@
         }
         final ClientMonitor client = mEnrollClient;
         if (client == null || client.token != token) return;
-        try {
-            int result = daemon.cancelEnrollment();
-            if (result != 0) {
-                Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+        if (initiatedByClient) {
+            try {
+                int result = daemon.cancelEnrollment();
+                if (result != 0) {
+                    Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "stopEnrollment failed", e);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "stopEnrollment failed", e);
-        }
-        if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mEnrollClient);
@@ -354,7 +361,7 @@
             Slog.w(TAG, "startAuthentication: no fingeprintd!");
             return;
         }
-        stopPendingOperations();
+        stopPendingOperations(true);
         mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
         if (inLockoutMode()) {
             Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -374,7 +381,13 @@
         }
     }
 
-    void stopAuthentication(IBinder token, boolean notify) {
+    /**
+     * Stop authentication in progress and inform client if they initiated it.
+     *
+     * @param token token for client
+     * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+     */
+    void stopAuthentication(IBinder token, boolean initiatedByClient) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopAuthentication: no fingeprintd!");
@@ -382,15 +395,15 @@
         }
         final ClientMonitor client = mAuthClient;
         if (client == null || client.token != token) return;
-        try {
-            int result = daemon.cancelAuthentication();
-            if (result != 0) {
-                Slog.w(TAG, "stopAuthentication failed, result=" + result);
+        if (initiatedByClient) {
+            try {
+                int result = daemon.cancelAuthentication();
+                if (result != 0) {
+                    Slog.w(TAG, "stopAuthentication failed, result=" + result);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "stopAuthentication failed", e);
             }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "stopAuthentication failed", e);
-        }
-        if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mAuthClient);
@@ -486,12 +499,14 @@
             receiver = null;
         }
 
+        @Override
         public void binderDied() {
             token = null;
             removeClient(this);
             receiver = null;
         }
 
+        @Override
         protected void finalize() throws Throwable {
             try {
                 if (token != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7cc857f..7602990 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -801,12 +801,9 @@
     }
 
     private static boolean hasValidDomains(ActivityIntentInfo filter) {
-        boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
-                filter.hasDataScheme(IntentFilter.SCHEME_HTTPS);
-        if (!hasHTTPorHTTPS) {
-            return false;
-        }
-        return true;
+        return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+                && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                        filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
     }
 
     private IntentFilterVerifier mIntentFilterVerifier;
@@ -4420,9 +4417,7 @@
             synchronized(mPackages) {
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, 0, sourceUserId, parent.id);
-                return xpDomainInfo != null
-                        && xpDomainInfo.bestDomainVerificationStatus !=
-                                INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+                return xpDomainInfo != null;
             }
         }
         return false;
@@ -4579,6 +4574,11 @@
                         result.bestDomainVerificationStatus);
             }
         }
+        // Don't consider matches with status NEVER across profiles.
+        if (result != null && result.bestDomainVerificationStatus
+                == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+            return null;
+        }
         return result;
     }
 
@@ -4716,8 +4716,7 @@
                 } else {
                     // Browser/generic handling case.  If there's a default browser, go straight
                     // to that (but only if there is no other higher-priority match).
-                    final String defaultBrowserPackageName = getDefaultBrowserPackageName(
-                            UserHandle.myUserId());
+                    final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
                     int maxMatchPrio = 0;
                     ResolveInfo defaultBrowserMatch = null;
                     final int numCandidates = matchAllList.size();
@@ -9929,7 +9928,7 @@
             if (packageName != null) {
                 result |= updateIntentVerificationStatus(packageName,
                         PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
-                        UserHandle.myUserId());
+                        userId);
                 mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
                         packageName, userId);
             }
@@ -15081,8 +15080,9 @@
         }
         if (filters != null && filters.size() > 0) {
             for (IntentFilter filter : filters) {
-                if (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
-                        filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+                if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+                        && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                                filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
                     result.addAll(filter.getHostsList());
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 4faf75a..bbdfe31 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -238,6 +238,7 @@
         installStatus = base.installStatus;
         keySetData = base.keySetData;
         verificationInfo = base.verificationInfo;
+        installerPackageName = base.installerPackageName;
     }
 
     private PackageUserState modifyUserState(int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 978ed51..13e075c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -126,6 +126,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 
@@ -1875,21 +1876,33 @@
         if (permission != null) {
             if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
                 final int callingUid = Binder.getCallingUid();
-                // check if this is a system uid first before bothering with
-                // obtaining package name
+                // system processes will be automatically allowed privilege to draw
                 if (callingUid == Process.SYSTEM_UID) {
                     return WindowManagerGlobal.ADD_OKAY;
                 }
 
+                // check if user has enabled this operation. SecurityException will be thrown if
+                // this app has not been allowed by the user
                 final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
                         attrs.packageName);
-                if (mode == AppOpsManager.MODE_DEFAULT) {
-                    if (mContext.checkCallingPermission(permission) !=
-                            PackageManager.PERMISSION_GRANTED) {
+                switch (mode) {
+                    case AppOpsManager.MODE_ALLOWED:
+                    case AppOpsManager.MODE_IGNORED:
+                        // although we return ADD_OKAY for MODE_IGNORED, the added window will
+                        // actually be hidden in WindowManagerService
+                        return WindowManagerGlobal.ADD_OKAY;
+                    case AppOpsManager.MODE_ERRORED:
                         return WindowManagerGlobal.ADD_PERMISSION_DENIED;
-                    }
+                    default:
+                        // in the default mode, we will make a decision here based on
+                        // checkCallingPermission()
+                        if (mContext.checkCallingPermission(permission) !=
+                                PackageManager.PERMISSION_GRANTED) {
+                            return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+                        } else {
+                            return WindowManagerGlobal.ADD_OKAY;
+                        }
                 }
-                return WindowManagerGlobal.ADD_OKAY;
             }
 
             if (mContext.checkCallingOrSelfPermission(permission)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 05c111c..c776e8f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2543,8 +2543,10 @@
             win.attach();
             mWindowMap.put(client.asBinder(), win);
             if (win.mAppOp != AppOpsManager.OP_NONE) {
-                if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
-                        != AppOpsManager.MODE_ALLOWED) {
+                int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
+                        win.getOwningPackage());
+                if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
+                        (startOpResult != AppOpsManager.MODE_DEFAULT)) {
                     win.setAppOpVisibilityLw(false);
                 }
             }
@@ -2728,10 +2730,10 @@
             wasVisible = win.isWinVisibleLw();
             if (wasVisible) {
 
-                int transit = WindowManagerPolicy.TRANSIT_EXIT;
-                if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
-                    transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
-                }
+                final int transit = (!startingWindow)
+                        ? WindowManagerPolicy.TRANSIT_EXIT
+                        : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+
                 // Try starting an animation.
                 if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
                     win.mExiting = true;
@@ -2743,12 +2745,13 @@
                 }
             }
             final AppWindowToken appToken = win.mAppToken;
+            final boolean isAnimating = win.mWinAnimator.isAnimating();
             // The starting window is the last window in this app token and it isn't animating.
             // Allow it to be removed now as there is no additional window or animation that will
             // trigger its removal.
             final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
-                    && appToken.allAppWindows.size() == 1 && !win.mWinAnimator.isAnimating();
-            if (!lastWinStartingNotAnimating && (win.mExiting || win.mWinAnimator.isAnimating())) {
+                    && appToken.allAppWindows.size() == 1 && !isAnimating;
+            if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) {
                 // The exit animation is running... wait for it!
                 win.mExiting = true;
                 win.mRemoveOnExit = true;
@@ -2899,7 +2902,8 @@
                     if (win.mAppOp != AppOpsManager.OP_NONE) {
                         final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
                                 win.getOwningPackage());
-                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+                        win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
+                                mode == AppOpsManager.MODE_DEFAULT);
                     }
                 }
             }
@@ -4524,7 +4528,10 @@
         }
 
         wtoken.willBeHidden = false;
-        if (wtoken.hidden == visible) {
+        // Allow for state changes and animation to be applied if token is transitioning
+        // visibility state or the token was marked as hidden and is exiting before we had a chance
+        // to play the transition animation.
+        if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) {
             boolean changed = false;
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 36478da..42f879c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -578,6 +578,44 @@
             }
         }
 
+        @Override
+        public void setDisabledShowContext(int flags) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
+                    return;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.setDisabledShowContextLocked(callingPid, callingUid, flags);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+
+        }
+
+        @Override
+        public int getDisabledShowContext() {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
+                    return 0;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.getDisabledShowContextLocked(callingPid, callingUid);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+
+        }
+
         //----------------- Model management APIs --------------------------------//
 
         @Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e5faf4d..7409f99 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -65,6 +65,7 @@
     IVoiceInteractionService mService;
 
     VoiceInteractionSessionConnection mActiveSession;
+    int mDisabledShowContext;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -146,7 +147,7 @@
             mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
                     mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
         }
-        return mActiveSession.showLocked(args, flags, showCallback);
+        return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback);
     }
 
     public boolean hideSessionLocked() {
@@ -222,6 +223,24 @@
         mActiveSession = null;
     }
 
+    public void setDisabledShowContextLocked(int callingPid, int callingUid, int flags) {
+        int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+        if (callingUid != activeUid) {
+            throw new SecurityException("Calling uid " + callingUid
+                    + " does not match active uid " + activeUid);
+        }
+        mDisabledShowContext = flags;
+    }
+
+    public int getDisabledShowContextLocked(int callingPid, int callingUid) {
+        int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+        if (callingUid != activeUid) {
+            throw new SecurityException("Calling uid " + callingUid
+                    + " does not match active uid " + activeUid);
+        }
+        return mDisabledShowContext;
+    }
+
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -235,6 +254,10 @@
         pw.print("  mComponent="); pw.println(mComponent.flattenToShortString());
         pw.print("  Session service="); pw.println(mInfo.getSessionService());
         pw.print("  Settings activity="); pw.println(mInfo.getSettingsActivity());
+        if (mDisabledShowContext != 0) {
+            pw.print("  mDisabledShowContext=");
+            pw.println(Integer.toHexString(mDisabledShowContext));
+        }
         pw.print("  mBound="); pw.print(mBound);  pw.print(" mService="); pw.println(mService);
         if (mActiveSession != null) {
             pw.println("  Active session:");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index bd043ac..dfdd639 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -183,7 +183,7 @@
         }
     }
 
-    public boolean showLocked(Bundle args, int flags,
+    public boolean showLocked(Bundle args, int flags, int disabledContext,
             IVoiceInteractionSessionShowCallback showCallback) {
         if (mBound) {
             if (!mFullyBound) {
@@ -200,15 +200,17 @@
             }
             boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                     Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0
-                    && isScreenCaptureAllowed;
+                    && isScreenCaptureAllowed
+                    && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0;
             boolean screenshotEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                     Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) != 0
-                    && isScreenCaptureAllowed;
+                    && isScreenCaptureAllowed
+                    && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0;
             mShowArgs = args;
             mShowFlags = flags;
             mHaveAssistData = false;
             boolean needDisclosure = false;
-            if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
+            if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && structureEnabled) {
@@ -226,7 +228,7 @@
                 mAssistData = null;
             }
             mHaveScreenshot = false;
-            if ((flags& VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
+            if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid,
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && screenshotEnabled) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f4a6064..32b7383 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -21,12 +21,15 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.telephony.Rlog;
 import android.os.Handler;
 import android.os.Message;
 import android.os.ServiceManager;
 import android.os.RemoteException;
+import android.util.DisplayMetrics;
 
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -248,6 +251,78 @@
     public static final String MNC = "mnc";
 
     /**
+     *  TelephonyProvider column name for extreme threat in CB settings
+     * @hide
+     */
+    public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+    /**
+     * TelephonyProvider column name for severe threat in CB settings
+     *@hide
+     */
+    public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+    /**
+     * TelephonyProvider column name for amber alert in CB settings
+     *@hide
+     */
+    public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+    /**
+     * TelephonyProvider column name for emergency alert in CB settings
+     *@hide
+     */
+    public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+    /**
+     * TelephonyProvider column name for alert sound duration in CB settings
+     *@hide
+     */
+    public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+    /**
+     * TelephonyProvider column name for alert reminder interval in CB settings
+     *@hide
+     */
+    public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+    /**
+     * TelephonyProvider column name for enabling vibrate in CB settings
+     *@hide
+     */
+    public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+    /**
+     * TelephonyProvider column name for enabling alert speech in CB settings
+     *@hide
+     */
+    public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+    /**
+     * TelephonyProvider column name for ETWS test alert in CB settings
+     *@hide
+     */
+    public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+    /**
+     * TelephonyProvider column name for enable channel50 alert in CB settings
+     *@hide
+     */
+    public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+    /**
+     * TelephonyProvider column name for CMAS test alert in CB settings
+     *@hide
+     */
+    public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+
+    /**
+     * TelephonyProvider column name for Opt out dialog in CB settings
+     *@hide
+     */
+    public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+    /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
      *
@@ -1137,6 +1212,112 @@
     }
 
     /**
+     * Store properties associated with SubscriptionInfo in database
+     * @param subId Subscription Id of Subscription
+     * @param propKey Column name in database associated with SubscriptionInfo
+     * @param propValue Value to store in DB for particular subId & column name
+     * @hide
+     */
+    public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                iSub.setSubscriptionProperty(subId, propKey, propValue);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+    }
+
+    /**
+     * Store properties associated with SubscriptionInfo in database
+     * @param subId Subscription Id of Subscription
+     * @param propKey Column name in SubscriptionInfo database
+     * @return Value associated with subId and propKey column in database
+     * @hide
+     */
+    private static String getSubscriptionProperty(int subId, String propKey,
+            Context context) {
+        String resultValue = null;
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                resultValue = iSub.getSubscriptionProperty(subId, propKey, 
+                    context.getOpPackageName());
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return resultValue;
+    }
+
+    /**
+     * Returns boolean value corresponding to query result.
+     * @param subId Subscription Id of Subscription
+     * @param propKey Column name in SubscriptionInfo database
+     * @param defValue Default boolean value to be returned
+     * @return boolean result value to be returned
+     * @hide
+     */
+    public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
+            boolean defValue, Context context) {
+        String result = getSubscriptionProperty(subId, propKey, context);
+        if (result != null) {
+            try {
+                return Integer.parseInt(result) == 1;
+            } catch (NumberFormatException err) {
+                logd("getBooleanSubscriptionProperty NumberFormat exception");
+            }
+        }
+        return defValue;
+    }
+
+    /**
+     * Returns integer value corresponding to query result.
+     * @param subId Subscription Id of Subscription
+     * @param propKey Column name in SubscriptionInfo database
+     * @param defValue Default integer value to be returned
+     * @return integer result value to be returned
+     * @hide
+     */
+    public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
+            Context context) {
+        String result = getSubscriptionProperty(subId, propKey, context);
+        if (result != null) {
+            try {
+                return Integer.parseInt(result);
+            } catch (NumberFormatException err) {
+                logd("getBooleanSubscriptionProperty NumberFormat exception");
+            }
+        }
+        return defValue;
+    }
+
+    /**
+     * Returns the resources associated with Subscription.
+     * @param context Context object
+     * @param subId Subscription Id of Subscription who's resources are required
+     * @return Resources associated with Subscription.
+     * @hide
+     */
+    public static Resources getResourcesForSubId(Context context, int subId) {
+        final SubscriptionInfo subInfo =
+                SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
+
+        Configuration config = context.getResources().getConfiguration();
+        Configuration newConfig = new Configuration();
+        newConfig.setTo(config);
+        if (subInfo != null) {
+            newConfig.mcc = subInfo.getMcc();
+            newConfig.mnc = subInfo.getMnc();
+        }
+        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        DisplayMetrics newMetrics = new DisplayMetrics();
+        newMetrics.setTo(metrics);
+        return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+    }
+
+    /**
      * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
      * and the SIM providing the subscription is present in a slot and in "LOADED" state.
      * @hide
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 0555121..f6aef08 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -172,6 +172,10 @@
 
     int[] getActiveSubIdList();
 
+    void setSubscriptionProperty(int subId, String propKey, String propValue);
+
+    String getSubscriptionProperty(int subId, String propKey, String callingPackage);
+
     /**
      * Get the SIM state for the slot idx
      * @return SIM state as the ordinal of IccCardConstants.State
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index 610f30b..dc4e31b 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -31,33 +31,56 @@
         android:layout_height="match_parent"
         android:fitsSystemWindows="true">
 
-        <LinearLayout android:id="@+id/top_content"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top"
-            android:orientation="horizontal"
-            android:background="#ffffffff"
-            android:elevation="8dp"
-            >
-            <ImageView android:id="@+id/screenshot"
-                android:layout_width="wrap_content"
-                android:layout_height="46dp"
-                android:adjustViewBounds="true" />
-            <View android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-            <Button android:id="@+id/do_tree"
-                android:layout_width="wrap_content"
+        <LinearLayout
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/tree" />
-            <Button android:id="@+id/do_text"
-                android:layout_width="wrap_content"
+                android:layout_gravity="top"
+                android:orientation="vertical"
+                android:background="#ffffffff"
+                android:elevation="8dp"
+                >
+            <LinearLayout android:id="@+id/top_content"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/text" />
-            <Button android:id="@+id/start"
-                android:layout_width="wrap_content"
+                android:orientation="horizontal"
+                >
+                <ImageView android:id="@+id/screenshot"
+                    android:layout_width="wrap_content"
+                    android:layout_height="46dp"
+                    android:adjustViewBounds="true" />
+                <View android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:layout_weight="1" />
+                <CheckBox android:id="@+id/show_options"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+                <Button android:id="@+id/do_tree"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/tree" />
+                <Button android:id="@+id/do_text"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/text" />
+                <Button android:id="@+id/start"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/start" />
+            </LinearLayout>
+            <LinearLayout android:id="@+id/options"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:text="@string/start" />
+                android:orientation="vertical"
+                >
+                <CheckBox android:id="@+id/disallow_structure"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Disallow context" />
+                <CheckBox android:id="@+id/disallow_screenshot"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Disallow screenshot" />
+            </LinearLayout>
         </LinearLayout>
 
         <LinearLayout android:id="@+id/bottom_content"
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index a6585ba..8796c9f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
+import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -45,6 +46,10 @@
     Button mTreeButton;
     Button mTextButton;
     Button mStartButton;
+    CheckBox mOptionsCheck;
+    View mOptionsContainer;
+    CheckBox mDisallowAssist;
+    CheckBox mDisallowScreenshot;
     ImageView mScreenshot;
     ImageView mFullScreenshot;
     Button mConfirmButton;
@@ -122,15 +127,34 @@
         mScreenshot = (ImageView)mContentView.findViewById(R.id.screenshot);
         mScreenshot.setOnClickListener(this);
         mFullScreenshot = (ImageView)mContentView.findViewById(R.id.full_screenshot);
+        mOptionsCheck = (CheckBox)mContentView.findViewById(R.id.show_options);
+        mOptionsCheck.setOnClickListener(this);
+        mOptionsContainer = mContentView.findViewById(R.id.options);
+        mDisallowAssist = (CheckBox)mContentView.findViewById(R.id.disallow_structure);
+        mDisallowAssist.setOnClickListener(this);
+        mDisallowScreenshot = (CheckBox)mContentView.findViewById(R.id.disallow_screenshot);
+        mDisallowScreenshot.setOnClickListener(this);
         mConfirmButton = (Button)mContentView.findViewById(R.id.confirm);
         mConfirmButton.setOnClickListener(this);
         mCompleteButton = (Button)mContentView.findViewById(R.id.complete);
         mCompleteButton.setOnClickListener(this);
         mAbortButton = (Button)mContentView.findViewById(R.id.abort);
         mAbortButton.setOnClickListener(this);
+        refreshOptions();
         return mContentView;
     }
 
+    void refreshOptions() {
+        if (mOptionsCheck.isChecked()) {
+            mOptionsContainer.setVisibility(View.VISIBLE);
+            int flags = getDisabledShowContext();
+            mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0);
+            mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0);
+        } else {
+            mOptionsContainer.setVisibility(View.GONE);
+        }
+    }
+
     public void onHandleAssist(Bundle assistBundle) {
     }
 
@@ -202,6 +226,24 @@
             if (mAssistVisualizer != null) {
                 mAssistVisualizer.logText();
             }
+        } else if (v == mOptionsCheck) {
+            refreshOptions();
+        } else if (v == mDisallowAssist) {
+            int flags = getDisabledShowContext();
+            if (mDisallowAssist.isChecked()) {
+                flags |= SHOW_WITH_ASSIST;
+            } else {
+                flags &= ~SHOW_WITH_ASSIST;
+            }
+            setDisabledShowContext(flags);
+        } else if (v == mDisallowScreenshot) {
+            int flags = getDisabledShowContext();
+            if (mDisallowScreenshot.isChecked()) {
+                flags |= SHOW_WITH_SCREENSHOT;
+            } else {
+                flags &= ~SHOW_WITH_SCREENSHOT;
+            }
+            setDisabledShowContext(flags);
         } else if (v == mStartButton) {
             mState = STATE_LAUNCHING;
             updateState();
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 2487e1ca..b0d6b39 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -103,6 +103,14 @@
                 }
             };
             mInteractor.submitRequest(mCurrentRequest, REQUEST_CONFIRM);
+            String[] cmds = new String[] {
+                    "com.android.test.voiceinteraction.COMMAND",
+                    "com.example.foo.bar"
+            };
+            boolean sup[] = mInteractor.supportsCommands(cmds);
+            for (int i=0; i<cmds.length; i++) {
+                mLog.append(cmds[i] + ": " + (sup[i] ? "SUPPORTED" : "NOT SUPPORTED") + "\n");
+            }
         } else {
             Log.i(TAG, "Restarting with active confirmation: " + mCurrentRequest);
         }
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 20b6e41..1e33e3a 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -25,6 +25,7 @@
 import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
 import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.util.ReflectionUtils;
@@ -33,10 +34,13 @@
 
 import org.xmlpull.v1.XmlPullParser;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.util.AttributeSet;
 
 import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
 
 import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext;
 
@@ -48,6 +52,7 @@
     private final LayoutlibCallback mLayoutlibCallback;
     private boolean mIsInMerge = false;
     private ResourceReference mResourceReference;
+    private Map<View, String> mOpenDrawerLayouts;
 
     /**
      * List of class prefixes which are tried first by default.
@@ -256,7 +261,14 @@
                     resourceId = 0;
                 }
                 RecyclerViewUtil.setAdapter(view, bc, mLayoutlibCallback, resourceId);
+            } else if (ReflectionUtils.isInstanceOf(view, DrawerLayoutUtil.CN_DRAWER_LAYOUT)) {
+                String attrVal = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI,
+                        BridgeConstants.ATTR_OPEN_DRAWER);
+                if (attrVal != null) {
+                    getDrawerLayoutMap().put(view, attrVal);
+                }
             }
+
         }
     }
 
@@ -312,4 +324,28 @@
 
         return viewKey;
     }
+
+    public void postInflateProcess(View view) {
+        if (mOpenDrawerLayouts != null) {
+            String gravity = mOpenDrawerLayouts.get(view);
+            if (gravity != null) {
+                DrawerLayoutUtil.openDrawer(view, gravity);
+            }
+            mOpenDrawerLayouts.remove(view);
+        }
+    }
+
+    @NonNull
+    private Map<View, String> getDrawerLayoutMap() {
+        if (mOpenDrawerLayouts == null) {
+            mOpenDrawerLayouts = new HashMap<View, String>(4);
+        }
+        return mOpenDrawerLayouts;
+    }
+
+    public void onDoneInflation() {
+        if (mOpenDrawerLayouts != null) {
+            mOpenDrawerLayouts.clear();
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 661c08b9..6228766 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -50,6 +50,9 @@
     public final static String FILL_PARENT = "fill_parent";
     public final static String WRAP_CONTENT = "wrap_content";
 
+    // Should be kept in sync with LayoutMetadata.KEY_LV_ITEM in tools/adt/idea
     /** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
-    public static final String ATTR_LIST_ITEM = "list_item";
+    @SuppressWarnings("SpellCheckingInspection")
+    public static final String ATTR_LIST_ITEM = "listitem";
+    public static final String ATTR_OPEN_DRAWER = "openDrawer";
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
new file mode 100644
index 0000000..40d3811
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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.layoutlib.bridge.android.support;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+
+import android.annotation.Nullable;
+import android.view.View;
+
+import static android.view.Gravity.END;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.START;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+
+public class DrawerLayoutUtil {
+
+    public static final String CN_DRAWER_LAYOUT = "android.support.v4.widget.DrawerLayout";
+
+    public static void openDrawer(View drawerLayout, @Nullable String drawerGravity) {
+        int gravity = -1;
+        if ("left".equals(drawerGravity)) {
+            gravity = LEFT;
+        } else if ("right".equals(drawerGravity)) {
+            gravity = RIGHT;
+        } else if ("start".equals(drawerGravity)) {
+            gravity = START;
+        } else if ("end".equals(drawerGravity)) {
+            gravity = END;
+        }
+        if (gravity > 0) {
+            openDrawer(drawerLayout, gravity);
+        }
+    }
+
+    private static void openDrawer(View drawerLayout, int gravity) {
+        try {
+            invoke(getMethod(drawerLayout.getClass(), "openDrawer", int.class), drawerLayout,
+                    gravity);
+        } catch (ReflectionException e) {
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to open navigation drawer",
+                    getCause(e), null);
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index 4182cd9..d14c80b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -21,6 +21,7 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.util.ReflectionUtils;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +31,7 @@
 import java.lang.reflect.Method;
 
 import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
 
@@ -70,11 +72,6 @@
         }
     }
 
-    private static Throwable getCause(Throwable throwable) {
-        Throwable cause = throwable.getCause();
-        return cause == null ? throwable : cause;
-    }
-
     private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
             @NonNull LayoutlibCallback callback) throws ReflectionException {
         if (getLayoutManager(recyclerView) == null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 72e97ad..23df3f1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -423,6 +423,7 @@
 
             // post-inflate process. For now this supports TabHost/TabWidget
             postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
+            mInflater.onDoneInflation();
 
             setActiveToolbar(view, context, params);
 
@@ -1342,6 +1343,7 @@
                 }
             }
         } else if (view instanceof ViewGroup) {
+            mInflater.postInflateProcess(view);
             ViewGroup group = (ViewGroup) view;
             final int count = group.getChildCount();
             for (int c = 0; c < count; c++) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
index b78b613..7ce27b6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -27,7 +27,7 @@
  */
 public class ReflectionUtils {
 
-    @Nullable
+    @NonNull
     public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
             @Nullable Class<?>... params) throws ReflectionException {
         try {
@@ -67,6 +67,12 @@
         return false;
     }
 
+    @NonNull
+    public static Throwable getCause(@NonNull Throwable throwable) {
+        Throwable cause = throwable.getCause();
+        return cause == null ? throwable : cause;
+    }
+
     /**
      * Wraps all reflection related exceptions. Created since ReflectiveOperationException was
      * introduced in 1.7 and we are still on 1.6