Make app status updates include parcelized version of status.
This means that we no longer need to receive an APK_URL and then directly ask the status manager for the relevant status object. This causes problems when consecutive updates happen in the same event loop, e.g. download started + download complete. In this case, the receiver will receive two events for the same app. When it asks for the associated status object for the first (download started) event, it will receive a status that says "download complete ready to install". This is because the status object has already been updated by the second event. Furthermore, the broadcast manager must receive a copy of the status object, not the original object. This is because the broadcast manager doesn't parcel the relevant extras until the end of the event loop. This means that if the status is changed twice in one frame, then both parcels will end up looking the same. By sending through a copy instead, this ensures that any listener receives the statuses in the correct order, rather than two parceled versions of the same status notification.
This commit is contained in:
parent
ee7055e118
commit
8e2a099e51
@ -527,13 +527,11 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
||||
private final BroadcastReceiver appStatusReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String apkUrl = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL);
|
||||
AppUpdateStatusManager.AppUpdateStatus status = AppUpdateStatusManager.getInstance(context).get(apkUrl);
|
||||
AppUpdateStatusManager.AppUpdateStatus status = intent.getParcelableExtra(AppUpdateStatusManager.EXTRA_STATUS);
|
||||
|
||||
boolean isRemoving = TextUtils.equals(intent.getAction(), AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED);
|
||||
// !TextUtils.equals(status.apk.packageName, app.packageName)
|
||||
if (status == null && currentStatus != null && isRemoving && !TextUtils.equals(apkUrl, currentStatus.getUniqueKey())) {
|
||||
Utils.debugLog(TAG, "Ignoring app status change because it belongs to " + apkUrl + " not " + currentStatus.getUniqueKey());
|
||||
if (currentStatus != null && isRemoving && !TextUtils.equals(status.getUniqueKey(), currentStatus.getUniqueKey())) {
|
||||
Utils.debugLog(TAG, "Ignoring app status change because it belongs to " + status.getUniqueKey() + " not " + currentStatus.getUniqueKey());
|
||||
} else if (status != null && !TextUtils.equals(status.apk.packageName, app.packageName)) {
|
||||
Utils.debugLog(TAG, "Ignoring app status change because it belongs to " + status.apk.packageName + " not " + app.packageName);
|
||||
} else {
|
||||
|
@ -7,6 +7,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
@ -66,6 +68,7 @@ public final class AppUpdateStatusManager {
|
||||
public static final String BROADCAST_APPSTATUS_REMOVED = "org.fdroid.fdroid.installer.appstatus.appchange.remove";
|
||||
|
||||
public static final String EXTRA_APK_URL = "urlstring";
|
||||
public static final String EXTRA_STATUS = "status";
|
||||
|
||||
public static final String EXTRA_REASON_FOR_CHANGE = "reason";
|
||||
|
||||
@ -102,7 +105,7 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
private static AppUpdateStatusManager instance;
|
||||
|
||||
public class AppUpdateStatus {
|
||||
public static class AppUpdateStatus implements Parcelable {
|
||||
public final App app;
|
||||
public final Apk apk;
|
||||
public Status status;
|
||||
@ -128,6 +131,59 @@ public final class AppUpdateStatusManager {
|
||||
public String toString() {
|
||||
return app.packageName + " [Status: " + status + ", Progress: " + progressCurrent + " / " + progressMax + "]";
|
||||
}
|
||||
|
||||
protected AppUpdateStatus(Parcel in) {
|
||||
app = in.readParcelable(getClass().getClassLoader());
|
||||
apk = in.readParcelable(getClass().getClassLoader());
|
||||
intent = in.readParcelable(getClass().getClassLoader());
|
||||
status = (Status) in.readSerializable();
|
||||
progressCurrent = in.readInt();
|
||||
progressMax = in.readInt();
|
||||
errorText = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(app, 0);
|
||||
dest.writeParcelable(apk, 0);
|
||||
dest.writeParcelable(intent, 0);
|
||||
dest.writeSerializable(status);
|
||||
dest.writeInt(progressCurrent);
|
||||
dest.writeInt(progressMax);
|
||||
dest.writeString(errorText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AppUpdateStatus> CREATOR = new Parcelable.Creator<AppUpdateStatus>() {
|
||||
@Override
|
||||
public AppUpdateStatus createFromParcel(Parcel in) {
|
||||
return new AppUpdateStatus(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppUpdateStatus[] newArray(int size) {
|
||||
return new AppUpdateStatus[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When passing to the broadcast manager, it is important to pass a copy rather than the original object.
|
||||
* This is because if two status changes are noticed in the same event loop, than they will both refer
|
||||
* to the same status object. The objects are not parceled until the end of the event loop, and so the first
|
||||
* parceled event will refer to the updated object (with a different status) rather than the intended
|
||||
* status (i.e. the one in existence when talking to the broadcast manager).
|
||||
*/
|
||||
public AppUpdateStatus copy() {
|
||||
AppUpdateStatus copy = new AppUpdateStatus(app, apk, status, intent);
|
||||
copy.errorText = errorText;
|
||||
copy.progressCurrent = progressCurrent;
|
||||
copy.progressMax = progressMax;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
@ -209,6 +265,7 @@ public final class AppUpdateStatusManager {
|
||||
if (!isBatchUpdating) {
|
||||
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_ADDED);
|
||||
broadcastIntent.putExtra(EXTRA_APK_URL, entry.getUniqueKey());
|
||||
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
|
||||
localBroadcastManager.sendBroadcast(broadcastIntent);
|
||||
}
|
||||
}
|
||||
@ -217,6 +274,7 @@ public final class AppUpdateStatusManager {
|
||||
if (!isBatchUpdating) {
|
||||
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_CHANGED);
|
||||
broadcastIntent.putExtra(EXTRA_APK_URL, entry.getUniqueKey());
|
||||
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
|
||||
broadcastIntent.putExtra(EXTRA_IS_STATUS_UPDATE, isStatusUpdate);
|
||||
localBroadcastManager.sendBroadcast(broadcastIntent);
|
||||
}
|
||||
@ -226,6 +284,7 @@ public final class AppUpdateStatusManager {
|
||||
if (!isBatchUpdating) {
|
||||
Intent broadcastIntent = new Intent(BROADCAST_APPSTATUS_REMOVED);
|
||||
broadcastIntent.putExtra(EXTRA_APK_URL, entry.getUniqueKey());
|
||||
broadcastIntent.putExtra(EXTRA_STATUS, entry.copy());
|
||||
localBroadcastManager.sendBroadcast(broadcastIntent);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user