Merge "Fixing: RecognitionService logcat spam "cancel called..."" 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/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fd84859..773c344 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -194,6 +194,7 @@
             }
             WeakReference<Resources> wr = mActiveResources.get(key);
             r = wr != null ? wr.get() : null;
+            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
             if (r != null && r.getAssets().isUpToDate()) {
                 if (false) {
                     Slog.w(TAG, "Returning cached resources " + r + " " + resDir
@@ -1752,6 +1753,10 @@
             Debug.getMemoryInfo(outInfo);
         }
 
+        public void dispatchPackageBroadcast(int cmd, String[] packages) {
+            queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
+        }
+        
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
@@ -1976,6 +1981,7 @@
         public static final int SUICIDE                 = 130;
         public static final int REMOVE_PROVIDER         = 131;
         public static final int ENABLE_JIT              = 132;
+        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -2012,6 +2018,7 @@
                     case SUICIDE: return "SUICIDE";
                     case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                     case ENABLE_JIT: return "ENABLE_JIT";
+                    case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
                 }
             }
             return "(unknown)";
@@ -2132,6 +2139,9 @@
                 case ENABLE_JIT:
                     ensureJitEnabled();
                     break;
+                case DISPATCH_PACKAGE_BROADCAST:
+                    handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
+                    break;
             }
         }
 
@@ -2239,16 +2249,16 @@
     // XXX For now we keep around information about all packages we have
     // seen, not removing entries from this map.
     final HashMap<String, WeakReference<PackageInfo>> mPackages
-        = new HashMap<String, WeakReference<PackageInfo>>();
+            = new HashMap<String, WeakReference<PackageInfo>>();
     final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
-        = new HashMap<String, WeakReference<PackageInfo>>();
+            = new HashMap<String, WeakReference<PackageInfo>>();
     Display mDisplay = null;
     DisplayMetrics mDisplayMetrics = null;
-    HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
-        = new HashMap<ResourcesKey, WeakReference<Resources> >();
+    final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
+            = new HashMap<ResourcesKey, WeakReference<Resources> >();
     final ArrayList<ActivityRecord> mRelaunchingActivities
             = new ArrayList<ActivityRecord>();
-        Configuration mPendingConfiguration = null;
+    Configuration mPendingConfiguration = null;
 
     // The lock of mProviderMap protects the following variables.
     final HashMap<String, ProviderRecord> mProviderMap
@@ -2271,6 +2281,8 @@
             }
             PackageInfo packageInfo = ref != null ? ref.get() : null;
             //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
+            //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
+            //        + ": " + packageInfo.mResources.getAssets().isUpToDate());
             if (packageInfo != null && (packageInfo.mResources == null
                     || packageInfo.mResources.getAssets().isUpToDate())) {
                 if (packageInfo.isSecurityViolation()
@@ -2358,21 +2370,6 @@
         }
     }
 
-    public final boolean hasPackageInfo(String packageName) {
-        synchronized (mPackages) {
-            WeakReference<PackageInfo> ref;
-            ref = mPackages.get(packageName);
-            if (ref != null && ref.get() != null) {
-                return true;
-            }
-            ref = mResourcePackages.get(packageName);
-            if (ref != null && ref.get() != null) {
-                return true;
-            }
-            return false;
-        }
-    }
-
     ActivityThread() {
     }
 
@@ -4054,6 +4051,31 @@
         }
     }
 
+    final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
+        boolean hasPkgInfo = false;
+        if (packages != null) {
+            for (int i=packages.length-1; i>=0; i--) {
+                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
+                if (!hasPkgInfo) {
+                    WeakReference<PackageInfo> ref;
+                    ref = mPackages.get(packages[i]);
+                    if (ref != null && ref.get() != null) {
+                        hasPkgInfo = true;
+                    } else {
+                        ref = mResourcePackages.get(packages[i]);
+                        if (ref != null && ref.get() != null) {
+                            hasPkgInfo = true;
+                        }
+                    }
+                }
+                mPackages.remove(packages[i]);
+                mResourcePackages.remove(packages[i]);
+            }
+        }
+        ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
+                hasPkgInfo);
+    }
+        
     final void handleLowMemory() {
         ArrayList<ComponentCallbacks> callbacks
                 = new ArrayList<ComponentCallbacks>();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 7cba13f..da26a78 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -393,6 +393,15 @@
             mi.writeToParcel(reply, 0);
             return true;
         }
+
+        case DISPATCH_PACKAGE_BROADCAST_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            int cmd = data.readInt();
+            String[] packages = data.readStringArray();
+            dispatchPackageBroadcast(cmd, packages);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -806,5 +815,16 @@
         data.recycle();
         reply.recycle();
     }
+    
+    public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeInt(cmd);
+        data.writeStringArray(packages);
+        mRemote.transact(DISPATCH_PACKAGE_BROADCAST_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+        data.recycle();
+        
+    }
 }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fd0edaa..f471f57 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2244,33 +2244,7 @@
             return null;
         }
 
-        private void establishPackageRemovedReceiver() {
-            // mContext.registerReceiverInternal() winds up acquiring the
-            // main ActivityManagerService.this lock.  If we hold our usual
-            // sSync global lock at the same time, we impose a required ordering
-            // on those two locks, which is not good for deadlock prevention.
-            // Use a dedicated lock around initialization of
-            // sPackageRemovedReceiver to avoid this.
-            synchronized (sPackageRemovedSync) {
-                if (sPackageRemovedReceiver == null) {
-                    sPackageRemovedReceiver = new PackageRemovedReceiver();
-                    IntentFilter filter = new IntentFilter(
-                            Intent.ACTION_PACKAGE_REMOVED);
-                    filter.addDataScheme("package");
-                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
-                            filter, null, null, null);
-                    // Register for events related to sdcard installation.
-                    IntentFilter sdFilter = new IntentFilter();
-                    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
-                            sdFilter, null, null, null);
-                }
-            }
-        }
-        
         private void putCachedIcon(ResourceName name, Drawable dr) {
-            establishPackageRemovedReceiver();
-
             synchronized (sSync) {
                 sIconCache.put(name, new WeakReference<Drawable>(dr));
                 if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
@@ -2278,29 +2252,17 @@
             }
         }
 
