VolumeInfo.java revision 1b8ef7e3165ff9aa52a4905dafc8d0f83e7403f9
1/*
2 * Copyright (C) 2015 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
17package android.os.storage;
18
19import android.content.Context;
20import android.content.Intent;
21import android.mtp.MtpStorage;
22import android.os.Environment;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.os.UserHandle;
26import android.text.TextUtils;
27import android.util.ArrayMap;
28import android.util.DebugUtils;
29import android.util.SparseArray;
30
31import com.android.internal.util.IndentingPrintWriter;
32import com.android.internal.util.Preconditions;
33
34import java.io.File;
35
36/**
37 * Information about a storage volume that may be mounted. A volume may be a
38 * partition on a physical {@link DiskInfo}, an emulated volume above some other
39 * storage medium, or a standalone container like an ASEC or OBB.
40 *
41 * @hide
42 */
43public class VolumeInfo implements Parcelable {
44    public static final String ID_EMULATED_INTERNAL = "emulated";
45
46    public static final int TYPE_PUBLIC = 0;
47    public static final int TYPE_PRIVATE = 1;
48    public static final int TYPE_EMULATED = 2;
49    public static final int TYPE_ASEC = 3;
50    public static final int TYPE_OBB = 4;
51
52    public static final int STATE_UNMOUNTED = 0;
53    public static final int STATE_MOUNTING = 1;
54    public static final int STATE_MOUNTED = 2;
55    public static final int STATE_FORMATTING = 3;
56    public static final int STATE_UNMOUNTING = 4;
57
58    public static final int FLAG_PRIMARY = 1 << 0;
59    public static final int FLAG_VISIBLE = 1 << 1;
60
61    public static SparseArray<String> sStateToEnvironment = new SparseArray<>();
62    public static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
63
64    static {
65        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
66        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING);
67        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
68        sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
69        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
70
71        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
72        sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
73        sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
74        sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
75    }
76
77    /** vold state */
78    public final String id;
79    public final int type;
80    public int flags = 0;
81    public int userId = -1;
82    public int state = STATE_UNMOUNTED;
83    public String fsType;
84    public String fsUuid;
85    public String fsLabel;
86    public String path;
87
88    /** Framework state */
89    public final int mtpIndex;
90    public String nickname;
91
92    public DiskInfo disk;
93
94    public VolumeInfo(String id, int type, int mtpIndex) {
95        this.id = Preconditions.checkNotNull(id);
96        this.type = type;
97        this.mtpIndex = mtpIndex;
98    }
99
100    public VolumeInfo(Parcel parcel) {
101        id = parcel.readString();
102        type = parcel.readInt();
103        flags = parcel.readInt();
104        userId = parcel.readInt();
105        state = parcel.readInt();
106        fsType = parcel.readString();
107        fsUuid = parcel.readString();
108        fsLabel = parcel.readString();
109        path = parcel.readString();
110        mtpIndex = parcel.readInt();
111        nickname = parcel.readString();
112    }
113
114    public String getDescription(Context context) {
115        if (ID_EMULATED_INTERNAL.equals(id)) {
116            return context.getString(com.android.internal.R.string.storage_internal);
117        } else if (!TextUtils.isEmpty(nickname)) {
118            return nickname;
119        } else if (!TextUtils.isEmpty(fsLabel)) {
120            return fsLabel;
121        } else {
122            return null;
123        }
124    }
125
126    public boolean isPrimary() {
127        return (flags & FLAG_PRIMARY) != 0;
128    }
129
130    public boolean isVisible() {
131        return (flags & FLAG_VISIBLE) != 0;
132    }
133
134    public boolean isVisibleToUser(int userId) {
135        if (type == TYPE_PUBLIC && userId == this.userId) {
136            return isVisible();
137        } else if (type == TYPE_EMULATED) {
138            return isVisible();
139        } else {
140            return false;
141        }
142    }
143
144    public File getPathForUser(int userId) {
145        if (type == TYPE_PUBLIC && userId == this.userId) {
146            return new File(path);
147        } else if (type == TYPE_EMULATED) {
148            return new File(path, Integer.toString(userId));
149        } else {
150            return null;
151        }
152    }
153
154    public StorageVolume buildStorageVolume(Context context, int userId) {
155        final boolean removable;
156        final boolean emulated;
157        final boolean allowMassStorage = false;
158        final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
159
160        File userPath = getPathForUser(userId);
161        if (userPath == null) {
162            userPath = new File("/dev/null");
163        }
164
165        String description = getDescription(context);
166        if (description == null) {
167            description = context.getString(android.R.string.unknownName);
168        }
169
170        String envState = sStateToEnvironment.get(state);
171        if (envState == null) {
172            envState = Environment.MEDIA_UNKNOWN;
173        }
174
175        long mtpReserveSize = 0;
176        long maxFileSize = 0;
177
178        if (type == TYPE_EMULATED) {
179            emulated = true;
180            mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
181
182            if (ID_EMULATED_INTERNAL.equals(id)) {
183                removable = false;
184            } else {
185                removable = true;
186            }
187
188        } else if (type == TYPE_PUBLIC) {
189            emulated = false;
190            removable = true;
191
192            if ("vfat".equals(fsType)) {
193                maxFileSize = 4294967295L;
194            }
195
196        } else {
197            throw new IllegalStateException("Unexpected volume type " + type);
198        }
199
200        return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
201                emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
202                fsUuid, envState);
203    }
204
205    public void dump(IndentingPrintWriter pw) {
206        pw.println("VolumeInfo:");
207        pw.increaseIndent();
208        pw.printPair("id", id);
209        pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
210        pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
211        pw.printPair("userId", userId);
212        pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
213        pw.println();
214        pw.printPair("fsType", fsType);
215        pw.printPair("fsUuid", fsUuid);
216        pw.printPair("fsLabel", fsLabel);
217        pw.println();
218        pw.printPair("path", path);
219        pw.printPair("mtpIndex", mtpIndex);
220        pw.decreaseIndent();
221        pw.println();
222    }
223
224    public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() {
225        @Override
226        public VolumeInfo createFromParcel(Parcel in) {
227            return new VolumeInfo(in);
228        }
229
230        @Override
231        public VolumeInfo[] newArray(int size) {
232            return new VolumeInfo[size];
233        }
234    };
235
236    @Override
237    public int describeContents() {
238        return 0;
239    }
240
241    @Override
242    public void writeToParcel(Parcel parcel, int flags) {
243        parcel.writeString(id);
244        parcel.writeInt(type);
245        parcel.writeInt(flags);
246        parcel.writeInt(userId);
247        parcel.writeInt(state);
248        parcel.writeString(fsType);
249        parcel.writeString(fsUuid);
250        parcel.writeString(fsLabel);
251        parcel.writeString(path);
252        parcel.writeInt(mtpIndex);
253        parcel.writeString(nickname);
254    }
255}
256