Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7912a29c authored by Oscar Montemayor's avatar Oscar Montemayor Committed by Android (Google) Code Review
Browse files

Merge "Apps on SD card project. Refactored recommendAppInstallLocation(..)...

Merge "Apps on SD card project. Refactored recommendAppInstallLocation(..) method in PackageManager by making it an instance method. Since PackageManager has only abstarct instance methods, moved implementation to ApplicationContext.ApplicationPackageManager class, in line with the rest of the method implementations. Tah way, chage is consistent with best coding practices. Also MockPackageManager received the additional method."
parents 9205b2ef 539d3c47
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -80,6 +81,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
import android.os.Vibrator;
import android.os.FileUtils.FileStatus;
import android.telephony.TelephonyManager;
@@ -2537,6 +2539,76 @@ class ApplicationContext extends Context {
            return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
        }

        // Constants related to app heuristics
        // No-installation limit for internal flash: 10% or less space available
        private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;

        // 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) {
            // 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)) {
                return INSTALL_PARSE_FAILED_NOT_APK;
            }

            StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath());
            StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath());

            long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() *
                    (long)internalFlashStats.getBlockSize();
            long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() *
                    (long)internalFlashStats.getBlockSize();
            long availSDSize = (long)sdcardStats.getAvailableBlocks() *
                    (long)sdcardStats.getBlockSize();

            double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;

            final String archiveFilePath = packageURI.getPath();
            File apkFile = new File(archiveFilePath);
            long pkgLen = apkFile.length();

            // 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;
                }
                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;
                }
            }
        }

        private final ApplicationContext mContext;
        private final IPackageManager mPM;

+17 −77
Original line number Diff line number Diff line
@@ -260,6 +260,13 @@ public abstract class PackageManager {
     */
    public static final int INSTALL_ON_SDCARD = 0x00000008;

    /**
     * Convenience flag parameter to indicate that this package has to be installed
     * on internal flash.
     * @hide
     */
    public static final int INSTALL_ON_INTERNAL_FLASH = 0x00000000;

    /**
     * Flag parameter for
     * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
@@ -605,88 +612,21 @@ public abstract class PackageManager {
    @SdkConstant(SdkConstantType.FEATURE)
    public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";

    // No-installation limit for internal flash: 10% or less space available
    private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;

    // SD-to-internal app size threshold: currently set to 1 MB
    private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);

    private static final int INSTALL_ON_INTERNAL_FLASH = 0;

    /**
     * Determines best place to install an application: either SD or internal FLASH.
     * Tweak the algorithm for best results.
     * @param tmpPackageFile APK file containing the application to install.
     * @return <code>PKG_INSTALL_INTERNAL</code> if it is best to install package on internal
     * storage, <code>PKG_INSTALL_ON_SD</code> if it is best to install package on SD card,
     * and <code>PKG_CANNOT_FIT</code> if insufficient space to safely install the app.
     * This response does not take into account the package's own flags.
     * @param appInfo ApplicationInfo object og the package to install.
     * Call utility method to obtain.
     * @param packageURI URI identifying the package's APK file.
     * @return <code>INSTALL_ON_INTERNAL_FLASH</code> if it is best to install package on internal
     * storage, <code>INSTALL_ON_SDCARD</code> if it is best to install package on SD card,
     * and <code>INSTALL_FAILED_INSUFFICIENT_STORAGE</code> if insufficient space to safely install
     * the application. <code>INSTALL_PARSE_FAILED_NOT_APK</code> Is returned if any input
     * parameter is <code>null</code>.
     * This recommendation does take into account the package's own flags.
     * @hide
     */
    public static int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
        // 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 5%
        // 0 = install on internal FLASH
        // 1 = install on SD card
        // (-1) = insufficient space - package cannot be installed.

        if ((packageURI == null) || (appInfo == null)) {
            return (-1);
        }

        StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath());
        StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath());

        long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() *
                (long)internalFlashStats.getBlockSize();
        long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() *
                (long)internalFlashStats.getBlockSize();
        long availSDSize = (long)sdcardStats.getAvailableBlocks() *
                (long)sdcardStats.getBlockSize();

        double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;

        final String archiveFilePath = packageURI.getPath();
        File apkFile = new File(archiveFilePath);
        long pkgLen = apkFile.length();

        // 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 (-1);
        }

        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;
            }
            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 (-1);
            }
        }
    }
    public abstract int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI);

    /**
     * Retrieve overall information about an application package that is
+8 −0
Original line number Diff line number Diff line
@@ -438,4 +438,12 @@ public class MockPackageManager extends PackageManager {
    public boolean isSafeMode() {
        throw new UnsupportedOperationException();
    }

    /**
     * @hide
     */
    @Override
    public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) {
        throw new UnsupportedOperationException();
    }
}