Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5154)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java

Issue 2464473002: [Download Home] Make the space display usable (Closed)
Patch Set: Added javadoc Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
index 6d9449f9c3517117682b1b5f0839286a60f2b308..dec67a4a29dd538856166b4f0bb90aabf5f750ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
@@ -15,112 +15,195 @@ import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Log;
+import org.chromium.base.ObserverList;
+import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import java.io.File;
+import java.util.concurrent.ExecutionException;
/** A View that manages the display of space used by the downloads. */
-class SpaceDisplay extends RecyclerView.AdapterDataObserver {
+public class SpaceDisplay extends RecyclerView.AdapterDataObserver {
+ /** Observes changes to the SpaceDisplay. */
+ public static interface Observer {
+ /** Called when the display has had its values updated. */
+ void onSpaceDisplayUpdated(SpaceDisplay spaceDisplay);
+ }
+
private static final String TAG = "download_ui";
private static final long BYTES_PER_KILOBYTE = 1024;
private static final long BYTES_PER_MEGABYTE = 1024 * 1024;
private static final long BYTES_PER_GIGABYTE = 1024 * 1024 * 1024;
+ private static final int[] USED_STRINGS = {
+ R.string.download_manager_ui_space_used_kb,
+ R.string.download_manager_ui_space_used_mb,
+ R.string.download_manager_ui_space_used_gb
+ };
+ private static final int[] FREE_STRINGS = {
+ R.string.download_manager_ui_space_free_kb,
+ R.string.download_manager_ui_space_free_mb,
+ R.string.download_manager_ui_space_free_gb
+ };
+ private static final int[] OTHER_STRINGS = {
+ R.string.download_manager_ui_space_other_kb,
+ R.string.download_manager_ui_space_other_mb,
+ R.string.download_manager_ui_space_other_gb
+ };
+
+ private static class StorageSizeTask extends AsyncTask<Void, Void, Long> {
+ /**
+ * If true, the task gets the total size of storage. If false, it fetches how much
+ * space is free.
+ */
+ private boolean mFetchTotalSize;
+
+ StorageSizeTask(boolean fetchTotalSize) {
+ mFetchTotalSize = fetchTotalSize;
+ }
+
+ @Override
+ protected Long doInBackground(Void... params) {
+ File downloadDirectory = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOWNLOADS);
+
+ // Create the downloads directory, if necessary.
+ if (!downloadDirectory.exists()) {
+ try {
+ // mkdirs() can fail, so we still need to check if the directory exists
+ // later.
+ downloadDirectory.mkdirs();
+ } catch (SecurityException e) {
+ Log.e(TAG, "SecurityException when creating download directory.", e);
+ }
+ }
+
+ // Determine how much space is available on the storage device where downloads
+ // reside. If the downloads directory doesn't exist, it is likely that the user
+ // doesn't have an SD card installed.
+ long blocks = 0;
+ if (downloadDirectory.exists()) {
+ StatFs statFs = new StatFs(downloadDirectory.getPath());
+ if (mFetchTotalSize) {
+ blocks = ApiCompatibilityUtils.getBlockCount(statFs);
+ } else {
+ blocks = ApiCompatibilityUtils.getAvailableBlocks(statFs);
+ }
+
+ return blocks * ApiCompatibilityUtils.getBlockSize(statFs);
+ } else {
+ Log.e(TAG, "Download directory doesn't exist.");
+ return 0L;
+ }
+ }
+ };
+
+ private final ObserverList<Observer> mObservers = new ObserverList<>();
private final AsyncTask<Void, Void, Long> mFileSystemBytesTask;
+ private AsyncTask<Void, Void, Long> mFreeBytesTask;
private DownloadHistoryAdapter mHistoryAdapter;
- private TextView mSpaceUsedTextView;
- private TextView mSpaceTotalTextView;
+ private TextView mSpaceUsedByDownloadsTextView;
+ private TextView mSpaceUsedByOtherAppsTextView;
+ private TextView mSpaceFreeTextView;
private ProgressBar mSpaceBar;
- private long mFileSystemBytes = Long.MAX_VALUE;
SpaceDisplay(final ViewGroup parent, DownloadHistoryAdapter historyAdapter) {
mHistoryAdapter = historyAdapter;
- mSpaceUsedTextView = (TextView) parent.findViewById(R.id.space_used_display);
- mSpaceTotalTextView = (TextView) parent.findViewById(R.id.space_total_display);
+ mSpaceUsedByDownloadsTextView = (TextView) parent.findViewById(R.id.size_downloaded);
+ mSpaceUsedByOtherAppsTextView = (TextView) parent.findViewById(R.id.size_other_apps);
+ mSpaceFreeTextView = (TextView) parent.findViewById(R.id.size_free);
mSpaceBar = (ProgressBar) parent.findViewById(R.id.space_bar);
mFileSystemBytesTask =
- createStorageSizeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ new StorageSizeTask(true).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- private AsyncTask<Void, Void, Long> createStorageSizeTask() {
- return new AsyncTask<Void, Void, Long>() {
- @Override
- protected Long doInBackground(Void... params) {
- File downloadDirectory = Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOWNLOADS);
-
- // Create the downloads directory, if necessary.
- if (!downloadDirectory.exists()) {
- try {
- // mkdirs() can fail, so we still need to check if the directory exists
- // later.
- downloadDirectory.mkdirs();
- } catch (SecurityException e) {
- Log.e(TAG, "SecurityException when creating download directory.", e);
- }
- }
+ @Override
+ public void onChanged() {
+ // Record how much the user has downloaded relative to the size of their storage.
+ try {
+ long bytesUsedByDownloads = Math.max(0, mHistoryAdapter.getTotalDownloadSize());
+ RecordHistogram.recordPercentageHistogram("Android.DownloadManager.SpaceUsed",
+ computePercentage(bytesUsedByDownloads, mFileSystemBytesTask.get()));
+ } catch (ExecutionException | InterruptedException e) {
+ // Can't record what we don't have.
+ }
- // Determine how much space is available on the storage device where downloads
- // reside. If the downloads directory doesn't exist, it is likely that the user
- // doesn't have an SD card installed.
- long fileSystemBytes = 0;
- if (downloadDirectory.exists()) {
- StatFs statFs = new StatFs(downloadDirectory.getPath());
- long totalBlocks = ApiCompatibilityUtils.getBlockCount(statFs);
- long blockSize = ApiCompatibilityUtils.getBlockSize(statFs);
- fileSystemBytes = totalBlocks * blockSize;
- } else {
- Log.e(TAG, "Download directory doesn't exist.");
- }
- return fileSystemBytes;
+ // Determine how much space is free now, then update the display.
+ mFreeBytesTask = new StorageSizeTask(false) {
+ @Override
+ protected void onPostExecute(Long bytes) {
+ update();
}
};
+ mFreeBytesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @Override
- public void onChanged() {
- if (mFileSystemBytes == Long.MAX_VALUE) {
- try {
- mFileSystemBytes = mFileSystemBytesTask.get();
- } catch (Exception e) {
- Log.e(TAG, "Failed to get file system size.");
- }
+ @VisibleForTesting
+ public void addObserverForTests(Observer observer) {
+ mObservers.addObserver(observer);
+ }
- // Display how big the storage is.
- mSpaceTotalTextView.setText(getStringForBytes(false, mFileSystemBytes));
- }
+ private void update() {
+ long fileSystemBytes = 0;
+ long freeBytes = 0;
- // Indicate how much space has been used by downloads.
- long usedBytes = mHistoryAdapter.getTotalDownloadSize();
- int percentage =
- mFileSystemBytes == 0 ? 0 : (int) (100.0 * usedBytes / mFileSystemBytes);
- mSpaceBar.setProgress(percentage);
- mSpaceUsedTextView.setText(getStringForBytes(true, usedBytes));
+ try {
+ fileSystemBytes = mFileSystemBytesTask.get();
+ freeBytes = mFreeBytesTask.get();
+ } catch (ExecutionException | InterruptedException e) {
+ // Can't do anything here.
+ }
- RecordHistogram.recordPercentageHistogram("Android.DownloadManager.SpaceUsed", percentage);
+ // Indicate how much space has been used by everything on the device via the progress bar.
+ long bytesUsedTotal = Math.max(0, fileSystemBytes - freeBytes);
+ long bytesUsedByDownloads = Math.max(0, mHistoryAdapter.getTotalDownloadSize());
+ long bytesUsedByOtherApps = Math.max(0, bytesUsedTotal - bytesUsedByDownloads);
+
+ // Describe how much space has been used by downloads in text.
+ mSpaceUsedByDownloadsTextView.setText(
+ getStringForBytes(USED_STRINGS, bytesUsedByDownloads));
+ mSpaceUsedByOtherAppsTextView.setText(
+ getStringForBytes(OTHER_STRINGS, bytesUsedByOtherApps));
+ mSpaceFreeTextView.setText(getStringForBytes(FREE_STRINGS, freeBytes));
+
+ // Set a minimum size for the download size so that it shows up in the progress bar.
+ long onePercentOfSystem = fileSystemBytes == 0 ? 0 : fileSystemBytes / 100;
+ long fudgedBytesUsedByDownloads = Math.max(bytesUsedByDownloads, onePercentOfSystem);
+ long fudgedbytesUsedByOtherApps = Math.max(0, bytesUsedTotal - fudgedBytesUsedByDownloads);
+
+ // Indicate how much space has been used as a progress bar. The percentage used by
+ // downloads is shown by the non-overlapped area of the primary and secondary progressbar.
+ int percentageUsedTotal = computePercentage(bytesUsedTotal, fileSystemBytes);
+ int percentageOtherApps = computePercentage(fudgedbytesUsedByOtherApps, fileSystemBytes);
+ mSpaceBar.setProgress(percentageUsedTotal);
+ mSpaceBar.setSecondaryProgress(percentageOtherApps);
+
+ for (Observer observer : mObservers) observer.onSpaceDisplayUpdated(this);
}
- private String getStringForBytes(boolean isUsedString, long bytes) {
+ private String getStringForBytes(int[] stringSet, long bytes) {
int resourceId;
float bytesInCorrectUnits;
if (bytes < BYTES_PER_MEGABYTE) {
- resourceId = isUsedString ? R.string.download_manager_ui_space_used_kb
- : R.string.download_manager_ui_space_available_kb;
+ resourceId = stringSet[0];
bytesInCorrectUnits = bytes / (float) BYTES_PER_KILOBYTE;
} else if (bytes < BYTES_PER_GIGABYTE) {
- resourceId = isUsedString ? R.string.download_manager_ui_space_used_mb
- : R.string.download_manager_ui_space_available_mb;
+ resourceId = stringSet[1];
bytesInCorrectUnits = bytes / (float) BYTES_PER_MEGABYTE;
} else {
- resourceId = isUsedString ? R.string.download_manager_ui_space_used_gb
- : R.string.download_manager_ui_space_available_gb;
+ resourceId = stringSet[2];
bytesInCorrectUnits = bytes / (float) BYTES_PER_GIGABYTE;
}
- Context context = mSpaceUsedTextView.getContext();
+ Context context = mSpaceUsedByDownloadsTextView.getContext();
return context.getResources().getString(resourceId, bytesInCorrectUnits);
}
+
+ private int computePercentage(long numerator, long denominator) {
+ if (denominator == 0) return 0;
+ return (int) Math.min(100.0f, Math.max(0.0f, 100.0f * numerator / denominator));
+ }
}

Powered by Google App Engine
This is Rietveld 408576698