-        private static final class PackageRemovedReceiver extends BroadcastReceiver {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String pkgList[] = null;
-                String action = intent.getAction();
-                boolean immediateGc = false;
-                if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                    immediateGc = true;
-                } else {
-                    Uri data = intent.getData();
-                    if (data != null) {
-                        String ssp = data.getSchemeSpecificPart();
-                        if (ssp != null) {
-                            pkgList = new String[] { ssp };
-                        }
-                    }
-                }
-                if (pkgList != null && (pkgList.length > 0)) {
-                    boolean needCleanup = false;
-                    boolean hasPkgInfo = false;
-                    for (String ssp : pkgList) {
-                        synchronized (sSync) {
+        static final void handlePackageBroadcast(int cmd, String[] pkgList,
+                boolean hasPkgInfo) {
+            boolean immediateGc = false;
+            if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
+                immediateGc = true;
+            }
+            if (pkgList != null && (pkgList.length > 0)) {
+                boolean needCleanup = false;
+                for (String ssp : pkgList) {
+                    synchronized (sSync) {
+                        if (sIconCache.size() > 0) {
                             Iterator<ResourceName> it = sIconCache.keySet().iterator();
                             while (it.hasNext()) {
                                 ResourceName nm = it.next();
@@ -2310,7 +2272,9 @@
                                     needCleanup = true;
                                 }
                             }
-                            it = sStringCache.keySet().iterator();
+                        }
+                        if (sStringCache.size() > 0) {
+                            Iterator<ResourceName> it = sStringCache.keySet().iterator();
                             while (it.hasNext()) {
                                 ResourceName nm = it.next();
                                 if (nm.packageName.equals(ssp)) {
@@ -2320,22 +2284,19 @@
                                 }
                             }
                         }
-                        if (!hasPkgInfo) {
-                            hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp);
-                        }
                     }
-                    if (needCleanup || hasPkgInfo) {
-                        if (immediateGc) {
-                            // Schedule an immediate gc.
-                            Runtime.getRuntime().gc();
-                        } else {
-                            ActivityThread.currentActivityThread().scheduleGcIdler();
-                        }
+                }
+                if (needCleanup || hasPkgInfo) {
+                    if (immediateGc) {
+                        // Schedule an immediate gc.
+                        Runtime.getRuntime().gc();
+                    } else {
+                        ActivityThread.currentActivityThread().scheduleGcIdler();
                     }
                 }
             }
         }
-
+        
         private static final class ResourceName {
             final String packageName;
             final int iconId;
@@ -2400,8 +2361,6 @@
         }
 
         private void putCachedString(ResourceName name, CharSequence cs) {
-            establishPackageRemovedReceiver();
-
             synchronized (sSync) {
                 sStringCache.put(name, new WeakReference<CharSequence>(cs));
             }
@@ -2665,8 +2624,6 @@
         private final IPackageManager mPM;
 
         private static final Object sSync = new Object();
-        private static final Object sPackageRemovedSync = new Object();
-        private static BroadcastReceiver sPackageRemovedReceiver;
         private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
                 = new HashMap<ResourceName, WeakReference<Drawable> >();
         private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ed810d3..c917e81 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -100,6 +100,9 @@
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
     void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
+    static final int PACKAGE_REMOVED = 0;
+    static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
+    void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
     
     String descriptor = "android.app.IApplicationThread";
 
@@ -135,4 +138,5 @@
     int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
     int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
     int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
+    int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
 }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 0bb2cb5..5245da5 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,42 +29,44 @@
 import java.io.IOException;
 
 /**
- * {@link android.app.backup.BackupAgent} is the central interface between an
+ * Provides the central interface between an
  * application and Android's data backup infrastructure.  An application that wishes
  * to participate in the backup and restore mechanism will declare a subclass of
  * {@link android.app.backup.BackupAgent}, implement the
- * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
- * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} methods,
- * and provide the name of its agent class in the AndroidManifest.xml file via
- * the &lt;application&gt; tag's android:backupAgent attribute.
- * <p>
- * <b>Basic Operation</b>
+ * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
+ * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods,
+ * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via
+ * the <code><a
+ * href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+ * tag's {@code android:backupAgent} attribute.
+ * <h3>Basic Operation</h3>
  * <p>
  * When the application makes changes to data that it wishes to keep backed up,
  * it should call the
  * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method.
- * This notifies the Android backup manager that the application needs an opportunity
- * to update its backup image.  The backup manager, in turn, will then schedule a
+ * This notifies the Android Backup Manager that the application needs an opportunity
+ * to update its backup image.  The Backup Manager, in turn, schedules a
  * backup pass to be performed at an opportune time.
  * <p>
- * Restore operations are typically only performed when applications are first
+ * Restore operations are typically performed only when applications are first
  * installed on a device.  At that time, the operating system checks to see whether
- * there is a previously-saved data set available for the application, and if so,
- * begins an immediate restore pass to deliver that data as part of the installation
+ * there is a previously-saved data set available for the application being installed, and if so,
+ * begins an immediate restore pass to deliver the backup data as part of the installation
  * process.
  * <p>
- * When a backup or restore pass is run, the application's process will be launched
- * (if not already running), the manifest-declared agent class instantiated within
- * that process, and the agent's {@link #onCreate()} method invoked.  This prepares the
+ * When a backup or restore pass is run, the application's process is launched
+ * (if not already running), the manifest-declared backup agent class (in the {@code
+ * android:backupAgent} attribute) is instantiated within
+ * that process, and the agent's {@link #onCreate()} method is invoked.  This prepares the
  * agent instance to run the actual backup or restore logic.  At this point the
  * agent's
  * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or
  * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be
  * invoked as appropriate for the operation being performed.
  * <p>
- * A backup data set consists of one or more "entities," flattened binary data records
- * that are each identified with a key string unique within the data set.  Adding a
- * record to the active data set, or updating an existing record, are done by simply
+ * A backup data set consists of one or more "entities," flattened binary data
+ * records that are each identified with a key string unique within the data set.  Adding a
+ * record to the active data set or updating an existing record is done by simply
  * writing new entity data under the desired key.  Deleting an entity from the data set
  * is done by writing an entity under that key with header specifying a negative data
  * size, and no actual entity data.
diff --git a/core/java/android/app/backup/BackupAgentHelper.java b/core/java/android/app/backup/BackupAgentHelper.java
index 6d73090..d47ca22 100644
--- a/core/java/android/app/backup/BackupAgentHelper.java
+++ b/core/java/android/app/backup/BackupAgentHelper.java
@@ -24,19 +24,19 @@
  * A convenient {@link BackupAgent} wrapper class that automatically manages
  * heterogeneous data sets within the backup data, each identified by a unique
  * key prefix.  When processing a backup or restore operation, the BackupAgentHelper
- * dispatches to one or more installed {@link BackupHelper helpers} objects, each
+ * dispatches to one or more installed {@link BackupHelper} objects, each
  * of which is responsible for a defined subset of the data being processed.
  * <p>
- * An application will typically extend this class in their own
+ * An application will typically extend this class in its own
  * backup agent. Then, within the agent's {@link BackupAgent#onCreate() onCreate()}
- * method, it will call {@link #addHelper(String, BackupHelper)} one or more times to
+ * method, it will call {@link #addHelper(String, BackupHelper) addHelper()} one or more times to
  * install the handlers for each kind of data it wishes to manage within its backups.
  * <p>
- * The Android framework currently provides two predefined {@link BackupHelper} classes:
- * {@link FileBackupHelper}, which manages the backup and restore of entire files
- * within an application's data directory hierarchy; and {@link SharedPreferencesBackupHelper},
- * which manages the backup and restore of an application's
- * {@link android.content.SharedPreferences} data.
+ * The Android framework currently provides two predefined {@link BackupHelper} classes:</p>
+ * <ul><li>{@link FileBackupHelper} - Manages the backup and restore of entire files
+ * within an application's data directory hierarchy.</li>
+ * <li>{@link SharedPreferencesBackupHelper} - Manages the backup and restore of an
+ * application's {@link android.content.SharedPreferences} data.</li></ul>
  * <p>
  * An application can also implement its own helper classes to work within the
  * {@link BackupAgentHelper} framework.  See the {@link BackupHelper} interface
diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java
index 976e0c9..43b920a 100644
--- a/core/java/android/app/backup/BackupDataInput.java
+++ b/core/java/android/app/backup/BackupDataInput.java
@@ -20,40 +20,42 @@
 import java.io.IOException;
 
 /**
- * BackupDataInput is the structured interface used for passing the contents of
- * a backup data set to an application's {@link BackupAgent} class in its
- * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)}
+ * Provides the structured interface through which a {@link BackupAgent} reads
+ * information from the backup data set, via its
+ * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
  * method.  The data is presented as a set of "entities," each
  * representing one named record as previously stored by the agent's
- * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor)}
- * implementation.  An entity is composed of a descriptive header plus a
- * byte array that holds its raw data.
+ * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} implementation.  An entity is composed of a descriptive header plus a
+ * byte array that holds the raw data saved in the remote backup.
  * <p>
  * The agent must consume every entity in the data stream, otherwise the
  * restored state of the application will be incomplete.
- * <p>
- * <b>Example</b>
+ * <h3>Example</h3>
  * <p>
  * A typical
- * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore(data, appVersionCode, newState)}
- * implementation might be structured something like this:
+ * {@link BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+ * onRestore()} implementation might be structured something like this:
  * <pre>
- * while (data.readNextHeader()) {
- *     String key = data.getKey();
- *     int dataSize = data.getDataSize();
+ * public void onRestore(BackupDataInput data, int appVersionCode,
+ *                       ParcelFileDescriptor newState) {
+ *     while (data.readNextHeader()) {
+ *         String key = data.getKey();
+ *         int dataSize = data.getDataSize();
  *
- *     if (key.equals(MY_BACKUP_KEY_ONE)) {
- *         // process this kind of record here
- *         byte[] buffer = new byte[dataSize];
- *         data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once
+ *         if (key.equals(MY_BACKUP_KEY_ONE)) {
+ *             // process this kind of record here
+ *             byte[] buffer = new byte[dataSize];
+ *             data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once
  *
- *         // now 'buffer' holds the raw data and can be processed however
- *         // the agent wishes
- *         processBackupKeyOne(buffer);
- *     } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) {
- *         // a key we recognize but wish to discard
- *         data.skipEntityData();
- *     } // ... etc.
+ *             // now 'buffer' holds the raw data and can be processed however
+ *             // the agent wishes
+ *             processBackupKeyOne(buffer);
+ *         } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) {
+ *             // a key we recognize but wish to discard
+ *             data.skipEntityData();
+ *         } // ... etc.
+ *    }
  * }</pre>
  */
 public class BackupDataInput {
diff --git a/core/java/android/app/backup/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java
index 465b3b6..94c7845 100644
--- a/core/java/android/app/backup/BackupDataInputStream.java
+++ b/core/java/android/app/backup/BackupDataInputStream.java
@@ -20,17 +20,17 @@
 import java.io.IOException;
 
 /**
- * Used by {@link BackupHelper} classes within the {@link BackupAgentHelper} mechanism,
- * this class provides an {@link java.io.InputStream}-like interface for accessing an
- * entity's data during a restore operation.
+ * Provides an {@link java.io.InputStream}-like interface for accessing an
+ * entity's data during a restore operation. Used by {@link BackupHelper} classes within the {@link
+ * BackupAgentHelper} mechanism.
  * <p>
- * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity(BackupDataInputStream)}
+ * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity()}
  * is called, the current entity's header has already been read from the underlying
  * {@link BackupDataInput}.  The entity's key string and total data size are available
  * through this class's {@link #getKey()} and {@link #size()} methods, respectively.
  * <p class="note">
- * <em>Note:</em> The caller should take care not to seek or close the underlying data
- * source, or to read more than {@link #size()} bytes total from the stream.</p>
+ * <strong>Note:</strong> The caller should take care not to seek or close the underlying data
+ * source, nor read more than {@link #size()} bytes from the stream.</p>
  *
  * @see BackupAgentHelper
  * @see BackupHelper
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index a69547a..22668b6 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -22,27 +22,28 @@
 import java.io.IOException;
 
 /**
- * This class is the structured conduit through which a {@link BackupAgent} commits
- * information to the current backup data set.  Data written for backup is presented
+ * Provides the structured interface through which a {@link BackupAgent} commits
+ * information to the backup data set, via its {@link
+ * BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} method.  Data written for backup is presented
  * as a set of "entities," key/value pairs in which each binary data record "value" is
  * named with a string "key."
  * <p>
  * To commit a data record to the backup transport, the agent's
- * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor)}
- * method first writes an "entity header" that supplies the key string for the record
+ * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} method first writes an "entity header" that supplies the key string for the record
  * and the total size of the binary value for the record.  After the header has been
- * written the agent then writes the binary entity value itself.  The entity value can
+ * written, the agent then writes the binary entity value itself.  The entity value can
  * be written in multiple chunks if desired, as long as the total count of bytes written
- * matches what was supplied to {@link #writeEntityHeader(String, int)}.
+ * matches what was supplied to {@link #writeEntityHeader(String, int) writeEntityHeader()}.
  * <p>
  * Entity key strings are considered to be unique within a given application's backup
- * data set.  If a new entity is written under an existing key string, its value will
- * replace any previous value in the transport's remote data store.  A record can be
- * removed entirely from the remote data set by writing a new entity header using the
+ * data set. If a backup agent writes a new entity under an existing key string, its value will
+ * replace any previous value in the transport's remote data store.  You can remove a record
+ * entirely from the remote data set by writing a new entity header using the
  * existing record's key, but supplying a negative <code>dataSize</code> parameter.
- * When doing this the agent does not need to call {@link #writeEntityData(byte[], int)}.
- * <p>
- * <b>Example</b>
+ * When you do so, the agent does not need to call {@link #writeEntityData(byte[], int)}.
+ * <h3>Example</h3>
  * <p>
  * Here is an example illustrating a way to back up the value of a String variable
  * called <code>mStringToBackUp</code>:
@@ -73,9 +74,9 @@
     }
 
     /**
-     * Mark the beginning of one record in the backup data stream.
-     *
-     * @param key
+     * Mark the beginning of one record in the backup data stream. This must be called before
+     * {@link #writeEntityData}.
+     * @param key A string key that uniquely identifies the data record within the application
      * @param dataSize The size in bytes of this record's data.  Passing a dataSize
      *    of -1 indicates that the record under this key should be deleted.
      * @return The number of bytes written to the backup stream
diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index 87b581b..e3f0d54 100644
--- a/core/java/android/app/backup/BackupHelper.java
+++ b/core/java/android/app/backup/BackupHelper.java
@@ -19,7 +19,7 @@
 import android.os.ParcelFileDescriptor;
 
 /**
- * This interface defines the calling interface that {@link BackupAgentHelper} uses
+ * Defines the calling interface that {@link BackupAgentHelper} uses
  * when dispatching backup and restore operations to the installed helpers.
  * Applications can define and install their own helpers as well as using those
  * provided as part of the Android framework.
@@ -43,15 +43,28 @@
      * exists now.
      * <p>
      * Implementing this method is much like implementing
-     * {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
-     * &mdash; the method parameters are the same.  When this method is invoked the
+     * {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)
+     * onBackup()} &mdash; the method parameters are the same.  When this method is invoked the
      * {@code oldState} descriptor points to the beginning of the state data
      * written during this helper's previous backup operation, and the {@code newState}
      * descriptor points to the file location at which the helper should write its
      * new state after performing the backup operation.
      * <p class="note">
-     * <em>Note:</em> The helper should not close or seek either the {@code oldState} or
+     * <strong>Note:</strong> The helper should not close or seek either the {@code oldState} or
      * the {@code newState} file descriptors.</p>
+     *
+     * @param oldState An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the
+     *            last backup state provided by the application. May be
+     *            <code>null</code>, in which case no prior state is being
+     *            provided and the application should perform a full backup.
+     * @param data An open, read/write {@link BackupDataOutput}
+     *            pointing to the backup data destination.
+     *            Typically the application will use backup helper classes to
+     *            write to this file.
+     * @param newState An open, read/write {@link android.os.ParcelFileDescriptor} pointing to an
+     *            empty file. The application should record the final backup
+     *            state here after writing the requested data to the <code>data</code>
+     *            output stream.
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState);
@@ -61,8 +74,11 @@
      * to restore a single entity from the restore data set.  This method will be
      * called for each entity in the data set that belongs to this handler.
      * <p class="note">
-     * <em>Note:</em> Do not close the <code>data</code> stream.  Do not read more than
-     * <code>data.size()</code> bytes from <code>data</code>.</p>
+     * <strong>Note:</strong> Do not close the <code>data</code> stream.  Do not read more than
+     * {@link android.app.backup.BackupDataInputStream#size() size()} bytes from
+     * <code>data</code>.</p>
+     *
+     * @param data An open {@link BackupDataInputStream} from which the backup data can be read.
      */
     public void restoreEntity(BackupDataInputStream data);
 
@@ -71,15 +87,18 @@
      * after a restore operation to write the backup state file corresponding to
      * the data as processed by the helper.  The data written here will be
      * available to the helper during the next call to its
-     * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
-     * method.
+     * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)
+     * performBackup()} method.
      * <p>
