am a8e09520: am 96100195: Fix the build.

* commit 'a8e09520010ccc32b303c3028e37f34942e1e48c':
  Fix the build.
diff --git a/api/current.xml b/api/current.xml
index 22cd6fb..ecfc556 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -119408,6 +119408,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="canMakeReadonly"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getCachedNdefMessage"
  return="android.nfc.NdefMessage"
  abstract="false"
@@ -119482,17 +119493,6 @@
  visibility="public"
 >
 </method>
-<method name="makeLowLevelReadonly"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="makeReadonly"
  return="boolean"
  abstract="false"
@@ -194184,10 +194184,10 @@
  synchronized="false"
  static="true"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
-<parameter name="addr" type="int">
+<parameter name="ipv4Address" type="int">
 </parameter>
 </method>
 <method name="formatShortFileSize"
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 2fa2834..f45cf2a 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -1373,6 +1373,7 @@
         public void handleMessage(Message msg) {
             long earliestFuturePollTime = Long.MAX_VALUE;
             long nextPendingSyncTime = Long.MAX_VALUE;
+
             // Setting the value here instead of a method because we want the dumpsys logs
             // to have the most recent value used.
             try {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b2937ba..20a22e5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3080,11 +3080,7 @@
         if (!sCompatibilityModeEnabled) {
             ai.disableCompatibilityMode();
         }
-        if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
-            ai.enabled = true;
-        } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
-            ai.enabled = false;
-        }
+        ai.enabled = p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         return ai;
     }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 8a653dd..f1bf852 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -125,24 +125,19 @@
 
     /**
      * Convert a IPv4 address from an integer to an InetAddress.
-     * @param hostAddr is an Int corresponding to the IPv4 address in network byte order
-     * @return the IP address as an {@code InetAddress}, returns null if
-     * unable to convert or if the int is an invalid address.
+     * @param hostAddress an int corresponding to the IPv4 address in network byte order
      */
     public static InetAddress intToInetAddress(int hostAddress) {
-        InetAddress inetAddress;
         byte[] addressBytes = { (byte)(0xff & hostAddress),
                                 (byte)(0xff & (hostAddress >> 8)),
                                 (byte)(0xff & (hostAddress >> 16)),
                                 (byte)(0xff & (hostAddress >> 24)) };
 
         try {
-           inetAddress = InetAddress.getByAddress(addressBytes);
-        } catch(UnknownHostException e) {
-           return null;
+           return InetAddress.getByAddress(addressBytes);
+        } catch (UnknownHostException e) {
+           throw new AssertionError();
         }
-
-        return inetAddress;
     }
 
     /**
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 23ed31f..b9d4711 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -603,6 +603,23 @@
                 }
                 return _result;
             }
+
+            public int encryptStorage(String password) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(password);
+                    mRemote.transact(Stub.TRANSACTION_encryptStorage, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -661,6 +678,8 @@
 
         static final int TRANSACTION_decryptStorage = IBinder.FIRST_CALL_TRANSACTION + 26;
 
+        static final int TRANSACTION_encryptStorage = IBinder.FIRST_CALL_TRANSACTION + 27;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -950,6 +969,14 @@
                     reply.writeInt(result);
                     return true;
                 }
+                case TRANSACTION_encryptStorage: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String password = data.readString();
+                    int result = encryptStorage(password);
+                    reply.writeNoException();
+                    reply.writeInt(result);
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -1114,4 +1141,9 @@
      * Decrypts any encrypted volumes.
      */
     public int decryptStorage(String password) throws RemoteException;
+
+    /**
+     * Encrypts storage.
+     */
+    public int encryptStorage(String password) throws RemoteException;
 }
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index baaa3ce..5ae65df 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -17,32 +17,33 @@
 package android.text.format;
 
 import android.content.Context;
