Merge "Fix "p.m." in lockscreen (locale: es)." into froyo
diff --git a/NOTICE b/NOTICE
index bb9c5f2..2006201 100644
--- a/NOTICE
+++ b/NOTICE
@@ -43,6 +43,16 @@
 These files are Copyright 2007 Nuance Communications, but released under
 the Apache2 License.
 
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Media Codecs code.                            ==
+   =========================================================================
+
+Media Codecs
+These files are Copyright 1998 - 2009 PacketVideo, but released under
+the Apache2 License.
+
                                Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index ae3daad..cdaefc8 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -150,6 +150,15 @@
     // Test case 1: Test enabling Wifi without associating with any AP
     @LargeTest
     public void test3GToWifiNotification() {
+        // To avoid UNKNOWN state when device boots up
+        cmActivity.enableWifi();
+        try {
+            Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
+        } catch (Exception e) {
+            Log.v(LOG_TAG, "exception: " + e.toString());
+        }
+
+        cmActivity.disableWifi();
         // As Wifi stays in DISCONNECTED, the connectivity manager will not broadcast
         // any network connectivity event for Wifi
         NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
index 8dfa850..91cbe2f 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.Log;
@@ -23,11 +24,21 @@
 import com.android.ddmlib.SyncService;
 import com.android.ddmlib.SyncService.ISyncProgressMonitor;
 import com.android.ddmlib.SyncService.SyncResult;
+import com.android.ddmlib.testrunner.ITestRunListener;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.hosttest.DeviceTestCase;
 import com.android.hosttest.DeviceTestSuite;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.InputStreamReader;
 import java.io.IOException;
+import java.io.StringReader;
+import java.lang.Runtime;
+import java.lang.Process;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import junit.framework.Assert;
 import com.android.hosttest.DeviceTestCase;
@@ -47,6 +58,21 @@
 
     private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
     private static final int WAIT_FOR_DEVICE_POLL_TIME = 10 * 1000;
+    private static final int MAX_WAIT_FOR_APP_LAUNCH_TIME = 60 * 1000;
+    private static final int WAIT_FOR_APP_LAUNCH_POLL_TIME = 5 * 1000;
+
+    // Install preference on the device-side
+    public static enum InstallLocPreference {
+        AUTO,
+        INTERNAL,
+        EXTERNAL
+    }
+
+    // Actual install location
+    public static enum InstallLocation {
+        DEVICE,
+        SDCARD
+    }
 
     /**
      * Constructor takes the device to use
@@ -90,6 +116,30 @@
     }
 
     /**
+     * Helper method to run tests and return the listener that collected the results.
+     * @param pkgName Android application package for tests
+     * @return the {@link CollectingTestRunListener}
+     */
+    private CollectingTestRunListener doRunTests(String pkgName) throws IOException {
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                pkgName, mDevice);
+        CollectingTestRunListener listener = new CollectingTestRunListener();
+        testRunner.run(listener);
+        return listener;
+    }
+
+    /**
+     * Runs the specified packages tests, and returns whether all tests passed or not.
+     *
+     * @param pkgName Android application package for tests
+     * @return true if every test passed, false otherwise.
+     */
+    public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException {
+        CollectingTestRunListener listener = doRunTests(pkgName);
+        return listener.didAllTestsPass();
+    }
+
+    /**
      * Helper method to push a file to device
      * @param apkAppPrivatePath
      * @throws IOException
@@ -102,18 +152,48 @@
     }
 
     /**
-     * Helper method to install a file to device
+     * Helper method to install a file
      * @param localFilePath the absolute file system path to file on local host to install
      * @param reinstall set to <code>true</code> if re-install of app should be performed
      * @throws IOException
      */
