diff --git a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java index 6ccdea17f..fb34c9db3 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java +++ b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusManager.java @@ -13,6 +13,7 @@ import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.installer.ErrorDialogActivity; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -43,14 +44,14 @@ public class AppUpdateStatusManager { return new AppUpdateStatusManager(context); } - class AppUpdateStatus { - final App app; - final Apk apk; - Status status; - PendingIntent intent; - int progressCurrent; - int progressMax; - String errorText; + public class AppUpdateStatus { + public final App app; + public final Apk apk; + public Status status; + public PendingIntent intent; + public int progressCurrent; + public int progressMax; + public String errorText; AppUpdateStatus(App app, Apk apk, Status status, PendingIntent intent) { this.app = app; @@ -59,7 +60,7 @@ public class AppUpdateStatusManager { this.intent = intent; } - String getUniqueKey() { + public String getUniqueKey() { return apk.getUrl(); } } @@ -86,6 +87,23 @@ public class AppUpdateStatusManager { } } + /** + * Get all entries associated with a package name. There may be several. + * @param packageName Package name of the app + * @return A list of entries, or an empty list + */ + public Collection getByPackageName(String packageName) { + ArrayList returnValues = new ArrayList<>(); + synchronized (appMapping) { + for (AppUpdateStatus entry : appMapping.values()) { + if (entry.apk.packageName.equalsIgnoreCase(packageName)) { + returnValues.add(entry); + } + } + } + return returnValues; + } + private void setApkInternal(Apk apk, Status status, PendingIntent intent) { if (apk == null) { return; diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index ec57e4d45..9b1e9bb6c 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -97,6 +97,7 @@ public class FDroidApp extends Application { @SuppressWarnings("unused") BluetoothAdapter bluetoothAdapter; + NotificationHelper notificationHelper; static { SPONGYCASTLE_PROVIDER = new org.spongycastle.jce.provider.BouncyCastleProvider(); @@ -262,7 +263,7 @@ public class FDroidApp extends Application { CleanCacheService.schedule(this); - NotificationHelper.create(getApplicationContext()); + notificationHelper = new NotificationHelper(getApplicationContext()); UpdateService.schedule(getApplicationContext()); bluetoothAdapter = getBluetoothAdapter(); diff --git a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java index 2b7bcae46..64a10b1d1 100644 --- a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.Typeface; import android.os.Build; import android.support.v4.app.NotificationCompat; @@ -15,9 +16,16 @@ import android.support.v4.content.LocalBroadcastManager; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.StyleSpan; +import android.view.View; +import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.ImageSize; +import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; +import com.nostra13.universalimageloader.utils.DiskCacheUtils; +import com.nostra13.universalimageloader.utils.MemoryCacheUtils; import org.fdroid.fdroid.data.App; @@ -40,25 +48,23 @@ class NotificationHelper { private static final String GROUP_UPDATES = "updates"; private static final String GROUP_INSTALLED = "installed"; - private static final String LOGTAG = "NotificationHelper"; - - private static NotificationHelper instance; - - public static NotificationHelper create(Context context) { - if (instance == null) { - instance = new NotificationHelper(context.getApplicationContext()); - } - return instance; - } - private final Context context; private final NotificationManagerCompat notificationManager; - private final AppUpdateStatusManager appUpdateStatusMananger; + private final AppUpdateStatusManager appUpdateStatusManager; + private final DisplayImageOptions displayImageOptions; + private ArrayList updates; + private ArrayList installed; - private NotificationHelper(Context context) { + NotificationHelper(Context context) { this.context = context; - appUpdateStatusMananger = AppUpdateStatusManager.getInstance(context); + appUpdateStatusManager = AppUpdateStatusManager.getInstance(context); notificationManager = NotificationManagerCompat.from(context); + displayImageOptions = new DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisk(true) + .imageScaleType(ImageScaleType.NONE) + .bitmapConfig(Bitmap.Config.RGB_565) + .build(); // We need to listen to when notifications are cleared, so that we "forget" all that we currently know about updates // and installs. @@ -67,12 +73,76 @@ class NotificationHelper { filter.addAction(BROADCAST_NOTIFICATIONS_ALL_INSTALLED_CLEARED); filter.addAction(BROADCAST_NOTIFICATIONS_UPDATE_CLEARED); filter.addAction(BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED); + BroadcastReceiver receiverNotificationsCleared = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED: + appUpdateStatusManager.clearAllUpdates(); + break; + case BROADCAST_NOTIFICATIONS_ALL_INSTALLED_CLEARED: + appUpdateStatusManager.clearAllInstalled(); + break; + case BROADCAST_NOTIFICATIONS_UPDATE_CLEARED: + break; + case BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED: + String key = intent.getStringExtra(EXTRA_NOTIFICATION_KEY); + appUpdateStatusManager.removeApk(key); + break; + } + } + }; context.registerReceiver(receiverNotificationsCleared, filter); filter = new IntentFilter(); filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED); filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_ADDED); filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED); filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED); + BroadcastReceiver receiverAppStatusChanges = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED: + notificationManager.cancelAll(); + updateStatusLists(); + createSummaryNotifications(); + for (AppUpdateStatusManager.AppUpdateStatus entry : appUpdateStatusManager.getAll()) { + createNotification(entry); + } + break; + case AppUpdateStatusManager.BROADCAST_APPSTATUS_ADDED: { + updateStatusLists(); + createSummaryNotifications(); + String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); + AppUpdateStatusManager.AppUpdateStatus entry = appUpdateStatusManager.get(url); + if (entry != null) { + createNotification(entry); + } + break; + } + case AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED: { + String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); + AppUpdateStatusManager.AppUpdateStatus entry = appUpdateStatusManager.get(url); + updateStatusLists(); + if (entry != null) { + createNotification(entry); + } + if (intent.getBooleanExtra(AppUpdateStatusManager.EXTRA_IS_STATUS_UPDATE, false)) { + createSummaryNotifications(); + } + break; + } + case AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED: { + String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); + notificationManager.cancel(url, NOTIFY_ID_INSTALLED); + notificationManager.cancel(url, NOTIFY_ID_UPDATES); + updateStatusLists(); + createSummaryNotifications(); + break; + } + } + } + }; LocalBroadcastManager.getInstance(context).registerReceiver(receiverAppStatusChanges, filter); } @@ -80,76 +150,100 @@ class NotificationHelper { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; } - private void updateSummaryNotifications() { + private void updateStatusLists() { if (!notificationManager.areNotificationsEnabled()) { return; } // Get the list of updates and installed available - ArrayList updates = new ArrayList<>(); - ArrayList installed = new ArrayList<>(); - for (AppUpdateStatusManager.AppUpdateStatus entry : appUpdateStatusMananger.getAll()) { - if (entry.status == AppUpdateStatusManager.Status.Unknown) { - continue; - } else if (entry.status != AppUpdateStatusManager.Status.Installed) { - updates.add(entry); - } else { + if (updates == null) { + updates = new ArrayList<>(); + } else { + updates.clear(); + } + if (installed == null) { + installed = new ArrayList<>(); + } else { + installed.clear(); + } + for (AppUpdateStatusManager.AppUpdateStatus entry : appUpdateStatusManager.getAll()) { + if (entry.status == AppUpdateStatusManager.Status.Installed) { installed.add(entry); + } else if (entry.status != AppUpdateStatusManager.Status.Unknown) { + updates.add(entry); } } - - NotificationCompat.Builder builder; - if (updates.size() == 0) { - // No updates, remove summary - notificationManager.cancel(GROUP_UPDATES, NOTIFY_ID_UPDATES); - } else if (updates.size() == 1 && !useStackedNotifications()) { - // If we use stacked notifications we have already created one. - doCreateNotification(updates.get(0)); - } else { - builder = createUpdateSummaryNotification(updates); - notificationManager.notify(GROUP_UPDATES, NOTIFY_ID_UPDATES, builder.build()); - } - if (installed.size() == 0) { - // No installed, remove summary - notificationManager.cancel(GROUP_INSTALLED, NOTIFY_ID_INSTALLED); - } else if (installed.size() == 1 && !useStackedNotifications()) { - // If we use stacked notifications we have already created one. - doCreateNotification(installed.get(0)); - } else { - builder = createInstalledSummaryNotification(installed); - notificationManager.notify(GROUP_INSTALLED, NOTIFY_ID_INSTALLED, builder.build()); - } } private void createNotification(AppUpdateStatusManager.AppUpdateStatus entry) { - if (useStackedNotifications() && notificationManager.areNotificationsEnabled() && entry.status != AppUpdateStatusManager.Status.Unknown) { - doCreateNotification(entry); + if (entry.status == AppUpdateStatusManager.Status.Unknown) { + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_UPDATES); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_INSTALLED); + return; + } + if (notificationManager.areNotificationsEnabled()) { + NotificationCompat.Builder builder; + if (entry.status == AppUpdateStatusManager.Status.Installed) { + if (useStackedNotifications()) { + builder = createInstalledNotification(entry); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_UPDATES); + notificationManager.notify(entry.getUniqueKey(), NOTIFY_ID_INSTALLED, builder.build()); + } else if (installed.size() == 1) { + builder = createInstalledNotification(entry); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_UPDATES); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_INSTALLED); + notificationManager.notify(GROUP_INSTALLED, NOTIFY_ID_INSTALLED, builder.build()); + } + } else { + if (useStackedNotifications()) { + builder = createUpdateNotification(entry); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_INSTALLED); + notificationManager.notify(entry.getUniqueKey(), NOTIFY_ID_UPDATES, builder.build()); + } else if (updates.size() == 1) { + builder = createUpdateNotification(entry); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_UPDATES); + notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_INSTALLED); + notificationManager.notify(GROUP_UPDATES, NOTIFY_ID_UPDATES, builder.build()); + } + } } } - private void doCreateNotification(AppUpdateStatusManager.AppUpdateStatus entry) { - NotificationCompat.Builder builder; - int id; - if (entry.status == AppUpdateStatusManager.Status.Installed) { - builder = createInstalledNotification(entry); - id = NOTIFY_ID_INSTALLED; - notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_UPDATES); - } else { - builder = createUpdateNotification(entry); - id = NOTIFY_ID_UPDATES; - notificationManager.cancel(entry.getUniqueKey(), NOTIFY_ID_INSTALLED); + + private void createSummaryNotifications() { + if (!notificationManager.areNotificationsEnabled()) { + return; + } + + NotificationCompat.Builder builder; + if (updates.size() != 1 || useStackedNotifications()) { + if (updates.size() == 0) { + // No updates, remove summary + notificationManager.cancel(GROUP_UPDATES, NOTIFY_ID_UPDATES); + } else { + builder = createUpdateSummaryNotification(updates); + notificationManager.notify(GROUP_UPDATES, NOTIFY_ID_UPDATES, builder.build()); + } + } + if (installed.size() != 1 || useStackedNotifications()) { + if (installed.size() == 0) { + // No installed, remove summary + notificationManager.cancel(GROUP_INSTALLED, NOTIFY_ID_INSTALLED); + } else { + builder = createInstalledSummaryNotification(installed); + notificationManager.notify(GROUP_INSTALLED, NOTIFY_ID_INSTALLED, builder.build()); + } } - notificationManager.notify(entry.getUniqueKey(), id, builder.build()); } private NotificationCompat.Action getAction(AppUpdateStatusManager.AppUpdateStatus entry) { if (entry.intent != null) { if (entry.status == AppUpdateStatusManager.Status.UpdateAvailable) { - return new NotificationCompat.Action(R.drawable.ic_notify_update_24dp, "Update", entry.intent); + return new NotificationCompat.Action(R.drawable.ic_notify_update_24dp, context.getString(R.string.notification_action_update), entry.intent); } else if (entry.status == AppUpdateStatusManager.Status.Downloading || entry.status == AppUpdateStatusManager.Status.Installing) { - return new NotificationCompat.Action(R.drawable.ic_notify_cancel_24dp, "Cancel", entry.intent); + return new NotificationCompat.Action(R.drawable.ic_notify_cancel_24dp, context.getString(R.string.notification_action_cancel), entry.intent); } else if (entry.status == AppUpdateStatusManager.Status.ReadyToInstall) { - return new NotificationCompat.Action(R.drawable.ic_notify_install_24dp, "Install", entry.intent); + return new NotificationCompat.Action(R.drawable.ic_notify_install_24dp, context.getString(R.string.notification_action_install), entry.intent); } } return null; @@ -158,17 +252,17 @@ class NotificationHelper { private String getSingleItemTitleString(App app, AppUpdateStatusManager.Status status) { switch (status) { case UpdateAvailable: - return "Update Available"; + return context.getString(R.string.notification_title_single_update_available); case Downloading: return app.name; case ReadyToInstall: - return "Update ready to install"; // TODO - "Update"? Should just be "ready to install"? + return context.getString(app.isInstalled() ? R.string.notification_title_single_ready_to_install_update : R.string.notification_title_single_ready_to_install); // TODO - "Update"? Should just be "ready to install"? case Installing: return app.name; case Installed: return app.name; case InstallError: - return "Install Failed"; + return context.getString(R.string.notification_title_single_install_error); } return ""; } @@ -178,15 +272,15 @@ class NotificationHelper { case UpdateAvailable: return app.name; case Downloading: - return String.format("Downloading update for \"%s\"...", app.name); + return context.getString(R.string.notification_content_single_downloading, app.name); case ReadyToInstall: return app.name; case Installing: - return String.format("Installing \"%s\"...", app.name); + return context.getString(R.string.notification_content_single_installing, app.name); case Installed: - return "Successfully installed"; + return context.getString(R.string.notification_content_single_installed); case InstallError: - return "Install Failed"; + return context.getString(R.string.notification_content_single_install_error); } return ""; } @@ -194,17 +288,17 @@ class NotificationHelper { private String getMultiItemContentString(App app, AppUpdateStatusManager.Status status) { switch (status) { case UpdateAvailable: - return "Update available"; + return context.getString(R.string.notification_title_summary_update_available); case Downloading: - return "Downloading update..."; + return context.getString(app.isInstalled() ? R.string.notification_title_summary_downloading_update : R.string.notification_title_summary_downloading); case ReadyToInstall: - return "Ready to install"; + return context.getString(app.isInstalled() ? R.string.notification_title_summary_ready_to_install_update : R.string.notification_title_summary_ready_to_install); case Installing: - return "Installing"; + return context.getString(R.string.notification_title_summary_installing); case Installed: - return "Successfully installed"; + return context.getString(R.string.notification_title_summary_installed); case InstallError: - return "Install Failed"; + return context.getString(R.string.notification_title_summary_install_error); } return ""; } @@ -213,18 +307,12 @@ class NotificationHelper { App app = entry.app; AppUpdateStatusManager.Status status = entry.status; - // TODO - async image loading - int largeIconSize = context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); - Bitmap iconLarge = ImageLoader.getInstance().loadImageSync(app.iconUrl, new ImageSize(largeIconSize, largeIconSize)); - - // TODO - why? - final int icon = Build.VERSION.SDK_INT >= 11 ? R.drawable.ic_stat_notify_updates : R.drawable.ic_launcher; - + Bitmap iconLarge = getLargeIconForEntry(entry); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setAutoCancel(false) .setLargeIcon(iconLarge) - .setSmallIcon(icon) + .setSmallIcon(R.drawable.ic_launcher) .setContentTitle(getSingleItemTitleString(app, status)) .setContentText(getSingleItemContentString(app, status)) .setGroup(GROUP_UPDATES); @@ -261,7 +349,7 @@ class NotificationHelper { } private NotificationCompat.Builder createUpdateSummaryNotification(ArrayList updates) { - String title = String.format("%d Updates", updates.size()); + String title = context.getString(R.string.notification_summary_updates, updates.size()); StringBuilder text = new StringBuilder(); NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); @@ -285,7 +373,7 @@ class NotificationHelper { } if (updates.size() > MAX_UPDATES_TO_SHOW) { int diff = updates.size() - MAX_UPDATES_TO_SHOW; - inboxStyle.setSummaryText(context.getString(R.string.update_notification_more, diff)); + inboxStyle.setSummaryText(context.getString(R.string.notification_summary_more, diff)); } // Intent to open main app list @@ -316,16 +404,14 @@ class NotificationHelper { private NotificationCompat.Builder createInstalledNotification(AppUpdateStatusManager.AppUpdateStatus entry) { App app = entry.app; - int largeIconSize = context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); - Bitmap iconLarge = ImageLoader.getInstance().loadImageSync(app.iconUrl, new ImageSize(largeIconSize, largeIconSize)); - + Bitmap iconLarge = getLargeIconForEntry(entry); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setAutoCancel(true) .setLargeIcon(iconLarge) .setSmallIcon(R.drawable.ic_stat_notify_updates) .setContentTitle(app.name) - .setContentText("Successfully Installed") + .setContentText(context.getString(R.string.notification_content_single_installed)) .setGroup(GROUP_INSTALLED); PackageManager pm = context.getPackageManager(); @@ -341,7 +427,7 @@ class NotificationHelper { } private NotificationCompat.Builder createInstalledSummaryNotification(ArrayList installed) { - String title = String.format("%d Apps Installed", installed.size()); + String title = context.getString(R.string.notification_summary_installed, installed.size()); StringBuilder text = new StringBuilder(); NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); @@ -357,7 +443,7 @@ class NotificationHelper { bigTextStyle.bigText(text); if (installed.size() > MAX_INSTALLED_TO_SHOW) { int diff = installed.size() - MAX_INSTALLED_TO_SHOW; - bigTextStyle.setSummaryText(context.getString(R.string.update_notification_more, diff)); + bigTextStyle.setSummaryText(context.getString(R.string.notification_summary_more, diff)); } // Intent to open main app list @@ -381,65 +467,58 @@ class NotificationHelper { return builder; } - private BroadcastReceiver receiverNotificationsCleared = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED: - appUpdateStatusMananger.clearAllUpdates(); - break; - case BROADCAST_NOTIFICATIONS_ALL_INSTALLED_CLEARED: - appUpdateStatusMananger.clearAllInstalled(); - break; - case BROADCAST_NOTIFICATIONS_UPDATE_CLEARED: - break; - case BROADCAST_NOTIFICATIONS_INSTALLED_CLEARED: - String key = intent.getStringExtra(EXTRA_NOTIFICATION_KEY); - appUpdateStatusMananger.removeApk(key); - break; - } + private Point getLargeIconSize() { + int w; + int h; + if (Build.VERSION.SDK_INT >= 11) { + w = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width); + h = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height); + } else { + w = h = context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); } - }; + return new Point(w, h); + } - private BroadcastReceiver receiverAppStatusChanges = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED: - notificationManager.cancelAll(); - for (AppUpdateStatusManager.AppUpdateStatus entry : appUpdateStatusMananger.getAll()) { - createNotification(entry); - } - updateSummaryNotifications(); - break; - case AppUpdateStatusManager.BROADCAST_APPSTATUS_ADDED: { - String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); - AppUpdateStatusManager.AppUpdateStatus entry = appUpdateStatusMananger.get(url); - if (entry != null) { - createNotification(entry); - } - updateSummaryNotifications(); - break; + private Bitmap getLargeIconForEntry(AppUpdateStatusManager.AppUpdateStatus entry) { + final Point largeIconSize = getLargeIconSize(); + Bitmap iconLarge = null; + if (DiskCacheUtils.findInCache(entry.app.iconUrl, ImageLoader.getInstance().getDiskCache()) != null) { + iconLarge = ImageLoader.getInstance().loadImageSync(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), displayImageOptions); + } else { + // Load it for later! + ImageLoader.getInstance().loadImage(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), displayImageOptions, new ImageLoadingListener() { + AppUpdateStatusManager.AppUpdateStatus entry; + ImageLoadingListener init(AppUpdateStatusManager.AppUpdateStatus entry) { + this.entry = entry; + return this; } - case AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED: { - String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); - AppUpdateStatusManager.AppUpdateStatus entry = appUpdateStatusMananger.get(url); - if (entry != null) { - createNotification(entry); - } - if (intent.getBooleanExtra(AppUpdateStatusManager.EXTRA_IS_STATUS_UPDATE, false)) { - updateSummaryNotifications(); - } - break; + + @Override + public void onLoadingStarted(String imageUri, View view) { + } - case AppUpdateStatusManager.BROADCAST_APPSTATUS_REMOVED: { - String url = intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL); - notificationManager.cancel(url, NOTIFY_ID_INSTALLED); - notificationManager.cancel(url, NOTIFY_ID_UPDATES); - updateSummaryNotifications(); - break; + + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason) { + } - } + + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + // Need to check that the notification is still valid, and also that the image + // is indeed cached now, so we won't get stuck in an endless loop. + AppUpdateStatusManager.AppUpdateStatus oldEntry = appUpdateStatusManager.get(entry.getUniqueKey()); + if (oldEntry != null && DiskCacheUtils.findInCache(oldEntry.app.iconUrl, ImageLoader.getInstance().getDiskCache()) != null) { + createNotification(oldEntry); // Update with new image! + } + } + + @Override + public void onLoadingCancelled(String imageUri, View view) { + + } + }.init(entry)); } - }; + return iconLarge; + } } diff --git a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java index 528c9bc7b..daec607db 100644 --- a/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java +++ b/app/src/main/java/org/fdroid/fdroid/installer/InstallManagerService.java @@ -14,6 +14,7 @@ import android.text.TextUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; +import org.fdroid.fdroid.AppDetails; import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.Hasher; import org.fdroid.fdroid.Utils; @@ -107,8 +108,9 @@ public class InstallManagerService extends Service { @Override public void onReceive(Context context, Intent intent) { String packageName = intent.getData().getSchemeSpecificPart(); - //TODO: do we need to mark as installed, or is this handled by other code already? - //appUpdateStatusManager.removeApk(packageName); + for (AppUpdateStatusManager.AppUpdateStatus status : appUpdateStatusManager.getByPackageName(packageName)) { + appUpdateStatusManager.updateApk(status.getUniqueKey(), AppUpdateStatusManager.Status.Installed, null); + } } }; IntentFilter intentFilter = new IntentFilter(); @@ -292,7 +294,7 @@ public class InstallManagerService extends Service { } break; case Downloader.ACTION_INTERRUPTED: - appUpdateStatusManager.updateApk(urlString, AppUpdateStatusManager.Status.UpdateAvailable, null); + appUpdateStatusManager.updateApk(urlString, AppUpdateStatusManager.Status.Unknown, null); localBroadcastManager.unregisterReceiver(this); break; default: @@ -325,28 +327,23 @@ public class InstallManagerService extends Service { localBroadcastManager.unregisterReceiver(this); break; case Installer.ACTION_INSTALL_INTERRUPTED: - appUpdateStatusManager.updateApk(downloadUrl, AppUpdateStatusManager.Status.ReadyToInstall, null); - + AppUpdateStatusManager.AppUpdateStatus status = appUpdateStatusManager.get(downloadUrl); + appUpdateStatusManager.removeApk(downloadUrl); apk = intent.getParcelableExtra(Installer.EXTRA_APK); String errorMessage = intent.getStringExtra(Installer.EXTRA_ERROR_MESSAGE); // show notification if app details is not visible if (!TextUtils.isEmpty(errorMessage)) { - appUpdateStatusManager.setApkError(apk, errorMessage); -// App app = getAppFromActive(downloadUrl); -// if (app == null) { -// ContentResolver resolver = context.getContentResolver(); -// app = AppProvider.Helper.findSpecificApp(resolver, apk.packageName, apk.repo); -// } - // TODO - show error + if (status == null || status.app == null || !AppDetails.isAppVisible(status.app.packageName)) { + appUpdateStatusManager.setApkError(apk, errorMessage); + } } localBroadcastManager.unregisterReceiver(this); break; case Installer.ACTION_INSTALL_USER_INTERACTION: apk = intent.getParcelableExtra(Installer.EXTRA_APK); - PendingIntent installPendingIntent = - intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI); + PendingIntent installPendingIntent = intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI); appUpdateStatusManager.addApk(apk, AppUpdateStatusManager.Status.ReadyToInstall, installPendingIntent); break; default: diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index d4e8e770e..274e49035 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -122,7 +122,7 @@ يتوفر تحديث. %d يتوفر على تحديثات. تحديثات اف-درويد متوفرة - +%1$d المزيد… + +%1$d المزيد… لا توجد طريقة إرسال بلوتوث، فضلاً إختر واحدة ! هذه المستودعات بالفعل موجودة، بهذا سوف يتم إضافة مفتاح معلومات جديد. هذه المستودعات بالفعل موجودة، تأكد إن كنت ترغب في إعادة تمكينه. diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 84d7f50cb..d769396e7 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -214,7 +214,7 @@ rehabilitar esti repositoriu pa instalar aplicaciones dende elli. Atrás Instaláu - +%1$d más… + +%1$d más… Buelga incorreuta Esto nun ye una URL válida. Rexistru de cambeos diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 8db31a1f1..8f6df2c82 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -181,7 +181,7 @@ Изходен код Инсталирани - + още %1$d… + + още %1$d… Актуализиране на хранилищата Инсталирането се провали поради неизвестна грешка Деинсталирането се провали поради неизвестна грешка diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 24eca82b3..43cd7a666 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -181,7 +181,7 @@ tornar a habilitar el dipòsit per instal·lar aplicacions d\'aquest. Enllaços Torna - +%1$d més… + +%1$d més… Idioma Wi-Fi Gràfics diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index b8f9cf24e..9d7c9f706 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -152,7 +152,7 @@ Pro instalaci aplikací z tohoto repozitáře ho bude nejprve třeba znovu povol Odkazy Zpět - +%1$d více… + +%1$d více… Nerozpoznána žádná Bluetooth metoda přenosu, nějakou vyberte! Vyberte metodu přenosu Bluetooth Tento repozitář je již nastaven, budou jen přidány nové klíče. diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 93d9dc9aa..1388c2e2a 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -78,7 +78,7 @@ 1 opdatering er tilgængelig. %d opdateringer er tilgængelige. F-Droid Opdateringer Tilgængelige - +%1$d flere… + +%1$d flere… Ingen Bluetooth afsendelsesmetode fundet, vælg en! Vælg Bluetooth afsendelsesmetode Send over Bluetooth diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b5a7e4e8f..44e75d98e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -182,7 +182,7 @@ um Anwendungen daraus installieren zu können. Inkompatibel Verweise Zurück - +%1$d weitere … + +%1$d weitere … Falscher Fingerabdruck Das ist keine gültige Adresse. Paketquellen werden aktualisiert diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index f546703ae..f004b3e07 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -142,7 +142,7 @@ Πίσω Εγκατεστημένο - +%1$d περισσότερα… + +%1$d περισσότερα… Αποστολή μέσω Bluetooth Λανθασμένο δακτυλικό αποτύπωμα diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 4d06f7d1f..b301ab46a 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -151,7 +151,7 @@ Instalitaj Instalitaj (%d) Ĝisdatigoj (%d) - ankoraŭ +%1$d… + ankoraŭ +%1$d… Neniu Bludenta metodo de sendo trovita, elektu iun! Elektu Bludentan metodon de sendo Fingrospuro (malnepra) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bf26e5baf..a2923498a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -182,7 +182,7 @@ Para ver las aplicaciones que ofrece tienes que activarlo. Enlaces Volver - +%1$d más… + +%1$d más… Actualiza/Desinstala la extensión con permisos de sistema Abre la pantalla de detalles de la extensión con permisos de sistema para actualizarla/desinstalarla Huella digital incorrecta diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index f9fbbac08..2b75d1e18 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -81,7 +81,7 @@ Üks värskendus on saadaval. %d värskendust on saadaval. F-Droid: värskendused saadaval - +%1$d veel… + +%1$d veel… Bluetoothiga saatmisviise ei leitud. Valige üks! Vali Bluetoothiga saatmise viis Saada Bluetoothiga diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index fbe4f6ee6..8ca03d7c1 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -99,7 +99,7 @@ Loturak Atzera - +%1$d gehiago… + +%1$d gehiago… Ez da aurkitu Bluetooth bidez bidaltzeko metodorik, aukeratu bat! Aukeratu Bluetooth bidez bidaltzeko metodoa Bidali Bluetooth bidez diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 23fea4a60..eeca7fdf3 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -116,7 +116,7 @@ به‌روز رسانی‌ها (%d) ۱ به‌روز رسانی موجود است. %d به روز رسانی موجود است. - +%1$d بیش‌تر… + +%1$d بیش‌تر… ارسال با بلوتوث این مخزن از پیش برپا شده است. این کار، اظّلاعات کلید جدیدی را می‌افزاید. diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index af32eda3f..b97a36663 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -183,7 +183,7 @@ Asennettu Asennettu (%d) Päivitykset (%d) - +%1$d lisää… + +%1$d lisää… Lataa päivitykset automaattisesti Lataa päivitykset taustalla Päivitä/Poista Privileged Extension diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2947b2114..1d130254c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -284,7 +284,7 @@ perdues. Elle ne requiert aucune autorisation particulière. Toutes les heures Fourni par %1$s. Ouvrir l\'écran des détails de l\'appli F-Droid Privileged Extension pour la mettre à jour/la désinstaller - %1$d de plus… + %1$d de plus… Téléchargement de \n%2$s depuis \n%1$s diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 23933a733..2f795d276 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -101,7 +101,7 @@ Sobreescribir Instalado - +%1$d máis… + +%1$d máis… Non se atopou ningún método de transmisión Bluetooth, escolla un! Escolla o método de transmisión Bluetooth Enviar por Bluetooth diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index d11df15e2..18fd1eeb8 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -57,7 +57,7 @@ עדכון 1 זמין. %d עדכונים זמינים. עדכוני F-Droid זמינים - +%1$d עוד… + +%1$d עוד… לא נמצאה שיטת שליחה של Bluetooth, בחר אחת! בחר שיטת שליחה של Bluetooth שלח דרך Bluetooth diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 6ae62ef52..276900dc7 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -150,7 +150,7 @@ १ अपडेट उपलब्ध है| %d अपडेटस उपलब्ध हैं| F-Droid अपडेट उपलब्ध - +%1$d और… + +%1$d और… Bluettoth से भेजने का तरीका उपलब नहीं है, एक चुने! Bluetooth से भेजने का तरीका चुने Bluetooth द्वारा भेजे diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 8a87b3402..68d0c5ea7 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -81,7 +81,7 @@ 1 ažuriranje je dostupno. %d ažuriranja je dostupno. Ažuriranja za F-Droid dostupna - +%1$d više… + +%1$d više… Nije pronađena metoda slanja preko Bluetootha, odaberite jednu! Odaberi metodu slanja preko Bluetootha Pošalji preko Bluetootha diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index a0e71c4b3..f57f2d214 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -126,7 +126,7 @@ Engedélyeznie kell, hogy megtekinthesse az általa kínált appokat. Telepítve Telepítve (%d) Frissítések (%d) - +%1$d további… + +%1$d további… Küldés Bluetooth-on Rossz ujjlenyomat diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 0c422dde7..2cef07854 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -166,7 +166,7 @@ Terakhir diperbarui Nama Tidak diketahui - +%1$d lainnya… + +%1$d lainnya… Pengaturan Jangan bedakan warna apl yang membutuhkan izin root Ini artinya daftar diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index ee53c696a..a539847ed 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -69,7 +69,7 @@ 1 uppfærsla er tiltæk. %d uppfærslur eru tiltækar. Uppfærslur á F-Droid eru tiltækar - +%1$d fleiri… + +%1$d fleiri… Engin aðferð til sendingar með Bluetooth fannst, veldu eina! Veldu aðferð til sendingar með Bluetooth Senda með Bluetooth diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 6816d5f7d..087465c82 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -333,7 +333,7 @@ non saranno rimossi. Non è richiesto alcun accesso speciale. di questa app integrata? I dati presenti non saranno rimossi. Non richiede alcun permesso speciale. Tutte - +%1$d rimanente… + +%1$d rimanente… Scambio ravvicinato Nessuna app installata corrispondente. Puoi aggiungere altre informazioni e commenti qui: diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1c99463ab..3ebec0d32 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -181,7 +181,7 @@ リンク 戻る - +%1$d 以上… + +%1$d 以上… フィンガープリントが違います 有効な URL ではありません。 変更履歴 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index b6e1f9fee..0a8977657 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -194,7 +194,7 @@ 설치됨 설치됨 (%d) 업데이트 (%d) - +%1$d 이상… + +%1$d 이상… 올바르지 않은 핑거프린트 올바른 URL이 아닙니다. 설정 diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index f71147699..2bfc0f244 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -77,7 +77,7 @@ အသစ္မြမ္းမံမႈ ၁ ခုရရွိႏိုင္သည္ အသစ္မြမ္းမံမႈ %d ခုရရွိႏိုင္သည္. F-Droid အသစ္မြမ္းမံမႈရရွိႏိုင္သည္ - +%1$d ေနာက္ထပ္.. + +%1$d ေနာက္ထပ္.. ဘလူးသုဒ့္ႏွင့္ပို႔ရန္နည္းလမ္းရွာမေတြ႕ပါ။ တစ္ခုေရြးပါ! ဘလူးသုဒ့္ႏွင့္ပို႔ေသာနည္းလမ္းကိုေရြးမည္ ဘလူးသုဒ့္မွတစ္ဆင့္ပို႔မည္ diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 3b481e6eb..64a3c0ee5 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -185,7 +185,7 @@ skru på denne pakkebrønnen igjen for å installere programmer fra den.Tilbake Installert - +%1$d mer… + +%1$d mer… Feil i fingeravtrykk Dette er ikke en gyldig nettadresse. Endringslogg diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index b3a5681a4..6b9e58fbd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -179,7 +179,7 @@ Je moet deze bron weer inschakelen indien je er apps van wil installeren.Links Terug - +%1$d meer… + +%1$d meer… Slechte vingerafdruk Dit is geen correcte URL. Lijst van veranderingen diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index bd646f2f5..7570096e5 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -155,7 +155,7 @@ Uwaga: Wszystkie poprzednio zainstalowane aplikacje zostaną na urządzeniu.Powrót Liczba dostępnych aktualizacji: %d. - +%1$d więcej… + +%1$d więcej… Nie znaleziono metody do wysłania przez Bluetooth! Wybierz metodę wysłania przez Bluetooth To repozytorium jest już dodane. Klucz zostanie zaktualizowany. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index f05d62636..b2c72e12f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -186,7 +186,7 @@ reativar este repositório para instalar aplicativos a partir dele. Links Voltar - Mais +%1$d… + Mais +%1$d… Falha na fingerprint Esta não é uma URL válida. Changelog diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index df67aa098..618a31938 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -66,7 +66,7 @@ 1 atualização disponível. %d atualizações disponíveis. Atualizações F-Droid disponíveis - +%1$d… + +%1$d… Nenhum método de envio Bluetooth encontrado. Escolha um! Escolha o método de envio Bluetooth Enviar por Bluetooth diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 4c2cf84d7..4ae5ada7b 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -97,7 +97,7 @@ Instalat (%d) Actualizari (%d) Actualizari disponibile in F-Droid - +%1$d mai mult… + +%1$d mai mult… Nu a fost gasita o metoda Bluetooth de a trimite, alegeti una! Alegeti metoda de a trimite prin Bluetooth Trimite prin Bluetooth diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 164deaf8f..b3cfbf3cf 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -212,7 +212,7 @@ Меньше Назад - Детали +%1$d … + Детали +%1$d … Неверный отпечаток ключа URL некорректен. Список изменений diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index b27a228ba..f5e0fbd99 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -184,7 +184,7 @@ Depes Ligàmenes In dae segus - +%1$d àteru(os)… + +%1$d àteru(os)… Custu no est unu ligàmene vàlidu. Lista modìficas Agiornende sos depòsitos diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index f8ddc6acc..53b71a12e 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -187,7 +187,7 @@ znovu povoliť tento repozitár pre inštaláciu aplikácií z neho. Späť Nainštalované - +%1$d viac… + +%1$d viac… Posielanie cez Bluetooth zlyhalo, zvoľte inú metódu! Vyberte posielanie cez Bluetooth Tento repozitár je už nastavený a povolený. diff --git a/app/src/main/res/values-sn/strings.xml b/app/src/main/res/values-sn/strings.xml index 4b6c7189e..521acf544 100644 --- a/app/src/main/res/values-sn/strings.xml +++ b/app/src/main/res/values-sn/strings.xml @@ -76,7 +76,7 @@ Chekunatsa 1 chiripo. Zvekunatsa %d zviripo. Zvekunatsa F-Droid zviripo - zvimwe +%1$d … + zvimwe +%1$d … Hapana mutowo wekutumira neBluetooth wawanikwa, sarudza imwe chete! Sarudza mutowo weBluetooth wekutumira nawo Tumira kuburikira neBluetooth diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 5e872ecc4..62d7a0b6a 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -188,7 +188,7 @@ Назад Инсталиране - +још %1$d… + +још %1$d… Лош отисак Ово није исправна адреса. Дневник измена diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index b5ce211ad..64f7ef44a 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -191,7 +191,7 @@ Du kommer Bakåt Installerade - +%1$d mer… + +%1$d mer… Felaktigt fingeravtryck Det här är inte en giltig hemsideadress. Inställningar diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index f85cf6149..88791c754 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -314,7 +314,7 @@ ไม่แสดงตัวบน Wi-Fi ไม่พบคนรอบข้างที่สามารถจะแบ่งปันโปรแกรมด้วยได้ QR Code ที่อ่านได้ ไม่ใช่โค้ดที่ใช้แบ่งปันโปรแกรม - มีอีก +%1$d… + มีอีก +%1$d… จัดให้โดย %1$s ไม่เจอคนที่ตามหาหรือ? แลกเปลี่ยนโปรแกรมกับคนข้างๆ diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c395ba64e..701ec9fc9 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -203,7 +203,7 @@ bu depoyu tekrar etkinleştirmeniz gerekecektir. Kurulu Kurulu (%d) Güncellemeler (%d) - +%1$d daha… + +%1$d daha… Yanlış parmak izi Bu, geçerli bir URL değildir. Ayarlar diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 9b3c0a68d..8a045d226 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -90,7 +90,7 @@ Одне оновлення доступно. %d оновлень доступно. F-Droid: доступні оновлення - +%1$d більше… + +%1$d більше… Надіслати через Bluetooth Поділитися diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 52bd4cf62..7f61fc486 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -168,7 +168,7 @@ Mã nguồn Không tương thích Đã cài đặt - +%1$d ứng dụng khác… + +%1$d ứng dụng khác… Đây không phải là URL hợp lệ. Lịch sử sửa đổi Bitcoin diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 414b45921..6cc9d8922 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -168,7 +168,7 @@ 已安装 已安装(%d) 可更新(%d) - +%1$d 更多… + +%1$d 更多… 用蓝牙发送 指纹错误 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index f92b5f6fd..6c4698543 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -228,7 +228,7 @@ 您想更新此應用程式嗎? 您不會失去現有的數據, 已更新的程式亦不需要任何特別的存取權。 - 還有 +%1$d 個… + 還有 +%1$d 個… 下一步 %1$s 至 %2$s 應用程式的新版本使用了不同的鑰匙簽署。若要安裝新版本,您必須先將舊版本卸載,然後再嘗試安裝。(注意:卸載將會把應用程式內的資料刪除) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b5ac9b000..8d4018a3a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -257,7 +257,7 @@ 使用私密連線 空的使用者名稱,憑證未改變 - +%1$d 更多… + +%1$d 更多… 此應用軟體倉庫已經設立。確認您要重新啟用它。 進入的儲存庫已設立並已啟用。 略過異常的應用軟體倉庫 URI:%s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ea70e6a6c..54eeb414a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,10 +88,7 @@ Updates Installed (%d) Updates (%d) - 1 update is available. - %d updates are available. F-Droid Updates Available - +%1$d more… No Bluetooth send method found, choose one! Choose Bluetooth send method Send via Bluetooth @@ -400,4 +397,29 @@ forcing the application to stop. Would you like to e-mail the details to help fix the issue? You can add extra information and comments here: + + + +%1$d more… + Update Available + Ready to install + Update ready to install + Install Failed + Downloading update for \"%1$s\"… + Installing \"%1$s\"… + Successfully installed + Install Failed + %1$d Updates + %1$d Apps Installed + Update available + Downloading… + Downloading update… + Ready to install + Update ready to install + Installing + Successfully installed + Install Failed + Update + Cancel + Install +