+import android.net.NetworkUtils;
 
 /**
  * Utility class to aid in formatting common values that are not covered
- * by the standard java.util.Formatter.
+ * by {@link java.util.Formatter}
  */
 public final class Formatter {
 
     /**
      * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc
-     * 
+     *
      * @param context Context to use to load the localized units
-     * @param number size value to be formated
-     * @return formated string with the number
+     * @param number size value to be formatted
+     * @return formatted string with the number
      */
     public static String formatFileSize(Context context, long number) {
         return formatFileSize(context, number, false);
     }
-    
+
     /**
      * Like {@link #formatFileSize}, but trying to generate shorter numbers
-     * (showing fewer digits of precisin).
+     * (showing fewer digits of precision).
      */
     public static String formatShortFileSize(Context context, long number) {
         return formatFileSize(context, number, true);
     }
-    
+
     private static String formatFileSize(Context context, long number, boolean shorter) {
         if (context == null) {
             return "";
@@ -92,21 +93,21 @@
             getString(com.android.internal.R.string.fileSizeSuffix,
                       value, context.getString(suffix));
     }
-    
+
     /**
      * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing
      * the IP address.  The IP address is expected to be in little-endian format (LSB first). That
      * is, 0x01020304 will return "4.3.2.1".
-     * 
-     * @param addr the IP address as a packed integer with LSB first.
+     *
+     * @param ipv4Address the IP address as a packed integer with LSB first.
      * @return string with canonical IP address format.
+     *
+     * @deprecated this method doesn't support IPv6 addresses. Prefer {@link
+     *     java.net.InetAddress#getHostAddress()}, which supports both IPv4 and
+     *     IPv6 addresses.
      */
-    public static String formatIpAddress(int addr) {
-        StringBuffer buf = new StringBuffer();
-        buf.append(addr  & 0xff).append('.').
-            append((addr >>>= 8) & 0xff).append('.').
-            append((addr >>>= 8) & 0xff).append('.').
-            append((addr >>>= 8) & 0xff);
-        return buf.toString();
+    @Deprecated
+    public static String formatIpAddress(int ipv4Address) {
+        return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress();
     }
 }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
index 43cf06a..96b028a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -19,6 +19,16 @@
 import android.content.Context;
 import android.test.InstrumentationTestCase;
 
+/**
+ * Stress test suite for Bluetooth related functions.
+ *
+ * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode,
+ * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying
+ * that remote connections/disconnections occur for the PAN profile.
+ * <p>
+ * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the
+ * number of iterations and the addresses of remote Bluetooth devices.
+ */
 public class BluetoothStressTest extends InstrumentationTestCase {
     private static final String TAG = "BluetoothStressTest";
     private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
@@ -40,6 +50,9 @@
         mTestUtils.close();
     }
 
+    /**
+     * Stress test for enabling and disabling Bluetooth.
+     */
     public void testEnable() {
         int iterations = BluetoothTestRunner.sEnableIterations;
         if (iterations == 0) {
@@ -55,6 +68,9 @@
         }
     }
 
+    /**
+     * Stress test for putting the device in and taking the device out of discoverable mode.
+     */
     public void testDiscoverable() {
         int iterations = BluetoothTestRunner.sDiscoverableIterations;
         if (iterations == 0) {
@@ -73,6 +89,9 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for starting and stopping Bluetooth scans.
+     */
     public void testScan() {
         int iterations = BluetoothTestRunner.sScanIterations;
         if (iterations == 0) {
@@ -91,6 +110,30 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for enabling and disabling the PAN NAP profile.
+     */
+    public void testEnablePan() {
+        int iterations = BluetoothTestRunner.sEnablePanIterations;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        mTestUtils.enable(adapter);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.enablePan(adapter);
+            mTestUtils.disablePan(adapter);
+        }
+
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for pairing and unpairing with a remote device.
+     * <p>
+     * In this test, the local device initiates pairing with a remote device, and then unpairs with
+     * the device after the pairing has successfully completed.
+     */
     public void testPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         if (iterations == 0) {
@@ -110,6 +153,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for accepting a pairing request and unpairing with a remote device.
+     * <p>
+     * In this test, the local device waits for a pairing request from a remote device.  It accepts
+     * the request and then unpairs after the paring has successfully completed.
+     */
     public void testAcceptPair() {
         int iterations = BluetoothTestRunner.sPairIterations;
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -125,6 +174,12 @@
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting with an A2DP source.
+     * <p>
+     * In this test, the local device plays the role of an A2DP sink, and initiates connections and
+     * disconnections with an A2DP source.
+     */
     public void testConnectA2dp() {
         int iterations = BluetoothTestRunner.sConnectA2dpIterations;
         if (iterations == 0) {
@@ -143,10 +198,16 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
         mTestUtils.disable(adapter);
     }
 
+    /**
+     * Stress test for connecting and disconnecting the HFP with a hands free device.
+     * <p>
+     * In this test, the local device plays the role of an HFP audio gateway, and initiates
+     * connections and disconnections with a hands free device.
+     */
     public void testConnectHeadset() {
         int iterations = BluetoothTestRunner.sConnectHeadsetIterations;
         if (iterations == 0) {
@@ -165,7 +226,94 @@
             mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
         }
 
-        // TODO: Unpair from device if device can accept pairing after unpairing
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a HID device.
+     * <p>
+     * In this test, the local device plays the role of a HID host, and initiates connections and
+     * disconnections with a HID device.
+     */
+    public void testConnectInput() {
+        int iterations = BluetoothTestRunner.sConnectInputIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sInputAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectInput(adapter, device);
+            mTestUtils.disconnectInput(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for connecting and disconnecting with a PAN NAP.
+     * <p>
+     * In this test, the local device plays the role of a PANU, and initiates connections and
+     * disconnections with a NAP.
+     */
+    public void testConnectPan() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
+            mTestUtils.connectPan(adapter, device);
+            mTestUtils.disconnectPan(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disable(adapter);
+    }
+
+    /**
+     * Stress test for verifying a PANU connecting and disconnecting with the device.
+     * <p>
+     * In this test, the local device plays the role of a NAP which a remote PANU connects and
+     * disconnects from.
+     */
+    public void testIncomingPanConnection() {
+        int iterations = BluetoothTestRunner.sConnectPanIterations;
+        if (iterations == 0) {
+            return;
+        }
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sPanAddress);
+        mTestUtils.enable(adapter);
+        mTestUtils.enablePan(adapter);
+        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sPairPasskey,
+                BluetoothTestRunner.sPairPin);
+
+        for (int i = 0; i < iterations; i++) {
+            mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
+                    + iterations);
+            mTestUtils.incomingPanConnection(adapter, device);
+            mTestUtils.incomingPanDisconnection(adapter, device);
+        }
+
+        mTestUtils.unpair(adapter, device);
+        mTestUtils.disablePan(adapter);
         mTestUtils.disable(adapter);
     }
 }
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
index 3e589fc..cede05a 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -23,19 +23,51 @@
 import android.test.InstrumentationTestSuite;
 import android.util.Log;
 
+/**
+ * Instrumentation test runner for Bluetooth tests.
+ * <p>
+ * To run:
+ * <pre>
+ * {@code
+ * adb shell am instrument \
+ *     [-e enable_iterations <iterations>] \
+ *     [-e discoverable_iterations <iterations>] \
+ *     [-e scan_iterations <iterations>] \
+ *     [-e enable_pan_iterations <iterations>] \
+ *     [-e pair_iterations <iterations>] \
+ *     [-e connect_a2dp_iterations <iterations>] \
+ *     [-e connect_headset_iterations <iterations>] \
+ *     [-e connect_input_iterations <iterations>] \
+ *     [-e connect_pan_iterations <iterations>] \
+ *     [-e pair_address <address>] \
+ *     [-e headset_address <address>] \
+ *     [-e a2dp_address <address>] \
+ *     [-e input_address <address>] \
+ *     [-e pan_address <address>] \
+ *     [-e pair_pin <pin>] \
+ *     [-e pair_passkey <passkey>] \
+ *     -w com.android.frameworks.coretests/android.bluetooth.BluetoothTestRunner
+ * }
+ * </pre>
+ */
 public class BluetoothTestRunner extends InstrumentationTestRunner {
     private static final String TAG = "BluetoothTestRunner";
 
     public static int sEnableIterations = 100;
     public static int sDiscoverableIterations = 1000;
     public static int sScanIterations = 1000;
+    public static int sEnablePanIterations = 1000;
     public static int sPairIterations = 100;
     public static int sConnectHeadsetIterations = 100;
     public static int sConnectA2dpIterations = 100;
+    public static int sConnectInputIterations = 100;
+    public static int sConnectPanIterations = 100;
 
     public static String sPairAddress = "";
     public static String sHeadsetAddress = "";
     public static String sA2dpAddress = "";
+    public static String sInputAddress = "";
+    public static String sPanAddress = "";
 
     public static byte[] sPairPin = {'1', '2', '3', '4'};
     public static int sPairPasskey = 123456;
@@ -81,6 +113,15 @@
             }
         }
 
+        val = arguments.getString("enable_pan_iterations");
+        if (val != null) {
+            try {
+                sEnablePanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_iterations");
         if (val != null) {
             try {
@@ -108,6 +149,24 @@
             }
         }
 
+        val = arguments.getString("connect_input_iterations");
+        if (val != null) {
+            try {
+                sConnectInputIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
+        val = arguments.getString("connect_pan_iterations");
+        if (val != null) {
+            try {
+                sConnectPanIterations = Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                // Invalid argument, fall back to default value
+            }
+        }
+
         val = arguments.getString("pair_address");
         if (val != null) {
             sPairAddress = val;
@@ -123,6 +182,16 @@
             sA2dpAddress = val;
         }
 
+        val = arguments.getString("input_address");
+        if (val != null) {
+            sInputAddress = val;
+        }
+
+        val = arguments.getString("pan_address");
+        if (val != null) {
+            sPanAddress = val;
+        }
+
         val = arguments.getString("pair_pin");
         if (val != null) {
             sPairPin = BluetoothDevice.convertPinToBytes(val);
@@ -143,9 +212,13 @@
         Log.i(TAG, String.format("pair_iterations=%d", sPairIterations));
         Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations));
         Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
+        Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
+        Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
         Log.i(TAG, String.format("pair_address=%s", sPairAddress));
         Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
         Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
+        Log.i(TAG, String.format("input_address=%s", sInputAddress));
+        Log.i(TAG, String.format("pan_address=%s", sPanAddress));
         Log.i(TAG, String.format("pair_pin=%s", new String(sPairPin)));
         Log.i(TAG, String.format("pair_passkey=%d", sPairPasskey));
 
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
index 6da38a7..effed76 100644
--- a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -35,49 +35,29 @@
 public class BluetoothTestUtils extends Assert {
 
     /**
-     * Timeout for {@link BluetoothAdapter#disable()} in ms.
+     * Timeout for enable/disable in ms.
      */
-    private static final int DISABLE_TIMEOUT = 20000;
+    private static final int ENABLE_DISABLE_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#enable()} in ms.
+     * Timeout for discoverable/undiscoverable in ms.
      */
-    private static final int ENABLE_TIMEOUT = 20000;
+    private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+     * Timeout for starting/stopping a scan in ms.
      */
-    private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+    private static final int START_STOP_SCAN_TIMEOUT = 5000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+     * Timeout for pair/unpair in ms.
      */
-    private static final int START_DISCOVERY_TIMEOUT = 5000;
+    private static final int PAIR_UNPAIR_TIMEOUT = 20000;
 
     /**
-     * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+     * Timeout for connecting/disconnecting a profile in ms.
      */
-    private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#createBond()} in ms.
-     */
-    private static final int PAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothDevice#removeBond()} in ms.
-     */
-    private static final int UNPAIR_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#connect(BluetoothDevice)} in ms.
-     */
-    private static final int CONNECT_PROFILE_TIMEOUT = 20000;
-
-    /**
-     * Timeout for {@link BluetoothProfile#disconnect(BluetoothDevice)} in ms.
-     */
-    private static final int DISCONNECT_PROFILE_TIMEOUT = 20000;
+    private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
 
     /**
      * Timeout to connect a profile proxy in ms.
@@ -265,7 +245,6 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
-
             if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
                 if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
                     return;
@@ -291,6 +270,91 @@
         }
     }
 
+    private class ConnectInputReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+
+        public ConnectInputReceiver(BluetoothDevice device, int expectedFlags) {
+            super(expectedFlags);
+
+            mDevice = device;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
+                return;
+            }
+
+            if (BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothInputDevice.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothInputDevice.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
+    private class ConnectPanReceiver extends FlagReceiver {
+        private static final int STATE_DISCONNECTED_FLAG = 1;
+        private static final int STATE_CONNECTING_FLAG = 1 << 1;
+        private static final int STATE_CONNECTED_FLAG = 1 << 2;
+        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
+
+        private BluetoothDevice mDevice;
+        private int mRole;
+
+        public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
+            super (expectedFlags);
+
+            mDevice = device;
+            mRole = role;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+                    || mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
+                return;
+            }
+
+            if (BluetoothPan.ACTION_PAN_STATE_CHANGED.equals(intent.getAction())) {
+                int state = intent.getIntExtra(BluetoothPan.EXTRA_PAN_STATE, -1);
+                assertNotSame(-1, state);
+                switch (state) {
+                    case BluetoothPan.STATE_DISCONNECTED:
+                        setFiredFlag(STATE_DISCONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTING:
+                        setFiredFlag(STATE_CONNECTING_FLAG);
+                        break;
+                    case BluetoothPan.STATE_CONNECTED:
+                        setFiredFlag(STATE_CONNECTED_FLAG);
+                        break;
+                    case BluetoothPan.STATE_DISCONNECTING:
+                        setFiredFlag(STATE_DISCONNECTING_FLAG);
+                        break;
+                }
+            }
+        }
+    }
+
     private BluetoothProfile.ServiceListener mServiceListener =
             new BluetoothProfile.ServiceListener() {
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -330,10 +394,24 @@
     private BluetoothA2dp mA2dp;
     private BluetoothHeadset mHeadset;
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     */
     public BluetoothTestUtils(Context context, String tag) {
         this(context, tag, null);
     }
 
+    /**
+     * Creates a utility instance for testing Bluetooth.
+     *
+     * @param context The context of the application using the utility.
+     * @param tag The log tag of the application using the utility.
+     * @param outputFile The path to an output file if the utility is to write results to a
+     *        separate file.
+     */
     public BluetoothTestUtils(Context context, String tag, String outputFile) {
         mContext = context;
         mTag = tag;
@@ -352,6 +430,9 @@
         }
     }
 
+    /**
+     * Closes the utility instance and unregisters any BroadcastReceivers.
+     */
     public void close() {
         while (!mReceivers.isEmpty()) {
             mContext.unregisterReceiver(mReceivers.remove(0));
@@ -366,6 +447,12 @@
         }
     }
 
+    /**
+     * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void enable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
                 | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
@@ -397,22 +484,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_ON) {
+            if (state == BluetoothAdapter.STATE_ON
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("enable() completed in %d ms", (finish - start)));
-                    } else {
-                        writeOutput("enable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("enable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("enable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -423,6 +507,12 @@
                 state, BluetoothAdapter.STATE_ON, firedFlags, mask));
     }
 
+    /**
+     * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void disable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
                 | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
@@ -454,23 +544,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
-            if (state == BluetoothAdapter.STATE_OFF) {
+            if (state == BluetoothAdapter.STATE_OFF
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.isEnabled());
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disable() completed in %d ms",
-                                (finish - start)));
-                    } else {
-                        writeOutput("disable() completed");
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disable() completed in %d ms", (finish - start)));
+                } else {
+                    writeOutput("disable() completed");
                 }
-            } else {
-                assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -481,6 +567,12 @@
                 state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into discoverable mode and checks to make sure that the local device
+     * is in discoverable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void discoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
 
@@ -499,17 +591,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("discoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("discoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -521,6 +610,12 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Puts the local device into connectable only mode and checks to make sure that the local
+     * device is in in connectable mode and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void undiscoverable(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
 
@@ -539,17 +634,14 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
 
-        while (System.currentTimeMillis() - start < SET_SCAN_MODE_TIMEOUT) {
+        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
             scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    writeOutput(String.format("undiscoverable() completed in %d ms",
-                            (receiver.getCompletedTime() - start)));
-                    removeReceiver(receiver);
-                    return;
-                }
-            } else {
-                assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
+            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                writeOutput(String.format("undiscoverable() completed in %d ms",
+                        (receiver.getCompletedTime() - start)));
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -561,6 +653,12 @@
                 mask));
     }
 
+    /**
+     * Starts a scan for remote devices and checks to make sure that the local device is scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void startScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
 
@@ -577,7 +675,7 @@
         long start = System.currentTimeMillis();
         assertTrue(adapter.startDiscovery());
 
-        while (System.currentTimeMillis() - start < START_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("startScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -593,6 +691,12 @@
                 adapter.isDiscovering(), firedFlags, mask));
     }
 
+    /**
+     * Stops a scan for remote devices and checks to make sure that the local device is not scanning
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     */
     public void stopScan(BluetoothAdapter adapter) {
         int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
 
@@ -610,7 +714,7 @@
         // TODO: put assertTrue() around cancelDiscovery() once it starts returning true.
         adapter.cancelDiscovery();
 
-        while (System.currentTimeMillis() - start < CANCEL_DISCOVERY_TIMEOUT) {
+        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
             if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                 writeOutput(String.format("stopScan() completed in %d ms",
                         (receiver.getCompletedTime() - start)));
@@ -627,20 +731,84 @@
 
     }
 
+    /**
+     * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void enablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(true);
+        long stop = System.currentTimeMillis();
+        assertTrue(pan.isTetheringOn());
+
+        writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Disables PAN tethering on the local device and checks to make sure that tethering is
+     * disabled.
+     *
+     * @param adapter The BT adapter.
+     */
+    public void disablePan(BluetoothAdapter adapter) {
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+
+        long start = System.currentTimeMillis();
+        pan.setBluetoothTethering(false);
+        long stop = System.currentTimeMillis();
+        assertFalse(pan.isTetheringOn());
+
+        writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
+    }
+
+    /**
+     * Initiates a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, true);
     }
 
+    /**
+     * Accepts a pairing with a remote device and checks to make sure that the devices are paired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     */
     public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
             byte[] pin) {
         pairOrAcceptPair(adapter, device, passkey, pin, false);
     }
 
+    /**
+     * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
+     * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
+     * a pairing request.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
+     * @param pin The pairing pin if pairing requires a pin. Any value if not.
+     * @param shouldPair Whether to pair or accept the pair.
+     */
     private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
-            byte[] pin, boolean pair) {
+            byte[] pin, boolean shouldPair) {
         int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
         long start = -1;
-        String methodName = pair ? "pair()" : "acceptPair()";
+        String methodName = shouldPair ? "pair()" : "acceptPair()";
 
         if (!adapter.isEnabled()) {
             fail(methodName + " bluetooth not enabled");
@@ -653,7 +821,7 @@
             case BluetoothDevice.BOND_NONE:
                 assertFalse(adapter.getBondedDevices().contains(device));
                 start = System.currentTimeMillis();
-                if (pair) {
+                if (shouldPair) {
                     assertTrue(device.createBond());
                 }
                 break;
@@ -670,21 +838,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < PAIR_TIMEOUT) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
             state = device.getBondState();
-            if (state == BluetoothDevice.BOND_BONDED) {
+            if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
                 assertTrue(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("%s completed: device=%s", methodName, device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -696,6 +862,13 @@
                 BluetoothDevice.BOND_BONDED, firedFlags, mask));
     }
 
+    /**
+     * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
     public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
         int mask = PairReceiver.STATE_NONE_FLAG;
         long start = -1;
@@ -727,20 +900,19 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < UNPAIR_TIMEOUT) {
-            if (device.getBondState() == BluetoothDevice.BOND_NONE) {
+        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
+            if (device.getBondState() == BluetoothDevice.BOND_NONE
+                    && (receiver.getFiredFlags() & mask) == mask) {
                 assertFalse(adapter.getBondedDevices().contains(device));
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("unpair() completed in %d ms: device=%s",
-                                (finish - start), device));
-                    } else {
-                        writeOutput(String.format("unpair() completed: device=%s", device));
-                    }
-                    removeReceiver(receiver);
-                    return;
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("unpair() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("unpair() completed: device=%s", device));
                 }
+                removeReceiver(receiver);
+                return;
             }
         }
 
@@ -751,6 +923,15 @@
                 firedFlags, mask));
     }
 
+    /**
+     * Connects a profile from the local device to a remote device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
@@ -794,21 +975,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < CONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_CONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("connectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("connectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("connectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -820,6 +1000,15 @@
                 BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Disconnects a profile between the local device and a remote device and checks to make sure
+     * that the profile is disconnected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP} or
+     *        {@link BluetoothProfile#HEADSET}.
+     */
     public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile) {
         int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
@@ -863,21 +1052,20 @@
         }
 
         long s = System.currentTimeMillis();
-        while (System.currentTimeMillis() - s < DISCONNECT_PROFILE_TIMEOUT) {
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
             state = proxy.getConnectionState(device);
-            if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                if ((receiver.getFiredFlags() & mask) == mask) {
-                    long finish = receiver.getCompletedTime();
-                    if (start != -1 && finish != -1) {
-                        writeOutput(String.format("disconnectProfile() completed in %d ms: "
-                                + "device=%s, profile=%d", (finish - start), device, profile));
-                    } else {
-                        writeOutput(String.format("disconnectProfile() completed: device=%s, "
-                                + "profile=%d", device, profile));
-                    }
-                    removeReceiver(receiver);
-                    return;
+            if (state == BluetoothProfile.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectProfile() completed in %d ms: "
+                            + "device=%s, profile=%d", (finish - start), device, profile));
+                } else {
+                    writeOutput(String.format("disconnectProfile() completed: device=%s, "
+                            + "profile=%d", device, profile));
                 }
+                removeReceiver(receiver);
+                return;
             }
             sleep(POLL_TIME);
         }
@@ -889,6 +1077,360 @@
                 BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
     }
 
+    /**
+     * Connects the local device with a remote HID device and checks to make sure that the profile
+     * is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_CONNECTING_FLAG
+                | ConnectInputReceiver.STATE_CONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("connectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("connectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.connectInputDevice(device));
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("connectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("connectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("connectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("connectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state, BluetoothInputDevice.STATE_CONNECTED,
+                firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the local device with a remote HID device and checks to make sure that the
+     * profile is connected and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectInput(BluetoothAdapter adapter, BluetoothDevice device) {
+        int mask = (ConnectInputReceiver.STATE_DISCONNECTING_FLAG
+                | ConnectInputReceiver.STATE_DISCONNECTED_FLAG);
+        long start = -1;
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("disconnectInput() bluetooth not enabled: device=%s", device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("disconnectInput() device not paired: device=%s", device));
+        }
+
+        BluetoothInputDevice inputDevice = new BluetoothInputDevice(mContext);
+        assertNotNull(inputDevice);
+        ConnectInputReceiver receiver = getConnectInputReceiver(device, mask);
+
+        int state = inputDevice.getInputDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                assertTrue(inputDevice.disconnectInputDevice(device));
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("disconnectInput() invalid state: device=%s, state=%d", device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = inputDevice.getInputDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("disconnectInput() completed in %d ms: device=%s",
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("disconnectInput() completed: device=%s", device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("disconnectInput() timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
+     * the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
+     * were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        connectPanOrIncomingPanConnection(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
+     * remote NAP or verify that a remote device connected to the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param connect If the method should initiate the connection (is PANU)
+     */
+    private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
+            boolean connect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (connect) {
+            methodName = "connectPan()";
+            mask = (ConnectPanReceiver.STATE_CONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_CONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanConnection()";
+            mask = ConnectPanReceiver.STATE_CONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothPan.STATE_CONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothPan.STATE_CONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            case BluetoothPan.STATE_DISCONNECTED:
+            case BluetoothPan.STATE_DISCONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    Log.i("BT", "connect to pan");
+                    assertTrue(pan.connect(device));
+                }
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothPan.STATE_CONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
+     * and that the correct actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
+    }
+
+    /**
+     * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
+     * actions were broadcast.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     */
+    public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
+        disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
+    }
+
+    /**
+     * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
+     * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
+     * from a remote NAP or verify that a remote device disconnected from the local NAP.
+     *
+     * @param adapter The BT adapter.
+     * @param device The remote device.
+     * @param disconnect Whether the method should connect or verify.
+     */
+    private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
+            BluetoothDevice device, boolean disconnect) {
+        long start = -1;
+        int mask, role;
+        String methodName;
+
+        if (disconnect) {
+            methodName = "disconnectPan()";
+            mask = (ConnectPanReceiver.STATE_DISCONNECTED_FLAG |
+                    ConnectPanReceiver.STATE_DISCONNECTING_FLAG);
+            role = BluetoothPan.LOCAL_PANU_ROLE;
+        } else {
+            methodName = "incomingPanDisconnection()";
+            mask = ConnectPanReceiver.STATE_DISCONNECTED_FLAG;
+            role = BluetoothPan.LOCAL_NAP_ROLE;
+        }
+
+        if (!adapter.isEnabled()) {
+            fail(String.format("%s bluetooth not enabled: device=%s", methodName, device));
+        }
+
+        if (!adapter.getBondedDevices().contains(device)) {
+            fail(String.format("%s device not paired: device=%s", methodName, device));
+        }
+
+        BluetoothPan pan = new BluetoothPan(mContext);
+        assertNotNull(pan);
+        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
+
+        int state = pan.getPanDeviceState(device);
+        switch (state) {
+            case BluetoothInputDevice.STATE_CONNECTED:
+            case BluetoothInputDevice.STATE_CONNECTING:
+                start = System.currentTimeMillis();
+                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
+                    assertTrue(pan.disconnect(device));
+                }
+                break;
+            case BluetoothInputDevice.STATE_DISCONNECTED:
+                removeReceiver(receiver);
+                return;
+            case BluetoothInputDevice.STATE_DISCONNECTING:
+                mask = 0; // Don't check for received intents since we might have missed them.
+                break;
+            default:
+                removeReceiver(receiver);
+                fail(String.format("%s invalid state: device=%s, state=%d", methodName, device,
+                        state));
+        }
+
+        long s = System.currentTimeMillis();
+        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
+            state = pan.getPanDeviceState(device);
+            if (state == BluetoothInputDevice.STATE_DISCONNECTED
+                    && (receiver.getFiredFlags() & mask) == mask) {
+                long finish = receiver.getCompletedTime();
+                if (start != -1 && finish != -1) {
+                    writeOutput(String.format("%s completed in %d ms: device=%s", methodName,
+                            (finish - start), device));
+                } else {
+                    writeOutput(String.format("%s completed: device=%s", methodName, device));
+                }
+                removeReceiver(receiver);
+                return;
+            }
+            sleep(POLL_TIME);
+        }
+
+        int firedFlags = receiver.getFiredFlags();
+        removeReceiver(receiver);
+        fail(String.format("%s timeout: device=%s, state=%d (expected %d), "
+                + "flags=0x%x (expected 0x%s)", methodName, device, state,
+                BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
+    }
+
+    /**
+     * Writes a string to the logcat and a file if a file has been specified in the constructor.
+     *
+     * @param s The string to be written.
+     */
     public void writeOutput(String s) {
         Log.i(mTag, s);
         if (mOutputWriter == null) {
@@ -902,38 +1444,60 @@
         }
     }
 
-    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
-        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+    private void addReceiver(BroadcastReceiver receiver, String[] actions) {
         IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
-        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
-        filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        for (String action: actions) {
+            filter.addAction(action);
+        }
         mContext.registerReceiver(receiver, filter);
         mReceivers.add(receiver);
+    }
+
+    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
+        String[] actions = {
+                BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
+                BluetoothAdapter.ACTION_DISCOVERY_STARTED,
+                BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
+                BluetoothAdapter.ACTION_STATE_CHANGED};
+        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothDevice.ACTION_PAIRING_REQUEST,
+                BluetoothDevice.ACTION_BOND_STATE_CHANGED};
         PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
-        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
     private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
             int expectedFlags) {
+        String[] actions = {
+                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
+                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED};
         ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
                 expectedFlags);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-        mContext.registerReceiver(receiver, filter);
-        mReceivers.add(receiver);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectInputReceiver getConnectInputReceiver(BluetoothDevice device,
+            int expectedFlags) {
+        String[] actions = {BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED};
+        ConnectInputReceiver receiver = new ConnectInputReceiver(device, expectedFlags);
+        addReceiver(receiver, actions);
+        return receiver;
+    }
+
+    private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
+            int expectedFlags) {
+        String[] actions = {BluetoothPan.ACTION_PAN_STATE_CHANGED};
+        ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
+        addReceiver(receiver, actions);
         return receiver;
     }
 
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index ca934ec..746597f 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -464,37 +464,28 @@
           <li><a href="<?cs var:toroot ?>guide/developing/tools/mksdcard.html">mksdcard</a></li>
 
           <li><a href="/guide/developing/tools/monkey.html">Monkey</a></li>
-              <li class="toggle-list">
-                 <div>
-                     <a href="/guide/developing/tools/monkeyrunner_concepts.html">
-                     <span class="en">monkeyrunner</span>
-                  </a>
-                  </div>
-                  <ul>
-                      <li>
-                          <a href="/guide/developing/tools/MonkeyDevice.html">
-                                <span class="en">MonkeyDevice</span>
-                        </a>
-                    </li>
-                    <li>
-                        <a href="/guide/developing/tools/MonkeyImage.html">
-                            <span class="en">MonkeyImage</span>
-                        </a>
-                    </li>
-                    <li>
-                        <a href="/guide/developing/tools/MonkeyRunner.html">
-                            <span class="en">MonkeyRunner</span>
-                        </a>
-                    </li>
-                  </ul>
-              </li>
-              <li><a href="<?cs var:toroot ?>guide/developing/tools/proguard.html">ProGuard</a>
-<span class="new">new!</span></li>
-              <li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html#sqlite">sqlite3</a></li>
-              <li><a href="<?cs var:toroot ?>guide/developing/tools/traceview.html" >Traceview</a></li>
-              <li><a href="<?cs var:toroot ?>guide/developing/tools/zipalign.html" >zipalign</a></li>
-          </ul>
-        </li>
+          <li class="toggle-list">
+            <div><a href="/guide/developing/tools/monkeyrunner_concepts.html">
+              <span class="en">monkeyrunner</span>
+            </a></div>
+            <ul>
+              <li><a href="/guide/developing/tools/MonkeyDevice.html">
+                <span class="en">MonkeyDevice</span>
+                </a></li>
+              <li><a href="/guide/developing/tools/MonkeyImage.html">
+                <span class="en">MonkeyImage</span>
+                </a></li>
+              <li><a href="/guide/developing/tools/MonkeyRunner.html">
+                <span class="en">MonkeyRunner</span>
+                </a></li>
+            </ul>
+          </li>
+          <li><a href="/guide/developing/tools/proguard.html">ProGuard</a></li>
+          <li><a href="/guide/developing/tools/adb.html#sqlite">sqlite3</a></li>
+          <li><a href="/guide/developing/tools/traceview.html">Traceview</a></li>
+          <li><a href="<?cs var:toroot ?>guide/developing/tools/zipalign.html">zipalign</a></li>
+        </ul>
+      </li>
     </ul>
   </li>
 
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index b6e0c30..ef7d274 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -87,7 +87,7 @@
 }
 
 status_t DrmManager::loadPlugIns() {
-    String8 pluginDirPath("/system/lib/drm/plugins/native");
+    String8 pluginDirPath("/system/lib/drm");
     return loadPlugIns(pluginDirPath);
 }
 
diff --git a/include/storage/IMountService.h b/include/storage/IMountService.h
index 68ccd95..472d8e5 100644
--- a/include/storage/IMountService.h
+++ b/include/storage/IMountService.h
@@ -67,6 +67,7 @@
     virtual bool isObbMounted(const String16& filename) = 0;
     virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
     virtual int32_t decryptStorage(const String16& password) = 0;
+    virtual int32_t encryptStorage(const String16& password) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index a7ab824..7fbf67a 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -49,6 +49,7 @@
     TRANSACTION_getMountedObbPath,
     TRANSACTION_isExternalStorageEmulated,
     TRANSACTION_decryptStorage,
+    TRANSACTION_encryptStorage,
 };
 
 class BpMountService: public BpInterface<IMountService>