-    public void installFile(final String localFilePath, final boolean replace)
-            throws IOException {
+    public void installFile(final String localFilePath, final boolean replace) throws IOException {
         String result = mDevice.installPackage(localFilePath, replace);
         assertEquals(null, result);
     }
 
     /**
+     * Helper method to install a file that should not be install-able
+     * @param localFilePath the absolute file system path to file on local host to install
+     * @param reinstall set to <code>true</code> if re-install of app should be performed
+     * @return the string output of the failed install attempt
+     * @throws IOException
+     */
+    public String installFileFail(final String localFilePath, final boolean replace)
+            throws IOException {
+        String result = mDevice.installPackage(localFilePath, replace);
+        assertNotNull(result);
+        return result;
+    }
+
+    /**
+     * Helper method to install a file to device as forward locked
+     * @param localFilePath the absolute file system path to file on local host to install
+     * @param reinstall set to <code>true</code> if re-install of app should be performed
+     * @throws IOException
+     */
+    public String installFileForwardLocked(final String localFilePath, final boolean replace)
+            throws IOException {
+        String remoteFilePath = mDevice.syncPackageToDevice(localFilePath);
+        InstallReceiver receiver = new InstallReceiver();
+        String cmd = String.format(replace ? "pm install -r -l \"%1$s\"" :
+                "pm install -l \"%1$s\"", remoteFilePath);
+        mDevice.executeShellCommand(cmd, receiver);
+        mDevice.removeRemotePackage(remoteFilePath);
+        return receiver.getErrorMessage();
+    }
+
+    /**
      * Helper method to determine if file on device exists.
      *
      * @param destPath the absolute path of file on device to check
@@ -128,7 +208,7 @@
     /**
      * Helper method to determine if file exists on the device containing a given string.
      *
-     * @param destPath the
+     * @param destPath the absolute path of the file
      * @return <code>true</code> if file exists containing given string,
      *         <code>false</code> otherwise.
      * @throws IOException if adb shell command failed
@@ -152,18 +232,18 @@
     }
 
     /**
-     * Helper method to determine if app was installed on device.
+     * Determines if app was installed on device.
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
      * @throws IOException if adb shell command failed
      */
-    private boolean doesAppExistOnDevice(String packageName) throws IOException {
+    public boolean doesAppExistOnDevice(String packageName) throws IOException {
         return doesRemoteFileExistContainingString(DEVICE_APP_PATH, packageName);
     }
 
     /**
-     * Helper method to determine if app was installed on SD card.
+     * Determines if app was installed on SD card.
      *
      * @param packageName package name to check for
      * @return <code>true</code> if file exists, <code>false</code> otherwise.
@@ -174,12 +254,23 @@
     }
 
     /**
+     * Helper method to determine if app was installed on SD card.
+     *
+     * @param packageName package name to check for
+     * @return <code>true</code> if file exists, <code>false</code> otherwise.
+     * @throws IOException if adb shell command failed
+     */
+    public boolean doesAppExistAsForwardLocked(String packageName) throws IOException {
+        return doesRemoteFileExistContainingString(APP_PRIVATE_PATH, packageName);
+    }
+
+    /**
      * Waits for device's package manager to respond.
      *
      * @throws InterruptedException
      * @throws IOException
      */
-    public void waitForDevice() throws InterruptedException, IOException {
+    public void waitForPackageManager() throws InterruptedException, IOException {
         Log.i(LOG_TAG, "waiting for device");
         int currentWaitTime = 0;
         // poll the package manager until it returns something for android
@@ -194,20 +285,125 @@
     }
 
     /**
+     * Helper to determine if the device is currently online and visible via ADB.
+     *
+     * @return true iff the device is currently available to ADB and online, false otherwise.
+     */
+    private boolean deviceIsOnline() {
+        AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
+        IDevice[] devices = bridge.getDevices();
+
+        for (IDevice device : devices) {
+            // only online if the device appears in the devices list, and its state is online
+            if ((mDevice != null) &&
+                    mDevice.getSerialNumber().equals(device.getSerialNumber()) &&
+                    device.isOnline()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Waits for device to be online (visible to ADB) before returning, or times out if we've
+     * waited too long. Note that this only means the device is visible via ADB, not that
+     * PackageManager is fully up and running yet.
+     *
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    public void waitForDeviceToComeOnline() throws InterruptedException, IOException {
+        Log.i(LOG_TAG, "waiting for device to be online");
+        int currentWaitTime = 0;
+
+        // poll ADB until we see the device is online
+        while (!deviceIsOnline()) {
+            Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
+            currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
+            if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
+                Log.e(LOG_TAG, "time out waiting for device");
+                throw new InterruptedException();
+            }
+        }
+        // Note: if we try to access the device too quickly after it is "officially" online,
+        // there are sometimes strange issues where it's actually not quite ready yet,
+        // so we pause for a bit once more before actually returning.
+        Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
+    }
+
+    /**
+     * Queries package manager and waits until a package is launched (or times out)
+     *
+     * @param packageName The name of the package to wait to load
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    public void waitForApp(String packageName) throws InterruptedException, IOException {
+        Log.i(LOG_TAG, "waiting for app to launch");
+        int currentWaitTime = 0;
+        // poll the package manager until it returns something for the package we're looking for
+        while (!doesPackageExist(packageName)) {
+            Thread.sleep(WAIT_FOR_APP_LAUNCH_POLL_TIME);
+            currentWaitTime += WAIT_FOR_APP_LAUNCH_POLL_TIME;
+            if (currentWaitTime > MAX_WAIT_FOR_APP_LAUNCH_TIME) {
+                Log.e(LOG_TAG, "time out waiting for app to launch: " + packageName);
+                throw new InterruptedException();
+            }
+        }
+    }
+
+    /**
      * Helper method which executes a adb shell command and returns output as a {@link String}
      * @return the output of the command
      * @throws IOException
      */
     public String executeShellCommand(String command) throws IOException {
-        Log.d(LOG_TAG, String.format("adb shell %s", command));
+        Log.i(LOG_TAG, String.format("adb shell %s", command));
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(command, receiver);
         String output = receiver.getOutput();
-        Log.d(LOG_TAG, String.format("Result: %s", output));
+        Log.i(LOG_TAG, String.format("Result: %s", output));
         return output;
     }
 
     /**
+     * Helper method ensures we are in root mode on the host side. It returns only after
+     * PackageManager is actually up and running.
+     * @throws IOException
+     */
+    public void runAdbRoot() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "adb root");
+        Runtime runtime = Runtime.getRuntime();
+        Process process = runtime.exec("adb root"); // adb should be in the path
+        BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+        String nextLine = null;
+        while (null != (nextLine = output.readLine())) {
+            Log.i(LOG_TAG, nextLine);
+        }
+        process.waitFor();
+        waitForDeviceToComeOnline();
+        waitForPackageManager(); // now wait for package manager to actually load
+    }
+
+    /**
+     * Helper method which reboots the device and returns once the device is online again
+     * and package manager is up and running (note this function is synchronous to callers).
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public void rebootDevice() throws IOException, InterruptedException {
+        String command = "reboot"; // no need for -s since mDevice is already tied to a device
+        Log.i(LOG_TAG, command);
+        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(command, receiver);
+        String output = receiver.getOutput();
+        Log.i(LOG_TAG, String.format("Result: %s", output));
+        waitForDeviceToComeOnline(); // wait for device to come online
+        runAdbRoot();
+    }
+
+    /**
      * A {@link IShellOutputReceiver} which collects the whole shell output into one {@link String}
      */
     private class CollectingOutputReceiver extends MultiLineReceiver {
@@ -255,6 +451,97 @@
         }
     }
 
+    // For collecting results from running device tests
+    private static class CollectingTestRunListener implements ITestRunListener {
+
+        private boolean mAllTestsPassed = true;
+        private String mTestRunErrorMessage = null;
+
+        public void testEnded(TestIdentifier test) {
+            // ignore
+        }
+
+        public void testFailed(TestFailure status, TestIdentifier test,
+                String trace) {
+            Log.w(LOG_TAG, String.format("%s#%s failed: %s", test.getClassName(),
+                    test.getTestName(), trace));
+            mAllTestsPassed = false;
+        }
+
+        public void testRunEnded(long elapsedTime) {
+            // ignore
+        }
+
+        public void testRunFailed(String errorMessage) {
+            Log.w(LOG_TAG, String.format("test run failed: %s", errorMessage));
+            mAllTestsPassed = false;
+            mTestRunErrorMessage = errorMessage;
+        }
+
+        public void testRunStarted(int testCount) {
+            // ignore
+        }
+
+        public void testRunStopped(long elapsedTime) {
+            // ignore
+        }
+
+        public void testStarted(TestIdentifier test) {
+            // ignore
+        }
+
+        boolean didAllTestsPass() {
+            return mAllTestsPassed;
+        }
+
+        /**
+         * Get the test run failure error message.
+         * @return the test run failure error message or <code>null</code> if test run completed.
+         */
+        String getTestRunErrorMessage() {
+            return mTestRunErrorMessage;
+        }
+    }
+
+    /**
+     * Output receiver for "pm install package.apk" command line.
+     *
+     */
+    private static final class InstallReceiver extends MultiLineReceiver {
+
+        private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
+        private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
+
+        private String mErrorMessage = null;
+
+        public InstallReceiver() {
+        }
+
+        @Override
+        public void processNewLines(String[] lines) {
+            for (String line : lines) {
+                if (line.length() > 0) {
+                    if (line.startsWith(SUCCESS_OUTPUT)) {
+                        mErrorMessage = null;
+                    } else {
+                        Matcher m = FAILURE_PATTERN.matcher(line);
+                        if (m.matches()) {
+                            mErrorMessage = m.group(1);
+                        }
+                    }
+                }
+            }
+        }
+
+        public boolean isCancelled() {
+            return false;
+        }
+
+        public String getErrorMessage() {
+            return mErrorMessage;
+        }
+    }
+
     /**
      * Helper method for installing an app to wherever is specified in its manifest, and
      * then verifying the app was installed onto SD Card.
@@ -280,7 +567,7 @@
         installFile(apkPath, overwrite);
         assertTrue(doesAppExistOnSDCard(pkgName));
         assertFalse(doesAppExistOnDevice(pkgName));
-        waitForDevice();
+        waitForPackageManager();
 
         // grep for package to make sure it is installed
         assertTrue(doesPackageExist(pkgName));
@@ -311,7 +598,39 @@
         installFile(apkPath, overwrite);
         assertFalse(doesAppExistOnSDCard(pkgName));
         assertTrue(doesAppExistOnDevice(pkgName));
-        waitForDevice();
+        waitForPackageManager();
+
+        // grep for package to make sure it is installed
+        assertTrue(doesPackageExist(pkgName));
+    }
+
+    /**
+     * Helper method for installing an app as forward-locked, and
+     * then verifying the app was installed in the proper forward-locked location.
+     *
+     * @param the path of the apk to install
+     * @param the name of the package
+     * @param <code>true</code> if the app should be overwritten, <code>false</code> otherwise
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void installFwdLockedAppAndVerifyExists(String apkPath,
+            String pkgName, boolean overwrite) throws IOException, InterruptedException {
+        // Start with a clean slate if we're not overwriting
+        if (!overwrite) {
+            // cleanup test app just in case it already exists
+            mDevice.uninstallPackage(pkgName);
+            // grep for package to make sure its not installed
+            assertFalse(doesPackageExist(pkgName));
+        }
+
+        String result = installFileForwardLocked(apkPath, overwrite);
+        assertEquals(null, result);
+        assertTrue(doesAppExistAsForwardLocked(pkgName));
+        assertFalse(doesAppExistOnSDCard(pkgName));
+        waitForPackageManager();
 
         // grep for package to make sure it is installed
         assertTrue(doesPackageExist(pkgName));
@@ -332,4 +651,74 @@
         assertFalse(doesPackageExist(pkgName));
     }
 
+    /**
+     * Helper method for clearing any installed non-system apps.
+     * Useful ensuring no non-system apps are installed, and for cleaning up stale files that
+     * may be lingering on the system for whatever reason.
+     *
+     * @throws IOException if adb shell command failed
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void wipeNonSystemApps() throws IOException {
+      String allInstalledPackages = executeShellCommand("pm list packages -f");
+      BufferedReader outputReader = new BufferedReader(new StringReader(allInstalledPackages));
+
+      // First use Package Manager to uninstall all non-system apps
+      String currentLine = null;
+      while ((currentLine = outputReader.readLine()) != null) {
+          // Skip over any system apps...
+          if (currentLine.contains("/system/")) {
+              continue;
+          }
+          String packageName = currentLine.substring(currentLine.indexOf('=') + 1);
+          mDevice.uninstallPackage(packageName);
+      }
+      // Make sure there are no stale app files under these directories
+      executeShellCommand(String.format("rm %s*", SDCARD_APP_PATH, "*"));
+      executeShellCommand(String.format("rm %s*", DEVICE_APP_PATH, "*"));
+      executeShellCommand(String.format("rm %s*", APP_PRIVATE_PATH, "*"));
+    }
+
+    /**
+     * Sets the device's install location preference.
+     *
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void setDevicePreferredInstallLocation(InstallLocPreference pref) throws IOException {
+        String command = "pm setInstallLocation %d";
+        int locValue = 0;
+        switch (pref) {
+            case INTERNAL:
+                locValue = 1;
+                break;
+            case EXTERNAL:
+                locValue = 2;
+                break;
+            default: // AUTO
+                locValue = 0;
+                break;
+        }
+        executeShellCommand(String.format(command, locValue));
+    }
+
+    /**
+     * Gets the device's install location preference.
+     *
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public InstallLocPreference getDevicePreferredInstallLocation() throws IOException {
+        String result = executeShellCommand("pm getInstallLocation");
+        if (result.indexOf('0') != -1) {
+            return InstallLocPreference.AUTO;
+        }
+        else if (result.indexOf('1') != -1) {
+            return InstallLocPreference.INTERNAL;
+        }
+        else {
+            return InstallLocPreference.EXTERNAL;
+        }
+    }
 }
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
index 90ddc3a..1b797d5 100644
--- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
@@ -59,6 +59,21 @@
     // Apk with install location set to preferExternal
     private static final String EXTERNAL_LOC_APK = "ExternalLocTestApp.apk";
     private static final String EXTERNAL_LOC_PKG = "com.android.framework.externalloctestapp";
+    // Apk with install location set to auto (2 versions, for update testing)
+    private static final String AUTO_LOC_VERSION_V1_APK = "AutoLocVersionedTestApp_v1.apk";
+    private static final String AUTO_LOC_VERSION_V2_APK = "AutoLocVersionedTestApp_v2.apk";
+    private static final String AUTO_LOC_VERSION_PKG =
+            "com.android.framework.autolocversionedtestapp";
+    // Apk with install location set to preferExternal (2 versions, for update testing)
+    private static final String EXTERNAL_LOC_VERSION_V1_APK = "ExternalLocVersionedTestApp_v1.apk";
+    private static final String EXTERNAL_LOC_VERSION_V2_APK = "ExternalLocVersionedTestApp_v2.apk";
+    private static final String EXTERNAL_LOC_VERSION_PKG =
+            "com.android.framework.externallocversionedtestapp";
+    // Apk with install location set to auto (2 versions, for update testing)
+    private static final String NO_LOC_VERSION_V1_APK = "NoLocVersionedTestApp_v1.apk";
+    private static final String NO_LOC_VERSION_V2_APK = "NoLocVersionedTestApp_v2.apk";
+    private static final String NO_LOC_VERSION_PKG =
+            "com.android.framework.nolocversionedtestapp";
     // Apk with no install location set
     private static final String NO_LOC_APK = "NoLocTestApp.apk";
     private static final String NO_LOC_PKG = "com.android.framework.noloctestapp";
@@ -76,6 +91,12 @@
             = "UpdateExtToIntLocTestApp_v2_int.apk";
     private static final String UPDATE_EXT_TO_INT_LOC_PKG
             = "com.android.framework.updateexttointloctestapp";
+    // Apk set to preferExternal, with Access Fine Location permissions set in its manifest
+    private static final String FL_PERMS_APK = "ExternalLocPermsFLTestApp.apk";
+    private static final String FL_PERMS_PKG = "com.android.framework.externallocpermsfltestapp";
+    // Apk set to preferExternal, with all permissions set in manifest
+    private static final String ALL_PERMS_APK = "ExternalLocAllPermsTestApp.apk";
+    private static final String ALL_PERMS_PKG = "com.android.framework.externallocallpermstestapp";
     // Apks with the same package name, but install location set to
     // one of: Internal, External, Auto, or None
     private static final String VERSATILE_LOC_PKG = "com.android.framework.versatiletestapp";
@@ -83,6 +104,20 @@
     private static final String VERSATILE_LOC_EXTERNAL_APK = "VersatileTestApp_External.apk";
     private static final String VERSATILE_LOC_AUTO_APK = "VersatileTestApp_Auto.apk";
     private static final String VERSATILE_LOC_NONE_APK = "VersatileTestApp_None.apk";
+    // Apks with shared UserID
+    private static final String SHARED_PERMS_APK = "ExternalSharedPermsTestApp.apk";
+    private static final String SHARED_PERMS_PKG
+            = "com.android.framework.externalsharedpermstestapp";
+    private static final String SHARED_PERMS_FL_APK = "ExternalSharedPermsFLTestApp.apk";
+    private static final String SHARED_PERMS_FL_PKG
+            = "com.android.framework.externalsharedpermsfltestapp";
+    private static final String SHARED_PERMS_BT_APK = "ExternalSharedPermsBTTestApp.apk";
+    private static final String SHARED_PERMS_BT_PKG
+            = "com.android.framework.externalsharedpermsbttestapp";
+    // Apk with shared UserID, but signed with a different cert (the media cert)
+    private static final String SHARED_PERMS_DIFF_KEY_APK = "ExternalSharedPermsDiffKeyTestApp.apk";
+    private static final String SHARED_PERMS_DIFF_KEY_PKG
+            = "com.android.framework.externalsharedpermsdiffkeytestapp";
 
     @Override
     protected void setUp() throws Exception {
@@ -95,6 +130,12 @@
         appPrivatePath = mPMHostUtils.getAppPrivatePath();
         deviceAppPath = mPMHostUtils.getDeviceAppPath();
         sdcardAppPath = mPMHostUtils.getSDCardAppPath();
+
+        // Ensure the default is set to let the system decide where to install apps
+        // (It's ok for individual tests to override and change this during their test, but should
+        // reset it back when they're done)
+        mPMHostUtils.setDevicePreferredInstallLocation(
+                PackageManagerHostTestUtils.InstallLocPreference.AUTO);
     }
 
     /**
@@ -115,6 +156,8 @@
      * the app, and otherwise cause the system to blow up.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testPushAppPrivate() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
@@ -129,7 +172,7 @@
         assertTrue(mPMHostUtils.doesRemoteFileExist(apkAppPrivatePath));
         mPMHostUtils.executeShellCommand("start");
 
-        mPMHostUtils.waitForDevice();
+        mPMHostUtils.waitForPackageManager();
 
         // grep for package to make sure its not installed
         assertFalse(mPMHostUtils.doesPackageExist(SIMPLE_PKG));
@@ -138,35 +181,346 @@
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=auto
-     * will install the app to the device.
+     * Helper to do a standard install of an apk and verify it installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @param apkName the file name of the test app apk
+     * @param pkgName the package name of the test app apk
+     * @param expectedLocation the file name of the test app apk
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppAutoLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=auto gets installed on device");
+    private void doStandardInstall(String apkName, String pkgName,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        if (expectedLocation == PackageManagerHostTestUtils.InstallLocation.DEVICE) {
+            mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(apkName), pkgName, false);
+        }
+        else {
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
+                    getTestAppFilePath(apkName), pkgName, false);
+        }
+    }
+
+    /**
+     * Installs the Auto app using the preferred device install location specified,
+     * and verifies it was installed on the device.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+                PackageManagerHostTestUtils.InstallLocPreference.AUTO;
 
         try {
-            mPMHostUtils.installAppAndVerifyExistsOnDevice(
-                    getTestAppFilePath(AUTO_LOC_APK), AUTO_LOC_PKG, false);
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(AUTO_LOC_APK, AUTO_LOC_PKG, expectedLocation);
         }
         // cleanup test app
         finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
             mPMHostUtils.uninstallApp(AUTO_LOC_PKG);
         }
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
-     * will install the app to the device.
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the device when device's preference is auto.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppInternalLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=internalOnly gets installed on device");
+    public void testInstallAppAutoLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=auto gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppAutoLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=internal gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=auto
+     * will install the app to the SD card when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppAutoLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=auto, prefer=external gets installed on device");
+        installAppAutoLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Installs the Internal app using the preferred device install location specified,
+     * and verifies it was installed to the location expected.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
 
         try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(INTERNAL_LOC_APK, INTERNAL_LOC_PKG, expectedLocation);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(INTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is auto.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=auto gets installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=internal is installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=internalOnly
+     * will install the app to the device when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppInternalLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=internal, prefer=external is installed on device");
+        installAppInternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.DEVICE);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the SD card.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @param preference the device's preferred location of where to install apps
+     * @param expectedLocation the expected location of where the apk was installed
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference preference,
+            PackageManagerHostTestUtils.InstallLocation expectedLocation)
+            throws IOException, InterruptedException {
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(preference);
+
+            doStandardInstall(EXTERNAL_LOC_APK, EXTERNAL_LOC_PKG, expectedLocation);
+
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is auto.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=auto gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.AUTO,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=internal gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.INTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
+     * will install the app to the device when device's preference is external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppExternalLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installLocation=external, pref=external gets installed on SD Card");
+        installAppExternalLoc(PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL,
+                PackageManagerHostTestUtils.InstallLocation.SDCARD);
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to let the
+     * system decide.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.AUTO);
             mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to install
+     * external.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on SD card");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app without installLocation in its manifest
+     * will install the app to the device by default when the system default pref is to install
+     * internal.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAppNoLocPrefIsInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLocation gets installed on device");
+
+        PackageManagerHostTestUtils.InstallLocPreference savedPref =
+            PackageManagerHostTestUtils.InstallLocPreference.AUTO;
+
+        try {
+            savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
+            mPMHostUtils.setDevicePreferredInstallLocation(
+                    PackageManagerHostTestUtils.InstallLocPreference.INTERNAL);
+            mPMHostUtils.installAppAndVerifyExistsOnDevice(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its installLocation set to internal that is
+     * forward-locked will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppInternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
                     getTestAppFilePath(INTERNAL_LOC_APK), INTERNAL_LOC_PKG, false);
         }
         // cleanup test app
@@ -176,21 +530,65 @@
     }
 
     /**
-     * Regression test to verify that an app with its manifest set to installLocation=preferExternal
-     * will install the app to the SD card.
+     * Regression test to verify that an app with its installLocation set to external that is
+     * forward-locked will get installed to the correct location.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
-    public void testInstallAppExternalLoc() throws IOException, InterruptedException {
-        Log.i(LOG_TAG, "Test an app with installLocation=preferExternal gets installed on SD Card");
+    public void testInstallFwdLockedAppExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");
 
         try {
-            mPMHostUtils.installAppAndVerifyExistsOnSDCard(
-                    getTestAppFilePath(EXTERNAL_LOC_APK), EXTERNAL_LOC_PKG, false);
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(INTERNAL_LOC_APK), INTERNAL_LOC_PKG, false);
         }
         // cleanup test app
         finally {
-            mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+            mPMHostUtils.uninstallApp(INTERNAL_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with its installLocation set to external that is
+     * forward-locked will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppAuto() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with installLoc set to Auto gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(AUTO_LOC_APK), AUTO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(AUTO_LOC_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with no installLocation set and is
+     * forward-locked installed will get installed to the correct location.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallFwdLockedAppNone() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test an app with no installLoc set gets installed to app-private");
+
+        try {
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(
+                    getTestAppFilePath(NO_LOC_APK), NO_LOC_PKG, false);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(NO_LOC_PKG);
         }
     }
 
@@ -199,6 +597,8 @@
      * uninstall it, and reinstall it onto the SD card.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
@@ -225,6 +625,8 @@
      * uninstall it, and reinstall it onto the device.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     // TODO: This currently relies on the app's manifest to switch from device to
     // SD card install locations. We might want to make Device's installPackage()
@@ -250,10 +652,37 @@
 
     /**
      * Regression test to verify that updating an app on the SD card will install
+     * the update onto the SD card as well when location is set to external for both versions
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testUpdateBothExternal() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
+
+        try {
+            // install the app externally
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V1_APK), EXTERNAL_LOC_VERSION_PKG, false);
+            // now replace the app with one where the location is still set to preferExternal
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V2_APK), EXTERNAL_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+          mPMHostUtils.uninstallApp(EXTERNAL_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that updating an app on the SD card will install
      * the update onto the SD card as well when location is not explicitly set in the
      * updated apps' manifest file.
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testUpdateToSDCard() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
@@ -274,10 +703,11 @@
 
     /**
      * Regression test to verify that updating an app on the SD card will install
-     * the update onto the SD card as well when location is not explicitly set in the
-     * updated apps' manifest file.
+     * the update onto the device if the manifest has changed to installLocation=internalOnly
      * <p/>
      * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
      */
     public void testUpdateSDCardToDevice() throws IOException, InterruptedException {
         Log.i(LOG_TAG, "Test updating an app on the SD card to the Device through manifest change");
@@ -286,7 +716,7 @@
             // install the app externally
             mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
                     UPDATE_EXT_TO_INT_LOC_V1_EXT_APK), UPDATE_EXT_TO_INT_LOC_PKG, false);
-            // now replace the app with an update marked for internalOnly...
+            // now replace the app with an update marked for internalOnly...(should move internal)
             mPMHostUtils.installAppAndVerifyExistsOnDevice(getTestAppFilePath(
                     UPDATE_EXT_TO_INT_LOC_V2_INT_APK), UPDATE_EXT_TO_INT_LOC_PKG, true);
         }
