/**
   * 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 DeviceNotAvailableException
   */
  private void doStandardInstall(
      String apkName, String pkgName, PackageManagerHostTestUtils.InstallLocation expectedLocation)
      throws DeviceNotAvailableException {

    if (expectedLocation == PackageManagerHostTestUtils.InstallLocation.DEVICE) {
      mPMHostUtils.installAppAndVerifyExistsOnDevice(getTestAppFilePath(apkName), pkgName, false);
    } else {
      mPMHostUtils.installAppAndVerifyExistsOnSDCard(getTestAppFilePath(apkName), pkgName, false);
    }
  }
  /**
   * 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.
   */
  public void testInstallFwdLockedAppExternal() throws Exception {
    Log.i(LOG_TAG, "Test an app with installLoc set to Internal gets installed to app-private");

    try {
      mPMHostUtils.installFwdLockedAppAndVerifyExists(
          getTestAppFilePath(EXTERNAL_LOC_APK), EXTERNAL_LOC_PKG, false);
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(EXTERNAL_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.
   */
  public void testInstallFwdLockedAppNone() throws Exception {
    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);
    }
  }
  // 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()
  // accept a installLocation flag so we can install a package to the
  // destination of our choosing.
  public void testReinstallInternalToExternal() throws Exception {
    Log.i(LOG_TAG, "Test installing an app first to the device, then to the SD Card");

    try {
      mPMHostUtils.installAppAndVerifyExistsOnDevice(
          getTestAppFilePath(VERSATILE_LOC_INTERNAL_APK), VERSATILE_LOC_PKG, false);
      mPMHostUtils.uninstallApp(VERSATILE_LOC_PKG);
      mPMHostUtils.installAppAndVerifyExistsOnSDCard(
          getTestAppFilePath(VERSATILE_LOC_EXTERNAL_APK), VERSATILE_LOC_PKG, false);
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(VERSATILE_LOC_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.
   */
  public void testInstallAndLaunchAllPermsAppOnSD() throws Exception {
    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 BLUE_TOOTH permissions can run without permissions
   * errors.
   *
   * <p>Assumes adb is running as root in device under test.
   */
  public void testInstallAndLaunchBTPermsAppOnSD() throws Exception {
    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 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.
   */
  public void testUpdateToSDCard() throws Exception {
    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(UPDATE_EXTERNAL_LOC_V1_EXT_APK), UPDATE_EXTERNAL_LOC_PKG, false);
      // now replace the app with one where the location is blank (app should stay external)
      mPMHostUtils.installAppAndVerifyExistsOnSDCard(
          getTestAppFilePath(UPDATE_EXTERNAL_LOC_V2_NONE_APK), UPDATE_EXTERNAL_LOC_PKG, true);
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(UPDATE_EXTERNAL_LOC_PKG);
    }
  }
  @Override
  protected void setUp() throws Exception {
    super.setUp();
    // ensure apk path has been set before test is run
    assertNotNull("Missing --app-repository-path option", mAppRepositoryPath);

    // setup the PackageManager host tests utilities class, and get various paths we'll need...
    mPMHostUtils = new PackageManagerHostTestUtils(getDevice());
    mPMHostUtils.determinePrivateAppPath(getTestAppFilePath(INTERNAL_LOC_APK), INTERNAL_LOC_PKG);

    // 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);
  }
  /**
   * 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.
   */
  public void testInstallAndUpdateExternalLocForwardLockedApp() throws Exception {
    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.
   */
  public void testInstallAndUpdateNoLocForwardLockedApp() throws Exception {
    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 updating an app on the SD card will install the update onto the
   * device if the manifest has changed to installLocation=internalOnly
   *
   * <p>Assumes adb is running as root in device under test.
   */
  public void testUpdateSDCardToDevice() throws Exception {
    Log.i(LOG_TAG, "Test updating an app on the SD card to the Device through manifest change");

    try {
      // 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...(should move internal)
      mPMHostUtils.installAppAndVerifyExistsOnDevice(
          getTestAppFilePath(UPDATE_EXT_TO_INT_LOC_V2_INT_APK), UPDATE_EXT_TO_INT_LOC_PKG, true);
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(UPDATE_EXT_TO_INT_LOC_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 set to external for both versions
   *
   * <p>Assumes adb is running as root in device under test.
   */
  public void testUpdateBothExternal() throws Exception {
    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);
    }
  }
  // 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()
  // accept a installLocation flag so we can install a package to the
  // destination of our choosing.
  public void testReinstallExternalToInternal() throws Exception {
    Log.i(LOG_TAG, "Test installing an app first to the SD Care, then to the device");

    try {
      // install the app externally
      mPMHostUtils.installAppAndVerifyExistsOnSDCard(
          getTestAppFilePath(VERSATILE_LOC_EXTERNAL_APK), VERSATILE_LOC_PKG, false);
      mPMHostUtils.uninstallApp(VERSATILE_LOC_PKG);
      // then replace the app with one marked for internalOnly
      mPMHostUtils.installAppAndVerifyExistsOnDevice(
          getTestAppFilePath(VERSATILE_LOC_INTERNAL_APK), VERSATILE_LOC_PKG, false);
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(VERSATILE_LOC_PKG);
    }
  }
 /**
  * Installing encrypted apk on SDCard works.
  *
  * @throws Exception
  */
 public void testEncryptedAppOnSdcard() throws Exception {
   if (mPMHostUtils.getIsExternalStorageEmulated()) {
     return;
   }
   PackageManagerHostTestUtils.InstallLocPreference preference =
       PackageManagerHostTestUtils.InstallLocPreference.EXTERNAL;
   PackageManagerHostTestUtils.InstallLocPreference savedPref =
       PackageManagerHostTestUtils.InstallLocPreference.AUTO;
   try {
     savedPref = mPMHostUtils.getDevicePreferredInstallLocation();
     mPMHostUtils.setDevicePreferredInstallLocation(preference);
     mPMHostUtils.installEncryptedAppAndVerifyExists(
         getTestAppFilePath(SIMPLE_ENCRYPTED_APK),
         SIMPLE_PKG,
         true,
         ENCRYPTION_ALGO,
         ENCRYPTION_IV,
         ENCRYPTION_KEY,
         MAC_ALGO,
         MAC_KEY,
         MAC_TAG);
     assert (mPMHostUtils.appExistsAsEncrypted(SIMPLE_PKG, true));
   }
   // cleanup test app
   finally {
     mPMHostUtils.setDevicePreferredInstallLocation(savedPref);
     mPMHostUtils.uninstallApp(SIMPLE_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.
   */
  public void testInstallAndLaunchSharedPermsAppOnSD_Reboot() throws Exception {
    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
      getDevice().reboot();

      // 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);
    }
  }
  /**
   * 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.
   */
  public void testInstallAppNoLocPrefIsAuto() throws Exception {
    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 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.
   */
  public void testInstallAndLaunchSharedPermsAppOnSD_NoPerms() throws Exception {
    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);
    }
  }
  /**
   * 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
   */
  public void installAppInternalLoc(
      PackageManagerHostTestUtils.InstallLocPreference preference,
      PackageManagerHostTestUtils.InstallLocation expectedLocation)
      throws Exception {

    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);
    }
  }
  /**
   * Test that ensures we are able to install an encrypted apk, and that the resulting files are in
   * the correct location.
   *
   * <p>Assumes adb is running as root in device under test.
   *
   * @throws Exception
   */
  public void testInstallEncryptedApp() throws Exception {
    Log.i(LOG_TAG, "Test an encrypted app works as intended.");

    try {
      mPMHostUtils.installEncryptedAppAndVerifyExists(
          getTestAppFilePath(SIMPLE_ENCRYPTED_APK),
          SIMPLE_PKG,
          true,
          ENCRYPTION_ALGO,
          ENCRYPTION_IV,
          ENCRYPTION_KEY,
          MAC_ALGO,
          MAC_KEY,
          MAC_TAG);
      assert (mPMHostUtils.appExistsAsEncrypted(SIMPLE_PKG, false));
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(SIMPLE_PKG);
    }
  }
  /**
   * 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 DeviceNotAvailableException
   */
  public void installAppAutoLoc(
      PackageManagerHostTestUtils.InstallLocPreference preference,
      PackageManagerHostTestUtils.InstallLocation expectedLocation)
      throws IOException, InterruptedException, TimeoutException, AdbCommandRejectedException,
          ShellCommandUnresponsiveException, InstallException, DeviceNotAvailableException {

    PackageManagerHostTestUtils.InstallLocPreference savedPref =
        PackageManagerHostTestUtils.InstallLocPreference.AUTO;

    try {
      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);
    }
  }
  /**
   * Test that ensures an update on the app from non-encrypted to encrypted works.
   *
   * <p>
   *
   * @throws Exception
   */
  public void testUpdateEncryptedApp() throws Exception {
    Log.i(LOG_TAG, "Test the update of an app which becomes encrypted works as intended.");

    try {
      // cleanup test app just in case it was accidently installed
      getDevice().uninstallPackage(SIMPLE_PKG);
      getDevice().executeShellCommand("stop");

      getDevice().executeShellCommand("start");

      mPMHostUtils.waitForPackageManager();

      mPMHostUtils.installFile(getTestAppFilePath(SIMPLE_APK), false);
      Assert.assertFalse(mPMHostUtils.appExistsAsEncrypted(SIMPLE_PKG, false));

      mPMHostUtils.installEncryptedAppAndVerifyExists(
          getTestAppFilePath(SIMPLE_ENCRYPTED_APK),
          SIMPLE_PKG,
          true,
          ENCRYPTION_ALGO,
          ENCRYPTION_IV,
          ENCRYPTION_KEY,
          MAC_ALGO,
          MAC_KEY,
          MAC_TAG);
      assert (mPMHostUtils.appExistsAsEncrypted(SIMPLE_PKG, false));
    }
    // cleanup test app
    finally {
      mPMHostUtils.uninstallApp(SIMPLE_PKG);
    }
  }
  /**
   * Regression test to verify that pushing an apk to the private app directory doesn't install the
   * app, and otherwise cause the system to blow up.
   *
   * <p>Assumes adb is running as root in device under test.
   *
   * @throws DeviceNotAvailableException
   */
  public void testPushAppPrivate()
      throws IOException, InterruptedException, InstallException, TimeoutException,
          AdbCommandRejectedException, ShellCommandUnresponsiveException, SyncException,
          DeviceNotAvailableException {
    Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
    final String apkAppPrivatePath = PackageManagerHostTestUtils.getAppPrivatePath() + SIMPLE_APK;

    // cleanup test app just in case it was accidently installed
    getDevice().uninstallPackage(SIMPLE_PKG);
    getDevice().executeShellCommand("stop");
    getDevice().pushFile(getTestAppFilePath(SIMPLE_APK), apkAppPrivatePath);

    // sanity check to make sure file is there
    assertTrue(getDevice().doesFileExist(apkAppPrivatePath));
    getDevice().executeShellCommand("start");

    mPMHostUtils.waitForPackageManager();

    // grep for package to make sure its not installed
    assertFalse(mPMHostUtils.doesPackageExist(SIMPLE_PKG));
    // TODO: Is the apk supposed to uninstall itself?
    // ensure it has been deleted from app-private
    // assertFalse(getDevice().doesFileExist(apkAppPrivatePath));
  }