use download URL as unique ID through the whole install process
InstallManagerService and DownloaderService both use the download URL as the unique ID to represent a given APK install through the whole lifecycle of the install and download process. This converts the installer stuff to use the same semantics. A Uri instance is mostly used there because its the most useful format, but ultimately, the String, Uri, and int all derive from the exact same URL. This then removes the local APK URI from use in the installer broadcasts. While I normally think reusing terms from Android is the best thing to do, "originating URI" drives me nuts because it is almost nonsense English. "Originating" is a verb in the continuous form, meaning that it is an action that is ongoing. A URI is a static thing, and in this case, a URI that points to a file that is completely downloaded. I left the term in place for DefaultInstaller because it wraps PackageManager, which is where that term originates. This handles "Use strings instead of Uris in InstallManagerService for urlString" as listed in #680
This commit is contained in:
parent
9c1b917604
commit
9d2fe4000d
@ -85,14 +85,13 @@ import org.fdroid.fdroid.data.App;
|
|||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
|
||||||
import org.fdroid.fdroid.installer.InstallManagerService;
|
import org.fdroid.fdroid.installer.InstallManagerService;
|
||||||
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
import org.fdroid.fdroid.installer.InstallerFactory;
|
import org.fdroid.fdroid.installer.InstallerFactory;
|
||||||
import org.fdroid.fdroid.installer.InstallerService;
|
import org.fdroid.fdroid.installer.InstallerService;
|
||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
import org.fdroid.fdroid.net.DownloaderService;
|
import org.fdroid.fdroid.net.DownloaderService;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -530,11 +529,8 @@ public class AppDetails extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
cleanUpFinishedDownload();
|
cleanUpFinishedDownload();
|
||||||
|
|
||||||
Uri localUri =
|
|
||||||
Uri.fromFile(new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH)));
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(localUri));
|
Installer.getInstallIntentFilter(intent.getData()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,34 +45,34 @@ public class DefaultInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "DefaultInstaller uri: " + uri + " file: " + new File(uri.getPath()));
|
Utils.debugLog(TAG, "DefaultInstaller uri: " + localApkUri + " file: " + new File(localApkUri.getPath()));
|
||||||
|
|
||||||
Uri sanitizedUri;
|
Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (Installer.InstallFailedException e) {
|
} catch (Installer.InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
|
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
|
||||||
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
|
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
|
||||||
installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri);
|
installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
|
||||||
installIntent.setData(sanitizedUri);
|
installIntent.setData(sanitizedUri);
|
||||||
|
|
||||||
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
||||||
context.getApplicationContext(),
|
context.getApplicationContext(),
|
||||||
uri.hashCode(),
|
localApkUri.hashCode(),
|
||||||
installIntent,
|
installIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
sendBroadcastInstall(uri, originatingUri,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION,
|
||||||
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
installPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,14 +42,11 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
public static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.UNINSTALL_PACKAGE";
|
public static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.UNINSTALL_PACKAGE";
|
||||||
|
|
||||||
public static final String EXTRA_UNINSTALL_PACKAGE_NAME = "uninstallPackageName";
|
public static final String EXTRA_UNINSTALL_PACKAGE_NAME = "uninstallPackageName";
|
||||||
public static final String EXTRA_ORIGINATING_URI = "originatingUri";
|
|
||||||
|
|
||||||
private static final int REQUEST_CODE_INSTALL = 0;
|
private static final int REQUEST_CODE_INSTALL = 0;
|
||||||
private static final int REQUEST_CODE_UNINSTALL = 1;
|
private static final int REQUEST_CODE_UNINSTALL = 1;
|
||||||
|
|
||||||
private Uri installOriginatingUri;
|
private Uri downloadUri;
|
||||||
private Uri installUri;
|
|
||||||
|
|
||||||
private String uninstallPackageName;
|
private String uninstallPackageName;
|
||||||
|
|
||||||
// for the broadcasts
|
// for the broadcasts
|
||||||
@ -64,10 +61,9 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (ACTION_INSTALL_PACKAGE.equals(action)) {
|
if (ACTION_INSTALL_PACKAGE.equals(action)) {
|
||||||
installUri = intent.getData();
|
Uri localApkUri = intent.getData();
|
||||||
installOriginatingUri = intent.getParcelableExtra(EXTRA_ORIGINATING_URI);
|
downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
|
||||||
|
installPackage(localApkUri);
|
||||||
installPackage(installUri, installOriginatingUri);
|
|
||||||
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
|
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
|
||||||
uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME);
|
uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME);
|
||||||
|
|
||||||
@ -78,7 +74,7 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private void installPackage(Uri uri, Uri originatingUri) {
|
private void installPackage(Uri uri) {
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
throw new RuntimeException("Set the data uri to point to an apk location!");
|
throw new RuntimeException("Set the data uri to point to an apk location!");
|
||||||
}
|
}
|
||||||
@ -121,12 +117,11 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
startActivityForResult(intent, REQUEST_CODE_INSTALL);
|
startActivityForResult(intent, REQUEST_CODE_INSTALL);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Log.e(TAG, "ActivityNotFoundException", e);
|
Log.e(TAG, "ActivityNotFoundException", e);
|
||||||
installer.sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
"This Android rom does not support ACTION_INSTALL_PACKAGE!");
|
"This Android rom does not support ACTION_INSTALL_PACKAGE!");
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
Installer.ACTION_INSTALL_STARTED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void uninstallPackage(String packageName) {
|
protected void uninstallPackage(String packageName) {
|
||||||
@ -172,31 +167,29 @@ public class DefaultInstallerActivity extends FragmentActivity {
|
|||||||
* never executed on Androids < 4.0
|
* never executed on Androids < 4.0
|
||||||
*/
|
*/
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631
|
// Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631
|
||||||
if ("N".equals(Build.VERSION.CODENAME)) {
|
if ("N".equals(Build.VERSION.CODENAME)) {
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case Activity.RESULT_OK:
|
case Activity.RESULT_OK:
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_COMPLETE);
|
Installer.ACTION_INSTALL_COMPLETE);
|
||||||
break;
|
break;
|
||||||
case Activity.RESULT_CANCELED:
|
case Activity.RESULT_CANCELED:
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_INTERRUPTED);
|
Installer.ACTION_INSTALL_INTERRUPTED);
|
||||||
break;
|
break;
|
||||||
case Activity.RESULT_FIRST_USER:
|
case Activity.RESULT_FIRST_USER:
|
||||||
default:
|
default:
|
||||||
// AOSP returns Activity.RESULT_FIRST_USER on error
|
// AOSP returns Activity.RESULT_FIRST_USER on error
|
||||||
installer.sendBroadcastInstall(installUri, installOriginatingUri,
|
installer.sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_INTERRUPTED,
|
Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
getString(R.string.install_error_unknown));
|
getString(R.string.install_error_unknown));
|
||||||
break;
|
break;
|
||||||
|
@ -46,14 +46,13 @@ public class ExtensionInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
|
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
Uri sanitizedUri;
|
Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (InstallFailedException e) {
|
} catch (InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage());
|
||||||
e.getMessage());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ public class ExtensionInstaller extends Installer {
|
|||||||
// NOTE: Disabled for debug builds to be able to use official extension from repo
|
// NOTE: Disabled for debug builds to be able to use official extension from repo
|
||||||
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context);
|
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context);
|
||||||
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
|
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
"APK signature of extension not correct!");
|
"APK signature of extension not correct!");
|
||||||
}
|
}
|
||||||
Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class);
|
Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class);
|
||||||
@ -70,15 +69,15 @@ public class ExtensionInstaller extends Installer {
|
|||||||
|
|
||||||
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
PendingIntent installPendingIntent = PendingIntent.getActivity(
|
||||||
context.getApplicationContext(),
|
context.getApplicationContext(),
|
||||||
uri.hashCode(),
|
localApkUri.hashCode(),
|
||||||
installIntent,
|
installIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
sendBroadcastInstall(uri, originatingUri,
|
sendBroadcastInstall(downloadUri,
|
||||||
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
|
||||||
|
|
||||||
// don't use broadcasts for the rest of this special installer
|
// don't use broadcasts for the rest of this special installer
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_COMPLETE);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,8 +55,10 @@ import java.util.Set;
|
|||||||
* <li>for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()}
|
* <li>for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()}
|
||||||
* <li>for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or
|
* <li>for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or
|
||||||
* {@link Intent#getDataString()}
|
* {@link Intent#getDataString()}
|
||||||
* <li>for an {@code int} ID, use {@link String#hashCode()}
|
* <li>for an {@code int} ID, use {@link String#hashCode()} or {@link Uri#hashCode()}
|
||||||
* </ul></p>
|
* </ul></p>
|
||||||
|
* The implementations of {@link Uri#toString()} and {@link Intent#getDataString()} both
|
||||||
|
* include caching of the generated {@code String}, so it should be plenty fast.
|
||||||
*/
|
*/
|
||||||
public class InstallManagerService extends Service {
|
public class InstallManagerService extends Service {
|
||||||
public static final String TAG = "InstallManagerService";
|
public static final String TAG = "InstallManagerService";
|
||||||
@ -154,7 +156,7 @@ public class InstallManagerService extends Service {
|
|||||||
Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK));
|
Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK));
|
||||||
addToActive(urlString, app, apk);
|
addToActive(urlString, app, apk);
|
||||||
|
|
||||||
NotificationCompat.Builder builder = createNotificationBuilder(intent.getDataString(), apk);
|
NotificationCompat.Builder builder = createNotificationBuilder(urlString, apk);
|
||||||
notificationManager.notify(urlString.hashCode(), builder.build());
|
notificationManager.notify(urlString.hashCode(), builder.build());
|
||||||
|
|
||||||
registerDownloaderReceivers(urlString, builder);
|
registerDownloaderReceivers(urlString, builder);
|
||||||
@ -224,18 +226,18 @@ public class InstallManagerService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
// elsewhere called urlString
|
// elsewhere called urlString
|
||||||
Uri originatingUri = intent.getData();
|
Uri downloadUri = intent.getData();
|
||||||
|
String urlString = downloadUri.toString();
|
||||||
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
|
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
|
||||||
Uri localUri = Uri.fromFile(localFile);
|
Uri localApkUri = Uri.fromFile(localFile);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "download completed of " + originatingUri
|
Utils.debugLog(TAG, "download completed of " + urlString + " to " + localApkUri);
|
||||||
+ " to " + localUri);
|
|
||||||
|
|
||||||
unregisterDownloaderReceivers(intent.getDataString());
|
unregisterDownloaderReceivers(urlString);
|
||||||
|
registerInstallerReceivers(downloadUri);
|
||||||
|
|
||||||
registerInstallerReceivers(localUri);
|
Apk apk = ACTIVE_APKS.get(urlString);
|
||||||
Apk apk = ACTIVE_APKS.get(originatingUri.toString());
|
InstallerService.install(context, localApkUri, downloadUri, apk.packageName);
|
||||||
InstallerService.install(context, localUri, originatingUri, apk.packageName);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BroadcastReceiver interruptedReceiver = new BroadcastReceiver() {
|
BroadcastReceiver interruptedReceiver = new BroadcastReceiver() {
|
||||||
@ -262,19 +264,18 @@ public class InstallManagerService extends Service {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerInstallerReceivers(Uri uri) {
|
private void registerInstallerReceivers(Uri downloadUri) {
|
||||||
|
|
||||||
BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
|
String downloadUrl = intent.getDataString();
|
||||||
|
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
case Installer.ACTION_INSTALL_STARTED:
|
case Installer.ACTION_INSTALL_STARTED:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
break;
|
break;
|
||||||
case Installer.ACTION_INSTALL_COMPLETE:
|
case Installer.ACTION_INSTALL_COMPLETE:
|
||||||
Apk apkComplete = removeFromActive(originatingUri.toString());
|
Apk apkComplete = removeFromActive(downloadUrl);
|
||||||
|
|
||||||
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
|
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
|
||||||
|
|
||||||
@ -286,16 +287,16 @@ public class InstallManagerService extends Service {
|
|||||||
|
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (!TextUtils.isEmpty(errorMessage)) {
|
if (!TextUtils.isEmpty(errorMessage)) {
|
||||||
App app = getAppFromActive(originatingUri.toString());
|
App app = getAppFromActive(downloadUrl);
|
||||||
String title = String.format(
|
String title = String.format(
|
||||||
getString(R.string.install_error_notify_title),
|
getString(R.string.install_error_notify_title),
|
||||||
app.name);
|
app.name);
|
||||||
|
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (AppDetails.isAppVisible(app.packageName)) {
|
if (AppDetails.isAppVisible(app.packageName)) {
|
||||||
cancelNotification(originatingUri.toString());
|
cancelNotification(downloadUrl);
|
||||||
} else {
|
} else {
|
||||||
notifyError(originatingUri.toString(), title, errorMessage);
|
notifyError(downloadUrl, title, errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,12 +306,12 @@ public class InstallManagerService extends Service {
|
|||||||
PendingIntent installPendingIntent =
|
PendingIntent installPendingIntent =
|
||||||
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
|
||||||
|
|
||||||
Apk apkUserInteraction = getApkFromActive(originatingUri.toString());
|
Apk apkUserInteraction = getApkFromActive(downloadUrl);
|
||||||
// show notification if app details is not visible
|
// show notification if app details is not visible
|
||||||
if (AppDetails.isAppVisible(apkUserInteraction.packageName)) {
|
if (AppDetails.isAppVisible(apkUserInteraction.packageName)) {
|
||||||
cancelNotification(originatingUri.toString());
|
cancelNotification(downloadUrl);
|
||||||
} else {
|
} else {
|
||||||
notifyDownloadComplete(apkUserInteraction, originatingUri.toString(), installPendingIntent);
|
notifyDownloadComplete(apkUserInteraction, downloadUrl, installPendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -321,7 +322,7 @@ public class InstallManagerService extends Service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(uri));
|
Installer.getInstallIntentFilter(downloadUri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) {
|
private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) {
|
||||||
|
@ -64,10 +64,14 @@ public abstract class Installer {
|
|||||||
public static final String ACTION_UNINSTALL_USER_INTERACTION = "org.fdroid.fdroid.installer.Installer.action.UNINSTALL_USER_INTERACTION";
|
public static final String ACTION_UNINSTALL_USER_INTERACTION = "org.fdroid.fdroid.installer.Installer.action.UNINSTALL_USER_INTERACTION";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as http://developer.android.com/reference/android/content/Intent.html#EXTRA_ORIGINATING_URI
|
* The URI where the APK was originally downloaded from. This is also used
|
||||||
* In InstallManagerService often called urlString
|
* as the unique ID representing this in the whole install process in
|
||||||
|
* {@link InstallManagerService}, there is is generally known as the
|
||||||
|
* "download URL" since it is the URL used to download the APK.
|
||||||
|
*
|
||||||
|
* @see Intent#EXTRA_ORIGINATING_URI
|
||||||
*/
|
*/
|
||||||
public static final String EXTRA_ORIGINATING_URI = "org.fdroid.fdroid.installer.Installer.extra.ORIGINATING_URI";
|
static final String EXTRA_DOWNLOAD_URI = "org.fdroid.fdroid.installer.Installer.extra.DOWNLOAD_URI";
|
||||||
public static final String EXTRA_PACKAGE_NAME = "org.fdroid.fdroid.installer.Installer.extra.PACKAGE_NAME";
|
public static final String EXTRA_PACKAGE_NAME = "org.fdroid.fdroid.installer.Installer.extra.PACKAGE_NAME";
|
||||||
public static final String EXTRA_USER_INTERACTION_PI = "org.fdroid.fdroid.installer.Installer.extra.USER_INTERACTION_PI";
|
public static final String EXTRA_USER_INTERACTION_PI = "org.fdroid.fdroid.installer.Installer.extra.USER_INTERACTION_PI";
|
||||||
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.installer.Installer.extra.ERROR_MESSAGE";
|
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.installer.Installer.extra.ERROR_MESSAGE";
|
||||||
@ -238,24 +242,23 @@ public abstract class Installer {
|
|||||||
return hasher.match(hash);
|
return hasher.match(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
|
public void sendBroadcastInstall(Uri downloadUri, String action,
|
||||||
PendingIntent pendingIntent) {
|
PendingIntent pendingIntent) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, pendingIntent, null);
|
sendBroadcastInstall(downloadUri, action, pendingIntent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action) {
|
public void sendBroadcastInstall(Uri downloadUri, String action) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, null, null);
|
sendBroadcastInstall(downloadUri, action, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action, String errorMessage) {
|
public void sendBroadcastInstall(Uri downloadUri, String action, String errorMessage) {
|
||||||
sendBroadcastInstall(uri, originatingUri, action, null, errorMessage);
|
sendBroadcastInstall(downloadUri, action, null, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
|
public void sendBroadcastInstall(Uri downloadUri, String action,
|
||||||
PendingIntent pendingIntent, String errorMessage) {
|
PendingIntent pendingIntent, String errorMessage) {
|
||||||
Intent intent = new Intent(action);
|
Intent intent = new Intent(action);
|
||||||
intent.setData(uri);
|
intent.setData(downloadUri);
|
||||||
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
|
|
||||||
intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent);
|
intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent);
|
||||||
if (!TextUtils.isEmpty(errorMessage)) {
|
if (!TextUtils.isEmpty(errorMessage)) {
|
||||||
intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage);
|
intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage);
|
||||||
@ -312,10 +315,20 @@ public abstract class Installer {
|
|||||||
return intentFilter;
|
return intentFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void installPackage(Uri uri, Uri originatingUri, String packageName);
|
/**
|
||||||
|
* @param localApkUri points to the local copy of the APK to be installed
|
||||||
|
* @param downloadUri serves as the unique ID for all actions related to the
|
||||||
|
* installation of that specific APK
|
||||||
|
* @param packageName package name of the app that should be installed
|
||||||
|
*/
|
||||||
|
protected abstract void installPackage(Uri localApkUri, Uri downloadUri, String packageName);
|
||||||
|
|
||||||
protected abstract void uninstallPackage(String packageName);
|
protected abstract void uninstallPackage(String packageName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This {@link Installer} instance is capable of "unattended" install and
|
||||||
|
* uninstall activities, without the system enforcing a user prompt.
|
||||||
|
*/
|
||||||
protected abstract boolean isUnattended();
|
protected abstract boolean isUnattended();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,10 @@ import android.net.Uri;
|
|||||||
* i.e., runs sequentially
|
* i.e., runs sequentially
|
||||||
* - no cancel operation is needed. Cancelling an installation
|
* - no cancel operation is needed. Cancelling an installation
|
||||||
* would be the same as starting uninstall afterwards
|
* 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}.
|
||||||
*/
|
*/
|
||||||
public class InstallerService extends IntentService {
|
public class InstallerService extends IntentService {
|
||||||
|
|
||||||
@ -50,9 +54,8 @@ public class InstallerService extends IntentService {
|
|||||||
|
|
||||||
if (ACTION_INSTALL.equals(intent.getAction())) {
|
if (ACTION_INSTALL.equals(intent.getAction())) {
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
|
Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
|
||||||
|
installer.installPackage(uri, downloadUri, packageName);
|
||||||
installer.installPackage(uri, originatingUri, packageName);
|
|
||||||
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
|
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
|
||||||
installer.uninstallPackage(packageName);
|
installer.uninstallPackage(packageName);
|
||||||
}
|
}
|
||||||
@ -61,16 +64,16 @@ public class InstallerService extends IntentService {
|
|||||||
/**
|
/**
|
||||||
* Install an apk from {@link Uri}
|
* Install an apk from {@link Uri}
|
||||||
*
|
*
|
||||||
* @param context this app's {@link Context}
|
* @param context this app's {@link Context}
|
||||||
* @param uri {@link Uri} pointing to (downloaded) local apk file
|
* @param localApkUri {@link Uri} pointing to (downloaded) local apk file
|
||||||
* @param originatingUri {@link Uri} where the apk has been downloaded from
|
* @param downloadUri {@link Uri} where the apk has been downloaded from
|
||||||
* @param packageName package name of the app that should be installed
|
* @param packageName package name of the app that should be installed
|
||||||
*/
|
*/
|
||||||
public static void install(Context context, Uri uri, Uri originatingUri, String packageName) {
|
public static void install(Context context, Uri localApkUri, Uri downloadUri, String packageName) {
|
||||||
Intent intent = new Intent(context, InstallerService.class);
|
Intent intent = new Intent(context, InstallerService.class);
|
||||||
intent.setAction(ACTION_INSTALL);
|
intent.setAction(ACTION_INSTALL);
|
||||||
intent.setData(uri);
|
intent.setData(localApkUri);
|
||||||
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
|
intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
|
||||||
intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName);
|
intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
@ -297,15 +297,15 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installPackage(final Uri uri, final Uri originatingUri, String packageName) {
|
protected void installPackage(final Uri localApkUri, final Uri downloadUri, String packageName) {
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
|
||||||
|
|
||||||
final Uri sanitizedUri;
|
final Uri sanitizedUri;
|
||||||
try {
|
try {
|
||||||
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
|
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
|
||||||
} catch (Installer.InstallFailedException e) {
|
} catch (Installer.InstallFailedException e) {
|
||||||
Log.e(TAG, "prepareApkFile failed", e);
|
Log.e(TAG, "prepareApkFile failed", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -318,9 +318,9 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
@Override
|
@Override
|
||||||
public void handleResult(String packageName, int returnCode) throws RemoteException {
|
public void handleResult(String packageName, int returnCode) throws RemoteException {
|
||||||
if (returnCode == INSTALL_SUCCEEDED) {
|
if (returnCode == INSTALL_SUCCEEDED) {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_COMPLETE);
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_COMPLETE);
|
||||||
} else {
|
} else {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
"Error " + returnCode + ": "
|
"Error " + returnCode + ": "
|
||||||
+ INSTALL_RETURN_CODES.get(returnCode));
|
+ INSTALL_RETURN_CODES.get(returnCode));
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
try {
|
try {
|
||||||
boolean hasPermissions = privService.hasPrivilegedPermissions();
|
boolean hasPermissions = privService.hasPrivilegedPermissions();
|
||||||
if (!hasPermissions) {
|
if (!hasPermissions) {
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
context.getString(R.string.system_install_denied_permissions));
|
context.getString(R.string.system_install_denied_permissions));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -339,7 +339,7 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
null, callback);
|
null, callback);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "RemoteException", e);
|
Log.e(TAG, "RemoteException", e);
|
||||||
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
|
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
|
||||||
"connecting to privileged service failed");
|
"connecting to privileged service failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -791,7 +791,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
Uri localUri = Uri.fromFile(apkFile);
|
Uri localUri = Uri.fromFile(apkFile);
|
||||||
|
|
||||||
localBroadcastManager.registerReceiver(installReceiver,
|
localBroadcastManager.registerReceiver(installReceiver,
|
||||||
Installer.getInstallIntentFilter(Uri.fromFile(apkFile)));
|
Installer.getInstallIntentFilter(originatingUri));
|
||||||
InstallerService.install(this, localUri, originatingUri, packageName);
|
InstallerService.install(this, localUri, originatingUri, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user