/* * Copyright (C) 2016 Blue Jay Wireless * Copyright (C) 2016 Dominik Schürmann <dominik@dominikschuermann.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.fdroid.fdroid.installer; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.net.Uri; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Apk; import java.io.File; import java.io.FileFilter; /** * This service handles the install process of apk files and * uninstall process of apps. * <p> * This service is based on an IntentService because: * - no parallel installs/uninstalls should be allowed, * i.e., runs sequentially * - no cancel operation is needed. Cancelling an installation * would be the same as starting uninstall afterwards * <p> * The download URL is only used as the unique ID that represents this * particular apk throughout the whole install process in * {@link InstallManagerService}. * <p> * This also handles deleting any associated OBB files when an app is * uninstalled, as per the * <a href="https://developer.android.com/google/play/expansion-files.html"> * APK Expansion Files</a> spec. */ public class InstallerService extends IntentService { public static final String TAG = "InstallerService"; private static final String ACTION_INSTALL = "org.fdroid.fdroid.installer.InstallerService.action.INSTALL"; private static final String ACTION_UNINSTALL = "org.fdroid.fdroid.installer.InstallerService.action.UNINSTALL"; public InstallerService() { super("InstallerService"); } @Override protected void onHandleIntent(Intent intent) { final Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK); if (apk == null) { Utils.debugLog(TAG, "ignoring intent with null EXTRA_APK: " + intent); return; } Installer installer = InstallerFactory.create(this, apk); if (ACTION_INSTALL.equals(intent.getAction())) { Uri uri = intent.getData(); Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI); installer.installPackage(uri, downloadUri); } else if (ACTION_UNINSTALL.equals(intent.getAction())) { installer.uninstallPackage(); new Thread() { @Override public void run() { setPriority(MIN_PRIORITY); File mainObbFile = apk.getMainObbFile(); if (mainObbFile == null) { return; } File obbDir = mainObbFile.getParentFile(); if (obbDir == null) { return; } FileFilter filter = new WildcardFileFilter("*.obb"); File[] obbFiles = obbDir.listFiles(filter); if (obbFiles == null) { return; } for (File f : obbFiles) { Utils.debugLog(TAG, "Uninstalling OBB " + f); FileUtils.deleteQuietly(f); } } }.start(); } } /** * Install an apk from {@link Uri} * * @param context this app's {@link Context} * @param localApkUri {@link Uri} pointing to (downloaded) local apk file * @param downloadUri {@link Uri} where the apk has been downloaded from * @param apk apk object of app that should be installed */ public static void install(Context context, Uri localApkUri, Uri downloadUri, Apk apk) { Intent intent = new Intent(context, InstallerService.class); intent.setAction(ACTION_INSTALL); intent.setData(localApkUri); intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri); intent.putExtra(Installer.EXTRA_APK, apk); context.startService(intent); } /** * Uninstall an app * * @param context this app's {@link Context} * @param apk {@link Apk} instance of the app that will be uninstalled */ public static void uninstall(Context context, Apk apk) { Intent intent = new Intent(context, InstallerService.class); intent.setAction(ACTION_UNINSTALL); intent.putExtra(Installer.EXTRA_APK, apk); context.startService(intent); } }