allow displaying localized icons

Move the logic of calculating the correct iconUrl from sql to java.

Fixes #1460.
This commit is contained in:
Marcus Hoffmann 2020-02-21 14:45:46 +01:00
parent a1701ca8c0
commit a500660a41
12 changed files with 51 additions and 66 deletions

View File

@ -309,7 +309,7 @@ public class SwapSuccessView extends SwapView implements LoaderManager.LoaderCal
nameView.setText(app.name); nameView.setText(app.name);
} }
ImageLoader.getInstance().displayImage(app.iconUrl, iconView, Utils.getRepoAppDisplayImageOptions()); ImageLoader.getInstance().displayImage(app.getIconUrl(iconView.getContext()), iconView, Utils.getRepoAppDisplayImageOptions());
if (app.hasUpdates()) { if (app.hasUpdates()) {
btnInstall.setText(R.string.menu_upgrade); btnInstall.setText(R.string.menu_upgrade);

View File

@ -493,7 +493,7 @@ class NotificationHelper {
private Bitmap getLargeIconForEntry(AppUpdateStatusManager.AppUpdateStatus entry) { private Bitmap getLargeIconForEntry(AppUpdateStatusManager.AppUpdateStatus entry) {
final Point largeIconSize = getLargeIconSize(); final Point largeIconSize = getLargeIconSize();
Bitmap iconLarge = null; Bitmap iconLarge = null;
if (TextUtils.isEmpty(entry.app.iconUrl)) { if (TextUtils.isEmpty(entry.app.getIconUrl(context))) {
return null; return null;
} else if (entry.status == AppUpdateStatusManager.Status.Downloading } else if (entry.status == AppUpdateStatusManager.Status.Downloading
|| entry.status == AppUpdateStatusManager.Status.Installing) { || entry.status == AppUpdateStatusManager.Status.Installing) {
@ -505,12 +505,12 @@ class NotificationHelper {
downloadIcon.draw(canvas); downloadIcon.draw(canvas);
} }
return bitmap; return bitmap;
} else if (DiskCacheUtils.findInCache(entry.app.iconUrl, ImageLoader.getInstance().getDiskCache()) != null) { } else if (DiskCacheUtils.findInCache(entry.app.getIconUrl(context), ImageLoader.getInstance().getDiskCache()) != null) {
iconLarge = ImageLoader.getInstance().loadImageSync( iconLarge = ImageLoader.getInstance().loadImageSync(
entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y)); entry.app.getIconUrl(context), new ImageSize(largeIconSize.x, largeIconSize.y));
} else { } else {
// Load it for later! // Load it for later!
ImageLoader.getInstance().loadImage(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), new ImageLoadingListener() { ImageLoader.getInstance().loadImage(entry.app.getIconUrl(context), new ImageSize(largeIconSize.x, largeIconSize.y), new ImageLoadingListener() {
AppUpdateStatusManager.AppUpdateStatus entry; AppUpdateStatusManager.AppUpdateStatus entry;
@ -536,8 +536,8 @@ class NotificationHelper {
AppUpdateStatusManager.AppUpdateStatus oldEntry = appUpdateStatusManager.get(entry.getCanonicalUrl()); AppUpdateStatusManager.AppUpdateStatus oldEntry = appUpdateStatusManager.get(entry.getCanonicalUrl());
if (oldEntry != null if (oldEntry != null
&& oldEntry.app != null && oldEntry.app != null
&& oldEntry.app.iconUrl != null && oldEntry.app.getIconUrl(context) != null
&& DiskCacheUtils.findInCache(oldEntry.app.iconUrl, ImageLoader.getInstance().getDiskCache()) != null) { && DiskCacheUtils.findInCache(oldEntry.app.getIconUrl(context), ImageLoader.getInstance().getDiskCache()) != null) {
createNotification(oldEntry); // Update with new image! createNotification(oldEntry); // Update with new image!
} }
} }

View File

@ -19,9 +19,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.io.filefilter.RegexFileFilter; import org.apache.commons.io.filefilter.RegexFileFilter;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
@ -217,7 +219,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
/** /**
* URL to download the app's icon. * URL to download the app's icon.
*/ */
public String iconUrl; private String iconUrl;
public static String getIconName(String packageName, int versionCode) { public static String getIconName(String packageName, int versionCode) {
return packageName + "_" + versionCode + ".png"; return packageName + "_" + versionCode + ".png";
@ -567,6 +569,10 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
if (!TextUtils.isEmpty(value)) { if (!TextUtils.isEmpty(value)) {
description = formatDescription(value); description = formatDescription(value);
} }
value = getLocalizedGraphicsEntry(localized, localesToUse, "icon");
if (!TextUtils.isEmpty(value)) {
iconUrl = value;
}
featureGraphic = getLocalizedGraphicsEntry(localized, localesToUse, "featureGraphic"); featureGraphic = getLocalizedGraphicsEntry(localized, localesToUse, "featureGraphic");
promoGraphic = getLocalizedGraphicsEntry(localized, localesToUse, "promoGraphic"); promoGraphic = getLocalizedGraphicsEntry(localized, localesToUse, "promoGraphic");
@ -656,6 +662,23 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
return description.replace("\n", "<br>"); return description.replace("\n", "<br>");
} }
public String getIconUrl(Context context) {
Repo repo = RepoProvider.Helper.findById(context, repoId);
if (TextUtils.isEmpty(iconUrl)) {
if (TextUtils.isEmpty(icon)){
return null;
}
String iconsDir;
if (repo.version >= Repo.VERSION_DENSITY_SPECIFIC_ICONS) {
iconsDir = Utils.getIconsDir(context, 1.0);
} else {
iconsDir = Utils.FALLBACK_ICONS_DIR;
}
return repo.address + iconsDir + icon;
}
return repo.address + "/" + packageName + "/" + iconUrl;
}
public String getFeatureGraphicUrl(Context context) { public String getFeatureGraphicUrl(Context context) {
if (TextUtils.isEmpty(featureGraphic)) { if (TextUtils.isEmpty(featureGraphic)) {
return null; return null;

View File

@ -1007,8 +1007,6 @@ public class AppProvider extends FDroidProvider {
updatePreferredMetadata(); updatePreferredMetadata();
updateCompatibleFlags(); updateCompatibleFlags();
updateSuggestedFromUpstream(null); updateSuggestedFromUpstream(null);
updateSuggestedFromLatest(null);
updateIconUrls();
} }
/** /**
@ -1182,51 +1180,4 @@ public class AppProvider extends FDroidProvider {
LoggingQuery.execSQL(db(), updateSql, args); LoggingQuery.execSQL(db(), updateSql, args);
} }
private void updateIconUrls() {
final String appTable = getTableName();
final String iconsDir = Utils.getIconsDir(getContext(), 1.0);
String repoVersion = Integer.toString(Repo.VERSION_DENSITY_SPECIFIC_ICONS);
Utils.debugLog(TAG, "Updating icon paths for apps belonging to repos with version >= " + repoVersion);
Utils.debugLog(TAG, "Using icons dir '" + iconsDir + "'");
String query = getIconUpdateQuery(appTable);
final String[] params = {
repoVersion, iconsDir, Utils.FALLBACK_ICONS_DIR,
};
db().execSQL(query, params);
}
/**
* Returns a query which requires two parameters to be bound. These are (in order):
* 1) The repo version that introduced density specific icons
* 2) The dir to density specific icons for the current device.
*/
private static String getIconUpdateQuery(String app) {
final String repo = RepoTable.NAME;
final String iconUrlQuery =
"SELECT " +
// Concatenate (using the "||" operator) the address, the
// icons directory (bound to the ? as the second parameter
// when executing the query) and the icon path.
"( " +
repo + "." + RepoTable.Cols.ADDRESS +
" || " +
// If the repo has the relevant version, then use a more
// intelligent icons dir, otherwise revert to the default
// one
" CASE WHEN " + repo + "." + RepoTable.Cols.VERSION + " >= ? THEN ? ELSE ? END " +
" || " +
app + "." + Cols.ICON +
") " +
" FROM " +
repo + " WHERE " + repo + "." + RepoTable.Cols._ID + " = " + app + "." + Cols.REPO_ID;
return "UPDATE " + app + " SET "
+ Cols.ICON_URL + " = ( " + iconUrlQuery + " )";
}
} }

View File

@ -227,7 +227,7 @@ public class DBHelper extends SQLiteOpenHelper {
+ "primary key(" + ApkAntiFeatureJoinTable.Cols.APK_ID + ", " + ApkAntiFeatureJoinTable.Cols.ANTI_FEATURE_ID + ") " + "primary key(" + ApkAntiFeatureJoinTable.Cols.APK_ID + ", " + ApkAntiFeatureJoinTable.Cols.ANTI_FEATURE_ID + ") "
+ " );"; + " );";
protected static final int DB_VERSION = 83; protected static final int DB_VERSION = 84;
private final Context context; private final Context context;
@ -456,6 +456,15 @@ public class DBHelper extends SQLiteOpenHelper {
addIsLocalized(db, oldVersion); addIsLocalized(db, oldVersion);
addTranslation(db, oldVersion); addTranslation(db, oldVersion);
switchRepoArchivePriorities(db, oldVersion); switchRepoArchivePriorities(db, oldVersion);
deleteOldIconUrls(db, oldVersion);
}
private void deleteOldIconUrls(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 84) {
return;
}
Utils.debugLog(TAG, "Clearing iconUrl field to enable localized icons on next update");
db.execSQL("UPDATE " + AppMetadataTable.NAME + " SET " + AppMetadataTable.Cols.ICON_URL + "= NULL");
} }
private void switchRepoArchivePriorities(SQLiteDatabase db, int oldVersion) { private void switchRepoArchivePriorities(SQLiteDatabase db, int oldVersion) {

View File

@ -76,7 +76,7 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost); TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost);
appName.setText(app.name); appName.setText(app.name);
ImageLoader.getInstance().displayImage(app.iconUrl, appIcon, ImageLoader.getInstance().displayImage(app.getIconUrl(this), appIcon,
Utils.getRepoAppDisplayImageOptions()); Utils.getRepoAppDisplayImageOptions());
tabHost.setup(); tabHost.setup();

View File

@ -149,7 +149,7 @@ public class AppDetailsActivity extends AppCompatActivity
DisplayImageOptions displayImageOptions = Utils.getRepoAppDisplayImageOptions(); DisplayImageOptions displayImageOptions = Utils.getRepoAppDisplayImageOptions();
String featureGraphicUrl = app.getFeatureGraphicUrl(this); String featureGraphicUrl = app.getFeatureGraphicUrl(this);
featureImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions, featureImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions,
featureGraphicUrl, app.iconUrl); featureGraphicUrl, app.getIconUrl(this));
} }
private String getPackageNameFromIntent(Intent intent) { private String getPackageNameFromIntent(Intent intent) {

View File

@ -480,7 +480,7 @@ public class AppDetailsRecyclerViewAdapter
} }
public void bindModel() { public void bindModel() {
ImageLoader.getInstance().displayImage(app.iconUrl, iconView, Utils.getRepoAppDisplayImageOptions()); ImageLoader.getInstance().displayImage(app.getIconUrl(iconView.getContext()), iconView, Utils.getRepoAppDisplayImageOptions());
titleView.setText(app.name); titleView.setText(app.name);
if (!TextUtils.isEmpty(app.authorName)) { if (!TextUtils.isEmpty(app.authorName)) {
authorView.setText(context.getString(R.string.by_author_format, app.authorName)); authorView.setText(context.getString(R.string.by_author_format, app.authorName));

View File

@ -191,7 +191,7 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
if (actionButton != null) actionButton.setEnabled(true); if (actionButton != null) actionButton.setEnabled(true);
if (app.iconUrl == null) { if (app.getIconUrl(icon.getContext()) == null) {
try { try {
icon.setImageDrawable(activity.getPackageManager().getApplicationIcon(app.packageName)); icon.setImageDrawable(activity.getPackageManager().getApplicationIcon(app.packageName));
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
@ -201,7 +201,7 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
: null); : null);
} }
} else { } else {
ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions()); ImageLoader.getInstance().displayImage(app.getIconUrl(icon.getContext()), icon, Utils.getRepoAppDisplayImageOptions());
} }
// Figures out the current install/update/download/etc status for the app we are viewing. // Figures out the current install/update/download/etc status for the app we are viewing.

View File

@ -96,7 +96,7 @@ public class AppCardController extends RecyclerView.ViewHolder
} }
} }
ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions()); ImageLoader.getInstance().displayImage(app.getIconUrl(icon.getContext()), icon, Utils.getRepoAppDisplayImageOptions());
} }
private boolean isConsideredNew(@NonNull App app) { private boolean isConsideredNew(@NonNull App app) {

View File

@ -154,6 +154,8 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME, Schema.AppMetadataTable.Cols.Package.PACKAGE_NAME,
Schema.AppMetadataTable.Cols.SUMMARY, Schema.AppMetadataTable.Cols.SUMMARY,
Schema.AppMetadataTable.Cols.ICON_URL, Schema.AppMetadataTable.Cols.ICON_URL,
Schema.AppMetadataTable.Cols.ICON,
Schema.AppMetadataTable.Cols.REPO_ID,
}, },
null, null,
null, null,
@ -167,7 +169,7 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
int topAppsId = currentCategory.hashCode(); int topAppsId = currentCategory.hashCode();
int countAllAppsId = topAppsId + 1; int countAllAppsId = topAppsId + 1;
// Anything other than these IDs indicates that the loader which just finished finished // Anything other than these IDs indicates that the loader which just finished
// is no longer the one this view holder is interested in, due to the user having // is no longer the one this view holder is interested in, due to the user having
// scrolled away already during the asynchronous query being run. // scrolled away already during the asynchronous query being run.
if (loader.getId() == topAppsId) { if (loader.getId() == topAppsId) {

View File

@ -68,7 +68,7 @@ public class AppIconsTest extends MultiIndexUpdaterTest {
App app = AppProvider.Helper.findHighestPriorityMetadata(context.getContentResolver(), App app = AppProvider.Helper.findHighestPriorityMetadata(context.getContentResolver(),
"org.adaway", new String[]{Schema.AppMetadataTable.Cols.ICON_URL}); "org.adaway", new String[]{Schema.AppMetadataTable.Cols.ICON_URL});
assertEquals(app.iconUrl, expectedUrl); assertEquals(app.getIconUrl(context), expectedUrl);
} }
} }