Add new manifest option for install location
Change recommendAppInstallLocation api
add code to parse new attribute.
Define flags in PackageInfo
Add new settings attributes for enabling setting and value for install location
Some tests
The policy for install location: if explicitly set in manifest as internal only we try to install the app only on internal storage. if set to preferExternal, we try to install it on sdcard if possible. If not we fall back to internal.
If the user enables setting SET_INSTALL_LOCATION(which will always
be set to false in final release builds) and sets a prefered location, we try
to honour it.
diff --git a/api/current.xml b/api/current.xml
index 7eedf876..7169d0d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4585,6 +4585,17 @@
  visibility="public"
 >
 </field>
+<field name="installLocation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843448"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="interpolator"
  type="int"
  transient="false"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9b9cbd5..0a18fe5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -52,6 +52,7 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageParser.Package;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -85,6 +86,7 @@
 import android.os.Vibrator;
 import android.os.FileUtils.FileStatus;
 import android.os.storage.StorageManager;
+import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.ClipboardManager;
 import android.util.AndroidRuntimeException;
@@ -2646,14 +2648,13 @@
         // SD-to-internal app size threshold: currently set to 1 MB
         private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
 
-        @Override
-        public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
+        public int recommendAppInstallLocation(Package pkg) {
             // Initial implementation:
             // Package size = code size + cache size + data size
             // If code size > 1 MB, install on SD card.
             // Else install on internal NAND flash, unless space on NAND is less than 10%
 
-            if ((packageURI == null) || (appInfo == null)) {
+            if (pkg == null) {
                 return INSTALL_PARSE_FAILED_NOT_APK;
             }
 
@@ -2669,44 +2670,71 @@
 
             double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;
 
-            final String archiveFilePath = packageURI.getPath();
+            final String archiveFilePath = pkg.mScanPath;
             File apkFile = new File(archiveFilePath);
             long pkgLen = apkFile.length();
 
+            boolean auto = true;
+            // To make final copy
+            long reqInstallSize = pkgLen;
+            // For dex files
+            long reqInternalSize = 1 * pkgLen;
+            boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
+            boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
+            boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
+                    (reqInternalSize < availInternalFlashSize);
+            boolean fitsOnInt = intThresholdOk && intAvailOk;
+
             // Consider application flags preferences as well...
-            boolean installOnlyOnSD = ((appInfo.flags & PackageManager.INSTALL_ON_SDCARD) != 0);
-
-            // These are not very precise measures, but I guess it is hard to estimate sizes
-            // before installing the package.
-            // As a shortcut, I am assuming that the package fits on NAND flash if the available
-            // space is three times that of the APK size. For SD, we only worry about the APK size.
-            // Since packages are downloaded into SD, this might not even be necessary.
-            boolean fitsOnSD = (pkgLen < availSDSize) && ((2 * pkgLen) < availInternalFlashSize);
-            boolean fitsOnInternalFlash = ((pkgLen * 3) < availInternalFlashSize);
-
-            // Does not fit, recommend no installation.
-            if (!fitsOnSD && !fitsOnInternalFlash) {
-                return INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
-
-            if (pkgLen < (INSTALL_ON_SD_THRESHOLD) && fitsOnInternalFlash && !(installOnlyOnSD)) {
-                // recommend internal NAND likely
-                if (pctNandFree < LOW_NAND_FLASH_TRESHOLD) {
-                    // Low space on NAND (<10%) - install on SD
-                    return INSTALL_ON_SDCARD;
+            boolean installOnlyOnSd = (pkg.installLocation ==
+                    PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
+            boolean installOnlyInternal = (pkg.installLocation ==
+                    PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+            if (installOnlyInternal) {
+                // If set explicitly in manifest,
+                // let that override everything else
+                auto = false;
+            } else if (installOnlyOnSd){
+                // Check if this can be accommodated on the sdcard
+                if (fitsOnSd) {
+                    auto = false;
                 }
-                return INSTALL_ON_INTERNAL_FLASH;
             } else {
-                if (fitsOnSD) {
-                    // Recommend SD card
-                    return INSTALL_ON_SDCARD;
-                } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) &&
-                        !(installOnlyOnSD)) {
-                    return INSTALL_ON_INTERNAL_FLASH;
-                } else {
-                    return INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                // Check if user option is enabled
+                boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(),
+                        Settings.System.SET_INSTALL_LOCATION, 0) != 0;
+                if (setInstallLoc) {
+                    // Pick user preference
+                    int installPreference = Settings.System.getInt(mContext.getContentResolver(),
+                            Settings.System.DEFAULT_INSTALL_LOCATION,
+                            PackageInfo.INSTALL_LOCATION_AUTO);
+                    if (installPreference == 1) {
+                        installOnlyInternal = true;
+                        auto = false;
+                    } else if (installPreference == 2) {
+                        installOnlyOnSd = true;
+                        auto = false;
+                    }
                 }
             }
+            if (!auto) {
+                if (installOnlyOnSd) {
+                    return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                } else if (installOnlyInternal){
+                    // Check on internal flash
+                    return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                }
+            }
+            // Try to install internally
+            if (fitsOnInt) {
+                return INSTALL_ON_INTERNAL_FLASH;
+            }
+            // Try the sdcard now.
+            if (fitsOnSd) {
+                return INSTALL_ON_SDCARD;
+            }
+            // Return error code
+            return INSTALL_FAILED_INSUFFICIENT_STORAGE;
         }
 
         private final ContextImpl mContext;
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index a8ce889..c003355 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -131,6 +131,34 @@
      * The features that this application has said it requires.
      */
     public FeatureInfo[] reqFeatures;
+
+    /**
+     * Constant corresponding to <code>auto</code> in
+     * the {@link android.R.attr#installLocation} attribute.
+     * @hide
+     */
+    public static final int INSTALL_LOCATION_AUTO = 0;
+    /**
+     * Constant corresponding to <code>internalOnly</code> in
+     * the {@link android.R.attr#installLocation} attribute.
+     * @hide
+     */
+    public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1;
+    /**
+     * Constant corresponding to <code>preferExternal</code> in
+     * the {@link android.R.attr#installLocation} attribute.
+     * @hide
+     */
+    public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
+    /**
+     * The launch mode style requested by the activity.  From the
+     * {@link android.R.attr#installLocation} attribute, one of
+     * {@link #INSTALL_LOCATION_AUTO},
+     * {@link #INSTALL_LOCATION_INTERNAL_ONLY},
+     * {@link #INSTALL_LOCATION_PREFER_EXTERNAL}
+     * @hide
+     */
+    public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
     
     public PackageInfo() {
     }
@@ -168,6 +196,7 @@
         dest.writeTypedArray(signatures, parcelableFlags);
         dest.writeTypedArray(configPreferences, parcelableFlags);
         dest.writeTypedArray(reqFeatures, parcelableFlags);
+        dest.writeInt(installLocation);
     }
 
     public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -202,5 +231,6 @@
         signatures = source.createTypedArray(Signature.CREATOR);
         configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
         reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
+        installLocation = source.readInt();
     }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fca8588..a61eab9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -630,10 +630,11 @@
     
     /**
      * Determines best place to install an application: either SD or internal FLASH.
-     * Tweak the algorithm for best results.
-     * @param appInfo ApplicationInfo object of the package to install.
+     * If applications explicitly set installLocation in their manifest, that
+     * preference takes precedence. If not a recommended location is returned
+     * based on current available storage on internal flash or sdcard.
+     * @param pkgInfo PackageParser.Package of the package that is to be installed.
      * Call utility method to obtain.
-     * @param packageURI URI identifying the package's APK file.
      * @return {@link INSTALL_ON_INTERNAL_FLASH} if it is best to install package on internal
      * storage, {@link INSTALL_ON_SDCARD} if it is best to install package on SD card,
      * and {@link INSTALL_FAILED_INSUFFICIENT_STORAGE} if insufficient space to safely install
@@ -642,7 +643,7 @@
      * This recommendation does take into account the package's own flags.
      * @hide
      */
-    public abstract int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI);
+    public abstract int recommendAppInstallLocation(PackageParser.Package pkg);
 
     /**
      * Retrieve overall information about an application package that is
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b31df32..0a6195f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -177,6 +177,7 @@
         pi.sharedUserId = p.mSharedUserId;
         pi.sharedUserLabel = p.mSharedUserLabel;
         pi.applicationInfo = p.applicationInfo;
+        pi.installLocation = p.installLocation;
         if ((flags&PackageManager.GET_GIDS) != 0) {
             pi.gids = gids;
         }
@@ -709,6 +710,9 @@
                     com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
         }
         sa.recycle();
+        pkg.installLocation = sa.getInteger(
+                com.android.internal.R.styleable.AndroidManifest_installLocation,
+                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
 
         // Resource boolean are -1, so 1 means we don't know the value.
         int supportsSmallScreens = 1;
@@ -2610,6 +2614,8 @@
          */
         public ArrayList<FeatureInfo> reqFeatures = null;
 
+        public int installLocation;
+
         public Package(String _name) {
             packageName = _name;
             applicationInfo.packageName = _name;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bacaf43..c2cdcc0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1473,6 +1473,21 @@
         public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
 
         /**
+         * Let user pick default install location.
+         * @hide
+         */
+        public static final String SET_INSTALL_LOCATION = "set_install_location";
+
+        /**
+         * Default install location value.
+         * 0 = auto, let system decide
+         * 1 = internal
+         * 2 = sdcard
+         * @hide
+         */
+        public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          * @hide
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54781e3..2da23eb 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -600,6 +600,20 @@
          Application class to avoid interference with application logic. -->
     <attr name="restoreNeedsApplication" format="boolean" />
 
+    <!-- The default install location defined by an application. -->
+    <attr name="installLocation">
+        <!-- Let the system decide ideal install location -->
+        <enum name="auto" value="0" />
+        <!-- Explicitly request to be installed on internal phone storate
+             only. -->
+        <enum name="internalOnly" value="1" />
+        <!-- Prefer to be installed on sdcard. There is no guarantee that
+             the system will honour this request. The application might end
+             up being installed on internal storage if external media
+             is unavailable or too full. -->
+        <enum name="preferExternal" value="2" />
+    </attr>
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -624,6 +638,7 @@
         <attr name="versionName" />
         <attr name="sharedUserId" />
         <attr name="sharedUserLabel" />
+        <attr name="installLocation" />
     </declare-styleable>
     
     <!-- The <code>application</code> tag describes application-level components
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bd4a3eb..596e0b2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1224,9 +1224,10 @@
   <public type="attr" name="expandableListViewWhiteStyle" id="0x010102b6" />
 
 <!-- ===============================================================
-     Resources proposed for Flan.
+     Resources proposed for Froyo.
      =============================================================== -->
   <eat-comment />
   <public type="attr" name="neverEncrypt" id="0x010102b7" />
+  <public type="attr" name="installLocation" id="0x010102b8" />
     
 </resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7686aa0..ba6024f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -56,5 +56,6 @@
     <bool name="def_mount_ums_autostart">false</bool>
     <bool name="def_mount_ums_prompt">true</bool>
     <bool name="def_mount_ums_notify_enabled">true</bool>
+    <bool name="set_install_location">true</bool>
 
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 015b487..ac20297 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -864,6 +864,8 @@
 
         loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
                 R.bool.def_notification_pulse);
+        loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION, R.bool.set_install_location);
+        loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION, 0);
         stmt.close();
     }
 
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index cbe0253..c8339ed 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
@@ -443,7 +444,7 @@
      * @hide
      */
     @Override
