chromium/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/storage/StorageSummaryProvider.java

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.download.home.storage;

import android.content.Context;

import androidx.annotation.Nullable;

import org.chromium.base.task.AsyncTask;
import org.chromium.chrome.browser.download.DirectoryOption;
import org.chromium.chrome.browser.download.DownloadDirectoryProvider;
import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterObserver;
import org.chromium.chrome.browser.download.home.filter.OfflineItemFilterSource;
import org.chromium.chrome.browser.download.internal.R;
import org.chromium.components.browser_ui.util.DownloadUtils;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItemState;

import java.io.File;
import java.util.Collection;

/**
 * Provides the storage summary text to be shown inside the download home.
 * TODO(shaktisahu): Rename this class to StorageSummaryMediator and have it manipulate the model
 * directly once migration to new download home is complete.
 */
public class StorageSummaryProvider implements OfflineItemFilterObserver {
    /** A delegate for updating the UI about the storage information. */
    public interface Delegate {
        void onStorageInfoChanged(String storageInfo);
    }

    private final Context mContext;
    private final Delegate mDelegate;

    // Contains total space and available space of the file system.
    private DirectoryOption mDirectoryOption;

    // The total size in bytes used by downloads.
    private long mTotalDownloadSize;

    public StorageSummaryProvider(
            Context context, Delegate delegate, @Nullable OfflineItemFilterSource filterSource) {
        mContext = context;
        mDelegate = delegate;

        if (filterSource != null) {
            filterSource.addObserver(this);
            mTotalDownloadSize = getTotalSize(filterSource.getItems());
        }

        computeTotalStorage();
    }

    // OfflineItemFilterObserver implementation.
    @Override
    public void onItemsAdded(Collection<OfflineItem> items) {
        mTotalDownloadSize += getTotalSize(items);
        update();
    }

    @Override
    public void onItemsRemoved(Collection<OfflineItem> items) {
        mTotalDownloadSize -= getTotalSize(items);
        update();
    }

    @Override
    public void onItemUpdated(OfflineItem oldItem, OfflineItem item) {
        // Computes the delta of storage used by downloads.
        mTotalDownloadSize -= oldItem.receivedBytes;
        mTotalDownloadSize += item.receivedBytes;

        if (item.state != OfflineItemState.IN_PROGRESS) update();
    }

    private void computeTotalStorage() {
        // Asynchronous task to query the default download directory option on primary storage.
        new AsyncTask<DirectoryOption>() {
            @Override
            protected DirectoryOption doInBackground() {
                File defaultDownloadDir = DownloadDirectoryProvider.getPrimaryDownloadDirectory();
                if (defaultDownloadDir == null) return null;

                DirectoryOption directoryOption =
                        new DirectoryOption(
                                "",
                                defaultDownloadDir.getAbsolutePath(),
                                defaultDownloadDir.getUsableSpace(),
                                defaultDownloadDir.getTotalSpace(),
                                DirectoryOption.DownloadLocationDirectoryType.DEFAULT);
                return directoryOption;
            }

            @Override
            protected void onPostExecute(DirectoryOption directoryOption) {
                mDirectoryOption = directoryOption;
                update();
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    private long getTotalSize(Collection<OfflineItem> items) {
        long totalSize = 0;
        for (OfflineItem item : items) totalSize += item.receivedBytes;
        return totalSize;
    }

    private void update() {
        if (mDirectoryOption == null) return;

        // Build the storage summary string.
        assert (mTotalDownloadSize >= 0);
        String storageSummary =
                mContext.getString(
                        R.string.download_manager_ui_space_using,
                        DownloadUtils.getStringForBytes(mContext, mTotalDownloadSize),
                        DownloadUtils.getStringForBytes(mContext, mDirectoryOption.totalSpace));
        mDelegate.onStorageInfoChanged(storageSummary);
    }
}