diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java index afe3d8e7b..554016be4 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java @@ -173,7 +173,7 @@ public class AppDetails2 extends AppCompatActivity // Load the feature graphic, if present final FeatureImage featureImage = (FeatureImage) findViewById(R.id.feature_graphic); - DisplayImageOptions displayImageOptions = Utils.getImageLoadingOptions().build(); + DisplayImageOptions displayImageOptions = Utils.getRepoAppDisplayImageOptions(); String featureGraphicUrl = app.getFeatureGraphicUrl(this); featureImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions, featureGraphicUrl, app.iconUrl); diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index 3306a32e9..58b16de3f 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -32,17 +32,13 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; -import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.StrictMode; -import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.view.WindowManager; import android.widget.Toast; -import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiskCache; -import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import info.guardianproject.netcipher.NetCipher; @@ -59,7 +55,6 @@ import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.InstalledAppProviderService; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; -import org.fdroid.fdroid.data.SanitizedFile; import org.fdroid.fdroid.installer.ApkFileProvider; import org.fdroid.fdroid.installer.InstallHistoryService; import org.fdroid.fdroid.net.ImageLoaderForUIL; @@ -302,6 +297,20 @@ public class FDroidApp extends Application { atStartTime.edit().putString(lastLocaleKey, currentLocale).apply(); } + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + if (level >= TRIM_MEMORY_BACKGROUND) { + ImageLoader.getInstance().clearMemoryCache(); + } + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + ImageLoader.getInstance().clearMemoryCache(); + } + @Override public void onCreate() { super.onCreate(); @@ -387,34 +396,8 @@ public class FDroidApp extends Application { ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()) .imageDownloader(new ImageLoaderForUIL(getApplicationContext())) - .diskCache(new LimitedAgeDiskCache( - Utils.getImageCacheDir(this), - null, - new FileNameGenerator() { - @NonNull - @Override - public String generate(String imageUri) { - if (TextUtils.isEmpty(imageUri)) { - return "null"; - } - - String fileNameToSanitize; - Uri uri = Uri.parse(imageUri); - if (TextUtils.isEmpty(uri.getPath())) { - // files with URL like "drawable://213083835209" used by the category backgrounds - fileNameToSanitize = imageUri.replaceAll("[:/]", ""); - } else { - fileNameToSanitize = uri.getPath().replace("/", "-"); - } - - return SanitizedFile.sanitizeFileName(fileNameToSanitize); - } - }, - // 30 days in secs: 30*24*60*60 = 2592000 - 2592000) - ) - .threadPoolSize(4) - .threadPriority(Thread.NORM_PRIORITY - 2) // Default is NORM_PRIORITY - 1 + .defaultDisplayImageOptions(Utils.getDefaultDisplayImageOptionsBuilder().build()) + .threadPoolSize(getThreadPoolSize()) .build(); ImageLoader.getInstance().init(config); @@ -487,6 +470,24 @@ public class FDroidApp extends Application { return false; } + /** + * Return the number of threads Universal Image Loader should use, based on + * the total RAM in the device. Devices with lots of RAM can do lots of + * parallel operations for fast icon loading. + */ + @TargetApi(16) + private int getThreadPoolSize() { + if (Build.VERSION.SDK_INT >= 16) { + ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + if (activityManager != null) { + activityManager.getMemoryInfo(memInfo); + return (int) Math.max(1, Math.min(16, memInfo.totalMem / 256 / 1024 / 1024)); + } + } + return 2; + } + @TargetApi(18) private BluetoothAdapter getBluetoothAdapter() { // to use the new, recommended way of getting the adapter diff --git a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java index 7d9a5d9d6..927b5626b 100644 --- a/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/NotificationHelper.java @@ -21,10 +21,8 @@ import android.text.Spanned; import android.text.TextUtils; 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; @@ -54,7 +52,6 @@ class NotificationHelper { private final Context context; private final NotificationManagerCompat notificationManager; private final AppUpdateStatusManager appUpdateStatusManager; - private final DisplayImageOptions displayImageOptions; private final ArrayList updates = new ArrayList<>(); private final ArrayList installed = new ArrayList<>(); @@ -62,12 +59,6 @@ class NotificationHelper { this.context = 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(); IntentFilter filter = new IntentFilter(); filter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED); @@ -506,7 +497,8 @@ class NotificationHelper { Bitmap iconLarge = null; if (TextUtils.isEmpty(entry.app.iconUrl)) { return null; - } else if (entry.status == AppUpdateStatusManager.Status.Downloading || entry.status == AppUpdateStatusManager.Status.Installing) { + } else if (entry.status == AppUpdateStatusManager.Status.Downloading + || entry.status == AppUpdateStatusManager.Status.Installing) { Bitmap bitmap = Bitmap.createBitmap(largeIconSize.x, largeIconSize.y, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Drawable downloadIcon = ContextCompat.getDrawable(context, R.drawable.ic_notification_download); @@ -516,10 +508,11 @@ class NotificationHelper { } return bitmap; } else if (DiskCacheUtils.findInCache(entry.app.iconUrl, ImageLoader.getInstance().getDiskCache()) != null) { - iconLarge = ImageLoader.getInstance().loadImageSync(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), displayImageOptions); + iconLarge = ImageLoader.getInstance().loadImageSync( + entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y)); } else { // Load it for later! - ImageLoader.getInstance().loadImage(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), displayImageOptions, new ImageLoadingListener() { + ImageLoader.getInstance().loadImage(entry.app.iconUrl, new ImageSize(largeIconSize.x, largeIconSize.y), new ImageLoadingListener() { AppUpdateStatusManager.AppUpdateStatus entry; diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java index bb3873309..a0480f461 100644 --- a/app/src/main/java/org/fdroid/fdroid/Utils.java +++ b/app/src/main/java/org/fdroid/fdroid/Utils.java @@ -92,6 +92,9 @@ public final class Utils { "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB", }; + private static DisplayImageOptions.Builder defaultDisplayImageOptionsBuilder; + private static DisplayImageOptions repoAppDisplayImageOptions; + public static final String FALLBACK_ICONS_DIR = "/icons/"; /* @@ -369,15 +372,33 @@ public final class Utils { return new Locale(languageTag); } - public static DisplayImageOptions.Builder getImageLoadingOptions() { - return new DisplayImageOptions.Builder() - .cacheInMemory(true) - .cacheOnDisk(true) - .imageScaleType(ImageScaleType.NONE) - .showImageOnLoading(R.drawable.ic_repo_app_default) - .showImageForEmptyUri(R.drawable.ic_repo_app_default) - .displayer(new FadeInBitmapDisplayer(200, true, true, false)) - .bitmapConfig(Bitmap.Config.RGB_565); + public static DisplayImageOptions.Builder getDefaultDisplayImageOptionsBuilder() { + if (defaultDisplayImageOptionsBuilder == null) { + defaultDisplayImageOptionsBuilder = new DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisk(true) + .considerExifParams(false) + .bitmapConfig(Bitmap.Config.RGB_565) + .imageScaleType(ImageScaleType.NONE); + } + return defaultDisplayImageOptionsBuilder; + } + + /** + * Gets the {@link DisplayImageOptions} instance used to configure + * {@link com.nostra13.universalimageloader.core.ImageLoader} instances + * used to display app icons. It lazy loads a reusable static instance. + */ + public static DisplayImageOptions getRepoAppDisplayImageOptions() { + if (repoAppDisplayImageOptions == null) { + repoAppDisplayImageOptions = getDefaultDisplayImageOptionsBuilder() + .showImageOnLoading(R.drawable.ic_repo_app_default) + .showImageForEmptyUri(R.drawable.ic_repo_app_default) + .showImageOnFail(R.drawable.ic_repo_app_default) + .displayer(new FadeInBitmapDisplayer(200, true, true, false)) + .build(); + } + return repoAppDisplayImageOptions; } // this is all new stuff being added @@ -554,8 +575,10 @@ public final class Utils { } } - // Need this to add the unimplemented support for ordered and unordered - // lists to Html.fromHtml(). + /** + * Need this to add the unimplemented support for ordered and unordered + * lists to Html.fromHtml(). + */ public static class HtmlTagHandler implements Html.TagHandler { int listNum; diff --git a/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java b/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java index 9c908e7a7..8e87b4347 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java +++ b/app/src/main/java/org/fdroid/fdroid/net/DownloaderFactory.java @@ -3,7 +3,6 @@ package org.fdroid.fdroid.net; import android.content.Context; import android.net.Uri; import android.support.v4.content.LocalBroadcastManager; - import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.Schema; @@ -41,11 +40,9 @@ public class DownloaderFactory { localBroadcastManager = LocalBroadcastManager.getInstance(context); } - if (isBluetoothAddress(url)) { + if ("bluetooth".equalsIgnoreCase(url.getProtocol())) { String macAddress = url.getHost().replace("-", ":"); downloader = new BluetoothDownloader(macAddress, url, destFile); - } else if (isLocalFile(url)) { - downloader = new LocalFileDownloader(url, destFile); } else { final String[] projection = {Schema.RepoTable.Cols.USERNAME, Schema.RepoTable.Cols.PASSWORD}; Repo repo = RepoProvider.Helper.findByUrl(context, Uri.parse(url.toString()), projection); @@ -57,12 +54,4 @@ public class DownloaderFactory { } return downloader; } - - private static boolean isBluetoothAddress(URL url) { - return "bluetooth".equalsIgnoreCase(url.getProtocol()); - } - - private static boolean isLocalFile(URL url) { - return "file".equalsIgnoreCase(url.getProtocol()); - } } diff --git a/app/src/main/java/org/fdroid/fdroid/net/ImageLoaderForUIL.java b/app/src/main/java/org/fdroid/fdroid/net/ImageLoaderForUIL.java index 508d9df06..883c2d9d2 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/ImageLoaderForUIL.java +++ b/app/src/main/java/org/fdroid/fdroid/net/ImageLoaderForUIL.java @@ -1,15 +1,18 @@ package org.fdroid.fdroid.net; import android.content.Context; - import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import java.io.IOException; import java.io.InputStream; /** - * Class used by the Universal Image Loader library (UIL) to fetch images for displaying in F-Droid. - * See {@link org.fdroid.fdroid.FDroidApp} for where this gets configured. + * Class used by the Universal Image Loader library (UIL) to fetch images for + * displaying in F-Droid. A custom subclass is needed since F-Droid's + * {@link HttpDownloader} provides support for Tor, proxying, and automatic + * mirror failover. + * + * @see org.fdroid.fdroid.FDroidApp#onCreate() for where this is setup */ public class ImageLoaderForUIL implements com.nostra13.universalimageloader.core.download.ImageDownloader { @@ -22,15 +25,10 @@ public class ImageLoaderForUIL implements com.nostra13.universalimageloader.core @Override public InputStream getStream(String imageUri, Object extra) throws IOException { switch (Scheme.ofUri(imageUri)) { - case ASSETS: - return context.getAssets().open(Scheme.ASSETS.crop(imageUri)); - - case DRAWABLE: - return new BaseImageDownloader(context).getStream(imageUri, extra); - - default: + case HTTP: + case HTTPS: return DownloaderFactory.create(context, imageUri).getInputStream(); } + return new BaseImageDownloader(context).getStream(imageUri, extra); } - } diff --git a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java deleted file mode 100644 index d9d85e5d6..000000000 --- a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.fdroid.fdroid.net; - -import org.fdroid.fdroid.Utils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; - -public class LocalFileDownloader extends Downloader { - - private InputStream inputStream; - - LocalFileDownloader(URL url, File destFile) throws FileNotFoundException, MalformedURLException { - super(url, destFile); - } - - @Override - protected InputStream getDownloadersInputStream() throws IOException { - inputStream = new FileInputStream(new File(sourceUrl.getPath())); - return inputStream; - } - - @Override - protected void close() { - if (inputStream != null) { - Utils.closeQuietly(inputStream); - } - } - - @Override - public boolean hasChanged() { - return false; - } - - @Override - public int totalDownloadSize() { - return 0; - } - - @Override - public void download() throws IOException, InterruptedException { - if (new File(sourceUrl.getPath()).exists()) { - downloadFromStream(1024 * 50, false); - } else { - notFound = true; - } - } -} diff --git a/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java b/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java index 5c3287074..f9f9791b8 100644 --- a/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java @@ -23,7 +23,6 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.FragmentActivity; @@ -36,11 +35,10 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TabHost; import android.widget.TextView; -import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageScaleType; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.App; @@ -71,15 +69,6 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel private App app; - private final DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() - .cacheInMemory(true) - .cacheOnDisk(true) - .imageScaleType(ImageScaleType.NONE) - .showImageOnLoading(R.drawable.ic_repo_app_default) - .showImageForEmptyUri(R.drawable.ic_repo_app_default) - .bitmapConfig(Bitmap.Config.RGB_565) - .build(); - private void startInstallConfirm() { View appSnippet = findViewById(R.id.app_snippet); TextView appName = (TextView) appSnippet.findViewById(R.id.app_name); @@ -87,7 +76,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost); appName.setText(app.name); - ImageLoader.getInstance().displayImage(app.iconUrl, appIcon, displayImageOptions); + ImageLoader.getInstance().displayImage(app.iconUrl, appIcon, + Utils.getRepoAppDisplayImageOptions()); tabHost.setup(); ViewPager viewPager = (ViewPager) findViewById(R.id.pager); diff --git a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java index d6dea4384..e31f174c1 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java +++ b/app/src/main/java/org/fdroid/fdroid/views/AppDetailsRecyclerViewAdapter.java @@ -6,7 +6,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; -import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.DrawableRes; import android.support.annotation.LayoutRes; @@ -34,11 +33,7 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; - -import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageScaleType; - import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; @@ -317,7 +312,6 @@ public class AppDetailsRecyclerViewAdapter final TextView progressLabel; final TextView progressPercent; final View progressCancel; - final DisplayImageOptions displayImageOptions; boolean descriptionIsExpanded; HeaderViewHolder(View view) { @@ -340,14 +334,6 @@ public class AppDetailsRecyclerViewAdapter progressLabel = (TextView) view.findViewById(R.id.progress_label); progressPercent = (TextView) view.findViewById(R.id.progress_percent); progressCancel = view.findViewById(R.id.progress_cancel); - displayImageOptions = new DisplayImageOptions.Builder() - .cacheInMemory(true) - .cacheOnDisk(true) - .imageScaleType(ImageScaleType.NONE) - .showImageOnLoading(R.drawable.ic_repo_app_default) - .showImageForEmptyUri(R.drawable.ic_repo_app_default) - .bitmapConfig(Bitmap.Config.RGB_565) - .build(); descriptionView.setMaxLines(MAX_LINES); descriptionView.setEllipsize(TextUtils.TruncateAt.MARQUEE); descriptionMoreView.setOnClickListener(new View.OnClickListener() { @@ -408,7 +394,7 @@ public class AppDetailsRecyclerViewAdapter } public void bindModel() { - ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions); + ImageLoader.getInstance().displayImage(app.iconUrl, iconView, Utils.getRepoAppDisplayImageOptions()); titleView.setText(app.name); if (!TextUtils.isEmpty(app.authorName)) { authorView.setText(context.getString(R.string.by_author_format, app.authorName)); diff --git a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java index d85988026..9d5aea335 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsActivity.java @@ -3,7 +3,6 @@ package org.fdroid.fdroid.views; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.os.Build; import android.os.Bundle; import android.support.annotation.Nullable; @@ -16,18 +15,21 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; - import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageScaleType; - import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; /** - * Full screen view of an apps screenshots to swipe through. + * Full screen view of an apps screenshots to swipe through. This will always + * download the image, even if the user has said not to use "unmetered" networks, + * e.g. WiFi. That is because the user has to click on the thumbnail in + * {@link org.fdroid.fdroid.AppDetails2} in order to bring up this activity. + * That makes it a specific request for that image, rather than regular + * background loading. */ public class ScreenShotsActivity extends AppCompatActivity { @@ -114,13 +116,9 @@ public class ScreenShotsActivity extends AppCompatActivity { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() - .cacheInMemory(true) - .cacheOnDisk(true) - .imageScaleType(ImageScaleType.NONE) + DisplayImageOptions displayImageOptions = Utils.getDefaultDisplayImageOptionsBuilder() .showImageOnLoading(R.drawable.screenshot_placeholder) .showImageForEmptyUri(R.drawable.screenshot_placeholder) - .bitmapConfig(Bitmap.Config.RGB_565) .build(); View rootView = inflater.inflate(R.layout.activity_screenshots_page, container, false); diff --git a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java index 1ce4aee02..a128f6d23 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java +++ b/app/src/main/java/org/fdroid/fdroid/views/ScreenShotsRecyclerViewAdapter.java @@ -1,20 +1,20 @@ package org.fdroid.fdroid.views; import android.content.Context; -import android.graphics.Bitmap; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; - import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageScaleType; - import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.App; +/** + * Loads and displays the small screenshots that are inline in {@link org.fdroid.fdroid.AppDetails2} + */ class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter { private final String[] screenshots; private final DisplayImageOptions displayImageOptions; @@ -25,13 +25,9 @@ class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter - *
  • app_list_item (see {@link StandardAppListItemController}
  • - *
  • updateable_app_list_status_item (see - * {@link org.fdroid.fdroid.views.updates.items.AppStatusListItemController}
  • - *
  • updateable_app_list_item (see - * {@link org.fdroid.fdroid.views.updates.items.UpdateableAppListItemController}
  • - *
  • installed_app_list_item (see {@link StandardAppListItemController}
  • + *
  • app_list_item (see {@link StandardAppListItemController}
  • + *
  • updateable_app_list_status_item (see + * {@link org.fdroid.fdroid.views.updates.items.AppStatusListItemController}
  • + *
  • updateable_app_list_item (see + * {@link org.fdroid.fdroid.views.updates.items.UpdateableAppListItemController}
  • + *
  • installed_app_list_item (see {@link StandardAppListItemController}
  • * - * + *

    * The state of the UI is defined in a dumb {@link AppListItemState} class, then applied to the UI * in the {@link #refreshView(App, AppUpdateStatus)} method. */ @@ -98,8 +95,6 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { @Nullable private final Button secondaryButton; - private final DisplayImageOptions displayImageOptions; - @Nullable private App currentApp; @@ -156,8 +151,6 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { cancelButton.setOnClickListener(onCancelDownload); } - displayImageOptions = Utils.getImageLoadingOptions().build(); - itemView.setOnClickListener(onAppClicked); } @@ -169,7 +162,7 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { public void bindModel(@NonNull App app) { currentApp = app; - ImageLoader.getInstance().displayImage(app.iconUrl, icon, displayImageOptions); + ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions()); // Figures out the current install/update/download/etc status for the app we are viewing. // Then, asks the view to update itself to reflect this status. @@ -193,7 +186,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { broadcastManager.registerReceiver(onStatusChanged, intentFilter); } - /** To be overridden if required */ + /** + * To be overridden if required + */ public boolean canDismiss() { return false; } @@ -214,6 +209,7 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { /** * Override to respond to the user swiping an app to dismiss it from the list. + * * @return Optionally return a description of what you did if it is not obvious to the user. It will be shown as * a {@link android.widget.Toast} for a {@link android.widget.Toast#LENGTH_SHORT} time. * @see #canDismiss() This must also be overriden and should return true. @@ -235,7 +231,7 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { /** * Queries the current state via {@link #getCurrentViewState(App, AppUpdateStatus)} * and then updates the relevant widgets depending on that state. - * + *

    * Should contain little to no business logic, this all belongs to * {@link #getCurrentViewState(App, AppUpdateStatus)}. * @@ -489,7 +485,8 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI); try { pendingIntent.send(); - } catch (PendingIntent.CanceledException ignored) { } + } catch (PendingIntent.CanceledException ignored) { + } } } }; @@ -503,8 +500,11 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } } - /** To be overridden by subclasses if desired */ - protected void onSecondaryButtonPressed(@NonNull App app) { } + /** + * To be overridden by subclasses if desired + */ + protected void onSecondaryButtonPressed(@NonNull App app) { + } @SuppressWarnings("FieldCanBeLocal") private final View.OnClickListener onCancelDownload = new View.OnClickListener() { diff --git a/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java b/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java index b3c963da4..914285220 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java @@ -18,7 +18,6 @@ import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; @@ -70,7 +69,6 @@ public class AppCardController extends RecyclerView.ViewHolder private App currentApp; private final Activity activity; - private final DisplayImageOptions displayImageOptions; public AppCardController(Activity activity, View itemView) { super(itemView); @@ -83,8 +81,6 @@ public class AppCardController extends RecyclerView.ViewHolder featuredImage = (FeatureImage) itemView.findViewById(R.id.featured_image); newTag = (TextView) itemView.findViewById(R.id.new_tag); - displayImageOptions = Utils.getImageLoadingOptions().build(); - itemView.setOnClickListener(this); } @@ -117,7 +113,7 @@ public class AppCardController extends RecyclerView.ViewHolder } } - ImageLoader.getInstance().displayImage(app.iconUrl, icon, displayImageOptions, this); + ImageLoader.getInstance().displayImage(app.iconUrl, icon, Utils.getRepoAppDisplayImageOptions(), this); if (featuredImage != null) { featuredImage.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue)); @@ -133,7 +129,7 @@ public class AppCardController extends RecyclerView.ViewHolder // feature image to be loaded). if (!TextUtils.isEmpty(app.featureGraphic)) { featuredImage.loadImageAndDisplay(ImageLoader.getInstance(), - displayImageOptions, app.getFeatureGraphicUrl(activity)); + Utils.getRepoAppDisplayImageOptions(), app.getFeatureGraphicUrl(activity)); } } } @@ -162,7 +158,8 @@ public class AppCardController extends RecyclerView.ViewHolder Pair iconTransitionPair = Pair.create((View) icon, activity.getString(R.string.transition_app_item_icon)); - @SuppressWarnings("unchecked") // the right type is passed as 2nd varargs arg: Pair + // unchecked since the right type is passed as 2nd varargs arg: Pair + @SuppressWarnings("unchecked") Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle(); activity.startActivity(intent, b); } else { diff --git a/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java b/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java index b4ca76bdc..371623c8e 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java @@ -5,7 +5,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.database.Cursor; -import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; @@ -23,9 +22,9 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.Schema; import org.fdroid.fdroid.views.apps.AppListActivity; @@ -67,11 +66,8 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade appCards.setAdapter(appCardsAdapter); appCards.addItemDecoration(new ItemDecorator(activity)); - displayImageOptions = new DisplayImageOptions.Builder() - .cacheInMemory(true) - .imageScaleType(ImageScaleType.NONE) + displayImageOptions = Utils.getDefaultDisplayImageOptionsBuilder() .displayer(new FadeInBitmapDisplayer(100, true, true, false)) - .bitmapConfig(Bitmap.Config.RGB_565) .build(); } diff --git a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java index 78547c6be..143f067a0 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java +++ b/app/src/main/java/org/fdroid/fdroid/views/swap/SwapAppsView.java @@ -36,10 +36,7 @@ import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; - -import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; - import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.R; import org.fdroid.fdroid.UpdateService; @@ -63,8 +60,6 @@ public class SwapAppsView extends ListView implements LoaderManager.LoaderCallbacks, SearchView.OnQueryTextListener { - private DisplayImageOptions displayImageOptions; - public SwapAppsView(Context context) { super(context); } @@ -113,8 +108,6 @@ public class SwapAppsView extends ListView implements // either reconnect with an existing loader or start a new one getActivity().getSupportLoaderManager().initLoader(LOADER_SWAPABLE_APPS, null, this); - displayImageOptions = Utils.getImageLoadingOptions().build(); - LocalBroadcastManager.getInstance(getActivity()).registerReceiver( pollForUpdatesReceiver, new IntentFilter(UpdateService.LOCAL_ACTION_STATUS)); @@ -354,7 +347,7 @@ public class SwapAppsView extends ListView implements nameView.setText(app.name); } - ImageLoader.getInstance().displayImage(app.iconUrl, iconView, displayImageOptions); + ImageLoader.getInstance().displayImage(app.iconUrl, iconView, Utils.getRepoAppDisplayImageOptions()); if (app.hasUpdates()) { btnInstall.setText(R.string.menu_upgrade);