Merge "Support specifying buffer start offset for USB requests." into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index c605295..53650e5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6716,6 +6716,7 @@
     method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract deprecated void removePackageFromPreferred(java.lang.String);
     method public abstract void removePermission(java.lang.String);
+    method public android.content.Intent buildPermissionRequestIntent(java.lang.String...);
     method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
     method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
     method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
diff --git a/cmds/interrupter/Android.mk b/cmds/interrupter/Android.mk
new file mode 100644
index 0000000..e324627
--- /dev/null
+++ b/cmds/interrupter/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    interrupter.c
+LOCAL_MODULE := interrupter
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_LDFLAGS := -ldl
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    interrupter.c
+LOCAL_MODULE := interrupter
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_LDFLAGS := -ldl
+
+include $(BUILD_HOST_SHARED_LIBRARY)
\ No newline at end of file
diff --git a/cmds/interrupter/interrupter.c b/cmds/interrupter/interrupter.c
new file mode 100644
index 0000000..ae55515
--- /dev/null
+++ b/cmds/interrupter/interrupter.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+
+/**
+ * The probability of a syscall failing from 0.0 to 1.0
+ */
+#define PROBABILITY 0.9
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* for various intercepted calls */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* For builds on glibc */
+#define __USE_GNU
+#include <dlfcn.h>
+
+#include "interrupter.h"
+
+static int probability = PROBABILITY * RAND_MAX;
+
+static int maybe_interrupt() {
+    if (rand() < probability) {
+        return 1;
+    }
+    return 0;
+}
+
+DEFINE_INTERCEPT(read, ssize_t, int, void*, size_t);
+DEFINE_INTERCEPT(write, ssize_t, int, const void*, size_t);
+DEFINE_INTERCEPT(accept, int, int, struct sockaddr*, socklen_t*);
+DEFINE_INTERCEPT(creat, int, const char*, mode_t);
diff --git a/cmds/interrupter/interrupter.h b/cmds/interrupter/interrupter.h
new file mode 100644
index 0000000..9ad0277e
--- /dev/null
+++ b/cmds/interrupter/interrupter.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012, 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.
+ */
+
+#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
+#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
+#define CONCATENATE2(arg1, arg2)  arg1##arg2
+
+#define INTERRUPTER(sym) \
+    if (real_##sym == NULL) \
+        __init_##sym(); \
+    if (maybe_interrupt()) { \
+        errno = EINTR; \
+        return -1; \
+    }
+
+#define CALL_FUNCTION_1(sym, ret, type1) \
+ret (*real_##sym)(type1) = NULL; \
+ret sym(type1 arg1) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1); \
+}
+
+#define CALL_FUNCTION_2(sym, ret, type1, type2) \
+ret (*real_##sym)(type1, type2) = NULL; \
+ret sym(type1 arg1, type2 arg2) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2); \
+}
+
+#define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \
+ret (*real_##sym)(type1, type2, type3) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3); \
+}
+
+#define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \
+ret (*real_##sym)(type1, type2, type3, type4) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3, arg4); \
+}
+
+#define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \
+ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3, arg4, arg5); \
+}
+
+#define DEFINE_INTERCEPT_N(N, sym, ret, ...) \
+static void __init_##sym(void); \
+CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \
+static void __init_##sym(void) { \
+    real_##sym = dlsym(RTLD_NEXT, #sym); \
+    if (real_##sym == NULL) { \
+        fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \
+    } \
+}
+
+#define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N())
+#define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__)
+#define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
+#define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+#define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__)
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 98c82b5..224945a 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1218,7 +1218,8 @@
         ComponentName cn = ComponentName.unflattenFromString(pkg);
         if (cn == null) {
             try {
-                mPm.setApplicationEnabledSetting(pkg, state, 0, userId);
+                mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
+                        "shell:" + android.os.Process.myUid());
                 System.err.println("Package " + pkg + " new state: "
                         + enabledSettingToString(
                         mPm.getApplicationEnabledSetting(pkg, userId)));
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6d55dd5..271494f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1279,7 +1279,8 @@
     public void setApplicationEnabledSetting(String packageName,
                                              int newState, int flags) {
         try {
-            mPM.setApplicationEnabledSetting(packageName, newState, flags, mContext.getUserId());
+            mPM.setApplicationEnabledSetting(packageName, newState, flags,
+                    mContext.getUserId(), mContext.getBasePackageName());
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 43c2392..81c0a6a 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -21,6 +21,7 @@
 import android.os.INetworkManagementService;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.DhcpResults;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
@@ -28,7 +29,10 @@
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
 import android.util.Log;
 import java.net.InterfaceAddress;
 import android.net.LinkAddress;
@@ -36,8 +40,11 @@
 import java.net.Inet4Address;
 import android.os.SystemProperties;
 
+import com.android.internal.util.AsyncChannel;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * This class tracks the data connection associated with Bluetooth
@@ -51,24 +58,29 @@
     private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
     private static final String TAG = "BluetoothTethering";
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean VDBG = true;
 
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
+    private final Object mLinkPropertiesLock = new Object();
     private LinkProperties mLinkProperties;
+
     private LinkCapabilities mLinkCapabilities;
+
+    private final Object mNetworkInfoLock = new Object();
     private NetworkInfo mNetworkInfo;
 
     private BluetoothPan mBluetoothPan;
-    private static String mIface;
-    private Thread mDhcpThread;
+    private static String mRevTetheredIface;
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
-    private Context mContext;
-    public static BluetoothTetheringDataTracker sInstance;
+    protected Context mContext;
+    private static BluetoothTetheringDataTracker sInstance;
+    private BtdtHandler mBtdtHandler;
+    private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);
 
     private BluetoothTetheringDataTracker() {
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
@@ -108,6 +120,7 @@
         if (adapter != null) {
             adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
         }
+        mBtdtHandler = new BtdtHandler(target.getLooper(), this);
     }
 
     private BluetoothProfile.ServiceListener mProfileServiceListener =
@@ -224,15 +237,19 @@
     /**
      * Fetch NetworkInfo for the network
      */
-    public synchronized NetworkInfo getNetworkInfo() {
-        return mNetworkInfo;
+    public NetworkInfo getNetworkInfo() {
+        synchronized (mNetworkInfoLock) {
+            return new NetworkInfo(mNetworkInfo);
+        }
     }
 
     /**
      * Fetch LinkProperties for the network
      */
-    public synchronized LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
+    public LinkProperties getLinkProperties() {
+        synchronized (mLinkPropertiesLock) {
+            return new LinkProperties(mLinkProperties);
+        }
     }
 
    /**
@@ -286,88 +303,68 @@
         return count;
     }
 
-
-    private boolean readLinkProperty(String iface) {
-        String DhcpPrefix = "dhcp." + iface + ".";
-        String ip = SystemProperties.get(DhcpPrefix + "ipaddress");
-        String dns1 = SystemProperties.get(DhcpPrefix + "dns1");
-        String dns2 = SystemProperties.get(DhcpPrefix + "dns2");
-        String gateway = SystemProperties.get(DhcpPrefix + "gateway");
-        String mask = SystemProperties.get(DhcpPrefix + "mask");
-        if(ip.isEmpty() || gateway.isEmpty()) {
-            Log.e(TAG, "readLinkProperty, ip: " +  ip + ", gateway: " + gateway + ", can not be empty");
-            return false;
+    void startReverseTether(final LinkProperties linkProperties) {
+        if (linkProperties == null || TextUtils.isEmpty(linkProperties.getInterfaceName())) {
+            Log.e(TAG, "attempted to reverse tether with empty interface");
+            return;
         }
-        int PrefixLen = countPrefixLength(NetworkUtils.numericToInetAddress(mask).getAddress());
-        mLinkProperties.addLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(ip), PrefixLen));
-        RouteInfo ri = new RouteInfo(NetworkUtils.numericToInetAddress(gateway));
-        mLinkProperties.addRoute(ri);
-        if(!dns1.isEmpty())
-            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns1));
-        if(!dns2.isEmpty())
-            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns2));
-        mLinkProperties.setInterfaceName(iface);
-        return true;
-    }
-    public synchronized void startReverseTether(String iface) {
-        mIface = iface;
-        if (DBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-         mDhcpThread = new Thread(new Runnable() {
+        synchronized (mLinkPropertiesLock) {
+            if (mLinkProperties.getInterfaceName() != null) {
+                Log.e(TAG, "attempted to reverse tether while already in process");
+                return;
+            }
+            mLinkProperties = linkProperties;
+        }
+        Thread dhcpThread = new Thread(new Runnable() {
             public void run() {
-                //TODO(): Add callbacks for failure and success case.
                 //Currently this thread runs independently.
-                if (DBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-                String DhcpResultName = "dhcp." + mIface + ".result";;
-                String result = "";
-                if (VDBG) Log.d(TAG, "waiting for change of sys prop dhcp result: " + DhcpResultName);
-                for(int i = 0; i < 30*5; i++) {
-                    try { Thread.sleep(200); } catch (InterruptedException ie) { return;}
-                    result = SystemProperties.get(DhcpResultName);
-                    if (VDBG) Log.d(TAG, "read " + DhcpResultName + ": " + result);
-                    if(result.equals("failed")) {
-                        Log.e(TAG, "startReverseTether, failed to start dhcp service");
+                DhcpResults dhcpResults = new DhcpResults();
+                boolean success = NetworkUtils.runDhcp(linkProperties.getInterfaceName(),
+                        dhcpResults);
+                synchronized (mLinkPropertiesLock) {
+                    if (linkProperties.getInterfaceName() != mLinkProperties.getInterfaceName()) {
+                        Log.e(TAG, "obsolete DHCP run aborted");
                         return;
                     }
-                    if(result.equals("ok")) {
-                        if (VDBG) Log.d(TAG, "startReverseTether, dhcp resut: " + result);
-                        if(readLinkProperty(mIface)) {
-
-                            mNetworkInfo.setIsAvailable(true);
-                            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-
-                            if (VDBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-                            if(mCsHandler != null) {
-                                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-                                msg.sendToTarget();
-
-                                msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-                                msg.sendToTarget();
-                            }
-                        }
+                    if (!success) {
+                        Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
                         return;
                     }
+                    mLinkProperties = dhcpResults.linkProperties;
+                    synchronized (mNetworkInfoLock) {
+                        mNetworkInfo.setIsAvailable(true);
+                        mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+                        if (mCsHandler != null) {
+                            Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
+                                    new NetworkInfo(mNetworkInfo));
+                            msg.sendToTarget();
+                       }
+                    }
+                    return;
                 }
-                Log.e(TAG, "startReverseTether, dhcp failed, resut: " + result);
             }
         });
-        mDhcpThread.start();
+        dhcpThread.start();
     }
 
-    public synchronized void stopReverseTether() {
-        //NetworkUtils.stopDhcp(iface);
-        if(mDhcpThread != null && mDhcpThread.isAlive()) {
-            mDhcpThread.interrupt();
-            try { mDhcpThread.join(); } catch (InterruptedException ie) { return; }
+    void stopReverseTether() {
+        synchronized (mLinkPropertiesLock) {
+            if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
+                Log.e(TAG, "attempted to stop reverse tether with nothing tethered");
+                return;
+            }
+            NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
+            mLinkProperties.clear();
+            synchronized (mNetworkInfoLock) {
+                mNetworkInfo.setIsAvailable(false);
+                mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+
+                if (mCsHandler != null) {
+                    mCsHandler.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)).
+                            sendToTarget();
+                }
+            }
         }
-        mLinkProperties.clear();
-        mNetworkInfo.setIsAvailable(false);
-        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-
-        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-        msg.sendToTarget();
-
-        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-        msg.sendToTarget();
     }
 
     public void setDependencyMet(boolean met) {
@@ -383,4 +380,54 @@
     public void removeStackedLink(LinkProperties link) {
         mLinkProperties.removeStackedLink(link);
     }
+
+    static class BtdtHandler extends Handler {
+        private AsyncChannel mStackChannel;
+        private final BluetoothTetheringDataTracker mBtdt;
+
+        BtdtHandler(Looper looper, BluetoothTetheringDataTracker parent) {
+            super(looper);
+            mBtdt = parent;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_HALF_CONNECTED");
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        AsyncChannel ac = (AsyncChannel)msg.obj;
+                        if (mBtdt.mAsyncChannel.compareAndSet(null, ac) == false) {
+                            Log.e(TAG, "Trying to set mAsyncChannel twice!");
+                        } else {
+                            ac.sendMessage(
+                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                        }
+                    }
+                    break;
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_DISCONNECTED");
+                    mBtdt.stopReverseTether();
+                    mBtdt.mAsyncChannel.set(null);
+                    break;
+                case NetworkStateTracker.EVENT_NETWORK_CONNECTED:
+                    LinkProperties linkProperties = (LinkProperties)(msg.obj);
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_CONNECTED, " + linkProperties);
+                    mBtdt.startReverseTether(linkProperties);
+                    break;
+                case NetworkStateTracker.EVENT_NETWORK_DISCONNECTED:
+                    linkProperties = (LinkProperties)(msg.obj);
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
+                    mBtdt.stopReverseTether();
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        if (messenger != null) {
+            new AsyncChannel().connect(mContext, mBtdtHandler, messenger);
+        }
+    }
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a32a201..a0e1555 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -239,7 +239,8 @@
     /**
      * As per {@link android.content.pm.PackageManager#setApplicationEnabledSetting}.
      */
-    void setApplicationEnabledSetting(in String packageName, in int newState, int flags, int userId);
+    void setApplicationEnabledSetting(in String packageName, in int newState, int flags,
+            int userId, String callingPackage);
     
     /**
      * As per {@link android.content.pm.PackageManager#getApplicationEnabledSetting}.
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 77ca7f6..a318cf1 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -154,7 +154,7 @@
     /**
      * Flag for {@link #requestedPermissionsFlags}: the requested permission
      * is required for the application to run; the user can not optionally
-     * disable it.  Currently all permissions are required.
+     * disable it.
      */
     public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0bea138..9afbe6f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -45,7 +45,7 @@
 
     /**
      * This exception is thrown when a given package, application, or component
-     * name can not be found.
+     * name cannot be found.
      */
     public static class NameNotFoundException extends AndroidException {
         public NameNotFoundException() {
@@ -267,7 +267,7 @@
      * user has explicitly disabled the application, regardless of what it has
      * specified in its manifest.  Because this is due to the user's request,
      * they may re-enable it if desired through the appropriate system UI.  This
-     * option currently <strong>can not</strong> be used with
+     * option currently <strong>cannot</strong> be used with
      * {@link #setComponentEnabledSetting(ComponentName, int, int)}.
      */
     public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
@@ -1264,6 +1264,23 @@
             = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
 
     /**
+     * The action used to request that the user approve a permission request
+     * from the application.
+     *
+     * @hide
+     */
+    public static final String ACTION_REQUEST_PERMISSION
+            = "android.content.pm.action.REQUEST_PERMISSION";
+
+    /**
+     * Extra field name for the list of permissions, which the user must approve.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REQUEST_PERMISSION_PERMISSION_LIST
+            = "android.content.pm.extra.PERMISSION_LIST";
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      * <p>
@@ -1283,9 +1300,9 @@
      *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
      *         package is not found in the list of installed applications, the
      *         package information is retrieved from the list of uninstalled
-     *         applications(which includes installed applications as well as
-     *         applications with data directory ie applications which had been
-     *         deleted with DONT_DELTE_DATA flag set).
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      * @see #GET_ACTIVITIES
      * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
@@ -1326,7 +1343,7 @@
      * null if neither are found.
      *
      * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param packageName The name of the package to inspect.
      *
@@ -1341,7 +1358,7 @@
      * assigned to a package.
      *
      * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *                    desired package.
@@ -1372,7 +1389,7 @@
      * Retrieve all of the information we know about a particular permission.
      *
      * <p>Throws {@link NameNotFoundException} if a permission with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param name The fully qualified name (i.e. com.google.permission.LOGIN)
      *             of the permission you are interested in.
@@ -1408,7 +1425,7 @@
      * permissions.
      *
      * <p>Throws {@link NameNotFoundException} if a permission group with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param name The fully qualified name (i.e. com.google.permission_group.APPS)
      *             of the permission you are interested in.
@@ -1437,7 +1454,7 @@
      * package/application.
      *
      * <p>Throws {@link NameNotFoundException} if an application with the given
-     * package name can not be found on the system.
+     * package name cannot be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of an
      *                    application.
@@ -1453,7 +1470,7 @@
      *         list of uninstalled applications(which includes
      *         installed applications as well as applications
      *         with data directory ie applications which had been
-     *         deleted with DONT_DELTE_DATA flag set).
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
@@ -1467,7 +1484,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if an activity with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity
@@ -1490,7 +1507,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if a receiver with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver
@@ -1513,7 +1530,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if a service with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service
@@ -1535,7 +1552,7 @@
      * provider class.
      *
      * <p>Throws {@link NameNotFoundException} if a provider with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.providers.media/com.google.providers.media.MediaProvider) of a
@@ -1572,7 +1589,7 @@
      *         installed on the device.  In the unlikely case of there being no
      *         installed packages, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_ACTIVITIES
@@ -1642,7 +1659,7 @@
      *         installed on the device.  In the unlikely case of there being no
      *         installed packages, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_ACTIVITIES
@@ -1735,6 +1752,29 @@
     public abstract void removePermission(String name);
 
     /**
+     * Returns an {@link Intent} suitable for passing to {@code startActivityForResult}
+     * which prompts the user to grant {@code permissions} to this application.
+     *
+     * @throws NullPointerException if {@code permissions} is {@code null}.
+     * @throws IllegalArgumentException if {@code permissions} contains {@code null}.
+     */
+    public Intent buildPermissionRequestIntent(String... permissions) {
+        if (permissions == null) {
+            throw new NullPointerException("permissions cannot be null");
+        }
+        for (String permission : permissions) {
+            if (permission == null) {
+                throw new IllegalArgumentException("permissions cannot contain null");
+            }
+        }
+
+        Intent i = new Intent(ACTION_REQUEST_PERMISSION);
+        i.putExtra(EXTRA_REQUEST_PERMISSION_PERMISSION_LIST, permissions);
+        i.setPackage("com.android.packageinstaller");
+        return i;
+    }
+
+    /**
      * Grant a permission to an application which the application does not
      * already have.  The permission must have been requested by the application,
      * but as an optional permission.  If the application is not allowed to
@@ -1847,7 +1887,7 @@
     /**
      * Return a List of all application packages that are installed on the
      * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all
-     * applications including those deleted with DONT_DELETE_DATA (partially
+     * applications including those deleted with {@code DONT_DELETE_DATA} (partially
      * installed apps with data directory) will be returned.
      *
      * @param flags Additional option flags. Use any combination of
@@ -1858,7 +1898,7 @@
      *         is installed on the device.  In the unlikely case of there being
      *         no installed applications, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_META_DATA
@@ -2164,7 +2204,7 @@
      * instrumentation class.
      *
      * <p>Throws {@link NameNotFoundException} if instrumentation with the
-     * given class name can not be found on the system.
+     * given class name cannot be found on the system.
      *
      * @param className The full name (i.e.
      *                  com.google.apps.contacts.InstrumentList) of an
@@ -2201,8 +2241,8 @@
      * icon.
      *
      * @param packageName The name of the package that this icon is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired image.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired image.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2218,7 +2258,7 @@
      * Retrieve the icon associated with an activity.  Given the full name of
      * an activity, retrieves the information about it and calls
      * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its icon.
-     * If the activity can not be found, NameNotFoundException is thrown.
+     * If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose icon is to be retrieved.
      *
@@ -2237,7 +2277,7 @@
      * set, this simply returns the result of
      * getActivityIcon(intent.getClassName()).  Otherwise it resolves the intent's
      * component and returns the icon associated with the resolved component.
-     * If intent.getClassName() can not be found or the Intent can not be resolved
+     * If intent.getClassName() cannot be found or the Intent cannot be resolved
      * to a component, NameNotFoundException is thrown.
      *
      * @param intent The intent for which you would like to retrieve an icon.
@@ -2276,7 +2316,7 @@
     /**
      * Retrieve the icon associated with an application.  Given the name of the
      * application's package, retrieves the information about it and calls
-     * getApplicationIcon() to return its icon. If the application can not be
+     * getApplicationIcon() to return its icon. If the application cannot be
      * found, NameNotFoundException is thrown.
      *
      * @param packageName Name of the package whose application icon is to be
@@ -2296,7 +2336,7 @@
      * Retrieve the logo associated with an activity.  Given the full name of
      * an activity, retrieves the information about it and calls
      * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
-     * If the activity can not be found, NameNotFoundException is thrown.
+     * If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose logo is to be retrieved.
      *
@@ -2316,7 +2356,7 @@
      * set, this simply returns the result of
      * getActivityLogo(intent.getClassName()).  Otherwise it resolves the intent's
      * component and returns the logo associated with the resolved component.
-     * If intent.getClassName() can not be found or the Intent can not be resolved
+     * If intent.getClassName() cannot be found or the Intent cannot be resolved
      * to a component, NameNotFoundException is thrown.
      *
      * @param intent The intent for which you would like to retrieve a logo.
@@ -2348,7 +2388,7 @@
     /**
      * Retrieve the logo associated with an application.  Given the name of the
      * application's package, retrieves the information about it and calls
-     * getApplicationLogo() to return its logo. If the application can not be
+     * getApplicationLogo() to return its logo. If the application cannot be
      * found, NameNotFoundException is thrown.
      *
      * @param packageName Name of the package whose application logo is to be
@@ -2372,8 +2412,8 @@
      * labels and other text.
      *
      * @param packageName The name of the package that this text is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired text.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired text.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2390,8 +2430,8 @@
      * retrieve XML meta data.
      *
      * @param packageName The name of the package that this xml is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired xml.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired xml.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2409,7 +2449,7 @@
      *
      * @return Returns the label associated with this application, or null if
      * it could not be found for any reason.
-     * @param info The application to get the label of
+     * @param info The application to get the label of.
      */
     public abstract CharSequence getApplicationLabel(ApplicationInfo info);
 
@@ -2417,7 +2457,7 @@
      * Retrieve the resources associated with an activity.  Given the full
      * name of an activity, retrieves the information about it and calls
      * getResources() to return its application's resources.  If the activity
-     * can not be found, NameNotFoundException is thrown.
+     * cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose resources are to be
      *                     retrieved.
@@ -2448,7 +2488,7 @@
      * Retrieve the resources associated with an application.  Given the full
      * package name of an application, retrieves the information about it and
      * calls getResources() to return its application's resources.  If the
-     * appPackageName can not be found, NameNotFoundException is thrown.
+     * appPackageName cannot be found, NameNotFoundException is thrown.
      *
      * @param appPackageName Package name of the application whose resources
      *                       are to be retrieved.
@@ -2617,7 +2657,7 @@
      * {@link PackageManager#VERIFICATION_REJECT}.
      *
      * @param id pending package identifier as passed via the
-     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW}
      *            or {@link PackageManager#VERIFICATION_REJECT}.
      * @throws SecurityException if the caller does not have the
@@ -2638,7 +2678,7 @@
      * will have no effect.
      *
      * @param id pending package identifier as passed via the
-     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCodeAtTimeout either
      *            {@link PackageManager#VERIFICATION_ALLOW} or
      *            {@link PackageManager#VERIFICATION_REJECT}. If
@@ -2870,7 +2910,7 @@
     /**
      * @deprecated This is a protected API that should not have been available
      * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this can not be directly modified.
+     * assigning preferred activities and this cannot be directly modified.
      *
      * Add a new preferred activity mapping to the system.  This will be used
      * to automatically select the given activity component when
@@ -2904,7 +2944,7 @@
     /**
      * @deprecated This is a protected API that should not have been available
      * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this can not be directly modified.
+     * assigning preferred activities and this cannot be directly modified.
      *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 149b8e5..c311656 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1023,16 +1023,14 @@
                 // that may change.
                 String name = sa.getNonResourceString(
                         com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
-                /* Not supporting optional permissions yet.
                 boolean required = sa.getBoolean(
                         com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
-                */
 
                 sa.recycle();
 
                 if (name != null && !pkg.requestedPermissions.contains(name)) {
                     pkg.requestedPermissions.add(name.intern());
-                    pkg.requestedPermissionsRequired.add(Boolean.TRUE);
+                    pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
                 }
 
                 XmlUtils.skipCurrentTag(parser);
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 3579977..dcd54fc 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -30,6 +30,8 @@
     public boolean installed;
     public int enabled;
 
+    public String lastDisableAppCaller;
+
     public HashSet<String> disabledComponents;
     public HashSet<String> enabledComponents;
 
@@ -43,6 +45,7 @@
         stopped = o.stopped;
         notLaunched = o.notLaunched;
         enabled = o.enabled;
+        lastDisableAppCaller = o.lastDisableAppCaller;
         disabledComponents = o.disabledComponents != null
                 ? new HashSet<String>(o.disabledComponents) : null;
         enabledComponents = o.enabledComponents != null
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index a554611..1165281 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Messenger;
 
 import com.android.internal.util.Preconditions;
 
@@ -165,4 +166,9 @@
     public void removeStackedLink(LinkProperties link) {
         mLinkProperties.removeStackedLink(link);
     }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3a04c27..4e4980d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.provider.Settings;
 
@@ -1280,4 +1281,17 @@
         }
     }
 
+    /**
+     * Supply the backend messenger for a network tracker
+     *
+     * @param type NetworkType to set
+     * @param messenger {@link Messenger}
+     * {@hide}
+     */
+    public void supplyMessenger(int networkType, Messenger messenger) {
+        try {
+            mService.supplyMessenger(networkType, messenger);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index db8f0bcb..15a81f3 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Messenger;
 import android.util.Slog;
 
 /**
@@ -213,6 +214,11 @@
         mLinkProperties.removeStackedLink(link);
     }
 
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
+
     static private void log(String s) {
         Slog.d(TAG, s);
     }
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index b744a47..27d5a58 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -22,6 +22,7 @@
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -417,4 +418,9 @@
     public void removeStackedLink(LinkProperties link) {
         mLinkProperties.removeStackedLink(link);
     }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 056fa03..9e9b43d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -22,6 +22,7 @@
 import android.net.NetworkState;
 import android.net.ProxyProperties;
 import android.os.IBinder;
+import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.net.LegacyVpnInfo;
@@ -126,4 +127,6 @@
     boolean updateLockdownVpn();
 
     void captivePortalCheckComplete(in NetworkInfo info);
+
+    void supplyMessenger(int networkType, in Messenger messenger);
 }
diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java
index eb9166f..fb444ea 100644
--- a/core/java/android/net/LinkCapabilities.java
+++ b/core/java/android/net/LinkCapabilities.java
@@ -314,8 +314,8 @@
             sb.append(":\"");
             sb.append(entry.getValue());
             sb.append("\"");
-            return mCapabilities.toString();
         }
+        sb.append("}");
         return sb.toString();
     }
 
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index eedc372..52b238f 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -290,7 +290,7 @@
             }
             stacked += "] ";
         }
-        return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked;
+        return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
     }
 
     /**
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index faf739b..e85dbcd 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -74,7 +74,6 @@
 
     private Handler mHandler;
     private AsyncChannel mDataConnectionTrackerAc;
-    private Messenger mMessenger;
 
     /**
      * Create a new MobileDataStateTracker
@@ -103,7 +102,6 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
-        filter.addAction(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
 
         mContext.registerReceiver(new MobileDataStateReceiver(), filter);
         mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
@@ -285,13 +283,6 @@
                                 " broadcast" + reason == null ? "" : "(" + reason + ")");
                 }
                 setDetailedState(DetailedState.FAILED, reason, apnName);
-            } else if (intent.getAction().equals(DctConstants
-                    .ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
-                if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
-                mMessenger =
-                    intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER);
-                AsyncChannel ac = new AsyncChannel();
-                ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
             } else {
                 if (DBG) log("Broadcast received: ignore " + intent.getAction());
             }
@@ -613,6 +604,12 @@
         return new LinkCapabilities(mLinkCapabilities);
     }
 
+    public void supplyMessenger(Messenger messenger) {
+        if (VDBG) log(mApnType + " got supplyMessenger");
+        AsyncChannel ac = new AsyncChannel();
+        ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger);
+    }
+
     private void log(String s) {
         Slog.d(TAG, mApnType + ": " + s);
     }
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index b22159c..cf77a1c 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -18,6 +18,9 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Messenger;
+
+import static com.android.internal.util.Protocol.BASE_NETWORK_STATE_TRACKER;
 
 /**
  * Interface provides the {@link com.android.server.ConnectivityService}
@@ -48,25 +51,38 @@
      * msg.what = EVENT_STATE_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_STATE_CHANGED = 1;
+    public static final int EVENT_STATE_CHANGED = BASE_NETWORK_STATE_TRACKER;
 
     /**
      * msg.what = EVENT_CONFIGURATION_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_CONFIGURATION_CHANGED = 3;
+    public static final int EVENT_CONFIGURATION_CHANGED = BASE_NETWORK_STATE_TRACKER + 1;
 
     /**
      * msg.what = EVENT_RESTORE_DEFAULT_NETWORK
      * msg.obj = FeatureUser object
      */
-    public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6;
+    public static final int EVENT_RESTORE_DEFAULT_NETWORK = BASE_NETWORK_STATE_TRACKER + 2;
 
     /**
      * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 7;
+    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = BASE_NETWORK_STATE_TRACKER + 3;
+
+    /**
+     * msg.what = EVENT_NETWORK_CONNECTED
+     * msg.obj = LinkProperties object
+     */
+    public static final int EVENT_NETWORK_CONNECTED = BASE_NETWORK_STATE_TRACKER + 4;
+
+    /**
+     * msg.what = EVENT_NETWORK_CONNECTION_DISCONNECTED
+     * msg.obj = LinkProperties object, same iface name
+     */
+    public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
+
 
     /**
      * -------------------------------------------------------------
@@ -207,4 +223,10 @@
      * Informs the state tracker that a stacked interface has been removed.
      **/
     public void removeStackedLink(LinkProperties link);
+
+    /*
+     * Called once to setup async channel between this and
+     * the underlying network specific code.
+     */
+    public void supplyMessenger(Messenger messenger);
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 4b83611..45524c8 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -152,16 +152,6 @@
     boolean isTetheringStarted();
 
     /**
-     * Start bluetooth reverse tethering services
-     */
-    void startReverseTethering(in String iface);
-
-    /**
-     * Stop currently running bluetooth reserse tethering services
-     */
-    void stopReverseTethering();
-
-    /**
      * Tethers the specified interface
      */
     void tetherInterface(String iface);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 98edeae..dd36022 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5890,6 +5890,11 @@
         private boolean mNeedResolution = false;
         private boolean mIsRtlCompatibilityMode = true;
 
+        private static int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
+
+        private boolean mLeftMarginUndefined = false;
+        private boolean mRightMarginUndefined = false;
+
         /**
          * Creates a new set of layout parameters. The values are extracted from
          * the supplied attributes set and context.
@@ -5916,16 +5921,26 @@
             } else {
                 leftMargin = a.getDimensionPixelSize(
                         R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
-                        DEFAULT_MARGIN_RESOLVED);
-                topMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
-                        DEFAULT_MARGIN_RESOLVED);
+                        UNDEFINED_MARGIN);
+                if (leftMargin == UNDEFINED_MARGIN) {
+                    mLeftMarginUndefined = true;
+                    leftMargin = DEFAULT_MARGIN_RESOLVED;
+                }
                 rightMargin = a.getDimensionPixelSize(
                         R.styleable.ViewGroup_MarginLayout_layout_marginRight,
+                        UNDEFINED_MARGIN);
+                if (rightMargin == UNDEFINED_MARGIN) {
+                    mRightMarginUndefined = true;
+                    rightMargin = DEFAULT_MARGIN_RESOLVED;
+                }
+
+                topMargin = a.getDimensionPixelSize(
+                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
                         DEFAULT_MARGIN_RESOLVED);
                 bottomMargin = a.getDimensionPixelSize(
                         R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
                         DEFAULT_MARGIN_RESOLVED);
+
                 startMargin = a.getDimensionPixelSize(
                         R.styleable.ViewGroup_MarginLayout_layout_marginStart,
                         DEFAULT_MARGIN_RELATIVE);
@@ -5949,6 +5964,9 @@
         public MarginLayoutParams(int width, int height) {
             super(width, height);
 
+            mLeftMarginUndefined = true;
+            mRightMarginUndefined = true;
+
             mNeedResolution = false;
             mIsRtlCompatibilityMode = false;
         }
@@ -5969,6 +5987,9 @@
             this.startMargin = source.startMargin;
             this.endMargin = source.endMargin;
 
+            this.mLeftMarginUndefined = source.mLeftMarginUndefined;
+            this.mRightMarginUndefined = source.mRightMarginUndefined;
+
             this.mNeedResolution = source.mNeedResolution;
             this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;
 
@@ -5981,6 +6002,9 @@
         public MarginLayoutParams(LayoutParams source) {
             super(source);
 
+            mLeftMarginUndefined = true;
+            mRightMarginUndefined = true;
+
             mNeedResolution = false;
             mIsRtlCompatibilityMode = false;
         }
@@ -6005,6 +6029,8 @@
             topMargin = top;
             rightMargin = right;
             bottomMargin = bottom;
+            mLeftMarginUndefined = false;
+            mRightMarginUndefined = false;
             mNeedResolution = isMarginRelative();
         }
 
@@ -6147,30 +6173,42 @@
 
             // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
             // Will use the left and right margins if no relative margin is defined.
-            if (!isMarginRelative() || !mNeedResolution || mIsRtlCompatibilityMode) return;
+            if (!isMarginRelative() || !mNeedResolution) return;
 
             // Proceed with resolution
             doResolveMargins();
         }
 
         private void doResolveMargins() {
-            // We have some relative margins (either the start one or the end one or both). So use
-            // them and override what has been defined for left and right margins. If either start
-            // or end margin is not defined, just set it to default "0".
-            switch(mLayoutDirection) {
-                case View.LAYOUT_DIRECTION_RTL:
-                    leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
-                            endMargin : DEFAULT_MARGIN_RESOLVED;
-                    rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
-                            startMargin : DEFAULT_MARGIN_RESOLVED;
-                    break;
-                case View.LAYOUT_DIRECTION_LTR:
-                default:
-                    leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
-                            startMargin : DEFAULT_MARGIN_RESOLVED;
-                    rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
-                            endMargin : DEFAULT_MARGIN_RESOLVED;
-                    break;
+
+            if (mIsRtlCompatibilityMode) {
+                // if left or right margins are not defined and if we have some start or end margin
+                // defined then use those start and end margins.
+                if (mLeftMarginUndefined && startMargin > DEFAULT_MARGIN_RELATIVE) {
+                    leftMargin = startMargin;
+                }
+                if (mRightMarginUndefined && endMargin > DEFAULT_MARGIN_RELATIVE) {
+                    rightMargin = endMargin;
+                }
+            } else {
+                // We have some relative margins (either the start one or the end one or both). So use
+                // them and override what has been defined for left and right margins. If either start
+                // or end margin is not defined, just set it to default "0".
+                switch(mLayoutDirection) {
+                    case View.LAYOUT_DIRECTION_RTL:
+                        leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                endMargin : DEFAULT_MARGIN_RESOLVED;
+                        rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                startMargin : DEFAULT_MARGIN_RESOLVED;
+                        break;
+                    case View.LAYOUT_DIRECTION_LTR:
+                    default:
+                        leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                startMargin : DEFAULT_MARGIN_RESOLVED;
+                        rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                endMargin : DEFAULT_MARGIN_RESOLVED;
+                        break;
+                }
             }
             mNeedResolution = false;
         }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 91b109e..b380403 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -52,5 +52,6 @@
     public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00042000;
     public static final int BASE_DNS_PINGER                                         = 0x00050000;
     public static final int BASE_NSD_MANAGER                                        = 0x00060000;
+    public static final int BASE_NETWORK_STATE_TRACKER                              = 0x00070000;
     //TODO: define all used protocols
 }
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6f59817..2e4d053 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -991,9 +991,8 @@
               permission, and it must always be granted when it is installed.
               If you set this to false, then in some cases the application may
               be installed with it being granted the permission, and it will
-              need to request the permission later if it needs it.
+              need to request the permission later if it needs it. -->
         <attr name="required" format="boolean" />
-        -->
     </declare-styleable>
 
     <!-- The <code>uses-configuration</code> tag specifies
@@ -1036,7 +1035,7 @@
               don't support it.  If you set this to false, then this will
               not impose a restriction on where the application can be
               installed. -->
-        <attr name="required" format="boolean" />
+        <attr name="required" />
     </declare-styleable>
 
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
diff --git a/docs/html/guide/practices/index.jd b/docs/html/guide/practices/index.jd
index 04a43c5..48a849a 100644
--- a/docs/html/guide/practices/index.jd
+++ b/docs/html/guide/practices/index.jd
@@ -19,7 +19,7 @@
     
     <a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">
       <h4>Say Goodbye to the Menu Button</h4>
-      <p>As Ice Cream Sandwich rolls out to more devices, it?s important that you begin to migrate
+      <p>As Ice Cream Sandwich rolls out to more devices, it's important that you begin to migrate
 your designs to the action bar in order to promote a consistent Android user experience.</p>
     </a>
     
@@ -49,4 +49,4 @@
   </div>
 
 
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd
index 0086913..24ecc46 100644
--- a/docs/html/training/basics/intents/result.jd
+++ b/docs/html/training/basics/intents/result.jd
@@ -62,7 +62,7 @@
 static final int PICK_CONTACT_REQUEST = 1;  // The request code
 ...
 private void pickContact() {
-    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
+    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
     pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
     startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
 }
diff --git a/docs/html/training/in-app-billing/purchase-iab-products.jd b/docs/html/training/in-app-billing/purchase-iab-products.jd
index 7fa77d3..4e6e035 100644
--- a/docs/html/training/in-app-billing/purchase-iab-products.jd
+++ b/docs/html/training/in-app-billing/purchase-iab-products.jd
@@ -104,7 +104,7 @@
 </pre>
 
 <h2 id="Consume">Consume a Purchase</h2>
-<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replensihable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
+<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replenishable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
 <p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
 <p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
 <p>To record a purchase consumption, call {@code consumeAsync(Purchase, OnConsumeFinishedListener)} on your {@code IabHelper} instance. The first argument that the method takes is the {@code Purchase} object representing the item to consume. The second argument is a {@code OnConsumeFinishedListener} that is notified when the consumption operation has completed and handles the consumption response from Google Play. It is safe to make this call fom your main thread.</p>
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 07daa3b..0b8f7e6 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -248,9 +248,7 @@
 }
 
 status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y) {
-    mLayers.add(layer);
-    mCaches.resourceCache.incrementRefcount(layer);
-
+    layer = refLayer(layer);
     addDrawOp(new (alloc()) DrawLayerOp(layer, x, y));
     return DrawGlInfo::kStatusDone;
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 50e552f..19f7eb6 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -271,6 +271,12 @@
         return copy;
     }
 
+    inline Layer* refLayer(Layer* layer) {
+        mLayers.add(layer);
+        mCaches.resourceCache.incrementRefcount(layer);
+        return layer;
+    }
+
     inline SkBitmap* refBitmap(SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 2998535..7f4977a 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -75,6 +75,13 @@
         return true;
     }
 
+    const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize;
+    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
+        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
+                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
+        return false;
+    }
+
     uint32_t oldWidth = getWidth();
     uint32_t oldHeight = getHeight();
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index bb02286..8451048 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -222,6 +222,21 @@
         return NULL;
     }
 
+    // We first obtain a layer before comparing against the max texture size
+    // because layers are not allocated at the exact desired size. They are
+    // always created slighly larger to improve recycling
+    const uint32_t maxTextureSize = caches.maxTextureSize;
+    if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
+        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
+                width, height, maxTextureSize, maxTextureSize);
+
+        // Creating a new layer always increment its refcount by 1, this allows
+        // us to destroy the layer object if one was created for us
+        Caches::getInstance().resourceCache.decrementRefcount(layer);
+
+        return NULL;
+    }
+
     layer->setFbo(fbo);
     layer->layer.set(0.0f, 0.0f, width, height);
     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
@@ -243,14 +258,11 @@
         layer->setEmpty(false);
         layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
 
+        // This should only happen if we run out of memory
         if (glGetError() != GL_NO_ERROR) {
-            ALOGD("Could not allocate texture for layer (fbo=%d %dx%d)",
-                    fbo, width, height);
-
+            ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
-            Caches::getInstance().resourceCache.decrementRefcount(layer);
-
+            caches.resourceCache.decrementRefcount(layer);
             return NULL;
         }
     }
@@ -272,7 +284,6 @@
             layer->texCoords.set(0.0f, height / float(layer->getHeight()),
                     width / float(layer->getWidth()), 0.0f);
         } else {
-            Caches::getInstance().resourceCache.decrementRefcount(layer);
             return false;
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5ad305c..ad5e20b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -989,6 +989,13 @@
             final Callback cb = getCallback();
             if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
                 if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
+                    // If we have a menu invalidation pending, do it now.
+                    if (mInvalidatePanelMenuPosted &&
+                            (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
+                        mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
+                        mInvalidatePanelMenuRunnable.run();
+                    }
+
                     final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
 
                     // If we don't have a menu or we're waiting for a full content refresh,
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 33e712a..924b9df 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -1081,9 +1081,9 @@
                         if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
                     } else if (off) {
                         if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
-		    } else {
+                    } else {
                         if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
-		    }
+                    }
                 } catch (RemoteException e) {
                     Log.e(TAG, "getState()", e);
                     break;
@@ -1091,9 +1091,9 @@
             }
             if (on || off) {
                 SystemClock.sleep(300);
-	    } else {
+            } else {
                 SystemClock.sleep(50);
-	    }
+            }
             i++;
         }
         Log.e(TAG,"waitForOnOff time out");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6dcb403..0bb0366 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -74,6 +74,7 @@
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.Process;
@@ -3220,7 +3221,7 @@
         throwIfLockdownEnabled();
         try {
             int type = mActiveDefaultNetwork;
-            if (ConnectivityManager.isNetworkTypeValid(type)) {
+            if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
                 mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
                 return true;
             }
@@ -3425,4 +3426,12 @@
             throw new IllegalStateException("Unavailable in lockdown mode");
         }
     }
+
+    public void supplyMessenger(int networkType, Messenger messenger) {
+        enforceConnectivityInternalPermission();
+
+        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
+            mNetTrackers[networkType].supplyMessenger(messenger);
+        }
+    }
 }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index d3e7c24..ab70e6f 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -2443,7 +2443,7 @@
                     == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                 ipm.setApplicationEnabledSetting(packageName,
                         PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                        PackageManager.DONT_KILL_APP, userId);
+                        PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
             }
         } catch (RemoteException e) {
         }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 2d53023..3b541ec 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1598,7 +1598,8 @@
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                         mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                                PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId());
+                                PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
+                                mContext.getBasePackageName());
                     }
                 } catch (RemoteException e) {
                 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 2210a18..d2acb40 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -839,33 +839,6 @@
         return event.getMessage().endsWith("started");
     }
 
-    // TODO(BT) Remove
-    @Override
-    public void startReverseTethering(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        // cmd is "tether start first_start first_stop second_start second_stop ..."
-        // an odd number of addrs will fail
-        try {
-            mConnector.execute("tether", "start-reverse", iface);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-        BluetoothTetheringDataTracker.getInstance().startReverseTether(iface);
-
-    }
-
-    // TODO(BT) Remove
-    @Override
-    public void stopReverseTethering() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("tether", "stop-reverse");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-        BluetoothTetheringDataTracker.getInstance().stopReverseTether();
-    }
-
     @Override
     public void tetherInterface(String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index afdd294..dc5916b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -8733,7 +8733,7 @@
                         false, //installed
                         true,  //stopped
                         true,  //notLaunched
-                        null, null);
+                        null, null, null);
                 if (!isSystemApp(ps)) {
                     if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                         // Other user still have this package installed, so all
@@ -9306,9 +9306,12 @@
 
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
-            int newState, int flags, int userId) {
+            int newState, int flags, int userId, String callingPackage) {
         if (!sUserManager.exists(userId)) return;
-        setEnabledSetting(appPackageName, null, newState, flags, userId);
+        if (callingPackage == null) {
+            callingPackage = Integer.toString(Binder.getCallingUid());
+        }
+        setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage);
     }
 
     @Override
@@ -9316,11 +9319,11 @@
             int newState, int flags, int userId) {
         if (!sUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
-                componentName.getClassName(), newState, flags, userId);
+                componentName.getClassName(), newState, flags, userId, null);
     }
 
-    private void setEnabledSetting(
-            final String packageName, String className, int newState, final int flags, int userId) {
+    private void setEnabledSetting(final String packageName, String className, int newState,
+            final int flags, int userId, String callingPackage) {
         if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
               || newState == COMPONENT_ENABLED_STATE_ENABLED
               || newState == COMPONENT_ENABLED_STATE_DISABLED
@@ -9366,7 +9369,12 @@
                     // Nothing to do
                     return;
                 }
-                pkgSetting.setEnabled(newState, userId);
+                if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+                    // Don't care about who enables an app.
+                    callingPackage = null;
+                }
+                pkgSetting.setEnabled(newState, userId, callingPackage);
                 // pkgSetting.pkg.mSetEnabled = newState;
             } else {
                 // We're dealing with a component level state change
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index ae1b213..e64ec6d 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -189,14 +189,20 @@
         return DEFAULT_USER_STATE;
     }
 
-    void setEnabled(int state, int userId) {
-        modifyUserState(userId).enabled = state;
+    void setEnabled(int state, int userId, String callingPackage) {
+        PackageUserState st = modifyUserState(userId);
+        st.enabled = state;
+        st.lastDisableAppCaller = callingPackage;
     }
 
     int getEnabled(int userId) {
         return readUserState(userId).enabled;
     }
 
+    String getLastDisabledAppCaller(int userId) {
+        return readUserState(userId).lastDisableAppCaller;
+    }
+
     void setInstalled(boolean inst, int userId) {
         modifyUserState(userId).installed = inst;
     }
@@ -249,13 +255,14 @@
     }
 
     void setUserState(int userId, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, HashSet<String> enabledComponents,
+            boolean notLaunched, String lastDisableAppCaller, HashSet<String> enabledComponents,
             HashSet<String> disabledComponents) {
         PackageUserState state = modifyUserState(userId);
         state.enabled = enabled;
         state.installed = installed;
         state.stopped = stopped;
         state.notLaunched = notLaunched;
+        state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
     }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index e645078..e13a17b 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -104,6 +104,7 @@
     private static final String ATTR_CODE = "code";
     private static final String ATTR_NOT_LAUNCHED = "nl";
     private static final String ATTR_ENABLED = "enabled";
+    private static final String ATTR_ENABLED_CALLER = "enabledCaller";
     private static final String ATTR_STOPPED = "stopped";
     private static final String ATTR_INSTALLED = "inst";
 
@@ -453,7 +454,7 @@
                                     installed,
                                     true, // stopped,
                                     true, // notLaunched
-                                    null, null);
+                                    null, null, null);
                             writePackageRestrictionsLPr(user.id);
                         }
                     }
@@ -850,7 +851,7 @@
                                 true,   // installed
                                 false,  // stopped
                                 false,  // notLaunched
-                                null, null);
+                                null, null, null);
                     }
                     return;
                 }
@@ -895,6 +896,8 @@
                     final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
                     final int enabled = enabledStr == null
                             ? COMPONENT_ENABLED_STATE_DEFAULT : Integer.parseInt(enabledStr);
+                    final String enabledCaller = parser.getAttributeValue(null,
+                            ATTR_ENABLED_CALLER);
                     final String installedStr = parser.getAttributeValue(null, ATTR_INSTALLED);
                     final boolean installed = installedStr == null
                             ? true : Boolean.parseBoolean(installedStr);
@@ -925,7 +928,7 @@
                     }
 
                     ps.setUserState(userId, enabled, installed, stopped, notLaunched,
-                            enabledComponents, disabledComponents);
+                            enabledCaller, enabledComponents, disabledComponents);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
                 } else {
@@ -1052,6 +1055,10 @@
                     if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
                         serializer.attribute(null, ATTR_ENABLED,
                                 Integer.toString(ustate.enabled));
+                        if (ustate.lastDisableAppCaller != null) {
+                            serializer.attribute(null, ATTR_ENABLED_CALLER,
+                                    ustate.lastDisableAppCaller);
+                        }
                     }
                     if (ustate.enabledComponents != null
                             && ustate.enabledComponents.size() > 0) {
@@ -2239,14 +2246,14 @@
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
                 try {
-                    packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */);
+                    packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */, null);
                 } catch (NumberFormatException e) {
                     if (enabledStr.equalsIgnoreCase("true")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, null);
                     } else if (enabledStr.equalsIgnoreCase("false")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
                     } else if (enabledStr.equalsIgnoreCase("default")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
                     } else {
                         PackageManagerService.reportSettingsProblem(Log.WARN,
                                 "Error in package manager settings: package " + name
@@ -2255,7 +2262,7 @@
                     }
                 }
             } else {
-                packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
+                packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
             }
 
             final String installStatusStr = parser.getAttributeValue(null, "installStatus");
@@ -2789,6 +2796,11 @@
             pw.print(ps.getNotLaunched(user.id));
             pw.print(" enabled=");
             pw.println(ps.getEnabled(user.id));
+            String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+            if (lastDisabledAppCaller != null) {
+                pw.print(prefix); pw.print("    lastDisabledCaller: ");
+                        pw.println(lastDisabledAppCaller);
+            }
             HashSet<String> cmp = ps.getDisabledComponents(user.id);
             if (cmp != null && cmp.size() > 0) {
                 pw.print(prefix); pw.println("    disabledComponents:");
diff --git a/services/java/com/android/server/wifi/README.txt b/services/java/com/android/server/wifi/README.txt
index c03bff5..39e14751 100644
--- a/services/java/com/android/server/wifi/README.txt
+++ b/services/java/com/android/server/wifi/README.txt
@@ -10,3 +10,10 @@
 
 WifiStateMachine: Tracks the various states on STA and AP connectivity and handles bring up and shut down.
 
+
+Feature description:
+
+Scan-only mode with Wi-Fi turned off:
+ - Setup wizard opts user into allowing scanning for improved location. We show no further dialogs in setup wizard since the user has just opted into the feature. This is the reason WifiService listens to DEVICE_PROVISIONED setting.
+ - Once the user has his device provisioned, turning off Wi-Fi from settings or from a third party app will show up a dialog reminding the user that scan mode will be on even though Wi-Fi is being turned off. The user has the choice to turn this notification off.
+ - In the scan mode, the device continues to allow scanning from any app with Wi-Fi turned off. This is done by disabling all networks and allowing only scans to be passed.
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index 9dde58f7..f8d5d2e 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -58,6 +58,7 @@
 import java.net.Inet4Address;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.android.internal.R;
 import com.android.internal.app.IBatteryStats;
@@ -101,6 +102,9 @@
     private int mMulticastEnabled;
     private int mMulticastDisabled;
 
+    private AtomicBoolean mDeviceProvisioned = new AtomicBoolean();
+    private AtomicBoolean mNotifyScanMode = new AtomicBoolean();
+
     private final IBatteryStats mBatteryStats;
     private final AppOpsManager mAppOps;
 
@@ -245,6 +249,8 @@
         mWifiController.start();
 
         registerForScanModeChange();
+        registerForDeviceProvisionedChange();
+        registerForNotifyUserOnScanModeChange();
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
@@ -399,10 +405,8 @@
 
             /* Turning off Wi-Fi when scans are still available */
             if (!enable && isScanningAlwaysAvailable()) {
-                /* This can be changed by user in the app to not be notified again */
-                boolean notifyUser = (Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE, 1) == 1);
-                if (notifyUser) {
+                /* Notify if device is provisioned and user has not opted out of the notification */
+                if (mNotifyScanMode.get() && mDeviceProvisioned.get()) {
                     Intent intent = new Intent(WifiManager.ACTION_NOTIFY_SCAN_ALWAYS_AVAILABLE);
                     mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
                 }
@@ -875,6 +879,51 @@
                 false, contentObserver);
     }
 
+    private void getPersistedDeviceProvisioned() {
+        mDeviceProvisioned.set(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0);
+    }
+
+    private void getPersistedNotifyScanMode() {
+        mNotifyScanMode.set(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE, 1) == 1);
+    }
+
+    /**
+     * Observes settings changes to notify the user when scan mode is active and
+     * Wi-Fi is turned off
+     */
+    private void registerForNotifyUserOnScanModeChange() {
+            ContentObserver contentObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                getPersistedNotifyScanMode();
+            }
+        };
+
+        getPersistedNotifyScanMode();
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE),
+                false, contentObserver);
+    }
+
+    /*
+     * Observes settings changes device provisioned status
+     */
+    private void registerForDeviceProvisionedChange() {
+       ContentObserver contentObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                getPersistedDeviceProvisioned();
+            }
+        };
+
+        getPersistedDeviceProvisioned();
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                false, contentObserver);
+    }
+
     private void registerForBroadcasts() {
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
@@ -899,6 +948,8 @@
         pw.println("Stay-awake conditions: " +
                 Settings.Global.getInt(mContext.getContentResolver(),
                                        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
+        pw.println("mDeviceProvisioned " + mDeviceProvisioned.get());
+        pw.println("mNotifyScanMode " + mNotifyScanMode.get());
         pw.println("mMulticastEnabled " + mMulticastEnabled);
         pw.println("mMulticastDisabled " + mMulticastDisabled);
         mWifiController.dump(fd, pw, args);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 1ab5f45..c501553 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -176,8 +176,8 @@
 
         // Enable/Disable a package
         PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
-        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
-        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
         assertEquals(COMPONENT_ENABLED_STATE_DISABLED, ps.getEnabled(0));
         assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
 
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index cacafd4..9d556c0 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -111,7 +111,4 @@
     public static final int ENABLED = 1;
 
     public static final String APN_TYPE_KEY = "apnType";
-    public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
-        "com.android.internal.telephony";
-    public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
 }
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 32cd2f6..f637e89 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -793,4 +793,14 @@
     public boolean p2pServDiscCancelReq(String id) {
         return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
     }
+
+    /* Set the current mode of miracast operation.
+     *  0 = disabled
+     *  1 = operating as source
+     *  2 = operating as sink
+     */
+    public void setMiracastMode(int mode) {
+        // Note: optional feature on the driver. It is ok for this to fail.
+        doBooleanCommand("DRIVER MIRACAST " + mode);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 81d2e11..cf75381 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -27,6 +27,7 @@
 import android.net.NetworkStateTracker;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Messenger;
 import android.util.Slog;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -262,4 +263,9 @@
     public void removeStackedLink(LinkProperties link) {
         mLinkProperties.removeStackedLink(link);
     }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index 381a450..1c9c40d 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -26,5 +26,6 @@
 interface IWifiP2pManager
 {
     Messenger getMessenger();
+    void setMiracastMode(int mode);
 }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 2e80064..737ab91 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1258,6 +1258,21 @@
         c.mAsyncChannel.sendMessage(REQUEST_PERSISTENT_GROUP_INFO, 0, c.putListener(listener));
     }
 
+    /** @hide */
+    public static final int MIRACAST_DISABLED = 0;
+    /** @hide */
+    public static final int MIRACAST_SOURCE   = 1;
+    /** @hide */
+    public static final int MIRACAST_SINK     = 2;
+    /** Internal use only @hide */
+    public void setMiracastMode(int mode) {
+        try {
+            mService.setMiracastMode(mode);
+        } catch(RemoteException e) {
+           // ignore
+        }
+    }
+
     /**
      * Get a reference to WifiP2pService handler. This is used to establish
      * an AsyncChannel communication with WifiService
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index e6a1df1..447ddb0 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -164,6 +164,8 @@
     public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
     public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
 
+    public static final int SET_MIRACAST_MODE               =   BASE + 14;
+
     private final boolean mP2pSupported;
 
     private WifiP2pDevice mThisDevice = new WifiP2pDevice();
@@ -310,6 +312,12 @@
                 "WifiP2pService");
     }
 
+    private void enforceConnectivityInternalPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                "WifiP2pService");
+    }
+
     /**
      * Get a reference to handler. This is used by a client to establish
      * an AsyncChannel communication with WifiP2pService
@@ -320,6 +328,20 @@
         return new Messenger(mP2pStateMachine.getHandler());
     }
 
+    /** This is used to provide information to drivers to optimize performance depending
+     * on the current mode of operation.
+     * 0 - disabled
+     * 1 - source operation
+     * 2 - sink operation
+     *
+     * As an example, the driver could reduce the channel dwell time during scanning
+     * when acting as a source or sink to minimize impact on miracast.
+     */
+    public void setMiracastMode(int mode) {
+        enforceConnectivityInternalPermission();
+        mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode);
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -572,6 +594,7 @@
                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                 case DhcpStateMachine.CMD_ON_QUIT:
                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
+                case SET_MIRACAST_MODE:
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
                     // Enable is lazy and has no response
@@ -878,7 +901,7 @@
                         sendPeersChangedBroadcast();
                     }
                     break;
-               case WifiP2pManager.ADD_LOCAL_SERVICE:
+                case WifiP2pManager.ADD_LOCAL_SERVICE:
                     if (DBG) logd(getName() + " add service");
                     WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
                     if (addLocalService(message.replyTo, servInfo)) {
@@ -916,7 +939,7 @@
                     clearServiceRequests(message.replyTo);
                     replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
                     break;
-               case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
+                case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
                     if (DBG) logd(getName() + " receive service response");
                     List<WifiP2pServiceResponse> sdRespList =
                         (List<WifiP2pServiceResponse>) message.obj;
@@ -927,13 +950,16 @@
                         sendServiceResponse(resp);
                     }
                     break;
-               case WifiP2pManager.DELETE_PERSISTENT_GROUP:
+                case WifiP2pManager.DELETE_PERSISTENT_GROUP:
                    if (DBG) logd(getName() + " delete persistent group");
                    mGroups.remove(message.arg1);
                    replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
                    break;
+                case SET_MIRACAST_MODE:
+                    mWifiNative.setMiracastMode(message.arg1);
+                    break;
                 default:
-                    return NOT_HANDLED;
+                   return NOT_HANDLED;
             }
             return HANDLED;
         }