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