-     * Note that this method will be called even if the handler's
-     * {@link #restoreEntity(BackupDataInputStream)} method was never invoked during
+     * This method will be called even if the handler's
+     * {@link #restoreEntity(BackupDataInputStream) restoreEntity()} method was never invoked during
      * the restore operation.
      * <p class="note">
-     * <em>Note:</em> The helper should not close or seek the {@code newState}
+     * <strong>Note:</strong> The helper should not close or seek the {@code newState}
      * file descriptor.</p>
+     *
+     * @param newState A {@link android.os.ParcelFileDescriptor} to which the new state will be
+     * written.
      */
     public void writeNewStateDescription(ParcelFileDescriptor newState);
 }
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 7070827..52dd707 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -25,9 +25,9 @@
 import android.util.Log;
 
 /**
- * The BackupManager class is interface through which an application's user interface
- * code will interact with the Android backup service.  Applications simply instantiate one
- * and then issue calls through that instance.
+ * The interface through which an application interacts with the Android backup service to
+ * request backup and restore operations.
+ * Applications instantiate it using the constructor and issue calls through that instance.
  * <p>
  * When an application has made changes to data which should be backed up, a
  * call to {@link #dataChanged()} will notify the backup service. The system
@@ -35,19 +35,16 @@
  * calls to {@link #dataChanged()} have no further effect until the backup
  * operation actually occurs.
  * <p>
- * A backup or restore operation begins with the system launching the
- * {@link android.app.backup.BackupAgent} subclass declared in your manifest. See the
+ * A backup or restore operation for your application begins when the system launches the
+ * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
  * documentation for {@link android.app.backup.BackupAgent} for a detailed description
  * of how the operation then proceeds.
  * <p>
- * <b>XML attributes</b>
- * <p>
  * Several attributes affecting the operation of the backup and restore mechanism
- * can be set on the &lt;application&gt; tag in the application's
- * AndroidManifest.xml file.  See the documentation on the
- * {@link android.R.styleable#AndroidManifestApplication AndroidManifest.xml's application attributes}
- * for details.
- * 
+ * can be set on the <code><a
+ * href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+ * tag in your application's AndroidManifest.xml file.
+ *
  * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
  * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
  * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
@@ -103,6 +100,8 @@
      * This method requires that the application hold the "android.permission.BACKUP"
      * permission if the package named in the argument does not run under the same uid
      * as the caller.
+     *
+     * @param packageName The package name identifying the application to back up.
      */
     public static void dataChanged(String packageName) {
         checkServiceBinder();
@@ -128,6 +127,9 @@
      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
      * method.
      *
+     * @param observer The {@link RestoreObserver} to receive callbacks during the restore
+     * operation. This must not be null.
+     *
      * @return Zero on success; nonzero on error.
      */
     public int requestRestore(RestoreObserver observer) {
diff --git a/core/java/android/app/backup/FileBackupHelper.java b/core/java/android/app/backup/FileBackupHelper.java
index a326941..c6a523a 100644
--- a/core/java/android/app/backup/FileBackupHelper.java
+++ b/core/java/android/app/backup/FileBackupHelper.java
@@ -23,16 +23,17 @@
 import java.io.File;
 
 /**
- * A helper class which can be used in conjunction with
+ * A helper class that can be used in conjunction with
  * {@link android.app.backup.BackupAgentHelper} to manage the backup of a set of
  * files. Whenever backup is performed, all files changed since the last backup
- * will be saved in their entirety.  During the first time the backup happens,
- * every file in the list will be backed up.  Note that this should only be
- * used with small configuration files, not with large binary files.
+ * will be saved in their entirety. When backup first occurs,
+ * every file in the list provided to {@link #FileBackupHelper} will be backed up.
  * <p>
  * During restore, if the helper encounters data for a file that was not
  * specified when the FileBackupHelper object was constructed, that data
  * will be ignored.
+ * <p class="note"><strong>Note:</strong> This should be
+ * used only with small configuration files, not large binary files.
  */
 public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
     private static final String TAG = "FileBackupHelper";
diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
index 9efecc5..23b1703 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -24,18 +24,18 @@
 import java.io.File;
 
 /**
- * A helper class which can be used in conjunction with
+ * A helper class that can be used in conjunction with
  * {@link android.app.backup.BackupAgentHelper} to manage the backup of
- * {@link android.content.SharedPreferences}. Whenever a backup is performed it
- * will back up all named shared preferences which have changed since the last
+ * {@link android.content.SharedPreferences}. Whenever a backup is performed, it
+ * will back up all named shared preferences that have changed since the last
  * backup operation.
  * <p>
- * To use this class, the application's agent class should extend
+ * To use this class, the application's backup agent class should extend
  * {@link android.app.backup.BackupAgentHelper}.  Then, in the agent's
  * {@link BackupAgent#onCreate()} method, an instance of this class should be
  * allocated and installed as a backup/restore handler within the BackupAgentHelper
- * framework.  An implementation of an agent supporting backup and restore for
- * an application that wishes to back up two groups of {@link android.content.SharedPreferences}
+ * framework.  For example, an agent supporting backup and restore for
+ * an application with two groups of {@link android.content.SharedPreferences}
  * data might look something like this:
  * <pre>
  * import android.app.backup.BackupAgentHelper;
@@ -59,12 +59,12 @@
  *     }
  * }</pre>
  * <p>
- * No further implementation is needed; the BackupAgentHelper mechanism automatically
+ * No further implementation is needed; the {@link BackupAgentHelper} mechanism automatically
  * dispatches the
  * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor) BackupAgent.onBackup()}
  * and
  * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore()}
- * callbacks to the SharedPreferencesBackupHelper as appropriate.  
+ * callbacks to the SharedPreferencesBackupHelper as appropriate.
  */
 public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
     private static final String TAG = "SharedPreferencesBackupHelper";
@@ -77,8 +77,9 @@
      * Construct a helper for backing up and restoring the
      * {@link android.content.SharedPreferences} under the given names.
      *
-     * @param context
-     * @param prefGroups
+     * @param context The application {@link android.content.Context}
+     * @param prefGroups The names of each {@link android.content.SharedPreferences} file to
+     * back up
      */
     public SharedPreferencesBackupHelper(Context context, String... prefGroups) {
         super(context);
@@ -88,7 +89,7 @@
     }
 
     /**
-     * Backs up the configured SharedPreferences groups
+     * Backs up the configured {@link android.content.SharedPreferences} groups.
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) {
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index 2a5b628..e2518ec 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -1,7 +1,9 @@
 <HTML>
 <BODY>
-<p>Package containing the backup and restore functionality available to
-applications. All backup management is controlled through
+<p>Contains the backup and restore functionality available to
+applications. If a user wipes the data on their device or upgrades to a new Android-powered
+device, all applications that have enabled backup will restore the user's previous data and/or
+preferences. {@more} All backup management is controlled through
 {@link android.app.backup.BackupManager}.  Individual backup functionality is
 implemented through a subclass {@link android.app.backup.BackupAgent} and a
 simple and easy-to-use implementation is provided in
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 456ceb6..88adabd 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -231,8 +231,14 @@
     /**
      * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
      */
-    @SuppressWarnings({"UnusedDeclaration"})
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+        AppWidgetHostView v;
+        synchronized (mViews) {
+            v = mViews.get(appWidgetId);
+        }
+        if (v != null) {
+            v.updateAppWidget(null, AppWidgetHostView.UPDATE_FLAGS_RESET);
+        }
     }
 
     void updateAppWidgetView(int appWidgetId, RemoteViews views) {
@@ -241,7 +247,7 @@
             v = mViews.get(appWidgetId);
         }
         if (v != null) {
-            v.updateAppWidget(views);
+            v.updateAppWidget(views, 0);
         }
     }
 }
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 792b289..5375193 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -46,6 +46,8 @@
     static final boolean LOGD = false;
     static final boolean CROSSFADE = false;
 
