1 /* 2 * Copyright (C) 2011 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 android.os.storage; 18 19 import android.content.Context; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.os.UserHandle; 23 24 import com.android.internal.util.IndentingPrintWriter; 25 26 import java.io.CharArrayWriter; 27 import java.io.File; 28 29 /** 30 * Description of a storage volume and its capabilities, including the 31 * filesystem path where it may be mounted. 32 * 33 * @hide 34 */ 35 public class StorageVolume implements Parcelable { 36 37 // TODO: switch to more durable token 38 private int mStorageId; 39 40 private final File mPath; 41 private final int mDescriptionId; 42 private final boolean mPrimary; 43 private final boolean mRemovable; 44 private final boolean mEmulated; 45 private final int mMtpReserveSpace; 46 private final boolean mAllowMassStorage; 47 /** Maximum file size for the storage, or zero for no limit */ 48 private final long mMaxFileSize; 49 /** When set, indicates exclusive ownership of this volume */ 50 private final UserHandle mOwner; 51 52 private String mUuid; 53 private String mUserLabel; 54 private String mState; 55 56 // StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING, 57 // ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED, 58 // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts. 59 public static final String EXTRA_STORAGE_VOLUME = "storage_volume"; 60 StorageVolume(File path, int descriptionId, boolean primary, boolean removable, boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize, UserHandle owner)61 public StorageVolume(File path, int descriptionId, boolean primary, boolean removable, 62 boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize, 63 UserHandle owner) { 64 mPath = path; 65 mDescriptionId = descriptionId; 66 mPrimary = primary; 67 mRemovable = removable; 68 mEmulated = emulated; 69 mMtpReserveSpace = mtpReserveSpace; 70 mAllowMassStorage = allowMassStorage; 71 mMaxFileSize = maxFileSize; 72 mOwner = owner; 73 } 74 StorageVolume(Parcel in)75 private StorageVolume(Parcel in) { 76 mStorageId = in.readInt(); 77 mPath = new File(in.readString()); 78 mDescriptionId = in.readInt(); 79 mPrimary = in.readInt() != 0; 80 mRemovable = in.readInt() != 0; 81 mEmulated = in.readInt() != 0; 82 mMtpReserveSpace = in.readInt(); 83 mAllowMassStorage = in.readInt() != 0; 84 mMaxFileSize = in.readLong(); 85 mOwner = in.readParcelable(null); 86 mUuid = in.readString(); 87 mUserLabel = in.readString(); 88 mState = in.readString(); 89 } 90 fromTemplate(StorageVolume template, File path, UserHandle owner)91 public static StorageVolume fromTemplate(StorageVolume template, File path, UserHandle owner) { 92 return new StorageVolume(path, template.mDescriptionId, template.mPrimary, 93 template.mRemovable, template.mEmulated, template.mMtpReserveSpace, 94 template.mAllowMassStorage, template.mMaxFileSize, owner); 95 } 96 97 /** 98 * Returns the mount path for the volume. 99 * 100 * @return the mount path 101 */ getPath()102 public String getPath() { 103 return mPath.toString(); 104 } 105 getPathFile()106 public File getPathFile() { 107 return mPath; 108 } 109 110 /** 111 * Returns a user visible description of the volume. 112 * 113 * @return the volume description 114 */ getDescription(Context context)115 public String getDescription(Context context) { 116 return context.getResources().getString(mDescriptionId); 117 } 118 getDescriptionId()119 public int getDescriptionId() { 120 return mDescriptionId; 121 } 122 isPrimary()123 public boolean isPrimary() { 124 return mPrimary; 125 } 126 127 /** 128 * Returns true if the volume is removable. 129 * 130 * @return is removable 131 */ isRemovable()132 public boolean isRemovable() { 133 return mRemovable; 134 } 135 136 /** 137 * Returns true if the volume is emulated. 138 * 139 * @return is removable 140 */ isEmulated()141 public boolean isEmulated() { 142 return mEmulated; 143 } 144 145 /** 146 * Returns the MTP storage ID for the volume. 147 * this is also used for the storage_id column in the media provider. 148 * 149 * @return MTP storage ID 150 */ getStorageId()151 public int getStorageId() { 152 return mStorageId; 153 } 154 155 /** 156 * Do not call this unless you are MountService 157 */ setStorageId(int index)158 public void setStorageId(int index) { 159 // storage ID is 0x00010001 for primary storage, 160 // then 0x00020001, 0x00030001, etc. for secondary storages 161 mStorageId = ((index + 1) << 16) + 1; 162 } 163 164 /** 165 * Number of megabytes of space to leave unallocated by MTP. 166 * MTP will subtract this value from the free space it reports back 167 * to the host via GetStorageInfo, and will not allow new files to 168 * be added via MTP if there is less than this amount left free in the storage. 169 * If MTP has dedicated storage this value should be zero, but if MTP is 170 * sharing storage with the rest of the system, set this to a positive value 171 * to ensure that MTP activity does not result in the storage being 172 * too close to full. 173 * 174 * @return MTP reserve space 175 */ getMtpReserveSpace()176 public int getMtpReserveSpace() { 177 return mMtpReserveSpace; 178 } 179 180 /** 181 * Returns true if this volume can be shared via USB mass storage. 182 * 183 * @return whether mass storage is allowed 184 */ allowMassStorage()185 public boolean allowMassStorage() { 186 return mAllowMassStorage; 187 } 188 189 /** 190 * Returns maximum file size for the volume, or zero if it is unbounded. 191 * 192 * @return maximum file size 193 */ getMaxFileSize()194 public long getMaxFileSize() { 195 return mMaxFileSize; 196 } 197 getOwner()198 public UserHandle getOwner() { 199 return mOwner; 200 } 201 setUuid(String uuid)202 public void setUuid(String uuid) { 203 mUuid = uuid; 204 } 205 getUuid()206 public String getUuid() { 207 return mUuid; 208 } 209 210 /** 211 * Parse and return volume UUID as FAT volume ID, or return -1 if unable to 212 * parse or UUID is unknown. 213 */ getFatVolumeId()214 public int getFatVolumeId() { 215 if (mUuid == null || mUuid.length() != 9) { 216 return -1; 217 } 218 try { 219 return (int)Long.parseLong(mUuid.replace("-", ""), 16); 220 } catch (NumberFormatException e) { 221 return -1; 222 } 223 } 224 setUserLabel(String userLabel)225 public void setUserLabel(String userLabel) { 226 mUserLabel = userLabel; 227 } 228 getUserLabel()229 public String getUserLabel() { 230 return mUserLabel; 231 } 232 setState(String state)233 public void setState(String state) { 234 mState = state; 235 } 236 getState()237 public String getState() { 238 return mState; 239 } 240 241 @Override equals(Object obj)242 public boolean equals(Object obj) { 243 if (obj instanceof StorageVolume && mPath != null) { 244 StorageVolume volume = (StorageVolume)obj; 245 return (mPath.equals(volume.mPath)); 246 } 247 return false; 248 } 249 250 @Override hashCode()251 public int hashCode() { 252 return mPath.hashCode(); 253 } 254 255 @Override toString()256 public String toString() { 257 final CharArrayWriter writer = new CharArrayWriter(); 258 dump(new IndentingPrintWriter(writer, " ", 80)); 259 return writer.toString(); 260 } 261 dump(IndentingPrintWriter pw)262 public void dump(IndentingPrintWriter pw) { 263 pw.println("StorageVolume:"); 264 pw.increaseIndent(); 265 pw.printPair("mStorageId", mStorageId); 266 pw.printPair("mPath", mPath); 267 pw.printPair("mDescriptionId", mDescriptionId); 268 pw.printPair("mPrimary", mPrimary); 269 pw.printPair("mRemovable", mRemovable); 270 pw.printPair("mEmulated", mEmulated); 271 pw.printPair("mMtpReserveSpace", mMtpReserveSpace); 272 pw.printPair("mAllowMassStorage", mAllowMassStorage); 273 pw.printPair("mMaxFileSize", mMaxFileSize); 274 pw.printPair("mOwner", mOwner); 275 pw.printPair("mUuid", mUuid); 276 pw.printPair("mUserLabel", mUserLabel); 277 pw.printPair("mState", mState); 278 pw.decreaseIndent(); 279 } 280 281 public static final Creator<StorageVolume> CREATOR = new Creator<StorageVolume>() { 282 @Override 283 public StorageVolume createFromParcel(Parcel in) { 284 return new StorageVolume(in); 285 } 286 287 @Override 288 public StorageVolume[] newArray(int size) { 289 return new StorageVolume[size]; 290 } 291 }; 292 293 @Override describeContents()294 public int describeContents() { 295 return 0; 296 } 297 298 @Override writeToParcel(Parcel parcel, int flags)299 public void writeToParcel(Parcel parcel, int flags) { 300 parcel.writeInt(mStorageId); 301 parcel.writeString(mPath.toString()); 302 parcel.writeInt(mDescriptionId); 303 parcel.writeInt(mPrimary ? 1 : 0); 304 parcel.writeInt(mRemovable ? 1 : 0); 305 parcel.writeInt(mEmulated ? 1 : 0); 306 parcel.writeInt(mMtpReserveSpace); 307 parcel.writeInt(mAllowMassStorage ? 1 : 0); 308 parcel.writeLong(mMaxFileSize); 309 parcel.writeParcelable(mOwner, flags); 310 parcel.writeString(mUuid); 311 parcel.writeString(mUserLabel); 312 parcel.writeString(mState); 313 } 314 } 315