-    public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
+    public int recommendAppInstallLocation(PackageParser.Package pkg) {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/tests/AndroidTests/res/raw/install_loc_auto b/tests/AndroidTests/res/raw/install_loc_auto
new file mode 100644
index 0000000..60dda18
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_auto
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_internal b/tests/AndroidTests/res/raw/install_loc_internal
new file mode 100644
index 0000000..1bc33ca
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_internal
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_sdcard b/tests/AndroidTests/res/raw/install_loc_sdcard
new file mode 100644
index 0000000..6604e35
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_sdcard
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_unspecified b/tests/AndroidTests/res/raw/install_loc_unspecified
new file mode 100644
index 0000000..88bbace
--- /dev/null
+++ b/tests/AndroidTests/res/raw/install_loc_unspecified
Binary files differ
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 3a4d38c..07bd489 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -37,6 +37,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageStats;
@@ -59,6 +60,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.provider.Settings;
 
 public class PackageManagerTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
@@ -761,6 +763,170 @@
             outFile.delete();
         }
     }
+
+    public void invokeRecommendAppInstallLocation(String outFileName,
+            int fileResId, int expected) {
+        int origSetting = Settings.System.getInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 0);
+        try {
+            // Make sure the set install location setting is diabled.
+            Settings.System.putInt(mContext.getContentResolver(),
+                    Settings.System.SET_INSTALL_LOCATION, 0);
+            File filesDir = mContext.getFilesDir();
+            File outFile = new File(filesDir, outFileName);
+            Uri packageURI = getInstallablePackage(fileResId, outFile);
+            PackageParser.Package pkg = parsePackage(packageURI);
+            assertNotNull(pkg);
+            int installLoc = getPm().recommendAppInstallLocation(pkg);
+            Log.i(TAG, "expected=" + expected +", installLoc="+installLoc);
+            // Atleast one of the specified expected flags should be set.
+            boolean onFlash = (installLoc &
+                    PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
+            boolean onSd = (installLoc &
+                    PackageManager.INSTALL_ON_SDCARD) != 0;
+            boolean expOnFlash = (expected &
+                    PackageManager.INSTALL_ON_INTERNAL_FLASH) != 0;
+            boolean expOnSd = (expected &
+                    PackageManager.INSTALL_ON_SDCARD) != 0;
+            assertTrue(expOnFlash == onFlash || expOnSd == onSd);
+        } finally {
+            // Restore original setting
+            Settings.System.putInt(mContext.getContentResolver(),
+                    Settings.System.SET_INSTALL_LOCATION, origSetting);
+        }
+    }
+
+    /*
+     * Tests if an apk can be installed on internal flash by
+     * explicitly specifying in its manifest.
+     */
+    public void testInstallLocationInternal() {
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_internal, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests if an apk can be installed on internal flash by
+     * explicitly specifying in its manifest and filling up
+     * internal flash. Should fail to install.
+     * TODO
+     */
+    public void xxxtestInstallLocationInternalFail() {
+    }
+
+    /*
+     * Tests if an apk can be installed on sdcard by
+     * explicitly specifying in its manifest.
+     */
+    public void testInstallLocationSdcard() {
+        // TODO No guarantee this will be on sdcard.
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_sdcard, PackageManager.INSTALL_ON_SDCARD
+                | PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests if an apk can be installed on sdcard by
+     * explicitly specifying in its manifest and filling up
+     * the sdcard. Should result in install failure
+     * TODO
+     */
+    public void xxxtestInstallLocationSdcardFail() {
+    }
+
+    /*
+     * Tests if an apk can be installed by specifying
+     * auto for install location
+     */
+    public void xxxtestInstallLocationAutoInternal() {
+        // TODO clear and make room on internal flash
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_auto, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests if an apk can be installed by specifying
+     * auto for install location
+     */
+    public void testInstallLocationAutoSdcard() {
+        // TODO clear and make room on sdcard.
+        // Fill up internal
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_auto, PackageManager.INSTALL_ON_SDCARD |
+                PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests if an apk can be installed by specifying
+     * auto for install location
+     * fill up both internal and sdcard
+     * TODO
+     */
+    public void xxxtestInstallLocationAutoFail() {
+    }
+    /*
+     * Tests where an apk gets installed based
+     * on a not specifying anything in manifest.
+     */
+    public void testInstallLocationUnspecifiedInt() {
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    public void xxxtestInstallLocationUnspecifiedStorage() {
+        // TODO Fill up internal storage
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD
+                | PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests where an apk gets installed by expcitly setting
+     * the user specified install location
+     */
+    public void testInstallLocationUserSpecifiedInternal() {
+        // Enable user setting
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 1);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.DEFAULT_INSTALL_LOCATION, 1);
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+    }
+
+    /*
+     * Tests where an apk gets installed by expcitly setting
+     * the user specified install location
+     */
+    public void testInstallLocationUserSpecifiedSdcard() {
+        // Enable user setting
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 1);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.DEFAULT_INSTALL_LOCATION, 2);
+        int i = Settings.System.getInt(mContext.getContentResolver(),
+                Settings.System.DEFAULT_INSTALL_LOCATION, 0);
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_SDCARD);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 0);
+    }
+    /*
+     * Tests where an apk gets installed by expcitly setting
+     * the user specified install location
+     */
+    public void testInstallLocationUserSpecifiedAuto() {
+        // Enable user setting
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 1);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.DEFAULT_INSTALL_LOCATION, 0);
+        invokeRecommendAppInstallLocation("install.apk",
+                R.raw.install_loc_unspecified, PackageManager.INSTALL_ON_INTERNAL_FLASH);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SET_INSTALL_LOCATION, 0);
+    }
+
     /*
      * TODO's
      * check version numbers for upgrades