+    static final int UPDATE_FLAGS_RESET = 0x00000001;
+
     static final int VIEW_MODE_NOINIT = 0;
     static final int VIEW_MODE_CONTENT = 1;
     static final int VIEW_MODE_ERROR = 2;
@@ -150,7 +152,16 @@
      * AppWidget provider. Will animate into these new views as needed
      */
     public void updateAppWidget(RemoteViews remoteViews) {
-        if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
+        updateAppWidget(remoteViews, 0);
+    }
+
+    void updateAppWidget(RemoteViews remoteViews, int flags) {
+        if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld + " flags=0x"
+                + Integer.toHexString(flags));
+
+        if ((flags & UPDATE_FLAGS_RESET) != 0) {
+            mViewMode = VIEW_MODE_NOINIT;
+        }
         
         boolean recycled = false;
         View content = null;
@@ -323,6 +334,9 @@
      * Inflate and return the default layout requested by AppWidget provider.
      */
     protected View getDefaultView() {
+        if (LOGD) {
+            Log.d(TAG, "getDefaultView");
+        }
         View defaultView = null;
         Exception exception = null;
         
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index caa3144..3826a01 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -21,9 +21,12 @@
 import android.app.ISearchManager;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Process;
 import android.util.Log;
 
 import java.util.List;
@@ -51,18 +54,38 @@
      */
     public SearchManagerService(Context context)  {
         mContext = context;
+        mContext.registerReceiver(new BootCompletedReceiver(),
+                new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
     }
 
     private synchronized Searchables getSearchables() {
         if (mSearchables == null) {
+            Log.i(TAG, "Building list of searchable activities");
+            new MyPackageMonitor().register(mContext, true);
             mSearchables = new Searchables(mContext);
             mSearchables.buildSearchableList();
-            new MyPackageMonitor().register(mContext, true);
         }
         return mSearchables;
     }
 
     /**
+     * Creates the initial searchables list after boot.
+     */
+    private final class BootCompletedReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            new Thread() {
+                @Override
+                public void run() {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    mContext.unregisterReceiver(BootCompletedReceiver.this);
+                    getSearchables();
+                }
+            }.start();
+        }
+    }
+
+    /**
      * Refreshes the "searchables" list when packages are added/removed.
      */
     class MyPackageMonitor extends PackageMonitor {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index bf94707..03efea9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2580,27 +2580,33 @@
     public void playSoundEffect(int effectId) {
         checkThread();
 
-        final AudioManager audioManager = getAudioManager();
+        try {
+            final AudioManager audioManager = getAudioManager();
 
-        switch (effectId) {
-            case SoundEffectConstants.CLICK:
-                audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
-                return;
-            case SoundEffectConstants.NAVIGATION_DOWN:
-                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
-                return;
-            case SoundEffectConstants.NAVIGATION_LEFT:
-                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
-                return;
-            case SoundEffectConstants.NAVIGATION_RIGHT:
-                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
-                return;
-            case SoundEffectConstants.NAVIGATION_UP:
-                audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
-                return;
-            default:
-                throw new IllegalArgumentException("unknown effect id " + effectId +
-                        " not defined in " + SoundEffectConstants.class.getCanonicalName());
+            switch (effectId) {
+                case SoundEffectConstants.CLICK:
+                    audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
+                    return;
+                case SoundEffectConstants.NAVIGATION_DOWN:
+                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
+                    return;
+                case SoundEffectConstants.NAVIGATION_LEFT:
+                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
+                    return;
+                case SoundEffectConstants.NAVIGATION_RIGHT:
+                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
+                    return;
+                case SoundEffectConstants.NAVIGATION_UP:
+                    audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
+                    return;
+                default:
+                    throw new IllegalArgumentException("unknown effect id " + effectId +
+                            " not defined in " + SoundEffectConstants.class.getCanonicalName());
+            }
+        } catch (IllegalStateException e) {
+            // Exception thrown by getAudioManager() when mView is null
+            Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
+            e.printStackTrace();
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 1543b62..9b58205 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -16,10 +16,12 @@
 
 package com.android.internal.view.menu;
 
-import com.android.internal.view.menu.MenuView.ItemView;
+import java.lang.ref.WeakReference;
 
+import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -28,12 +30,14 @@
 import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
 
-import java.lang.ref.WeakReference;
+import com.android.internal.view.menu.MenuView.ItemView;
 
 /**
  * @hide
  */
 public final class MenuItemImpl implements MenuItem {
+    private static final String TAG = "MenuItemImpl";
+    
     private final int mId;
     private final int mGroup;
     private final int mCategoryOrder;
@@ -147,8 +151,12 @@
         }
         
         if (mIntent != null) {
-            mMenu.getContext().startActivity(mIntent);
-            return true;
+            try {
+                mMenu.getContext().startActivity(mIntent);
+                return true;
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
+            }
         }
         
         return false;
diff --git a/core/res/res/layout-land/icon_menu_layout.xml b/core/res/res/layout-land/icon_menu_layout.xml
index 58f7bfb..70e3e83 100644
--- a/core/res/res/layout-land/icon_menu_layout.xml
+++ b/core/res/res/layout-land/icon_menu_layout.xml
@@ -18,7 +18,7 @@
     android:id="@+android:id/icon_menu" 
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:rowHeight="65dip"
+    android:rowHeight="66dip"
     android:maxItems="6"
     android:maxRows="2"
     android:maxItemsPerRow="6" />
diff --git a/core/res/res/layout-port/icon_menu_layout.xml b/core/res/res/layout-port/icon_menu_layout.xml
index c84f7d2..82082da 100644
--- a/core/res/res/layout-port/icon_menu_layout.xml
+++ b/core/res/res/layout-port/icon_menu_layout.xml
@@ -18,7 +18,7 @@
     android:id="@+android:id/icon_menu" 
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:rowHeight="65dip"
+    android:rowHeight="66dip"
     android:maxItems="6"
     android:maxRows="3"
     android:maxItemsPerRow="3" />
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 79ca617..200a1b2 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -65,7 +65,7 @@
         android:layout_below="@id/carrier"
         android:layout_marginTop="52dip"
         android:layout_marginLeft="20dip"
-        android:layout_marginBottom="8dip"
+        android:paddingBottom="8dip"
         >
 
         <TextView android:id="@+id/timeDisplay"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 8353887..23505c2 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -66,7 +66,7 @@
             android:layout_height="wrap_content"
             android:layout_below="@id/carrier"
             android:layout_marginTop="56dip"
-            android:layout_marginBottom="8dip"
+            android:paddingBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 83381a1..b5cd442 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -65,7 +65,7 @@
             android:layout_alignParentTop="true"
             android:layout_alignParentLeft="true"
             android:layout_marginTop="8dip"
-            android:layout_marginBottom="8dip"
+            android:paddingBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 8dacfaf..9ac0a47 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -55,7 +55,7 @@
             android:layout_alignParentTop="true"
             android:layout_marginTop="15dip"
             android:layout_marginLeft="20dip"
-            android:layout_marginBottom="8dip"
+            android:paddingBottom="8dip"
             >
 
             <TextView android:id="@+id/timeDisplay"
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..657d0a40
--- /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/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index 6cd2199..05f61be 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -600,7 +600,7 @@
   Every application must have at least one entry point &mdash; a way
   for the user or system to access activities inside the
   application. Each icon in the application launcher at home
-  represents an entry point. Applications can also from another
+  represents an entry point. Applications can also be launched from another
   application. Each activity is a potential entry point into the
   application.&nbsp;
 </p>
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/docs/html/resources/tutorials/views/hello-gallery.jd b/docs/html/resources/tutorials/views/hello-gallery.jd
index 12d5a91..00757f5 100644
--- a/docs/html/resources/tutorials/views/hello-gallery.jd
+++ b/docs/html/resources/tutorials/views/hello-gallery.jd
@@ -101,9 +101,9 @@
 
     public ImageAdapter(Context c) {
         mContext = c;
-        TypedArray a = obtainStyledAttributes(android.R.styleable.Theme);
+        TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery);
         mGalleryItemBackground = a.getResourceId(
-                android.R.styleable.Theme_galleryItemBackground, 0);
+                R.styleable.HelloGallery_android_galleryItemBackground, 0);
         a.recycle();
     }
 
diff --git a/include/binder/Binder.h b/include/binder/Binder.h
index 47b2bb9..ba3ac4b 100644
--- a/include/binder/Binder.h
+++ b/include/binder/Binder.h
@@ -71,7 +71,6 @@
 
             Extras*     mExtras;
             void*       mReserved0;
-    static  String16    sEmptyDescriptor;
 };
 
 // ---------------------------------------------------------------------------
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/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 3f8bc51..4edfb88 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -36,6 +36,7 @@
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_VORBIS;
 
 }  // namespace android
 
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/libs/binder/Android.mk b/libs/binder/Android.mk
index 2df6775..13dc500 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -12,34 +12,35 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
 # we have the common sources, plus some device-specific stuff
