blob: e33baa9ebdda3b7bef580eb8b2de069407814a8a [file] [log] [blame]
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001/*
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
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070021import android.content.Context;
22import android.content.Intent;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070023import android.content.res.Resources;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070024import android.mtp.MtpStorage;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070025import android.net.Uri;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070026import android.os.Environment;
27import android.os.Parcel;
28import android.os.Parcelable;
29import android.os.UserHandle;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070030import android.provider.DocumentsContract;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070031import android.text.TextUtils;
32import android.util.ArrayMap;
33import android.util.DebugUtils;
34import android.util.SparseArray;
Jeff Sharkey5fc24732015-06-10 14:21:27 -070035import android.util.SparseIntArray;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070036
Jeff Sharkey5fc24732015-06-10 14:21:27 -070037import com.android.internal.R;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070038import com.android.internal.util.IndentingPrintWriter;
39import com.android.internal.util.Preconditions;
40
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070041import java.io.CharArrayWriter;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070042import java.io.File;
Jeff Sharkeye2d45be2015-04-15 17:14:12 -070043import java.util.Comparator;
44import java.util.Objects;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070045
46/**
47 * Information about a storage volume that may be mounted. A volume may be a
48 * partition on a physical {@link DiskInfo}, an emulated volume above some other
49 * storage medium, or a standalone container like an ASEC or OBB.
50 *
51 * @hide
52 */
53public class VolumeInfo implements Parcelable {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -070054 public static final String ACTION_VOLUME_STATE_CHANGED =
55 "android.os.storage.action.VOLUME_STATE_CHANGED";
56 public static final String EXTRA_VOLUME_ID =
57 "android.os.storage.extra.VOLUME_ID";
Jeff Sharkeyc7acac62015-06-12 16:16:56 -070058 public static final String EXTRA_VOLUME_STATE =
59 "android.os.storage.extra.VOLUME_STATE";
Jeff Sharkey56bd3122015-04-14 10:30:34 -070060
Jeff Sharkey59d577a2015-04-11 21:27:21 -070061 /** Stub volume representing internal private storage */
62 public static final String ID_PRIVATE_INTERNAL = "private";
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070063 /** Real volume representing internal emulated storage */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070064 public static final String ID_EMULATED_INTERNAL = "emulated";
65
66 public static final int TYPE_PUBLIC = 0;
67 public static final int TYPE_PRIVATE = 1;
68 public static final int TYPE_EMULATED = 2;
69 public static final int TYPE_ASEC = 3;
70 public static final int TYPE_OBB = 4;
71
72 public static final int STATE_UNMOUNTED = 0;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070073 public static final int STATE_CHECKING = 1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070074 public static final int STATE_MOUNTED = 2;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070075 public static final int STATE_MOUNTED_READ_ONLY = 3;
76 public static final int STATE_FORMATTING = 4;
77 public static final int STATE_EJECTING = 5;
78 public static final int STATE_UNMOUNTABLE = 6;
79 public static final int STATE_REMOVED = 7;
80 public static final int STATE_BAD_REMOVAL = 8;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070081
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070082 public static final int MOUNT_FLAG_PRIMARY = 1 << 0;
83 public static final int MOUNT_FLAG_VISIBLE = 1 << 1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070084
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070085 private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
86 private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
Jeff Sharkey5fc24732015-06-10 14:21:27 -070087 private static SparseIntArray sStateToDescrip = new SparseIntArray();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070088
Jeff Sharkeye2d45be2015-04-15 17:14:12 -070089 private static final Comparator<VolumeInfo>
90 sDescriptionComparator = new Comparator<VolumeInfo>() {
91 @Override
92 public int compare(VolumeInfo lhs, VolumeInfo rhs) {
93 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.getId())) {
94 return -1;
95 } else if (lhs.getDescription() == null) {
96 return 1;
97 } else if (rhs.getDescription() == null) {
98 return -1;
99 } else {
100 return lhs.getDescription().compareTo(rhs.getDescription());
101 }
102 }
103 };
104
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700105 static {
106 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700107 sStateToEnvironment.put(VolumeInfo.STATE_CHECKING, Environment.MEDIA_CHECKING);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700108 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700109 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, Environment.MEDIA_MOUNTED_READ_ONLY);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700110 sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700111 sStateToEnvironment.put(VolumeInfo.STATE_EJECTING, Environment.MEDIA_EJECTING);
Jeff Sharkey16c9c242015-04-04 21:37:20 -0700112 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700113 sStateToEnvironment.put(VolumeInfo.STATE_REMOVED, Environment.MEDIA_REMOVED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700114 sStateToEnvironment.put(VolumeInfo.STATE_BAD_REMOVAL, Environment.MEDIA_BAD_REMOVAL);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700115
116 sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
117 sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
118 sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700119 sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED_READ_ONLY, Intent.ACTION_MEDIA_MOUNTED);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700120 sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
Jeff Sharkey16c9c242015-04-04 21:37:20 -0700121 sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700122 sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700123 sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL);
Jeff Sharkey5fc24732015-06-10 14:21:27 -0700124
125 sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTED, R.string.ext_media_status_unmounted);
126 sStateToDescrip.put(VolumeInfo.STATE_CHECKING, R.string.ext_media_status_checking);
127 sStateToDescrip.put(VolumeInfo.STATE_MOUNTED, R.string.ext_media_status_mounted);
128 sStateToDescrip.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, R.string.ext_media_status_mounted_ro);
129 sStateToDescrip.put(VolumeInfo.STATE_FORMATTING, R.string.ext_media_status_formatting);
130 sStateToDescrip.put(VolumeInfo.STATE_EJECTING, R.string.ext_media_status_ejecting);
131 sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTABLE, R.string.ext_media_status_unmountable);
132 sStateToDescrip.put(VolumeInfo.STATE_REMOVED, R.string.ext_media_status_removed);
133 sStateToDescrip.put(VolumeInfo.STATE_BAD_REMOVAL, R.string.ext_media_status_bad_removal);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700134 }
135
136 /** vold state */
137 public final String id;
138 public final int type;
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700139 public final DiskInfo disk;
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700140 public final String partGuid;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700141 public int mountFlags = 0;
142 public int mountUserId = -1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700143 public int state = STATE_UNMOUNTED;
144 public String fsType;
145 public String fsUuid;
146 public String fsLabel;
147 public String path;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700148 public String internalPath;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700149
150 /** Framework state */
151 public final int mtpIndex;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700152
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700153 public VolumeInfo(String id, int type, DiskInfo disk, String partGuid, int mtpIndex) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700154 this.id = Preconditions.checkNotNull(id);
155 this.type = type;
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700156 this.disk = disk;
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700157 this.partGuid = partGuid;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700158 this.mtpIndex = mtpIndex;
159 }
160
161 public VolumeInfo(Parcel parcel) {
162 id = parcel.readString();
163 type = parcel.readInt();
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700164 if (parcel.readInt() != 0) {
165 disk = DiskInfo.CREATOR.createFromParcel(parcel);
166 } else {
167 disk = null;
168 }
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700169 partGuid = parcel.readString();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700170 mountFlags = parcel.readInt();
171 mountUserId = parcel.readInt();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700172 state = parcel.readInt();
173 fsType = parcel.readString();
174 fsUuid = parcel.readString();
175 fsLabel = parcel.readString();
176 path = parcel.readString();
Jeff Sharkey50a05452015-04-29 11:24:52 -0700177 internalPath = parcel.readString();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700178 mtpIndex = parcel.readInt();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700179 }
180
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700181 public static @NonNull String getEnvironmentForState(int state) {
182 final String envState = sStateToEnvironment.get(state);
183 if (envState != null) {
184 return envState;
185 } else {
186 return Environment.MEDIA_UNKNOWN;
187 }
188 }
189
190 public static @Nullable String getBroadcastForEnvironment(String envState) {
191 return sEnvironmentToBroadcast.get(envState);
192 }
193
194 public static @Nullable String getBroadcastForState(int state) {
195 return getBroadcastForEnvironment(getEnvironmentForState(state));
196 }
197
Jeff Sharkeye2d45be2015-04-15 17:14:12 -0700198 public static @NonNull Comparator<VolumeInfo> getDescriptionComparator() {
199 return sDescriptionComparator;
200 }
201
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700202 public @NonNull String getId() {
203 return id;
204 }
205
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700206 public @Nullable DiskInfo getDisk() {
207 return disk;
208 }
209
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700210 public @Nullable String getDiskId() {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700211 return (disk != null) ? disk.id : null;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700212 }
213
214 public int getType() {
215 return type;
216 }
217
218 public int getState() {
219 return state;
220 }
221
Jeff Sharkey5fc24732015-06-10 14:21:27 -0700222 public int getStateDescription() {
223 return sStateToDescrip.get(state, 0);
224 }
225
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700226 public @Nullable String getFsUuid() {
227 return fsUuid;
228 }
229
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700230 public int getMountUserId() {
231 return mountUserId;
232 }
233
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700234 public @Nullable String getDescription() {
235 if (ID_PRIVATE_INTERNAL.equals(id)) {
236 return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700237 } else if (!TextUtils.isEmpty(fsLabel)) {
238 return fsLabel;
239 } else {
240 return null;
241 }
242 }
243
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700244 public boolean isMountedReadable() {
245 return state == STATE_MOUNTED || state == STATE_MOUNTED_READ_ONLY;
246 }
247
248 public boolean isMountedWritable() {
249 return state == STATE_MOUNTED;
250 }
251
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700252 public boolean isPrimary() {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700253 return (mountFlags & MOUNT_FLAG_PRIMARY) != 0;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700254 }
255
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700256 public boolean isPrimaryPhysical() {
257 return isPrimary() && (getType() == TYPE_PUBLIC);
258 }
259
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700260 public boolean isVisible() {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700261 return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700262 }
263
264 public boolean isVisibleToUser(int userId) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700265 if (type == TYPE_PUBLIC && userId == this.mountUserId) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700266 return isVisible();
267 } else if (type == TYPE_EMULATED) {
268 return isVisible();
269 } else {
270 return false;
271 }
272 }
273
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700274 public File getPath() {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700275 return (path != null) ? new File(path) : null;
276 }
277
278 public File getInternalPath() {
279 return (internalPath != null) ? new File(internalPath) : null;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700280 }
281
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700282 public File getPathForUser(int userId) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700283 if (path == null) {
284 return null;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700285 } else if (type == TYPE_PUBLIC && userId == this.mountUserId) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700286 return new File(path);
287 } else if (type == TYPE_EMULATED) {
288 return new File(path, Integer.toString(userId));
289 } else {
290 return null;
291 }
292 }
293
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700294 /**
295 * Path which is accessible to apps holding
296 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
297 */
298 public File getInternalPathForUser(int userId) {
299 if (type == TYPE_PUBLIC) {
300 // TODO: plumb through cleaner path from vold
301 return new File(path.replace("/storage/", "/mnt/media_rw/"));
302 } else {
303 return getPathForUser(userId);
304 }
305 }
306
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700307 public StorageVolume buildStorageVolume(Context context, int userId) {
308 final boolean removable;
309 final boolean emulated;
310 final boolean allowMassStorage = false;
311 final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700312 final String envState = getEnvironmentForState(state);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700313
314 File userPath = getPathForUser(userId);
315 if (userPath == null) {
316 userPath = new File("/dev/null");
317 }
318
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700319 String description = getDescription();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700320 if (description == null) {
321 description = context.getString(android.R.string.unknownName);
322 }
323
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700324 long mtpReserveSize = 0;
325 long maxFileSize = 0;
326
327 if (type == TYPE_EMULATED) {
328 emulated = true;
329 mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
330
331 if (ID_EMULATED_INTERNAL.equals(id)) {
332 removable = false;
333 } else {
334 removable = true;
335 }
336
337 } else if (type == TYPE_PUBLIC) {
338 emulated = false;
339 removable = true;
340
341 if ("vfat".equals(fsType)) {
342 maxFileSize = 4294967295L;
343 }
344
345 } else {
346 throw new IllegalStateException("Unexpected volume type " + type);
347 }
348
349 return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
350 emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
351 fsUuid, envState);
352 }
353
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700354 // TODO: avoid this layering violation
355 private static final String DOCUMENT_AUTHORITY = "com.android.externalstorage.documents";
356 private static final String DOCUMENT_ROOT_PRIMARY_EMULATED = "primary";
357
358 /**
359 * Build an intent to browse the contents of this volume. Only valid for
360 * {@link #TYPE_EMULATED} or {@link #TYPE_PUBLIC}.
361 */
362 public Intent buildBrowseIntent() {
363 final Uri uri;
364 if (type == VolumeInfo.TYPE_PUBLIC) {
365 uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700366 } else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700367 uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
368 DOCUMENT_ROOT_PRIMARY_EMULATED);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700369 } else {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700370 return null;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700371 }
372
373 final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
374 intent.addCategory(Intent.CATEGORY_DEFAULT);
375 intent.setData(uri);
376 return intent;
377 }
378
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700379 @Override
380 public String toString() {
381 final CharArrayWriter writer = new CharArrayWriter();
382 dump(new IndentingPrintWriter(writer, " ", 80));
383 return writer.toString();
384 }
385
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700386 public void dump(IndentingPrintWriter pw) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700387 pw.println("VolumeInfo{" + id + "}:");
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700388 pw.increaseIndent();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700389 pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700390 pw.printPair("diskId", getDiskId());
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700391 pw.printPair("partGuid", partGuid);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700392 pw.printPair("mountFlags", DebugUtils.flagsToString(getClass(), "MOUNT_FLAG_", mountFlags));
393 pw.printPair("mountUserId", mountUserId);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700394 pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
395 pw.println();
396 pw.printPair("fsType", fsType);
397 pw.printPair("fsUuid", fsUuid);
398 pw.printPair("fsLabel", fsLabel);
399 pw.println();
400 pw.printPair("path", path);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700401 pw.printPair("internalPath", internalPath);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700402 pw.printPair("mtpIndex", mtpIndex);
403 pw.decreaseIndent();
404 pw.println();
405 }
406
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700407 @Override
408 public VolumeInfo clone() {
409 final Parcel temp = Parcel.obtain();
410 try {
411 writeToParcel(temp, 0);
412 temp.setDataPosition(0);
413 return CREATOR.createFromParcel(temp);
414 } finally {
415 temp.recycle();
416 }
417 }
418
Jeff Sharkeye2d45be2015-04-15 17:14:12 -0700419 @Override
420 public boolean equals(Object o) {
421 if (o instanceof VolumeInfo) {
422 return Objects.equals(id, ((VolumeInfo) o).id);
423 } else {
424 return false;
425 }
426 }
427
428 @Override
429 public int hashCode() {
430 return id.hashCode();
431 }
432
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700433 public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() {
434 @Override
435 public VolumeInfo createFromParcel(Parcel in) {
436 return new VolumeInfo(in);
437 }
438
439 @Override
440 public VolumeInfo[] newArray(int size) {
441 return new VolumeInfo[size];
442 }
443 };
444
445 @Override
446 public int describeContents() {
447 return 0;
448 }
449
450 @Override
451 public void writeToParcel(Parcel parcel, int flags) {
452 parcel.writeString(id);
453 parcel.writeInt(type);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700454 if (disk != null) {
455 parcel.writeInt(1);
456 disk.writeToParcel(parcel, flags);
457 } else {
458 parcel.writeInt(0);
459 }
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700460 parcel.writeString(partGuid);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700461 parcel.writeInt(mountFlags);
462 parcel.writeInt(mountUserId);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700463 parcel.writeInt(state);
464 parcel.writeString(fsType);
465 parcel.writeString(fsUuid);
466 parcel.writeString(fsLabel);
467 parcel.writeString(path);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700468 parcel.writeString(internalPath);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700469 parcel.writeInt(mtpIndex);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700470 }
471}