@@ -505,7 +506,7 @@
         path = reply.readString16();
         return true;
     }
-    
+
     int32_t decryptStorage(const String16& password)
     {
         Parcel data, reply;
@@ -522,6 +523,23 @@
         }
         return reply.readInt32();
     }
+
+    int32_t encryptStorage(const String16& password)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(password);
+        if (remote()->transact(TRANSACTION_encryptStorage, data, &reply) != NO_ERROR) {
+            LOGD("encryptStorage could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("encryptStorage caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MountService, "IMountService");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index a3d8ac9..32d61b7 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2126,7 +2126,8 @@
         if (proxy == null) proxy = new ProxyProperties("", 0, "");
         log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
         mContext.sendStickyBroadcast(intent);
     }
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index bf81457..d6804f9 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1653,6 +1653,29 @@
         return 0;
     }
 
+    public int encryptStorage(String password) {
+        if (password == null) {
+            throw new IllegalArgumentException("password cannot be null");
+        }
+
+        // TODO: Enforce a permission
+
+        waitForReady();
+
+        if (DEBUG_EVENTS) {
+            Slog.i(TAG, "decrypting storage...");
+        }
+
+        try {
+            mConnector.doCommand(String.format("cryptfs enablecrypto wipe %s", password));
+        } catch (NativeDaemonConnectorException e) {
+            // Encryption failed
+            return e.getCode();
+        }
+
+        return 0;
+    }
+
     private void addObbStateLocked(ObbState obbState) throws RemoteException {
         final IBinder binder = obbState.getBinder();
         List<ObbState> obbStates = mObbMounts.get(binder);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
old mode 100755
new mode 100644
index 761dcd1..3c8fb01
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9574,7 +9574,7 @@
                 // r.record is null if findServiceLocked() failed the caller permission check
                 if (r.record == null) {
                     throw new SecurityException(
-                            "Permission Denial: Accessing service "
+                            "Permission Denial: Accessing service " + r.record.name
                             + " from pid=" + Binder.getCallingPid()
                             + ", uid=" + Binder.getCallingUid()
                             + " requires " + r.permission);