-LOCAL_SRC_FILES:= \
-	Binder.cpp \
-	BpBinder.cpp \
-	IInterface.cpp \
-	IMemory.cpp \
-	IPCThreadState.cpp \
-	IPermissionController.cpp \
-	IServiceManager.cpp \
-	MemoryDealer.cpp \
+sources := \
+    Binder.cpp \
+    BpBinder.cpp \
+    IInterface.cpp \
+    IMemory.cpp \
+    IPCThreadState.cpp \
+    IPermissionController.cpp \
+    IServiceManager.cpp \
+    MemoryDealer.cpp \
     MemoryBase.cpp \
     MemoryHeapBase.cpp \
     MemoryHeapPmem.cpp \
-	Parcel.cpp \
-	Permission.cpp \
-	ProcessState.cpp \
-	Static.cpp
+    Parcel.cpp \
+    Permission.cpp \
+    ProcessState.cpp \
+    Static.cpp
 
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
 LOCAL_LDLIBS += -lpthread
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcutils \
-	libutils
-
-LOCAL_MODULE:= libbinder
-
+LOCAL_MODULE := libbinder
+LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
+LOCAL_SRC_FILES := $(sources)
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_LDLIBS += -lpthread
+LOCAL_MODULE := libbinder
+LOCAL_SRC_FILES := $(sources)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 0dd7622..9945f91 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -69,8 +69,6 @@
 
 // ---------------------------------------------------------------------------
 
