1 /* 2 * Copyright (C) 2017 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.settings.deviceinfo.storage; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.provider.Settings; 22 import android.support.annotation.VisibleForTesting; 23 import android.util.SparseArray; 24 25 import com.android.settingslib.applications.StorageStatsSource; 26 import com.android.settingslib.deviceinfo.PrivateStorageInfo; 27 28 import java.util.concurrent.TimeUnit; 29 30 public class CachedStorageValuesHelper { 31 32 @VisibleForTesting public static final String SHARED_PREFERENCES_NAME = "CachedStorageValues"; 33 public static final String TIMESTAMP_KEY = "last_query_timestamp"; 34 public static final String FREE_BYTES_KEY = "free_bytes"; 35 public static final String TOTAL_BYTES_KEY = "total_bytes"; 36 public static final String GAME_APPS_SIZE_KEY = "game_apps_size"; 37 public static final String MUSIC_APPS_SIZE_KEY = "music_apps_size"; 38 public static final String VIDEO_APPS_SIZE_KEY = "video_apps_size"; 39 public static final String PHOTO_APPS_SIZE_KEY = "photo_apps_size"; 40 public static final String OTHER_APPS_SIZE_KEY = "other_apps_size"; 41 public static final String CACHE_APPS_SIZE_KEY = "cache_apps_size"; 42 public static final String EXTERNAL_TOTAL_BYTES = "external_total_bytes"; 43 public static final String EXTERNAL_AUDIO_BYTES = "external_audio_bytes"; 44 public static final String EXTERNAL_VIDEO_BYTES = "external_video_bytes"; 45 public static final String EXTERNAL_IMAGE_BYTES = "external_image_bytes"; 46 public static final String EXTERNAL_APP_BYTES = "external_apps_bytes"; 47 public static final String USER_ID_KEY = "user_id"; 48 private final Long mClobberThreshold; 49 private final SharedPreferences mSharedPreferences; 50 private final int mUserId; 51 // This clock is used to provide the time. By default, it uses the system clock, but can be 52 // replaced for test purposes. 53 protected Clock mClock; 54 55 public CachedStorageValuesHelper(Context context, int userId) { 56 mSharedPreferences = 57 context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); 58 mClock = new Clock(); 59 mUserId = userId; 60 mClobberThreshold = 61 Settings.Global.getLong( 62 context.getContentResolver(), 63 Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD, 64 TimeUnit.MINUTES.toMillis(5)); 65 } 66 67 public PrivateStorageInfo getCachedPrivateStorageInfo() { 68 if (!isDataValid()) { 69 return null; 70 } 71 final long freeBytes = mSharedPreferences.getLong(FREE_BYTES_KEY, -1); 72 final long totalBytes = mSharedPreferences.getLong(TOTAL_BYTES_KEY, -1); 73 if (freeBytes < 0 || totalBytes < 0) { 74 return null; 75 } 76 77 return new PrivateStorageInfo(freeBytes, totalBytes); 78 } 79 80 public SparseArray<StorageAsyncLoader.AppsStorageResult> getCachedAppsStorageResult() { 81 if (!isDataValid()) { 82 return null; 83 } 84 final long gamesSize = mSharedPreferences.getLong(GAME_APPS_SIZE_KEY, -1); 85 final long musicAppsSize = mSharedPreferences.getLong(MUSIC_APPS_SIZE_KEY, -1); 86 final long videoAppsSize = mSharedPreferences.getLong(VIDEO_APPS_SIZE_KEY, -1); 87 final long photoAppSize = mSharedPreferences.getLong(PHOTO_APPS_SIZE_KEY, -1); 88 final long otherAppsSize = mSharedPreferences.getLong(OTHER_APPS_SIZE_KEY, -1); 89 final long cacheSize = mSharedPreferences.getLong(CACHE_APPS_SIZE_KEY, -1); 90 if (gamesSize < 0 91 || musicAppsSize < 0 92 || videoAppsSize < 0 93 || photoAppSize < 0 94 || otherAppsSize < 0 95 || cacheSize < 0) { 96 return null; 97 } 98 99 final long externalTotalBytes = mSharedPreferences.getLong(EXTERNAL_TOTAL_BYTES, -1); 100 final long externalAudioBytes = mSharedPreferences.getLong(EXTERNAL_AUDIO_BYTES, -1); 101 final long externalVideoBytes = mSharedPreferences.getLong(EXTERNAL_VIDEO_BYTES, -1); 102 final long externalImageBytes = mSharedPreferences.getLong(EXTERNAL_IMAGE_BYTES, -1); 103 final long externalAppBytes = mSharedPreferences.getLong(EXTERNAL_APP_BYTES, -1); 104 if (externalTotalBytes < 0 105 || externalAudioBytes < 0 106 || externalVideoBytes < 0 107 || externalImageBytes < 0 108 || externalAppBytes < 0) { 109 return null; 110 } 111 112 final StorageStatsSource.ExternalStorageStats externalStats = 113 new StorageStatsSource.ExternalStorageStats( 114 externalTotalBytes, 115 externalAudioBytes, 116 externalVideoBytes, 117 externalImageBytes, 118 externalAppBytes); 119 final StorageAsyncLoader.AppsStorageResult result = 120 new StorageAsyncLoader.AppsStorageResult(); 121 result.gamesSize = gamesSize; 122 result.musicAppsSize = musicAppsSize; 123 result.videoAppsSize = videoAppsSize; 124 result.photosAppsSize = photoAppSize; 125 result.otherAppsSize = otherAppsSize; 126 result.cacheSize = cacheSize; 127 result.externalStats = externalStats; 128 final SparseArray<StorageAsyncLoader.AppsStorageResult> resultArray = new SparseArray<>(); 129 resultArray.append(mUserId, result); 130 return resultArray; 131 } 132 133 public void cacheResult( 134 PrivateStorageInfo storageInfo, StorageAsyncLoader.AppsStorageResult result) { 135 mSharedPreferences 136 .edit() 137 .putLong(FREE_BYTES_KEY, storageInfo.freeBytes) 138 .putLong(TOTAL_BYTES_KEY, storageInfo.totalBytes) 139 .putLong(GAME_APPS_SIZE_KEY, result.gamesSize) 140 .putLong(MUSIC_APPS_SIZE_KEY, result.musicAppsSize) 141 .putLong(VIDEO_APPS_SIZE_KEY, result.videoAppsSize) 142 .putLong(PHOTO_APPS_SIZE_KEY, result.photosAppsSize) 143 .putLong(OTHER_APPS_SIZE_KEY, result.otherAppsSize) 144 .putLong(CACHE_APPS_SIZE_KEY, result.cacheSize) 145 .putLong(EXTERNAL_TOTAL_BYTES, result.externalStats.totalBytes) 146 .putLong(EXTERNAL_AUDIO_BYTES, result.externalStats.audioBytes) 147 .putLong(EXTERNAL_VIDEO_BYTES, result.externalStats.videoBytes) 148 .putLong(EXTERNAL_IMAGE_BYTES, result.externalStats.imageBytes) 149 .putLong(EXTERNAL_APP_BYTES, result.externalStats.appBytes) 150 .putInt(USER_ID_KEY, mUserId) 151 .putLong(TIMESTAMP_KEY, mClock.getCurrentTime()) 152 .apply(); 153 } 154 155 private boolean isDataValid() { 156 final int cachedUserId = mSharedPreferences.getInt(USER_ID_KEY, -1); 157 if (cachedUserId != mUserId) { 158 return false; 159 } 160 161 final long lastQueryTime = mSharedPreferences.getLong(TIMESTAMP_KEY, Long.MAX_VALUE); 162 final long currentTime = mClock.getCurrentTime(); 163 return currentTime - lastQueryTime < mClobberThreshold; 164 } 165 166 /** Clock provides the current time. */ 167 static class Clock { 168 public long getCurrentTime() { 169 return System.currentTimeMillis(); 170 } 171 } 172 } 173