1 /* 2 * Copyright (C) 2021 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.os.Parcel; 21 import android.os.Parcelable; 22 import android.os.storage.DiskInfo; 23 import android.os.storage.StorageManager; 24 import android.os.storage.VolumeInfo; 25 import android.os.storage.VolumeRecord; 26 import android.text.TextUtils; 27 28 import androidx.annotation.NonNull; 29 30 import com.android.settings.R; 31 32 import java.io.File; 33 34 /** 35 * This object contains a {@link VolumeInfo} for a mountable storage or a {@link DiskInfo} for an 36 * unsupported disk which is not able to be mounted automatically. 37 */ 38 public class StorageEntry implements Comparable<StorageEntry>, Parcelable { 39 40 private final VolumeInfo mVolumeInfo; 41 private final DiskInfo mUnsupportedDiskInfo; 42 private final VolumeRecord mMissingVolumeRecord; 43 44 private final String mVolumeInfoDescription; 45 StorageEntry(@onNull Context context, @NonNull VolumeInfo volumeInfo)46 public StorageEntry(@NonNull Context context, @NonNull VolumeInfo volumeInfo) { 47 mVolumeInfo = volumeInfo; 48 mUnsupportedDiskInfo = null; 49 mMissingVolumeRecord = null; 50 51 if (isDefaultInternalStorage()) { 52 // Shows "This device" for default internal storage. 53 mVolumeInfoDescription = context.getResources() 54 .getString(R.string.storage_default_internal_storage); 55 } else { 56 mVolumeInfoDescription = context.getSystemService(StorageManager.class) 57 .getBestVolumeDescription(mVolumeInfo); 58 } 59 } 60 StorageEntry(@onNull DiskInfo diskInfo)61 public StorageEntry(@NonNull DiskInfo diskInfo) { 62 mVolumeInfo = null; 63 mUnsupportedDiskInfo = diskInfo; 64 mMissingVolumeRecord = null; 65 mVolumeInfoDescription = null; 66 } 67 StorageEntry(@onNull VolumeRecord volumeRecord)68 public StorageEntry(@NonNull VolumeRecord volumeRecord) { 69 mVolumeInfo = null; 70 mUnsupportedDiskInfo = null; 71 mMissingVolumeRecord = volumeRecord; 72 mVolumeInfoDescription = null; 73 } 74 StorageEntry(Parcel in)75 private StorageEntry(Parcel in) { 76 mVolumeInfo = in.readParcelable(VolumeInfo.class.getClassLoader()); 77 mUnsupportedDiskInfo = in.readParcelable(DiskInfo.class.getClassLoader()); 78 mMissingVolumeRecord = in.readParcelable(VolumeRecord.class.getClassLoader()); 79 mVolumeInfoDescription = in.readString(); 80 } 81 82 @Override describeContents()83 public int describeContents() { 84 return 0; 85 } 86 87 @Override writeToParcel(Parcel out, int flags)88 public void writeToParcel(Parcel out, int flags) { 89 out.writeParcelable(mVolumeInfo, 0 /* parcelableFlags */); 90 out.writeParcelable(mUnsupportedDiskInfo, 0 /* parcelableFlags */); 91 out.writeParcelable(mMissingVolumeRecord , 0 /* parcelableFlags */); 92 out.writeString(mVolumeInfoDescription); 93 } 94 95 public static final Parcelable.Creator<StorageEntry> CREATOR = 96 new Parcelable.Creator<StorageEntry>() { 97 public StorageEntry createFromParcel(Parcel in) { 98 return new StorageEntry(in); 99 } 100 101 public StorageEntry[] newArray(int size) { 102 return new StorageEntry[size]; 103 } 104 }; 105 106 @Override equals(Object o)107 public boolean equals(Object o) { 108 if (o == this) { 109 return true; 110 } 111 if (!(o instanceof StorageEntry)) { 112 return false; 113 } 114 115 final StorageEntry StorageEntry = (StorageEntry) o; 116 if (isVolumeInfo()) { 117 return mVolumeInfo.equals(StorageEntry.mVolumeInfo); 118 } 119 if (isDiskInfoUnsupported()) { 120 return mUnsupportedDiskInfo.equals(StorageEntry.mUnsupportedDiskInfo); 121 } 122 return mMissingVolumeRecord.equals(StorageEntry.mMissingVolumeRecord); 123 } 124 125 @Override hashCode()126 public int hashCode() { 127 if (isVolumeInfo()) { 128 return mVolumeInfo.hashCode(); 129 } 130 if (isDiskInfoUnsupported()) { 131 return mUnsupportedDiskInfo.hashCode(); 132 } 133 return mMissingVolumeRecord.hashCode(); 134 } 135 136 @Override toString()137 public String toString() { 138 if (isVolumeInfo()) { 139 return mVolumeInfo.toString(); 140 } 141 if (isDiskInfoUnsupported()) { 142 return mUnsupportedDiskInfo.toString(); 143 } 144 return mMissingVolumeRecord.toString(); 145 } 146 147 @Override compareTo(StorageEntry other)148 public int compareTo(StorageEntry other) { 149 if (isDefaultInternalStorage() && !other.isDefaultInternalStorage()) { 150 return -1; 151 } 152 if (!isDefaultInternalStorage() && other.isDefaultInternalStorage()) { 153 return 1; 154 } 155 156 if (isVolumeInfo() && !other.isVolumeInfo()) { 157 return -1; 158 } 159 if (!isVolumeInfo() && other.isVolumeInfo()) { 160 return 1; 161 } 162 163 if (isPrivate() && !other.isPrivate()) { 164 return -1; 165 } 166 if (!isPrivate() && other.isPrivate()) { 167 return 1; 168 } 169 170 if (isMounted() && !other.isMounted()) { 171 return -1; 172 } 173 if (!isMounted() && other.isMounted()) { 174 return 1; 175 } 176 177 if (!isVolumeRecordMissed() && other.isVolumeRecordMissed()) { 178 return -1; 179 } 180 if (isVolumeRecordMissed() && !other.isVolumeRecordMissed()) { 181 return 1; 182 } 183 184 if (getDescription() == null) { 185 return 1; 186 } 187 if (other.getDescription() == null) { 188 return -1; 189 } 190 return getDescription().compareTo(other.getDescription()); 191 } 192 193 /** Returns default internal storage. */ getDefaultInternalStorageEntry(Context context)194 public static StorageEntry getDefaultInternalStorageEntry(Context context) { 195 return new StorageEntry(context, context.getSystemService(StorageManager.class) 196 .findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)); 197 } 198 199 /** If it's a VolumeInfo. */ isVolumeInfo()200 public boolean isVolumeInfo() { 201 return mVolumeInfo != null; 202 } 203 204 /** If it's an unsupported DiskInfo. */ isDiskInfoUnsupported()205 public boolean isDiskInfoUnsupported() { 206 return mUnsupportedDiskInfo != null; 207 } 208 209 /** If it's a missing VolumeRecord. */ isVolumeRecordMissed()210 public boolean isVolumeRecordMissed() { 211 return mMissingVolumeRecord != null; 212 } 213 214 /** If it's a default internal storage. */ isDefaultInternalStorage()215 public boolean isDefaultInternalStorage() { 216 if (isVolumeInfo()) { 217 return mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE 218 && TextUtils.equals(mVolumeInfo.getId(), VolumeInfo.ID_PRIVATE_INTERNAL); 219 } 220 return false; 221 } 222 223 /** If it's a mounted storage. */ isMounted()224 public boolean isMounted() { 225 return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED 226 || mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY); 227 } 228 229 /** If it's an unmounted storage. */ isUnmounted()230 public boolean isUnmounted() { 231 return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTED); 232 } 233 234 /** If it's an unmountable storage. */ isUnmountable()235 public boolean isUnmountable() { 236 return mVolumeInfo == null ? false : mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTABLE; 237 } 238 239 /** If it's a private storage. */ isPrivate()240 public boolean isPrivate() { 241 return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE; 242 } 243 244 /** If it's a public storage. */ isPublic()245 public boolean isPublic() { 246 return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PUBLIC; 247 } 248 249 /** Returns description. */ getDescription()250 public String getDescription() { 251 if (isVolumeInfo()) { 252 return mVolumeInfoDescription; 253 } 254 if (isDiskInfoUnsupported()) { 255 return mUnsupportedDiskInfo.getDescription(); 256 } 257 return mMissingVolumeRecord.getNickname(); 258 } 259 260 /** Returns ID. */ getId()261 public String getId() { 262 if (isVolumeInfo()) { 263 return mVolumeInfo.getId(); 264 } 265 if (isDiskInfoUnsupported()) { 266 return mUnsupportedDiskInfo.getId(); 267 } 268 return mMissingVolumeRecord.getFsUuid(); 269 } 270 271 /** Returns disk ID. */ getDiskId()272 public String getDiskId() { 273 if (isVolumeInfo()) { 274 return mVolumeInfo.getDiskId(); 275 } 276 if (isDiskInfoUnsupported()) { 277 return mUnsupportedDiskInfo.getId(); 278 } 279 return null; 280 } 281 282 /** Returns fsUuid. */ getFsUuid()283 public String getFsUuid() { 284 if (isVolumeInfo()) { 285 return mVolumeInfo.getFsUuid(); 286 } 287 if (isDiskInfoUnsupported()) { 288 return null; 289 } 290 return mMissingVolumeRecord.getFsUuid(); 291 } 292 293 /** Returns root file if it's a VolumeInfo. */ getPath()294 public File getPath() { 295 return mVolumeInfo == null ? null : mVolumeInfo.getPath(); 296 } 297 298 /** Returns VolumeInfo of the StorageEntry. */ getVolumeInfo()299 public VolumeInfo getVolumeInfo() { 300 return mVolumeInfo; 301 } 302 } 303 304