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