-String16 BBinder::sEmptyDescriptor;
-
 BBinder::BBinder()
     : mExtras(NULL)
 {
@@ -88,6 +86,9 @@
 
 const String16& BBinder::getInterfaceDescriptor() const
 {
+    // This is a local static rather than a global static,
+    // to avoid static initializer ordering issues.
+    static String16 sEmptyDescriptor;
     LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
     return sEmptyDescriptor;
 }
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index d0eedb4..afecdcb 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -104,3 +104,13 @@
 LOCAL_MODULE:= libutils
 include $(BUILD_SHARED_LIBRARY)
 
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES += external/zlib external/icu4c/common
+LOCAL_LDLIBS := -lrt -ldl -lpthread
+LOCAL_MODULE := libutils
+LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
+include $(BUILD_STATIC_LIBRARY)
+endif
+endif
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index 3a34838..636cd83 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -136,10 +136,11 @@
 
 void initialize_string8()
 {
-#ifdef LIBUTILS_NATIVE
-	  // Bite me, Darwin!
-		gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
-#endif
+    // HACK: This dummy dependency forces linking libutils Static.cpp,
+    // which is needed to initialize String8/String16 classes.
+    // These variables are named for Darwin, but are needed elsewhere too,
+    // including static linking on any platform.
+    gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
 
     SharedBuffer* buf = SharedBuffer::alloc(1);
     char* str = (char*)buf->data();
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a6d8d2c..3e1f4a5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -678,6 +678,26 @@
     return PV_PLAYER;
 }
 
+// By default we use the VORBIS_PLAYER for vorbis playback (duh!),
+// but if the magic property is set we will use our new experimental
+// stagefright code instead.
+static player_type OverrideStagefrightForVorbis(player_type player) {
+    if (player != VORBIS_PLAYER) {
+        return player;
+    }
+
+#if BUILD_WITH_FULL_STAGEFRIGHT
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.enable-vorbis", value, NULL)
+        && (!strcmp(value, "1") || !strcmp(value, "true"))) {
+        return STAGEFRIGHT_PLAYER;
+    }
+#endif
+
+    return VORBIS_PLAYER;
+}
+
+
 player_type getPlayerType(int fd, int64_t offset, int64_t length)
 {
     char buf[20];
@@ -689,7 +709,7 @@
 
     // Ogg vorbis?
     if (ident == 0x5367674f) // 'OggS'
-        return VORBIS_PLAYER;
+        return OverrideStagefrightForVorbis(VORBIS_PLAYER);
 
 #ifndef NO_OPENCORE
     if (ident == 0x75b22630) {
@@ -725,6 +745,13 @@
         return TEST_PLAYER;
     }
 
+    bool useStagefrightForHTTP = false;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.enable-http", value, NULL)
+        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        useStagefrightForHTTP = true;
+    }
+
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
@@ -732,17 +759,18 @@
         int start = lenURL - len;
         if (start > 0) {
             if (!strncmp(url + start, FILE_EXTS[i].extension, len)) {
-                return FILE_EXTS[i].playertype;
+                if (FILE_EXTS[i].playertype == VORBIS_PLAYER
+                    && !strncasecmp(url, "http://", 7)
+                    && useStagefrightForHTTP) {
+                    return STAGEFRIGHT_PLAYER;
+                }
+                return OverrideStagefrightForVorbis(FILE_EXTS[i].playertype);
             }
         }
     }
 
     if (!strncasecmp(url, "http://", 7)) {
-        char value[PROPERTY_VALUE_MAX];
-        if (!property_get("media.stagefright.enable-http", value, NULL)
-            || (strcmp(value, "1") && strcasecmp(value, "true"))) {
-            // For now, we're going to use PV for http-based playback
-            // by default until we can clear up a few more issues.
+        if (!useStagefrightForHTTP) {
             return PV_PLAYER;
         }
     }
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/Android.mk b/media/libstagefright/Android.mk
index 2a65766..0420a60 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -39,6 +39,7 @@
         StagefrightMetadataRetriever.cpp \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
+        VorbisExtractor.cpp       \
         WAVExtractor.cpp          \
         string.cpp
 
@@ -101,8 +102,6 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_PRELINK_MODULE:= false
-
 LOCAL_MODULE:= libstagefright
 
 include $(BUILD_SHARED_LIBRARY)
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/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 86e4bfe..5db3201 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -18,6 +18,7 @@
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
+#include "include/VorbisExtractor.h"
 
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
@@ -92,6 +93,7 @@
     RegisterSniffer(SniffMPEG4);
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffWAV);
+    RegisterSniffer(SniffVorbis);
 }
 
 // static
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/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 3a89170..db18ab6 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -34,5 +34,6 @@
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
+const char *MEDIA_MIMETYPE_CONTAINER_VORBIS = "application/ogg";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 738e18a..dfddbe0 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -22,6 +22,7 @@
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
+#include "include/VorbisExtractor.h"
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
@@ -35,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) {
@@ -62,6 +67,8 @@
         return new AMRExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
         return new WAVExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_VORBIS)) {
+        return new VorbisExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp
new file mode 100644
index 0000000..e7b62d6
--- /dev/null
+++ b/media/libstagefright/VorbisExtractor.cpp
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VorbisExtractor"
+#include <utils/Log.h>
+
+#include "include/VorbisExtractor.h"
+
+#include <cutils/properties.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+#include <ivorbisfile.h>
+
+namespace android {
+
+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;
+
+    ssize_t n = vds->mDataSource->readAt(vds->mOffset, ptr, size * nmemb);
+
+    if (n < 0) {
+        return n;
+    }
+
+    vds->mOffset += n;
+
+    return n / size;
+}
+
+static int VorbisSeek(
+        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;
+            break;
+        case SEEK_END:
+        {
+            off_t size;
+            if (vds->mDataSource->getSize(&size) != OK) {
+                errno = ESPIPE;
+                return -1;
+            }
+
+            vds->mOffset = offset + size;
+            break;
+        }
+
+        case SEEK_CUR:
+        {
+            vds->mOffset += offset;
+            break;
+        }
+
+        default:
+        {
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int VorbisClose(void *datasource) {
+    return 0;
+}
+
+static long VorbisTell(void *datasource) {
+    VorbisDataSource *vds = (VorbisDataSource *)datasource;
+
+    return vds->mOffset;
+}
+
+static const ov_callbacks gVorbisCallbacks = {
+    &VorbisRead,
+    &VorbisSeek,
+    &VorbisClose,
+    &VorbisTell
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct VorbisSource : public MediaSource {
+    VorbisSource(const sp<VorbisExtractor> &extractor,
+                 const sp<MetaData> &meta, OggVorbis_File *file);
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~VorbisSource();
+
+private:
+    enum {
+        kMaxBufferSize = 8192
+    };
+
+    sp<VorbisExtractor> mExtractor;
+    sp<MetaData> mMeta;
+    OggVorbis_File *mFile;
+    MediaBufferGroup *mGroup;
+
+    VorbisSource(const VorbisSource &);
+    VorbisSource &operator=(const VorbisSource &);
+};
+
+VorbisSource::VorbisSource(
+        const sp<VorbisExtractor> &extractor,
+        const sp<MetaData> &meta, OggVorbis_File *file)
+    : mExtractor(extractor),
+      mMeta(meta),
+      mFile(file),
+      mGroup(NULL) {
+}
+
+VorbisSource::~VorbisSource() {
+    if (mGroup) {
+        stop();
+    }
+}
+
+sp<MetaData> VorbisSource::getFormat() {
+    return mMeta;
+}
+
+status_t VorbisSource::start(MetaData *params) {
+    if (mGroup != NULL) {
+        return INVALID_OPERATION;
+    }
+
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(kMaxBufferSize));
+
+    return OK;
+}
+
+status_t VorbisSource::stop() {
+    delete mGroup;
+    mGroup = NULL;
+
+    return OK;
+}
+
+status_t VorbisSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        ov_time_seek(mFile, seekTimeUs / 1000ll);
+    }
+
+    MediaBuffer *buffer;
+    CHECK_EQ(OK, mGroup->acquire_buffer(&buffer));
+
+    ogg_int64_t positionMs = ov_time_tell(mFile);
+
+    int bitstream;
+    long n = ov_read(mFile, buffer->data(), buffer->size(), &bitstream);
+
+    if (n <= 0) {
+        LOGE("ov_read returned %ld", n);
+
+        buffer->release();
+        buffer = NULL;
+
+        return n < 0 ? ERROR_MALFORMED : ERROR_END_OF_STREAM;
+    }
+
+    buffer->set_range(0, n);
+    buffer->meta_data()->setInt64(kKeyTime, positionMs * 1000ll);
+
+    *out = buffer;
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+VorbisExtractor::VorbisExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mFile(new OggVorbis_File),
+      mVorbisDataSource(new VorbisDataSource),
+      mInitCheck(NO_INIT) {
+    mVorbisDataSource->mDataSource = mDataSource;
+    mVorbisDataSource->mOffset = 0;
+    mVorbisDataSource->mSeekDisabled = ShouldDisableSeek(mDataSource);
+
+    int res = ov_open_callbacks(
+            mVorbisDataSource, mFile, NULL, 0, gVorbisCallbacks);
+
+    if (res != 0) {
+        return;
+    }
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+    vorbis_info *vi = ov_info(mFile, -1);
+    mMeta->setInt32(kKeySampleRate, vi->rate);
+    mMeta->setInt32(kKeyChannelCount, vi->channels);
+
+    ogg_int64_t durationMs = ov_time_total(mFile, -1);
+    mMeta->setInt64(kKeyDuration, durationMs * 1000ll);
+
+    LOGI("Successfully initialized.");
+
+    mInitCheck = OK;
+}
+
+VorbisExtractor::~VorbisExtractor() {
+    CHECK_EQ(0, ov_clear(mFile));
+
+    delete mVorbisDataSource;
+    mVorbisDataSource = NULL;
+
+    delete mFile;
+    mFile = NULL;
+}
+
+size_t VorbisExtractor::countTracks() {
+    return mInitCheck != OK ? 0 : 1;
+}
+
+sp<MediaSource> VorbisExtractor::getTrack(size_t index) {
+    if (index >= 1) {
+        return NULL;
+    }
+
+    return new VorbisSource(this, mMeta, mFile);
+}
+
+sp<MetaData> VorbisExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    if (index >= 1) {
+        return NULL;
+    }
+
+    return mMeta;
+}
+
+sp<MetaData> VorbisExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+
+    if (mInitCheck != OK) {
+        return meta;
+    }
+
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_VORBIS);
+
+    return meta;
+}
+
+bool SniffVorbis(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    OggVorbis_File file;
+
+    VorbisDataSource vds;
+    vds.mDataSource = source;
+    vds.mOffset = 0;
+    vds.mSeekDisabled = ShouldDisableSeek(source);
+
+    int res = ov_test_callbacks(&vds, &file, NULL, 0, gVorbisCallbacks);
+
+    CHECK_EQ(0, ov_clear(&file));
+
+    if (res != 0) {
+        return false;
+    }
+
+    *mimeType = MEDIA_MIMETYPE_CONTAINER_VORBIS;
+    *confidence = 0.4f;
+
+    LOGV("This looks like an Ogg file.");
+
+    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/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 2657a52..30ce29c 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -69,8 +69,6 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
 
-LOCAL_PRELINK_MODULE:= false
-
 LOCAL_MODULE := libstagefright_amrnb_common
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk
index 39c6da8..22dee15 100644
--- a/media/libstagefright/codecs/avc/common/Android.mk
+++ b/media/libstagefright/codecs/avc/common/Android.mk
@@ -16,6 +16,4 @@
 	$(LOCAL_PATH)/src \
  	$(LOCAL_PATH)/include
 
-LOCAL_PRELINK_MODULE:= false
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index e7a571a..b9ba1be 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -17,8 +17,6 @@
         libsurfaceflinger_client\
         libcamera_client
 
-LOCAL_PRELINK_MODULE:= false
-
 LOCAL_MODULE:= libstagefright_color_conversion
 
 include $(BUILD_SHARED_LIBRARY)
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
new file mode 100644
index 0000000..2bb7deb
--- /dev/null
+++ b/media/libstagefright/include/VorbisExtractor.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef VORBIS_EXTRACTOR_H_
+
+#define VORBIS_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+struct OggVorbis_File;
+
+namespace android {
+
+class DataSource;
+class String8;
+
+struct VorbisDataSource;
+
+struct VorbisExtractor : public MediaExtractor {
+    VorbisExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+    uint32_t flags() const;
+
+protected:
+    virtual ~VorbisExtractor();
+
+private:
+    sp<DataSource> mDataSource;
+    struct OggVorbis_File *mFile;
+    struct VorbisDataSource *mVorbisDataSource;
+    status_t mInitCheck;
+    sp<MetaData> mMeta;
+
+    VorbisExtractor(const VorbisExtractor &);
+    VorbisExtractor &operator=(const VorbisExtractor &);
+};
+
+bool SniffVorbis(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // VORBIS_EXTRACTOR_H_
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 2473731..f4f5cc1 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -42,8 +42,6 @@
 LOCAL_SHARED_LIBRARIES += libdl
 endif
 
-LOCAL_PRELINK_MODULE:= false
-
 LOCAL_MODULE:= libstagefright_omx
 
 include $(BUILD_SHARED_LIBRARY)
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/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index ba326d6..b9204c7 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5780,6 +5780,18 @@
                 }
                 mSettings.writeLP();
             }
+        } else {
+            // If this is an update to an existing update, setup 
+            // to remove the existing update.
+            synchronized (mPackages) {
+                PackageSetting ps = mSettings.getDisabledSystemPkg(packageName);
+                if (ps != null && ps.codePathString != null &&
+                        !ps.codePathString.equals(oldPkgSetting.codePathString)) {
+                    int installFlags = 0;
+                    res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString,
+                            oldPkgSetting.resourcePathString);
+                }
+            }
         }
     }
 
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) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8383ca3..706e15a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12269,6 +12269,18 @@
         }
     }
     
