1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.settings.storage; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.usage.StorageStatsManager; 22 import android.car.userlib.CarUserManagerHelper; 23 import android.content.Context; 24 import android.os.Bundle; 25 import android.os.storage.StorageManager; 26 import android.os.storage.VolumeInfo; 27 import android.util.SparseArray; 28 29 import androidx.loader.app.LoaderManager; 30 import androidx.loader.content.Loader; 31 32 import com.android.settingslib.applications.StorageStatsSource; 33 import com.android.settingslib.deviceinfo.PrivateStorageInfo; 34 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * Class to manage all the callbacks needed to calculate the total volume, storage used by each app 41 * category and notifying the listeners when the data is loaded. 42 */ 43 public class StorageSettingsManager { 44 45 /** 46 * Callback that is called once the volume of data is loaded for the mounted device. 47 */ 48 public interface VolumeListener { 49 /** 50 * Called when the data is successfully loaded from {@link VolumeSizeCallback} and the 51 * total and used size for the mounted device is calculated from {@link AppsStorageResult} 52 */ onDataLoaded(SparseArray<StorageAsyncLoader.AppsStorageResult> result, long usedSizeBytes, long totalSizeBytes)53 void onDataLoaded(SparseArray<StorageAsyncLoader.AppsStorageResult> result, 54 long usedSizeBytes, long totalSizeBytes); 55 } 56 57 private static final int STORAGE_JOB_ID = 0; 58 private static final int VOLUME_SIZE_JOB_ID = 1; 59 60 private final Context mContext; 61 private final VolumeInfo mVolumeInfo; 62 63 private List<VolumeListener> mVolumeListeners = new ArrayList<>(); 64 private PrivateStorageInfo mPrivateStorageInfo; 65 private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsStorageResultSparseArray; 66 StorageSettingsManager(Context context, VolumeInfo volume)67 StorageSettingsManager(Context context, VolumeInfo volume) { 68 mContext = context; 69 mVolumeInfo = volume; 70 } 71 72 /** 73 * Registers a listener that will be notified once the data is loaded. 74 */ registerListener(VolumeListener volumeListener)75 public void registerListener(VolumeListener volumeListener) { 76 if (!mVolumeListeners.contains(volumeListener)) { 77 mVolumeListeners.add(volumeListener); 78 } 79 } 80 81 /** 82 * Unregisters the listener. 83 */ unregisterlistener(VolumeListener volumeListener)84 public void unregisterlistener(VolumeListener volumeListener) { 85 mVolumeListeners.remove(volumeListener); 86 } 87 88 /** 89 * Start calculating the storage and volume. 90 */ startLoading(LoaderManager loaderManager)91 public void startLoading(LoaderManager loaderManager) { 92 loaderManager.restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, new AppsStorageResult()); 93 loaderManager.restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallback()); 94 } 95 onReceivedSizes()96 private void onReceivedSizes() { 97 if (mAppsStorageResultSparseArray != null && mPrivateStorageInfo != null) { 98 long privateUsedBytes = mPrivateStorageInfo.totalBytes - mPrivateStorageInfo.freeBytes; 99 for (VolumeListener listener : mVolumeListeners) { 100 listener.onDataLoaded(mAppsStorageResultSparseArray, privateUsedBytes, 101 mPrivateStorageInfo.totalBytes); 102 } 103 } 104 } 105 106 /** 107 * Callback to get the storage volume information for the device that is mounted. 108 */ 109 private class VolumeSizeCallback 110 implements LoaderManager.LoaderCallbacks<PrivateStorageInfo> { 111 112 @Override onCreateLoader(int id, Bundle args)113 public Loader<PrivateStorageInfo> onCreateLoader(int id, Bundle args) { 114 StorageManager sm = mContext.getSystemService(StorageManager.class); 115 StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(sm); 116 StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class); 117 return new VolumeSizesLoader(mContext, smvp, stats, mVolumeInfo); 118 } 119 120 @Override onLoadFinished( Loader<PrivateStorageInfo> loader, PrivateStorageInfo privateStorageInfo)121 public void onLoadFinished( 122 Loader<PrivateStorageInfo> loader, PrivateStorageInfo privateStorageInfo) { 123 if (privateStorageInfo == null) { 124 return; 125 } 126 mPrivateStorageInfo = privateStorageInfo; 127 onReceivedSizes(); 128 } 129 130 @Override onLoaderReset(Loader<PrivateStorageInfo> loader)131 public void onLoaderReset(Loader<PrivateStorageInfo> loader) { 132 } 133 } 134 135 /** 136 * Callback to calculate how much space each category of applications is using. 137 */ 138 private class AppsStorageResult implements 139 LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> { 140 141 @NonNull 142 @Override onCreateLoader(int id, @Nullable Bundle args)143 public Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> onCreateLoader(int id, 144 @Nullable Bundle args) { 145 return new StorageAsyncLoader(mContext, new CarUserManagerHelper(mContext), 146 new StorageStatsSource(mContext)); 147 } 148 149 @Override onLoadFinished( @onNull Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader, SparseArray<StorageAsyncLoader.AppsStorageResult> data)150 public void onLoadFinished( 151 @NonNull Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader, 152 SparseArray<StorageAsyncLoader.AppsStorageResult> data) { 153 mAppsStorageResultSparseArray = data; 154 onReceivedSizes(); 155 } 156 157 @Override onLoaderReset( @onNull Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader)158 public void onLoaderReset( 159 @NonNull Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) { 160 } 161 } 162 } 163