Merge "Remove redundant cancel events from FingerprintService" into mnc-dev
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/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/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/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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 221e925..eb84e18 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;
@@ -15075,8 +15072,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..bc63c69 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);
                 }
             }
@@ -2899,7 +2901,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);
                     }
                 }
             }
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/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