+    private final void sendPackageBroadcastLocked(int cmd, String[] packages) {
+        for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+            ProcessRecord r = mLruProcesses.get(i);
+            if (r.thread != null) {
+                try {
+                    r.thread.dispatchPackageBroadcast(cmd, packages);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+    
     private final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
@@ -12315,6 +12327,8 @@
                             for (String pkg : list) {
                                 forceStopPackageLocked(pkg, -1, false, true, true);
                             }
+                            sendPackageBroadcastLocked(
+                                    IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list);
                         }
                     } else {
                         Uri data = intent.getData();
@@ -12324,6 +12338,10 @@
                                 forceStopPackageLocked(ssp,
                                         intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
                             }
+                            if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                                sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+                                        new String[] {ssp});
+                            }
                         }
                     }
                 }
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 735a80d..1e8b395 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -523,10 +523,48 @@
             bool actWidgetReceivers = false;
             bool actImeService = false;
             bool actWallpaperService = false;
-            bool specCameraFeature = false;
+
+            // This next group of variables is used to implement a group of
+            // backward-compatibility heuristics necessitated by the addition of
+            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
+            // heuristic is "if an app requests a permission but doesn't explicitly
+            // request the corresponding <uses-feature>, presume it's there anyway".
+            bool specCameraFeature = false; // camera-related
+            bool specCameraAutofocusFeature = false;
+            bool reqCameraAutofocusFeature = false;
+            bool reqCameraFlashFeature = false;
             bool hasCameraPermission = false;
+            bool specLocationFeature = false; // location-related
+            bool specNetworkLocFeature = false;
+            bool reqNetworkLocFeature = false;
             bool specGpsFeature = false;
+            bool reqGpsFeature = false;
+            bool hasMockLocPermission = false;
+            bool hasCoarseLocPermission = false;
             bool hasGpsPermission = false;
