Merge branch 'improvements-to-update-workflow' into 'master'

Improvements to update workflow

Closes #922

See merge request !468
This commit is contained in:
Hans-Christoph Steiner 2017-04-07 16:46:50 +00:00
commit 49f7248d45
6 changed files with 114 additions and 73 deletions

View File

@ -371,7 +371,7 @@ class NotificationHelper {
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_UPDATE_CLEARED);
intentDeleted.putExtra(EXTRA_NOTIFICATION_KEY, entry.getUniqueKey());
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, 0);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);
return builder.build();
}
@ -429,7 +429,7 @@ class NotificationHelper {
}
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, 0);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);
return builder.build();
}
@ -456,7 +456,7 @@ class NotificationHelper {
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED);
intentDeleted.putExtra(EXTRA_NOTIFICATION_KEY, entry.getUniqueKey());
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, 0);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);
return builder.build();
}
@ -484,7 +484,7 @@ class NotificationHelper {
// Intent to open main app list
Intent intentObject = new Intent(context, MainActivity.class);
PendingIntent piAction = PendingIntent.getActivity(context, 0, intentObject, 0);
PendingIntent piAction = PendingIntent.getActivity(context, 0, intentObject, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
@ -501,7 +501,7 @@ class NotificationHelper {
.setGroupSummary(true);
}
Intent intentDeleted = new Intent(BROADCAST_NOTIFICATIONS_ALL_INSTALLED_CLEARED);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, 0);
PendingIntent piDeleted = PendingIntent.getBroadcast(context, 0, intentDeleted, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(piDeleted);
return builder.build();
}

View File

@ -6,6 +6,7 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Outline;
import android.net.Uri;
import android.os.Build;
@ -96,7 +97,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
installButton = (ImageView) itemView.findViewById(R.id.install);
if (installButton != null) {
installButton.setOnClickListener(onInstallClicked);
installButton.setOnClickListener(onActionClicked);
if (Build.VERSION.SDK_INT >= 21) {
installButton.setOutlineProvider(new ViewOutlineProvider() {
@ -126,7 +127,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
actionButton = (Button) itemView.findViewById(R.id.action_button);
if (actionButton != null) {
actionButton.setOnClickListener(onInstallClicked);
actionButton.setOnClickListener(onActionClicked);
}
if (cancelButton != null) {
@ -149,9 +150,11 @@ public class AppListItemController extends RecyclerView.ViewHolder {
final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(activity.getApplicationContext());
broadcastManager.unregisterReceiver(onDownloadProgress);
broadcastManager.unregisterReceiver(onInstallAction);
broadcastManager.unregisterReceiver(onStatusRemoved);
broadcastManager.registerReceiver(onDownloadProgress, DownloaderService.getIntentFilter(currentAppDownloadUrl));
broadcastManager.registerReceiver(onInstallAction, Installer.getInstallIntentFilter(Uri.parse(currentAppDownloadUrl)));
broadcastManager.registerReceiver(onStatusRemoved, new IntentFilter(AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED));
configureAppName(app);
configureStatusText(app);
@ -255,14 +258,17 @@ public class AppListItemController extends RecyclerView.ViewHolder {
/**
* Queries the {@link AppUpdateStatusManager} and asks if the app was just successfully installed.
* For convenience, returns the {@link org.fdroid.fdroid.AppUpdateStatusManager.AppUpdateStatus}
* object if it was sucessfully installed, or null otherwise.
*/
private boolean wasSuccessfullyInstalled(@NonNull App app) {
@Nullable
private AppUpdateStatusManager.AppUpdateStatus wasSuccessfullyInstalled(@NonNull App app) {
for (AppUpdateStatusManager.AppUpdateStatus appStatus : AppUpdateStatusManager.getInstance(activity).getByPackageName(app.packageName)) {
if (appStatus.status == AppUpdateStatusManager.Status.Installed) {
return true;
return appStatus;
}
}
return false;
return null;
}
/**
@ -288,7 +294,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
}
} else if (isDownloading(app)) {
name.setText(activity.getString(R.string.app_list__name__downloading_in_progress, app.name));
} else if (wasSuccessfullyInstalled(app)) {
} else if (wasSuccessfullyInstalled(app) != null) {
name.setText(activity.getString(R.string.app_list__name__successfully_installed, app.name));
} else {
name.setText(Utils.formatAppNameAndSummary(app.name, app.summary));
@ -305,15 +311,18 @@ public class AppListItemController extends RecyclerView.ViewHolder {
return;
}
if (!isReadyToInstall(app)) {
actionButton.setVisibility(View.GONE);
} else {
actionButton.setVisibility(View.VISIBLE);
actionButton.setVisibility(View.VISIBLE);
if (wasSuccessfullyInstalled(app) != null) {
actionButton.setText(R.string.menu_launch);
} else if (isReadyToInstall(app)) {
if (app.isInstalled()) {
actionButton.setText(R.string.app__install_downloaded_update);
} else {
actionButton.setText(R.string.menu_install);
}
} else {
actionButton.setVisibility(View.GONE);
}
}
@ -329,9 +338,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
}
if (isReadyToInstall(app)) {
installButton.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_download_complete));
installButton.setVisibility(View.VISIBLE);
// TODO: If in the downloading phase, then need to reflect that instead of this "download complete" icon.
installButton.setVisibility(View.GONE);
} else {
boolean installable = app.canAndWantToUpdate(activity) || !app.isInstalled();
boolean shouldAllow = app.compatible && !app.isFiltered();
@ -386,7 +393,7 @@ public class AppListItemController extends RecyclerView.ViewHolder {
private void onDownloadComplete() {
if (installButton != null) {
installButton.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_download_complete));
installButton.setVisibility(View.GONE);
}
if (progressBar != null) {
@ -473,14 +480,47 @@ public class AppListItemController extends RecyclerView.ViewHolder {
}
};
/**
* If the app goes from "Successfully installed" to anything else, then reset the action button
* and the app label text to whatever they should be.
*/
private final BroadcastReceiver onStatusRemoved = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (currentApp == null || currentAppDownloadUrl == null) {
return;
}
if (!TextUtils.equals(intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL), currentAppDownloadUrl)) {
return;
}
configureAppName(currentApp);
configureActionButton(currentApp);
}
};
@SuppressWarnings("FieldCanBeLocal")
private final View.OnClickListener onInstallClicked = new View.OnClickListener() {
private final View.OnClickListener onActionClicked = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentApp == null) {
return;
}
// When the button says "Run", then launch the app.
AppUpdateStatusManager.AppUpdateStatus successfullyInstalledStatus = wasSuccessfullyInstalled(currentApp);
if (successfullyInstalledStatus != null) {
Intent intent = activity.getPackageManager().getLaunchIntentForPackage(currentApp.packageName);
activity.startActivity(intent);
// Once it is explicitly launched by the user, then we can pretty much forget about
// any sort of notification that the app was successfully installed. It should be
// apparent to the user because they just launched it.
AppUpdateStatusManager.getInstance(activity).removeApk(successfullyInstalledStatus.getUniqueKey());
return;
}
final Apk suggestedApk = ApkProvider.Helper.findApkFromAnyRepo(activity, currentApp.packageName, currentApp.suggestedVersionCode);
if (isReadyToInstall(currentApp)) {

View File

@ -316,7 +316,7 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
// After adding the new item to our list (somewhere) we can then look it back up again in
// order to notify the recycler view and scroll to that item.
int positionOfNewApp = 0;
int positionOfNewApp = -1;
for (int i = 0; i < appsToShowStatus.size(); i++) {
if (TextUtils.equals(appsToShowStatus.get(i).status.getUniqueKey(), apkUrl)) {
positionOfNewApp = i;
@ -324,17 +324,19 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
}
notifyItemInserted(positionOfNewApp);
if (positionOfNewApp != -1) {
notifyItemInserted(positionOfNewApp);
if (recyclerView != null) {
recyclerView.smoothScrollToPosition(positionOfNewApp);
if (recyclerView != null) {
recyclerView.smoothScrollToPosition(positionOfNewApp);
}
}
}
private void onAppStatusRemoved(String apkUrl) {
// Find out where the item is in our internal data structure, so that we can remove it and
// also notify the recycler view appropriately.
int positionOfOldApp = 0;
int positionOfOldApp = -1;
for (int i = 0; i < appsToShowStatus.size(); i++) {
if (TextUtils.equals(appsToShowStatus.get(i).status.getUniqueKey(), apkUrl)) {
positionOfOldApp = i;
@ -342,10 +344,12 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
}
appsToShowStatus.remove(positionOfOldApp);
if (positionOfOldApp != -1) {
appsToShowStatus.remove(positionOfOldApp);
populateItems();
notifyItemRemoved(positionOfOldApp);
populateItems();
notifyItemRemoved(positionOfOldApp);
}
}
private final BroadcastReceiver receiverAppStatusChanges = new BroadcastReceiver() {

View File

@ -1,33 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="90dp"
android:height="90dp"
android:viewportWidth="90.0"
android:viewportHeight="90.0">
<path
android:pathData="m45,9.73c19.49,0 35.27,15.78 35.27,35.27 0,19.49 -15.78,35.27 -35.27,35.27 -19.49,0 -35.27,-15.78 -35.27,-35.27 0,-19.49 15.78,-35.27 35.27,-35.27z"
android:strokeLineCap="butt"
android:fillAlpha="1"
android:strokeColor="#00000000"
android:fillColor="#ffffff"
android:strokeWidth="2"
android:strokeLineJoin="miter"
android:strokeAlpha="1"/>
<path
android:pathData="m45,7.73c-2.14,0 -4.24,0.19 -6.29,0.54l0.44,1.95c1.9,-0.32 3.86,-0.49 5.85,-0.49 19.49,0 35.27,15.78 35.27,35.27 0,19.49 -15.78,35.27 -35.27,35.27 -19.49,0 -35.27,-15.78 -35.27,-35.27 0,-1.94 0.16,-3.85 0.46,-5.7l-1.97,-0.35c-0.32,1.97 -0.5,3.99 -0.5,6.05 0,20.57 16.7,37.27 37.27,37.27 20.57,0 37.27,-16.7 37.27,-37.27 0,-20.57 -16.7,-37.27 -37.27,-37.27zM30.57,10.64c-3,1.26 -5.8,2.92 -8.34,4.88l1.26,1.53c2.41,-1.86 5.07,-3.42 7.92,-4.61l-0.85,-1.81zM16.08,21.52c-2.24,2.75 -4.09,5.82 -5.47,9.14l1.84,0.76c1.31,-3.15 3.07,-6.06 5.19,-8.67l-1.56,-1.23z"
android:strokeLineCap="butt"
android:fillAlpha="1"
android:strokeColor="#00000000"
android:fillColor="#0066cc"
android:strokeWidth="2"
android:strokeLineJoin="miter"
android:strokeAlpha="1"/>
<path
android:pathData="m59.21,32.08a2.5,2.5 0,0 0,-1.72 0.76l-18.12,18.12 -8.09,-8.09a2.5,2.5 0,1 0,-3.54 3.54l9.85,9.86a2.5,2.5 0,0 0,3.54 0l19.89,-19.89a2.5,2.5 0,0 0,-1.82 -4.29z"
android:strokeLineCap="round"
android:fillAlpha="1"
android:strokeColor="#00000000"
android:fillColor="#0066cc"
android:strokeWidth="5"
android:strokeLineJoin="round"
android:strokeAlpha="1"/>
</vector>

View File

@ -36,7 +36,7 @@
app:layout_constraintTop_toTopOf="@+id/icon"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
app:layout_constraintEnd_toStartOf="@+id/install"
app:layout_constraintEnd_toStartOf="@+id/buttons"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp" />
@ -57,18 +57,34 @@
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp" />
<ImageView
android:id="@+id/install"
tools:src="@drawable/ic_download"
android:scaleType="fitXY"
android:contentDescription="@string/menu_install"
android:layout_width="64dp"
android:layout_height="64dp"
android:elevation="2dp"
android:padding="4dp"
<FrameLayout
android:id="@+id/buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/icon" />
app:layout_constraintTop_toTopOf="@+id/icon">
<ImageView
android:id="@+id/install"
tools:src="@drawable/ic_download"
android:scaleType="fitXY"
android:contentDescription="@string/menu_install"
android:layout_width="64dp"
android:layout_height="64dp"
android:elevation="2dp"
android:padding="4dp" />
<Button
android:id="@+id/action_button"
style="@style/DetailsPrimaryButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
tools:text="Update" />
</FrameLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -55,8 +55,22 @@
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@+id/action_button"
app:layout_constraintTop_toTopOf="@+id/icon"
app:layout_constraintBottom_toBottomOf="@+id/icon" />
<Button
android:id="@+id/action_button"
style="@style/DetailsPrimaryButtonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Update" />
</android.support.constraint.ConstraintLayout>