@@ -295,4 +725,264 @@
             mPMHostUtils.uninstallApp(UPDATE_EXT_TO_INT_LOC_PKG);
         }
     }
+
+    /**
+     * Regression test to verify that installing and updating a forward-locked app will install
+     * the update onto the device's forward-locked location
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndUpdateExternalLocForwardLockedApp()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating a forward-locked app marked preferExternal");
+
+        try {
+            // first try to install the forward-locked app externally
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V1_APK), EXTERNAL_LOC_VERSION_PKG, false);
+            // now replace the app with an update marked for internalOnly and as forward locked
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    EXTERNAL_LOC_VERSION_V2_APK), EXTERNAL_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(EXTERNAL_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that updating a forward-locked app will install
+     * the update onto the device's forward-locked location
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndUpdateNoLocForwardLockedApp()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating a forward-locked app with no installLocation pref set");
+
+        try {
+            // install the app
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    NO_LOC_VERSION_V1_APK), NO_LOC_VERSION_PKG, false);
+            // now replace the app with an update marked for internalOnly...
+            mPMHostUtils.installFwdLockedAppAndVerifyExists(getTestAppFilePath(
+                    NO_LOC_VERSION_V2_APK), NO_LOC_VERSION_PKG, true);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(NO_LOC_VERSION_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with all permissions set can be installed on SD card
+     * and then launched without crashing.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchAllPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with all perms set, installed on SD card");
+
+        try {
+            // install the app
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    ALL_PERMS_APK), ALL_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(ALL_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(ALL_PERMS_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with ACCESS_FINE_LOCATION (GPS) permissions can
+     * run without permissions errors.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchFLPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with BLUE_TOOTH permissions can
+     * run without permissions errors.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchBTPermsAppOnSD()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with bluetooth perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_BT_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions throws a
+     * SecurityException when launched if its other shared apps are not installed.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_NoPerms()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
+
+        try {
+            // Make sure the 2 shared apps with needed permissions are not installed...
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+
+            // now install the app and see if when we launch it we get a permissions error
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assertEquals("Shared perms app should fail to run", false, testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions can run if its other
+     * shared apps are installed.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_GrantedPerms()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with no explicit perms set, installed on SD card");
+
+        try {
+            // install the 2 shared apps with needed permissions first
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+
+            // now install the test app and see if we can launch it without errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that an app with ACCESS_FINE_LOCATION (GPS) permissions can
+     * run without permissions errors even after a reboot
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchFLPermsAppOnSD_Reboot()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app with location perms set, installed on SD card");
+
+        try {
+            // install the app and verify we can launch it without permissions errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+
+            mPMHostUtils.rebootDevice();
+
+            testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_FL_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
+
+    /**
+     * Regression test to verify that a shared app with no explicit permissions can run if its other
+     * shared apps are installed, even after a reboot.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     * @throws IOException if adb shell command failed
+     * @throws InterruptedException if the thread was interrupted
+     */
+    public void testInstallAndLaunchSharedPermsAppOnSD_Reboot()
+            throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test launching an app on SD, with no explicit perms set after reboot");
+
+        try {
+            // install the 2 shared apps with needed permissions first
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_FL_APK), SHARED_PERMS_FL_PKG, false);
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_BT_APK), SHARED_PERMS_BT_PKG, false);
+
+            // now install the test app and see if we can launch it without errors
+            mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(
+                    SHARED_PERMS_APK), SHARED_PERMS_PKG, false);
+            boolean testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+
+            // reboot
+            mPMHostUtils.rebootDevice();
+
+            // Verify we can still launch the app
+            testsPassed = mPMHostUtils.runDeviceTestsDidAllTestsPass(SHARED_PERMS_PKG);
+            assert(testsPassed);
+        }
+        // cleanup test app
+        finally {
+            mPMHostUtils.uninstallApp(SHARED_PERMS_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_BT_PKG);
+            mPMHostUtils.uninstallApp(SHARED_PERMS_FL_PKG);
+        }
+    }
 }
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
new file mode 100644
index 0000000..715c55b
--- /dev/null
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerStressHostTests.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log;
+import com.android.hosttest.DeviceTestCase;
+import com.android.hosttest.DeviceTestSuite;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Test;
+
+/**
+ * Set of tests that verify host side stress scenarios (large apps, multiple upgrades, etc.)
+ */
+public class PackageManagerStressHostTests extends DeviceTestCase {
+
+    private static final String LOG_TAG = "PackageManagerStressHostTests";
+    private PackageManagerHostTestUtils mPMHostUtils = null;
+
+    // Path to the app repository and various subdirectories of it
+    // Note: These stress tests require large apks that cannot be checked into the tree.
+    // These variables define static locations that point to existing APKs (not built from
+    // the tree) which can be used by the the stress tests in this file.
+    private static final String LARGE_APPS_DIRECTORY_NAME = "largeApps";
+    private static final String MISC_APPS_DIRECTORY_NAME = "miscApps";
+    private static final String VERSIONED_APPS_DIRECTORY_NAME = "versionedApps";
+    private static final String MANY_APPS_DIRECTORY_NAME = "manyApps";
+
+    // Note: An external environment variable "ANDROID_TEST_APP_REPOSITORY" must be set
+    // which points to the root location of the app respository.
+    private static String AppRepositoryPath = null;
+
+    // Large apps (>1mb) - filenames and their corresponding package names:
+    private static enum APK {
+            FILENAME,
+            PACKAGENAME;
+    }
+    private static final String[][] LARGE_APPS = {
+       {"External1mb.apk", "com.appsonsd.mytests.External1mb"},
+       {"External2mb.apk", "com.appsonsd.mytests.External2mb"},
+       {"External3mb.apk", "com.appsonsd.mytests.External3mb"},
+       {"External4mb.apk", "com.appsonsd.mytests.External4mb"},
+       {"External5mb.apk", "com.appsonsd.mytests.External5mb"},
+       {"External6mb.apk", "com.appsonsd.mytests.External6mb"},
+       {"External7mb.apk", "com.appsonsd.mytests.External7mb"},
+       {"External8mb.apk", "com.appsonsd.mytests.External8mb"},
+       {"External9mb.apk", "com.appsonsd.mytests.External9mb"},
+       {"External10mb.apk", "com.appsonsd.mytests.External10mb"},
+       {"External16mb.apk", "com.appsonsd.mytests.External16mb"},
+       {"External28mb.apk", "com.appsonsd.mytests.External28mb"},
+       {"External34mb.apk", "com.appsonsd.mytests.External34mb"},
+       {"External46mb.apk", "com.appsonsd.mytests.External46mb"},
+       {"External58mb.apk", "com.appsonsd.mytests.External58mb"},
+       {"External65mb.apk", "com.appsonsd.mytests.External65mb"},
+       {"External72mb.apk", "com.appsonsd.mytests.External72mb"},
+       {"External79mb.apk", "com.appsonsd.mytests.External79mb"},
+       {"External86mb.apk", "com.appsonsd.mytests.External86mb"},
+       {"External93mb.apk", "com.appsonsd.mytests.External93mb"}};
+
+    // Various test files and their corresponding package names
+    private static final String AUTO_LOC_APK = "Auto241kb.apk";
+    private static final String AUTO_LOC_PKG = "com.appsonsd.mytests.Auto241kb";
+    private static final String INTERNAL_LOC_APK = "Internal781kb.apk";
+    private static final String INTERNAL_LOC_PKG = "com.appsonsd.mytests.Internal781kb";
+    private static final String EXTERNAL_LOC_APK = "External931kb.apk";
+    private static final String EXTERNAL_LOC_PKG = "com.appsonsd.mytests.External931kb";
+    private static final String NO_LOC_APK = "Internal751kb_EclairSDK.apk";
+    private static final String NO_LOC_PKG = "com.appsonsd.mytests.Internal751kb_EclairSDK";
+    // Versioned test apps
+    private static final String VERSIONED_APPS_FILENAME_PREFIX = "External455kb_v";
+    private static final String VERSIONED_APPS_PKG = "com.appsonsd.mytests.External455kb";
+    private static final int VERSIONED_APPS_START_VERSION = 1;  // inclusive
+    private static final int VERSIONED_APPS_END_VERSION = 250;  // inclusive
+    // Large number of app installs
+    // @TODO: increase the max when we can install more apps
+    private static final int MANY_APPS_START = 1;
+    private static final int MANY_APPS_END = 100;
+    private static final String MANY_APPS_PKG_PREFIX = "com.appsonsd.mytests.External49kb_";
+    private static final String MANY_APPS_APK_PREFIX = "External49kb_";
+
+    public static Test suite() {
+        return new DeviceTestSuite(PackageManagerStressHostTests.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // setup the PackageManager host tests utilities class, and get various paths we'll need...
+        mPMHostUtils = new PackageManagerHostTestUtils(getDevice());
+        AppRepositoryPath = System.getenv("ANDROID_TEST_APP_REPOSITORY");
+        assertNotNull(AppRepositoryPath);
+
+        // Make sure path ends with a separator
+        if (!AppRepositoryPath.endsWith(File.separator)) {
+            AppRepositoryPath += File.separator;
+        }
+    }
+
+    /**
+     * Get the absolute file system location of repository test app with given filename
+     * @param fileName the file name of the test app apk
+     * @return {@link String} of absolute file path
+     */
+    private String getRepositoryTestAppFilePath(String fileDirectory, String fileName) {
+        return String.format("%s%s%s%s", AppRepositoryPath, fileDirectory,
+                File.separator, fileName);
+    }
+
+    /**
+     * Get the absolute file system location of test app with given filename
+     * @param fileName the file name of the test app apk
+     * @return {@link String} of absolute file path
+     */
+    public String getTestAppFilePath(String fileName) {
+        return String.format("%s%s%s", getTestAppPath(), File.separator, fileName);
+    }
+
+    /**
+     * Stress test to verify that we can update an app multiple times on the SD card.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testUpdateAppManyTimesOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on SD numerous times");
+
+        // cleanup test app just in case it already exists
+        mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG);
+        // grep for package to make sure its not installed
+        assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+
+        try {
+            for (int i = VERSIONED_APPS_START_VERSION; i <= VERSIONED_APPS_END_VERSION; ++i) {
+                String currentApkName = String.format("%s%d.apk",
+                        VERSIONED_APPS_FILENAME_PREFIX, i);
+
+                Log.i(LOG_TAG, "Installing app " + currentApkName);
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(VERSIONED_APPS_DIRECTORY_NAME,
+                        currentApkName), true);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(VERSIONED_APPS_PKG));
+                assertTrue(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+            }
+        }
+        finally {
+            // cleanup test app
+            mPMHostUtils.uninstallApp(VERSIONED_APPS_PKG);
+            // grep for package to make sure its not installed
+            assertFalse(mPMHostUtils.doesPackageExist(VERSIONED_APPS_PKG));
+        }
+    }
+
+    /**
+     * Stress test to verify that an app can be installed, uninstalled, and
+     * reinstalled on SD many times.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testUninstallReinstallAppOnSDManyTimes() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test updating an app on the SD card stays on the SD card");
+
+        // cleanup test app just in case it was already exists
+        mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+        // grep for package to make sure its not installed
+        assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+
+        for (int i = 0; i <= 500; ++i) {
+            Log.i(LOG_TAG, "Installing app");
+
+            try {
+                // install the app
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(MISC_APPS_DIRECTORY_NAME,
+                        EXTERNAL_LOC_APK), false);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(EXTERNAL_LOC_PKG));
+                assertTrue(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+            }
+            finally {
+                // now uninstall the app
+                Log.i(LOG_TAG, "Uninstalling app");
+                mPMHostUtils.uninstallApp(EXTERNAL_LOC_PKG);
+                mPMHostUtils.waitForPackageManager();
+                assertFalse(mPMHostUtils.doesPackageExist(EXTERNAL_LOC_PKG));
+            }
+        }
+    }
+
+    /**
+     * Stress test to verify that we can install, 20 large apps (>1mb each)
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testInstallManyLargeAppsOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installing 20 large apps onto the sd card");
+
+        try {
+            // Install all the large apps
+            for (int i=0; i < LARGE_APPS.length; ++i) {
+                String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()];
+                String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()];
+
+                // cleanup test app just in case it already exists
+                mPMHostUtils.uninstallApp(pkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(pkgName));
+
+                Log.i(LOG_TAG, "Installing app " + apkName);
+                // install the app
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(LARGE_APPS_DIRECTORY_NAME,
+                        apkName), false);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(pkgName));
+                assertTrue(mPMHostUtils.doesPackageExist(pkgName));
+            }
+        }
+        finally {
+            // Cleanup - ensure we uninstall all large apps if they were installed
+            for (int i=0; i < LARGE_APPS.length; ++i) {
+                String apkName = LARGE_APPS[i][APK.FILENAME.ordinal()];
+                String pkgName = LARGE_APPS[i][APK.PACKAGENAME.ordinal()];
+
+                Log.i(LOG_TAG, "Uninstalling app " + apkName);
+                // cleanup test app just in case it was accidently installed
+                mPMHostUtils.uninstallApp(pkgName);
+                // grep for package to make sure its not installed anymore
+                assertFalse(mPMHostUtils.doesPackageExist(pkgName));
+                assertFalse(mPMHostUtils.doesAppExistOnSDCard(pkgName));
+            }
+        }
+    }
+
+    /**
+     * Stress test to verify that we can install many small apps onto SD.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testInstallManyAppsOnSD() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "Test installing 500 small apps onto SD");
+
+        try {
+            for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) {
+                String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i);
+
+                // cleanup test app just in case it already exists
+                mPMHostUtils.uninstallApp(currentPkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(currentPkgName));
+
+                String currentApkName = String.format("%s%d.apk", MANY_APPS_APK_PREFIX, i);
+                Log.i(LOG_TAG, "Installing app " + currentApkName);
+                mPMHostUtils.installFile(getRepositoryTestAppFilePath(MANY_APPS_DIRECTORY_NAME,
+                        currentApkName), true);
+                mPMHostUtils.waitForPackageManager();
+                assertTrue(mPMHostUtils.doesAppExistOnSDCard(currentPkgName));
+                assertTrue(mPMHostUtils.doesPackageExist(currentPkgName));
+            }
+        }
+        finally {
+            for (int i = MANY_APPS_START; i <= MANY_APPS_END; ++i) {
+                String currentPkgName = String.format("%s%d", MANY_APPS_PKG_PREFIX, i);
+
+                // cleanup test app
+                mPMHostUtils.uninstallApp(currentPkgName);
+                // grep for package to make sure its not installed
+                assertFalse(mPMHostUtils.doesPackageExist(currentPkgName));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..a887bac
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..867871d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.autolocversionedtestapp"
+       android:installLocation="auto"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="AutoLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..49575b7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.autolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class AutoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..69084bf
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..98e5606
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.autolocversionedtestapp"
+       android:installLocation="auto"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="AutoLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..49575b7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/src/com/android/framework/autolocversionedtestapp/AutoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.autolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class AutoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
new file mode 100644
index 0000000..c70c1d3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocAllPermsTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..0c502c0
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/AndroidManifest.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocallpermstestapp"
+       android:installLocation="preferExternal">
+
+    <uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.BATTERY_STATS" />
+    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+    <uses-permission android:name="android.permission.BIND_INPUT_METHOD" />
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BRICK" />
+    <uses-permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED" />
+    <uses-permission android:name="android.permission.BROADCAST_SMS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.BROADCAST_WAP_PUSH" />
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+    <uses-permission android:name="android.permission.CONTROL_LOCATION_UPDATES" />
+    <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.DIAGNOSTIC" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <uses-permission android:name="android.permission.FACTORY_TEST" />
+    <uses-permission android:name="android.permission.FLASHLIGHT" />
+    <uses-permission android:name="android.permission.FORCE_BACK" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.GLOBAL_SEARCH" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.MASTER_CLEAR" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
+    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+    <uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
+    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+    <uses-permission android:name="android.permission.READ_HISTORY_BOOKMARKS" />
+    <uses-permission android:name="android.permission.READ_INPUT_STATE" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.READ_OWNER_DATA" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_SMS" />
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_SYNC_STATS" />
+    <uses-permission android:name="android.permission.REBOOT" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.RECEIVE_MMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
+    <uses-permission android:name="android.permission.RESTART_PACKAGES" />
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />
+    <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+    <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
+    <uses-permission android:name="android.permission.SET_DEBUG_APP" />
+    <uses-permission android:name="android.permission.SET_ORIENTATION" />
+    <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+    <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
+    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER" />
+    <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+    <uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
+    <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_GSERVICES" />
+    <uses-permission android:name="android.permission.WRITE_HISTORY_BOOKMARKS" />
+    <uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SMS" />
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externallocallpermstestapp"
+                     android:label="Test for instrumentation with an app granted all permissions" />
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java
new file mode 100644
index 0000000..8456255
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/src/com/android/framework/externallocallpermstestapp/ExternalLocAllPermsTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocallpermstestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import junit.framework.TestCase;
+
+
+public class ExternalLocAllPermsTest extends TestCase {
+    /**
+     * Test method that should get run. Doesn't need to actually do anything here,
+     * we just need to verify the test runs without errors.
+     */
+    public void testInstrumentationCanRun() {
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..05f62cd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..84bd5df
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocversionedtestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="ExternalLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..a7487c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class ExternalLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..aa31759
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..7acba15
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externallocversionedtestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="ExternalLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..a7487c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/src/com/android/framework/externallocversionedtestapp/ExternalLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externallocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class ExternalLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
new file mode 100644
index 0000000..7946e1a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml
new file mode 100644
index 0000000..263a0fb
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermstestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermstestapp"
+                     android:label="Test for instrumentation with an external app with shared permissions (BT and FL)" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java b/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java
new file mode 100644
index 0000000..da9600c
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/src/com/android/framework/externalsharedpermstestapp/ExternalSharedPermsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermstestapp;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+
+import android.util.Log;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of location manager and bluetooth below are simply to simulate an app that
+     *  tries to use them, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunLocationAndBluetooth()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
new file mode 100644
index 0000000..657d0a4
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsBTTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml
new file mode 100644
index 0000000..98f7177
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsbttestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <uses-permission android:name="android.permission.BLUETOOTH" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsbttestapp"
+                     android:label="Test for instrumentation with an external app granted BLUETOOTH permissions" />
+
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java
new file mode 100644
index 0000000..c7bcdfc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/src/com/android/framework/externalsharedpermsbttestapp/ExternalSharedPermsBTTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsbttestapp;
+
+import android.bluetooth.BluetoothAdapter;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsBTTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of bluetooth below is simply to simulate an activity that tries to use bluetooth
+     *  upon creation, so we can verify whether permissions are granted and accessible to the
+     *  activity once it launches.
+     * */
+    public void testRunBluetooth()
+    {
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
new file mode 100644
index 0000000..d4450dc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsDiffKeyTestApp
+
+LOCAL_CERTIFICATE := media
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml
new file mode 100644
index 0000000..d0e8fb9
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsdiffkeytestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsdiffkeytestapp"
+                     android:label="Test for instrumentation with an app with shared permissions but signed by different key" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java
new file mode 100644
index 0000000..adc906a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/src/com/android/framework/externalsharedpermsdiffkeytestapp/ExternalSharedPermsDiffKeyTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsdiffkeytestapp;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.Bundle;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsDiffKeyTest extends InstrumentationTestCase
+{
+    private static final int REQUEST_ENABLE_BT = 2;
+
+    /** The use of location manager and bluetooth below are simply to simulate an app that
+     *  tries to use them, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunBluetoothAndFineLocation()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        if ((mBluetoothAdapter != null) && (!mBluetoothAdapter.isEnabled())) {
+            mBluetoothAdapter.getName();
+        }
+        fail("this app was signed by a different cert and should crash/fail to run by now");
+    }
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
new file mode 100644
index 0000000..8154862
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := ExternalSharedPermsFLTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml
new file mode 100644
index 0000000..15cc912
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.externalsharedpermsfltestapp"
+       android:installLocation="preferExternal"
+       android:versionCode="1"
+       android:versionName="1.0"
+       android:sharedUserId="com.android.framework.externalsharedpermstestapp">
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.externalsharedpermsfltestapp"
+                     android:label="Test for instrumentation with an app granted FINE_LOCATION permissions" />
+</manifest>
+
+
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java
new file mode 100644
index 0000000..307034e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/src/com/android/framework/externalsharedpermsfltestapp/ExternalSharedPermsFLTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.externalsharedpermsfltestapp;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.test.InstrumentationTestCase;
+
+public class ExternalSharedPermsFLTest extends InstrumentationTestCase
+{
+    /** The use of location manager below is simply to simulate an app that
+     *  tries to use it, so we can verify whether permissions are granted and accessible.
+     * */
+    public void testRunFineLocation()
+    {
+        LocationManager locationManager = (LocationManager)getInstrumentation().getContext(
+                ).getSystemService(Context.LOCATION_SERVICE);
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
+                new LocationListener() {
+                        public void onLocationChanged(Location location) {}
+                        public void onProviderDisabled(String provider) {}
+                        public void onProviderEnabled(String provider) {}
+                        public void onStatusChanged(String provider, int status, Bundle extras) {}
+                }
+        );
+    }
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..36413ee
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v1
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..c98f1c2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.nolocversionedtestapp"
+       android:versionCode="1"
+       android:versionName="1.0">
+
+    <application android:label="NoLocVersionedTestApp_v1"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..0540e5a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.nolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class NoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..27d03b0
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2010 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v2
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..1af1e68
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.nolocversionedtestapp"
+       android:versionCode="2"
+       android:versionName="2.0">
+
+    <application android:label="NoLocVersionedTestApp_v2"/>
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
new file mode 100644
index 0000000..0540e5a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/src/com/android/framework/nolocversionedtestapp/NoLocVersionedTestAppActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.framework.nolocversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class NoLocVersionedTestAppActivity extends Activity {
+
+}
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
new file mode 100644
index 0000000..0b1afae
--- /dev/null
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -0,0 +1,307 @@
+page.title=Market Filters

+@jd:body

+

+<div id="qv-wrapper">

+<div id="qv">

+

+<h2 align="left">Market Filters quickview</h2>

+<ul> <li>Android Market applies filters to control which apps are visible to a

+user.</li> <li>Filtering is determined by elements in an app's manifest file,

+aspects of the device being used, and other factors.</li> </ul>

+

+<h2>In this document</h2>

+

+<ol> <li><a href="#how-filters-work">How Filters Work in Android Market</a></li>

+<li><a href="#manifest-filters">The Manifest File</a>

+  <ol>

+    <li><a href="#affects-filtering">Elements that affect filtering</a></li>

+  </ol>

+</li>

+<li><a href="#other-filters">Other Filters</a></li> 

+</ol>

+

+<h2>See also</h2>

+ <ol> 

+<li><code><a

+href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code></li>

+<li><code><a

+href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code></li>

+<li><code><a

+href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code></li>

+<li><code><a

+href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code></li>

+<li><code><a

+href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code></li>

+<li><code><a

+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</code></a></li>

+</ol>

+

+<div id="qv-extra"> <img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png">

+<div id="qv-sub-rule"> <img src="{@docRoot}assets/images/icon_market.jpg"

+style="float:left;margin:0;padding:0;"> <p style="color:#669999;">Interested in

+publishing your app on Android Market?</p> <a id="publish-link"

+href="http://market.android.com/publish">Go to Android Market &raquo;</a> </div>

+</div>

+

+</div> </div>

+

+<p>When a user searches or browses in Android Market, the results are filtered, and

+some applications might not be visible. For example, if an application requires a

+trackball (as specified in the manifest file), then Android Market will not show

+the app on any device that does not have a trackball.</p> <p>The manifest file and

+the device's hardware and features are only part of how applications are filtered

+&#8212; filtering also depends on the country and carrier, the presence or absence

+of a SIM card, and other factors. </p>

+

+<p>Changes to the Android Market filters are independent of changes 

+to the Android platform itself. This document will be updated periodically to reflect 

+any changes that might occur. </p>

+

+<h2 id="how-filters-work">How Filters Work in Android Market</h2>

+

+<p>If any one of the filter restrictions described in the following sections applies to

+an application, then the application will not appear in search results or category

+browsing on Android Market. </p><p> You can request any combination of the available filters for your

+app &#8212; for example, you could set a <code>minSdkVersion</code> of 4 and set

+<code>smallScreens</code> to false in the app, then when uploading the app to

+Market you could target European countries (carriers) only. Android Market's

+filters would prevent the application from being visible on any device that did not

+match all three of these requirements. </p>

+

+ <p>A filtered app is not visible within Market, even if a user specifically requests 

+the app by clicking a deep link that points directly to the app's ID within Market. 

+All filtering restrictions are associated with an application's version and can

+change between versions. For example:</p> 

+

+<ul> 

+<li>If you publish a new version of

+your app with stricter restrictions, the app will not be visible to users for whom

+it is filtered, even if those users were able see the previous version.</li> <li>If

+a user has installed your application and you publish an upgrade that makes the app

+invisible to the user, the user will not see that an upgrade is available. 

+</li>

+</ul>

+

+<h2 id="manifest-filters">The Manifest File</h2>

+<p>Most Market filters are triggered by elements within an application's manifest file, <a

+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>, 

+although not everything in the manifest file can trigger filtering. </p>

+<h3 id="affects-filtering">Elements that affect filtering</h3>

+<p>The following table lists the manifest elements that can be used to trigger 

+Android Market filtering, and explains how they work.</p>

+<table border="1">

+  <tr>

+    <th>Manifest Element</th>

+    <th>Filter Name</th>

+    <th>How It Works</th>

+  </tr>

+  <tr>

+    <td valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>

+      <!-- ##api level 4## --></td>

+    <td valign="top">Screen Size</td>

+    <td valign="top">

+

+<p>An application indicates the screen sizes that it is capable of supporting by

+setting attributes of the <code>&lt;supports-screens&gt;</code> element. When

+the application is published, Market uses those attributes to determine whether

+to show the application to users, based on the screen sizes of their

+devices. </p>

+

+<p>As a general rule, Market assumes that the platform on the device can adapt

+smaller layouts to larger screens, but cannot adapt larger layouts to smaller

+screens. Thus, if an application declares support for "normal" screen size only,

+Market makes the application available to both normal- and large-screen devices,

+but filters the application so that it is not available to small-screen

+devices.</p>

+

+<p>If an application does not declare attributes for

+<code>&lt;supports-screens&gt;</code>, Market uses the default values for those

+attributes, which vary by API Level. Specifically: </p>

+

+<ul>

+<li><p>In API level 3, the <code>&lt;supports-screens&gt;</code> element itself

+is undefined and no attributes are available. In this case, Market assumes that

+the application is designed for normal-size screens and shows the application to

+devices that have normal or large screens. </p>

+

+<p>This behavior is especially significant for applications that set their

+<code><a

+href="@docRoot}guide/topics/manifest/uses-sdk-element.html">android:

+minSdkVersion</a></code> to 3 or lower, since Market will filter them from

+small-screen devices by default. Such applications can enable support for

+small-screen devices by adding a <code>android:targetSdkVersion="4"</code>

+attribute to the <code>&lt;uses-sdk&gt;</code> element in their manifest

+files. For more information, see <a

+href="{@docRoot}guide/practices/screens_support.html#strategies">Strategies for

+Legacy Applications</a>.</p></li>

+

+<li>In API Level 4, the defaults for all of the attributes is

+<code>"true"</code>. If an application does not declare a

+<code>&lt;supports-screens&gt;</code> element, Market assumes that the

+application is designed for all screen sizes and does not filter it from any

+devices. If the application does not declare one of the attributes, Market uses

+the default value of <code>"true"</code> and does not filter the app for devices

+of corresponding screen size.</li>

+</ul>

+

+    <p><strong>Example 1</strong><br />

+    The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"&gt;</code>

+    and does not does not include a <code>&lt;supports-screens&gt;</code> element.

+    <strong>Result</strong>: Android Market will not show the app to a user of a

+    small-screen device, but will show it to users of normal and large-screen

+    devices,  users, unless  other filters apply. </p>

+    <p><strong>Example 2<br />

+    </strong>The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"

+    android:targetSdkVersion="4"&gt;</code> and does not include a

+    <code>&lt;supports-screens&gt;</code> element.

+    <strong>Result</strong>: Android Market will show the app to users on all 

+    devices, unless other filters apply. </p>

+    <p><strong>Example 3<br />

+    </strong>The manifest declares <code>&lt;uses-sdk android:minSdkVersion="4"&gt;</code>

+    and does not include a <code>&lt;supports-screens&gt;</code> element.

+    <strong>Result</strong>: Android Market will show the app to all users,

+    unless  other filters apply. </p>

+    <p>For more information on how to declare support for screen sizes in your

+    application, see <code><a

+    href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>

+    and <a href="{@docRoot}guide/practices/screens-support.html">Supporting Multiple

+    Screens</a>.</p>

+</td>

+  </tr>

+  <tr>

+    <td valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>

+      <!-- ##api level 3## --></td>

+    <td valign="top">Device

+    Configuration: <br />

+    keyboard, navigation, touch screen</td>

+    <td valign="top"><p>An application can

+    request certain hardware features, and Android Market will  show the app only on devices that have the required hardware.</p>

+      <p><strong>Example 1<br />

+      </strong>The manifest includes <code>&lt;uses-configuration android:reqFiveWayNav=&quot;true&quot; /&gt;</code>, and a user is searching for apps on a device that does not have a five-way navigational control. <strong>Result</strong>: Android Market will not show the app to the user. </p>

+      <p><strong>Example 2<br />

+      </strong>The manifest does not include a <code>&lt;uses-configuration&gt;</code> element. <strong>Result</strong>: Android Market will show the app to all users, unless other filters apply.</p>

+<p>For more details, see  <a

+href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><code>&lt;uses-configuration&gt;</code></a>.</p></td>

+  </tr>

+  <tr>

+    <td rowspan="2" valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>

+      <!-- ##api level 4## --></td>

+    <td valign="top">Device Features<br />

+      (<code>name</code>)</td>

+    <td valign="top"><p>An

+      application can require certain device features to be present on the device. This functionality

+      was introduced in Android 2.0 (API Level 5).</p>

+      <p><strong>Example 1<br />

+      </strong>The manifest includes <code>&lt;uses-feature android:name=&quot;android.hardware.sensor.light&quot; /&gt;</code>, and a user is searching for apps on a device that does not have a light sensor. <strong>Result</strong>: Android Market will not show the app to the user. </p>

+      <p><strong>Example 2<br />

+      </strong>The manifest does not include a <code>&lt;uses-feature&gt;</code> element. <strong>Result</strong>: Android Market will show the app to all users, unless other filters apply.</p>

+      <p>For more details, see <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>.</p>

+<p><em>A note about camera:</em> If an

+        application requests the CAMERA permission using the <a

+href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> <code>&lt;uses-permission&gt;</code></a> element, Market assumes that the

+        application requires the camera and autofocus features. For applications that require the camera and are designed to run on Android 1.5 (API Level 3), declaring the CAMERA permission is an effective way of ensuring that Market filters your app properly, since <code>uses-feature</code> filtering is not available to applications compiled against the Android 1.5 platform. For more details about requiring or requesting a camera, see the <a href="{@docRoot}guide/topics/manifest/uses-library-element.html#required"> <code>required</code></a> attribute of <code>&lt;uses-feature&gt;</code>. </p></td>

+  </tr>

+  <tr>

+    <td valign="top">OpenGL-ES

+    Version<br />

+(<code>openGlEsVersion</code>)</td>

+    <td valign="top"><p>An application can require that the device support a specific

+      OpenGL-ES version using the <code>&lt;uses-feature

+        android:openGlEsVersion=&quot;int&quot;&gt;</code> attribute.</p>

+      <p><strong>Example 1<br />

+      </strong>An app

+        requests multiple OpenGL-ES versions by specifying <code>openGlEsVersion</code> multiple times in the

+        manifest.  <strong>Result</strong>: Market assumes that the app requires the highest of the indicated versions.</p>

+<p><strong>Example 2<br />

+</strong>An app

+        requests OpenGL-ES version 1.1, and a user is searching for apps on a device that supports OpenGL-ES version 2.0. <strong>Result</strong>: Android Market will show the app to the user, unless other filters apply. If a

+  device reports that it supports OpenGL-ES version <em>X</em>,  Market assumes that it

+  also supports any version earlier than <em>X</em>.

+</p>

+<p><strong>Example 3<br />

+</strong>A user is searching for apps on a device that does not

+        report an OpenGL-ES version (for example, a device running Android 1.5 or earlier). <strong>Result</strong>: Android Market assumes that the device

+  supports only OpenGL-ES 1.0. Market will only show the user apps that do not specify <code>openGlEsVersion</code>, or apps that do not specify an OpenGL-ES version higher than 1.0. </p>

+      <p><strong>Example 4<br />

+      </strong>The manifest does not specify <code>openGlEsVersion</code>. <strong>Result</strong>: Android Market will show the app to all users, unless other filters apply. </p>

+<p>For more details, see <a

+href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>.</p></td>

+  </tr>

+  <tr>

+    <td valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code></td>

+    <td valign="top">Software Libraries</td>

+    <td valign="top"><p>An application can require specific

+    shared libraries to be present on the device. </p>

+      <p><strong>Example 1<br />

+      </strong>An app requires the <code>com.google.android.maps</code> library, and a user is searching for apps on a device that does not have the <code>com.google.android.maps</code> library. <strong>Result</strong>: Android Market will not show the app to the user. </p>

+      <p><strong>Example 2</strong><br />

+        The manifest does not include a <code>&lt;uses-library&gt;</code> element. <strong>Result</strong>: Android Market will show the app to all users, unless other filters apply.</p>

+<p>For more details, see <a

+href="{@docRoot}guide/topics/manifest/uses-library-element.html"><code>&lt;uses-library&gt;</code></a>.</p></td>

+  </tr>

+  <tr>

+    <td valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code></td>

+    <td valign="top">&nbsp;</td>

+    <td valign="top"><em>(See the note in the description of <code>&lt;uses-feature&gt;</code>, above.)</em></td>

+  </tr>

+  <tr>

+    <td rowspan="2" valign="top" style="white-space:nowrap;"><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></code></td>

+    <td valign="top">Minimum Framework Version (<code>minSdkVersion</code>)</td>

+    <td valign="top"><p>An application can require a minimum API level.  </p>

+      <p><strong>Example 1</strong><br />

+        The manifest includes <code>&lt;uses-sdk

+      android:minSdkVersion=&quot;3&quot;&gt;</code>, and the app uses APIs that were introduced in API Level 3. A user is searching for apps on a device that has API Level 2. <strong>Result</strong>: Android Market will not show the app to the user. </p>

+      <p><strong>Example 2</strong><br />

+      The manifest does not include <code>minSdkVersion</code>, and the app uses APIs that were introduced in API Level 3. A user is searching for apps on a device that has API Level 2. <strong>Result</strong>: Android Market assumes that <code>minSdkVersion</code> is &quot;1&quot; and that the app is compatible with all versions of Android. Market  shows the app to the user and allows the user to download the app. The app crashes at runtime. </p>

+    <p>Because you want to avoid this second scenario, we recommend that you always declare a <code>minSdkVersion</code>. For details, see <a

+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min"><code>android:minSdkVersion</code></a>.</p></td>

+  </tr>

+  <tr>

+    <td valign="top">Maximum Framework Version (<code>maxSdkVersion</code>)</td>

+    <td valign="top"><p><em>Deprecated.</em> Android

+    2.1 and later do not check or enforce the <code>maxSdkVersion</code> attribute, and

+    the SDK will not compile if <code>maxSdkVersion</code> is set in an app's manifest. For devices already

+    compiled with <code>maxSdkVersion</code>, Market will respect it and use it for

+    filtering.</p>

+<p> Declaring <code>maxSdkVersion</code> is <em>not</em> recommended. For details, see <a

+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#max"><code>android:maxSdkVersion</code></a>.</p></td>

+  </tr>

+</table>

+

+<h2 id="other-filters">Other Filters</h2>

+<p>The following table describes other application characteristics that trigger Android Market filtering. </p>

+

+<table border="1"> <tr>

+    <th>Filter Name</th> <th>How It Works</th> </tr>

+

+  <tr>

+    <td valign="top">Publishing Status</td> <td valign="top"><p>Only published applications will appear in

+      searches and browsing within Android Market.</p> <p>Even if an app is unpublished, it can

+        be installed if users can see it in their Downloads area among their purchased,

+        installed, or recently uninstalled apps.</p> <p>If an application has been

+  suspended, users will not be able to reinstall or update it, even if it appears in their Downloads.</p> </td></tr>

+  <tr>

+  <td valign="top">Priced

+    Status</td> <td valign="top"><p>Not all users can see paid apps. To show paid apps, a device

+must have a SIM card and be running Android 1.1 or later, and it must be in a

+country (as determined by SIM carrier) in which paid apps are available.</p></td>

+</tr> <tr>

+  <td valign="top">Country / Carrier Targeting</td> <td valign="top"> <p>When you upload your app to

+    the Android Market, you can select specific countries to target. The app will only

+    be visible to the countries (carriers) that you select, as follows:</p>

+    <ul><li><p>A device's country is determined based on the carrier, if a carrier is

+      available. If no carrier can be determined, the Market application tries to

+      determine the country based on IP.</p></li> <li><p>Carrier is determined based on

+      the device's SIM (for GSM devices), not the current roaming carrier.</p></li></ul>

+</td> </tr> <tr>

+  <td valign="top">Native Platform</td> <td valign="top"><p>An application that includes native

+    libraries that target a specific platform (ARM EABI v7, for example) will only be

+    visible on devices that support that platform. For details about the NDK and using

+    native libraries, see <a href="{@docRoot}sdk/ndk/index.html#overview">What is the

+      Android NDK?</a></p> </tr> <tr>

+        <td valign="top">Forward-Locked Applications</td> <td valign="top"><p>To

+          forward lock an application, set copy protection to "On" when you upload the

+          application to Market. Market will not show copy-protected applications on

+developer devices or unreleased devices.</p></td> </tr> </table>

+

+

diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 8f66bdd..11058a6 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -410,6 +410,9 @@
       <li><a href="<?cs var:toroot ?>guide/appendix/api-levels.html">
             <span class="en">Android API Levels</span>
           </a></li>
+      <li><a href="<?cs var:toroot ?>guide/appendix/market-filters.html">
+            <span class="en">Market Filters </span>
+          </a><span class="new">new!</span></li>
       <li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
             <span class="en">Supported Media Formats</span>
           </a></li>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 8594452..4066daa 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -27,7 +27,8 @@
 <code>&lt;uses-feature&gt;</code> elements in each application's manifest, to
 establish the app's feature needs. Market then shows or hides the application to
 each user, based on a comparison with the features available on the user's
-device. </p>
+device. For more information, see <a
+href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a>.</p>
 
 <p style="margin-top:1em;">By specifying the features your application requires,
 you enable Android Market to present your application only to users whose
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index f8aff1e..971d4cb 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -39,7 +39,8 @@
 version-compatibility. To do this, Market checks the <code>&lt;uses-sdk&gt;</code>
 attributes in each application's manifest to establish its version-compatibility
 range, then shows or hides the application based on a comparison with the API
-Level of the user's Android system version. </p>
+Level of the user's Android system version. For more information, see <a
+href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a>.</p>
   </div>
 </div>
 
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 913da47..6f7dc38 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -33,7 +33,8 @@
 class DataSource : public RefBase {
 public:
     enum Flags {
-        kWantsPrefetching = 1,
+        kWantsPrefetching      = 1,
+        kStreamedFromLocalHost = 2,
     };
 
     static sp<DataSource> CreateFromURI(
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index ea31942..f3b44fd 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -45,9 +45,7 @@
 
     virtual status_t getSize(off_t *size);
 
-    virtual uint32_t flags() {
-        return kWantsPrefetching;
-    }
+    virtual uint32_t flags();
 
 protected:
     virtual ~HTTPDataSource();
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 0ed7b40..21338ca 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -44,6 +44,16 @@
     // returns an empty metadata object.
     virtual sp<MetaData> getMetaData();
 
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,
+        CAN_SEEK_FORWARD   = 2,
+        CAN_PAUSE          = 4,
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE
+    virtual uint32_t flags() const;
+
 protected:
     MediaExtractor() {}
     virtual ~MediaExtractor() {}
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 7776b4e..2c96d6d 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -6,6 +6,9 @@
 
 #include "AwesomePlayer.h"
 
+#include <media/Metadata.h>
+#include <media/stagefright/MediaExtractor.h>
+
 namespace android {
 
 StagefrightPlayer::StagefrightPlayer()
@@ -109,7 +112,8 @@
     status_t err = mPlayer->getDuration(&durationUs);
 
     if (err != OK) {
-        return err;
+        *msec = 0;
+        return OK;
     }
 
     *msec = (durationUs + 500) / 1000;
@@ -156,4 +160,27 @@
     mPlayer->setAudioSink(audioSink);
 }
 
+status_t StagefrightPlayer::getMetadata(
+        const media::Metadata::Filter& ids, Parcel *records) {
+    using media::Metadata;
+
+    uint32_t flags = mPlayer->flags();
+
+    Metadata metadata(records);
+
+    metadata.appendBool(
+            Metadata::kPauseAvailable,
+            flags & MediaExtractor::CAN_PAUSE);
+
+    metadata.appendBool(
+            Metadata::kSeekBackwardAvailable,
+            flags & MediaExtractor::CAN_SEEK_BACKWARD);
+
+    metadata.appendBool(
+            Metadata::kSeekForwardAvailable,
+            flags & MediaExtractor::CAN_SEEK_FORWARD);
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 4446582..781eb44 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -53,6 +53,9 @@
     virtual status_t suspend();
     virtual status_t resume();
 
+    virtual status_t getMetadata(
+            const media::Metadata::Filter& ids, Parcel *records);
+
 private:
     AwesomePlayer *mPlayer;
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b14a03c..475160e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -184,6 +184,7 @@
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
       mFlags(0),
+      mExtractorFlags(0),
       mLastVideoBuffer(NULL),
       mVideoBuffer(NULL),
       mSuspensionState(NULL) {
@@ -310,7 +311,13 @@
         }
     }
 
-    return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
+    if (!haveAudio && !haveVideo) {
+        return UNKNOWN_ERROR;
+    }
+
+    mExtractorFlags = extractor->flags();
+
+    return OK;
 }
 
 void AwesomePlayer::reset() {
@@ -390,6 +397,7 @@
 
     mDurationUs = -1;
     mFlags = 0;
+    mExtractorFlags = 0;
     mVideoWidth = mVideoHeight = -1;
     mTimeSourceDeltaUs = 0;
     mVideoTimeUs = 0;
@@ -683,8 +691,14 @@
 }
 
 status_t AwesomePlayer::seekTo(int64_t timeUs) {
-    Mutex::Autolock autoLock(mLock);
-    return seekTo_l(timeUs);
+    if (mExtractorFlags
+            & (MediaExtractor::CAN_SEEK_FORWARD
+                | MediaExtractor::CAN_SEEK_BACKWARD)) {
+        Mutex::Autolock autoLock(mLock);
+        return seekTo_l(timeUs);
+    }
+
+    return OK;
 }
 
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
@@ -1362,5 +1376,9 @@
     return OK;
 }
 
+uint32_t AwesomePlayer::flags() const {
+    return mExtractorFlags;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index cca6062..8e26c37e 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -425,5 +425,16 @@
     }
 }
 
+uint32_t HTTPDataSource::flags() {
+    uint32_t f = kWantsPrefetching;
+
+    if (!strcasecmp(mStartingHost.string(), "localhost")
+            || !strcmp(mStartingHost.string(), "127.0.0.1")) {
+        f |= kStreamedFromLocalHost;
+    }
+
+    return f;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 832db04..dfddbe0 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -36,6 +36,10 @@
     return new MetaData;
 }
 
+uint32_t MediaExtractor::flags() const {
+    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+}
+
 // static
 sp<MediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp
index 96b05c0..e7b62d6 100644
--- a/media/libstagefright/VorbisExtractor.cpp
+++ b/media/libstagefright/VorbisExtractor.cpp
@@ -20,6 +20,7 @@
 
 #include "include/VorbisExtractor.h"
 
+#include <cutils/properties.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -37,8 +38,23 @@
 struct VorbisDataSource {
     sp<DataSource> mDataSource;
     off_t mOffset;
+    bool mSeekDisabled;
 };
 
+static bool ShouldDisableSeek(const sp<DataSource> &source) {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.vorbis.always-allow-seek", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        return false;
+    }
+
+    // This is a workaround for an application streaming data through
+    // a local HTTP proxy that doesn't really conform to the HTTP/1.1
+    // specs. We have to disable seek functionality in this case.
+
+    return source->flags() & DataSource::kStreamedFromLocalHost;
+}
+
 static size_t VorbisRead(
         void *ptr, size_t size, size_t nmemb, void *datasource) {
     VorbisDataSource *vds = (VorbisDataSource *)datasource;
@@ -58,6 +74,11 @@
         void *datasource, ogg_int64_t offset, int whence) {
     VorbisDataSource *vds = (VorbisDataSource *)datasource;
 
+    if (vds->mSeekDisabled) {
+        errno = ESPIPE;
+        return -1;
+    }
+
     switch (whence) {
         case SEEK_SET:
             vds->mOffset = offset;
@@ -218,6 +239,7 @@
       mInitCheck(NO_INIT) {
     mVorbisDataSource->mDataSource = mDataSource;
     mVorbisDataSource->mOffset = 0;
+    mVorbisDataSource->mSeekDisabled = ShouldDisableSeek(mDataSource);
 
     int res = ov_open_callbacks(
             mVorbisDataSource, mFile, NULL, 0, gVorbisCallbacks);
@@ -291,6 +313,7 @@
     VorbisDataSource vds;
     vds.mDataSource = source;
     vds.mOffset = 0;
+    vds.mSeekDisabled = ShouldDisableSeek(source);
 
     int res = ov_test_callbacks(&vds, &file, NULL, 0, gVorbisCallbacks);
 
@@ -308,4 +331,13 @@
     return true;
 }
 
+uint32_t VorbisExtractor::flags() const {
+    if (ShouldDisableSeek(mDataSource)) {
+        LOGI("This is streamed from local host, seek disabled");
+        return CAN_PAUSE;
+    } else {
+        return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 9e8a674..9455743 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -84,10 +84,13 @@
     status_t suspend();
     status_t resume();
 
+    // This is a mask of MediaExtractor::Flags.
+    uint32_t flags() const;
+
 private:
     friend struct AwesomeEvent;
 
-    enum Flags {
+    enum {
         PLAYING             = 1,
         LOOPING             = 2,
         FIRST_FRAME         = 4,
@@ -126,6 +129,7 @@
     int64_t mDurationUs;
 
     uint32_t mFlags;
+    uint32_t mExtractorFlags;
 
     int32_t mVideoWidth, mVideoHeight;
     int64_t mTimeSourceDeltaUs;
diff --git a/media/libstagefright/include/VorbisExtractor.h b/media/libstagefright/include/VorbisExtractor.h
index 8e38a93..2bb7deb 100644
--- a/media/libstagefright/include/VorbisExtractor.h
+++ b/media/libstagefright/include/VorbisExtractor.h
@@ -38,6 +38,8 @@
 
     virtual sp<MetaData> getMetaData();
 
+    uint32_t flags() const;
+
 protected:
     virtual ~VorbisExtractor();
 
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index b7ae4a9..7b741db 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -3,8 +3,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PRELINK_MODULE := false
-
 # setup for skia optimizations
 #
 ifneq ($(ARCH_ARM_HAVE_VFP),true)
diff --git a/packages/TtsService/jni/Android.mk b/packages/TtsService/jni/Android.mk
index 665d6d2..b41759a 100755
--- a/packages/TtsService/jni/Android.mk
+++ b/packages/TtsService/jni/Android.mk
@@ -25,7 +25,5 @@
 
 LOCAL_ARM_MODE := arm
 
-LOCAL_PRELINK_MODULE := false
-
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 6a5bbd2..23c1adc 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.net.INetworkManagementEventObserver;
 import android.net.IThrottleManager;
 import android.net.SntpClient;
 import android.net.ThrottleManager;
@@ -45,6 +46,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -109,6 +111,7 @@
     private Notification mThrottlingNotification;
     private boolean mWarningNotificationSent = false;
 
+    private InterfaceObserver mInterfaceObserver;
     private SettingsObserver mSettingsObserver;
 
     private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
@@ -125,6 +128,7 @@
 
         mNtpActive = false;
 
+        mIface = mContext.getResources().getString(R.string.config_datause_iface);
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
         Intent pollIntent = new Intent(ACTION_POLL, null);
         mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -138,6 +142,38 @@
                 Context.NOTIFICATION_SERVICE);
     }
 
+    private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
+        private int mMsg;
+        private Handler mHandler;
+        private String mIface;
+
+        InterfaceObserver(Handler handler, int msg, String iface) {
+            super();
+            mHandler = handler;
+            mMsg = msg;
+            mIface = iface;
+        }
+
+        public void interfaceLinkStatusChanged(String iface, boolean link) {
+            if (link) {
+                if (TextUtils.equals(iface, mIface)) {
+                    mHandler.obtainMessage(mMsg).sendToTarget();
+                }
+            }
+        }
+
+        public void interfaceAdded(String iface) {
+            // TODO - an interface added in the UP state should also trigger a StatusChanged
+            // notification..
+            if (TextUtils.equals(iface, mIface)) {
+                mHandler.obtainMessage(mMsg).sendToTarget();
+            }
+        }
+
+        public void interfaceRemoved(String iface) {}
+    }
+
+
     private static class SettingsObserver extends ContentObserver {
         private int mMsg;
         private Handler mHandler;
@@ -273,6 +309,13 @@
         mHandler = new MyHandler(mThread.getLooper());
         mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
 
+        mInterfaceObserver = new InterfaceObserver(mHandler, EVENT_IFACE_UP, mIface);
+        try {
+            mNMService.registerObserver(mInterfaceObserver);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Could not register InterfaceObserver " + e);
+        }
+
         mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
         mSettingsObserver.observe(mContext);
 
@@ -299,6 +342,7 @@
     private static final int EVENT_POLICY_CHANGED  = 1;
     private static final int EVENT_POLL_ALARM      = 2;
     private static final int EVENT_RESET_ALARM     = 3;
+    private static final int EVENT_IFACE_UP        = 4;
     private class MyHandler extends Handler {
         public MyHandler(Looper l) {
             super(l);
@@ -318,6 +362,9 @@
                 break;
             case EVENT_RESET_ALARM:
                 onResetAlarm();
+                break;
+            case EVENT_IFACE_UP:
+                onIfaceUp();
             }
         }
 
@@ -374,7 +421,6 @@
                 Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
             }
-            mIface = mContext.getResources().getString(R.string.config_datause_iface);
             synchronized (ThrottleService.this) {
                 if (mIface == null) {
                     mPolicyThreshold = 0;
@@ -454,6 +500,20 @@
             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
         }
 
+        private void onIfaceUp() {
+            // if we were throttled before, be sure and set it again - the iface went down
+            // (and may have disappeared all together) and these settings were lost
+            if (mThrottleIndex == 1) {
+                try {
+                    mNMService.setInterfaceThrottle(mIface, -1, -1);
+                    mNMService.setInterfaceThrottle(mIface,
+                            mPolicyThrottleValue, mPolicyThrottleValue);
+                } catch (Exception e) {
+                    Slog.e(TAG, "error setting Throttle: " + e);
+                }
+            }
+        }
+
         private void checkThrottleAndPostNotification(long currentTotal) {
             // is throttling enabled?
             if (mPolicyThreshold == 0) {