+            bool hasGeneralLocPermission = false;
+            bool specBluetoothFeature = false; // Bluetooth API-related
+            bool hasBluetoothPermission = false;
+            bool specMicrophoneFeature = false; // microphone-related
+            bool hasRecordAudioPermission = false;
+            bool specWiFiFeature = false;
+            bool hasWiFiPermission = false;
+            bool specTelephonyFeature = false; // telephony-related
+            bool reqTelephonySubFeature = false;
+            bool hasTelephonyPermission = false;
+            bool specTouchscreenFeature = false; // touchscreen-related
+            bool specMultitouchFeature = false;
+            bool reqDistinctMultitouchFeature = false;
+            // 2.2 also added some other features that apps can request, but that
+            // have no corresponding permission, so we cannot implement any
+            // back-compatibility heuristic for them. The below are thus unnecessary
+            // (but are retained here for documentary purposes.)
+            //bool specCompassFeature = false;
+            //bool specAccelerometerFeature = false;
+            //bool specProximityFeature = false;
+            //bool specAmbientLightFeature = false;
+            //bool specLiveWallpaperFeature = false;
+
             int targetSdk = 0;
             int smallScreen = 1;
             int normalScreen = 1;
@@ -719,10 +757,45 @@
                         if (name != "" && error == "") {
                             int req = getIntegerAttribute(tree,
                                     REQUIRED_ATTR, NULL, 1);
+
                             if (name == "android.hardware.camera") {
                                 specCameraFeature = true;
+                            } else if (name == "android.hardware.camera.autofocus") {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational camera permission
+                                reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
+                                specCameraAutofocusFeature = true;
+                            } else if (req && (name == "android.hardware.camera.flash")) {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational camera permission
+                                reqCameraFlashFeature = true;
+                            } else if (name == "android.hardware.location") {
+                                specLocationFeature = true;
+                            } else if (name == "android.hardware.location.network") {
+                                specNetworkLocFeature = true;
+                                reqNetworkLocFeature = reqNetworkLocFeature || req;
                             } else if (name == "android.hardware.location.gps") {
                                 specGpsFeature = true;
+                                reqGpsFeature = reqGpsFeature || req;
+                            } else if (name == "android.hardware.bluetooth") {
+                                specBluetoothFeature = true;
+                            } else if (name == "android.hardware.touchscreen") {
+                                specTouchscreenFeature = true;
+                            } else if (name == "android.hardware.touchscreen.multitouch") {
+                                specMultitouchFeature = true;
+                            } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
+                                reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
+                            } else if (name == "android.hardware.microphone") {
+                                specMicrophoneFeature = true;
+                            } else if (name == "android.hardware.wifi") {
+                                specWiFiFeature = true;
+                            } else if (name == "android.hardware.telephony") {
+                                specTelephonyFeature = true;
+                            } else if (req && (name == "android.hardware.telephony.gsm" ||
+                                               name == "android.hardware.telephony.cdma")) {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational telephony permission
+                                reqTelephonySubFeature = true;
                             }
                             printf("uses-feature%s:'%s'\n",
                                     req ? "" : "-not-required", name.string());
@@ -740,6 +813,34 @@
                                 hasCameraPermission = true;
                             } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
                                 hasGpsPermission = true;
+                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
+                                hasMockLocPermission = true;
+                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+                                hasCoarseLocPermission = true;
+                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+                                hasGeneralLocPermission = true;
+                            } else if (name == "android.permission.BLUETOOTH" ||
+                                       name == "android.permission.BLUETOOTH_ADMIN") {
+                                hasBluetoothPermission = true;
+                            } else if (name == "android.permission.RECORD_AUDIO") {
+                                hasRecordAudioPermission = true;
+                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+                                       name == "android.permission.CHANGE_WIFI_STATE" ||
+                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+                                hasWiFiPermission = true;
+                            } else if (name == "android.permission.CALL_PHONE" ||
+                                       name == "android.permission.CALL_PRIVILEGED" ||
+                                       name == "android.permission.MODIFY_PHONE_STATE" ||
+                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+                                       name == "android.permission.READ_SMS" ||
+                                       name == "android.permission.RECEIVE_SMS" ||
+                                       name == "android.permission.RECEIVE_MMS" ||
+                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
+                                       name == "android.permission.SEND_SMS" ||
+                                       name == "android.permission.WRITE_APN_SETTINGS" ||
+                                       name == "android.permission.WRITE_SMS") {
+                                hasTelephonyPermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
                         } else {
@@ -856,22 +957,89 @@
                 }
             }
 
-            if (!specCameraFeature && hasCameraPermission) {
-                // For applications that have not explicitly stated their
-                // camera feature requirements, but have requested the camera
-                // permission, we are going to give them compatibility treatment
-                // of requiring the equivalent to original android devices.
-                printf("uses-feature:'android.hardware.camera'\n");
-                printf("uses-feature:'android.hardware.camera.autofocus'\n");
+            /* The following blocks handle printing "inferred" uses-features, based
+             * on whether related features or permissions are used by the app.
+             * Note that the various spec*Feature variables denote whether the
+             * relevant tag was *present* in the AndroidManfest, not that it was
+             * present and set to true.
+             */
+            // Camera-related back-compatibility logic
+            if (!specCameraFeature) {
+                if (reqCameraFlashFeature || reqCameraAutofocusFeature) {
+                    // if app requested a sub-feature (autofocus or flash) and didn't
+                    // request the base camera feature, we infer that it meant to
+                    printf("uses-feature:'android.hardware.camera'\n");
+                } else if (hasCameraPermission) {
+                    // if app wants to use camera but didn't request the feature, we infer 
+                    // that it meant to, and further that it wants autofocus
+                    // (which was the 1.0 - 1.5 behavior)
+                    printf("uses-feature:'android.hardware.camera'\n");
+                    if (!specCameraAutofocusFeature) {
+                        printf("uses-feature:'android.hardware.camera.autofocus'\n");
+                    }
+                }
             }
 
+            // Location-related back-compatibility logic
+            if (!specLocationFeature &&
+                (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
+                 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
+                // if app either takes a location-related permission or requests one of the
+                // sub-features, we infer that it also meant to request the base location feature
+                printf("uses-feature:'android.hardware.location'\n");
+            }
             if (!specGpsFeature && hasGpsPermission) {
-                // For applications that have not explicitly stated their
-                // GPS feature requirements, but have requested the "fine" (GPS)
-                // permission, we are going to give them compatibility treatment
-                // of requiring the equivalent to original android devices.
+                // if app takes GPS (FINE location) perm but does not request the GPS
+                // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.location.gps'\n");
             }
+            if (!specNetworkLocFeature && hasCoarseLocPermission) {
+                // if app takes Network location (COARSE location) perm but does not request the
+                // network location feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.location.network'\n");
+            }
+
+            // Bluetooth-related compatibility logic
+            if (!specBluetoothFeature && hasBluetoothPermission) {
+                // if app takes a Bluetooth permission but does not request the Bluetooth
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.bluetooth'\n");
+            }
+
+            // Microphone-related compatibility logic
+            if (!specMicrophoneFeature && hasRecordAudioPermission) {
+                // if app takes the record-audio permission but does not request the microphone
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.microphone'\n");
+            }
+
+            // WiFi-related compatibility logic
+            if (!specWiFiFeature && hasWiFiPermission) {
+                // if app takes one of the WiFi permissions but does not request the WiFi
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.wifi'\n");
+            }
+
+            // Telephony-related compatibility logic
+            if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
+                // if app takes one of the telephony permissions or requests a sub-feature but
+                // does not request the base telephony feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.telephony'\n");
+            }
+
+            // Touchscreen-related back-compatibility logic
+            if (!specTouchscreenFeature) { // not a typo!
+                // all apps are presumed to require a touchscreen, unless they explicitly say
+                // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
+                // Note that specTouchscreenFeature is true if the tag is present, regardless
+                // of whether its value is true or false, so this is safe
+                printf("uses-feature:'android.hardware.touchscreen'\n");
+            }
+            if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
+                // if app takes one of the telephony permissions or requests a sub-feature but
+                // does not request the base telephony feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
+            }
 
             if (hasMainActivity) {
                 printf("main\n");