blob: f3498d55c7797f00b9e813e5de28c9cc8f45f58c [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;
35
36import com.android.internal.util.IndentingPrintWriter;
37import com.android.internal.util.Preconditions;
38
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070039import java.io.CharArrayWriter;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070040import java.io.File;
Jeff Sharkeye2d45be2015-04-15 17:14:12 -070041import java.util.Comparator;
42import java.util.Objects;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070043
44/**
45 * Information about a storage volume that may be mounted. A volume may be a
46 * partition on a physical {@link DiskInfo}, an emulated volume above some other
47 * storage medium, or a standalone container like an ASEC or OBB.
48 *
49 * @hide
50 */
51public class VolumeInfo implements Parcelable {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -070052 public static final String ACTION_VOLUME_STATE_CHANGED =
53 "android.os.storage.action.VOLUME_STATE_CHANGED";
54 public static final String EXTRA_VOLUME_ID =
55 "android.os.storage.extra.VOLUME_ID";
Jeff Sharkey56bd3122015-04-14 10:30:34 -070056
Jeff Sharkey59d577a2015-04-11 21:27:21 -070057 /** Stub volume representing internal private storage */
58 public static final String ID_PRIVATE_INTERNAL = "private";
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070059 /** Real volume representing internal emulated storage */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070060 public static final String ID_EMULATED_INTERNAL = "emulated";
61
62 public static final int TYPE_PUBLIC = 0;
63 public static final int TYPE_PRIVATE = 1;
64 public static final int TYPE_EMULATED = 2;
65 public static final int TYPE_ASEC = 3;
66 public static final int TYPE_OBB = 4;
67
68 public static final int STATE_UNMOUNTED = 0;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070069 public static final int STATE_CHECKING = 1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070070 public static final int STATE_MOUNTED = 2;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070071 public static final int STATE_MOUNTED_READ_ONLY = 3;
72 public static final int STATE_FORMATTING = 4;
73 public static final int STATE_EJECTING = 5;
74 public static final int STATE_UNMOUNTABLE = 6;
75 public static final int STATE_REMOVED = 7;
76 public static final int STATE_BAD_REMOVAL = 8;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070077
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070078 public static final int MOUNT_FLAG_PRIMARY = 1 << 0;
79 public static final int MOUNT_FLAG_VISIBLE = 1 << 1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070080
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070081 public static final int USER_FLAG_INITED = 1 << 0;
82 public static final int USER_FLAG_SNOOZED = 1 << 1;
83
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070084 private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
85 private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070086
Jeff Sharkeye2d45be2015-04-15 17:14:12 -070087 private static final Comparator<VolumeInfo>
88 sDescriptionComparator = new Comparator<VolumeInfo>() {
89 @Override
90 public int compare(VolumeInfo lhs, VolumeInfo rhs) {
91 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.getId())) {
92 return -1;
93 } else if (lhs.getDescription() == null) {
94 return 1;
95 } else if (rhs.getDescription() == null) {
96 return -1;
97 } else {
98 return lhs.getDescription().compareTo(rhs.getDescription());
99 }
100 }
101 };
102
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700103 static {
104 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700105 sStateToEnvironment.put(VolumeInfo.STATE_CHECKING, Environment.MEDIA_CHECKING);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700106 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700107 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, Environment.MEDIA_MOUNTED_READ_ONLY);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700108 sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700109 sStateToEnvironment.put(VolumeInfo.STATE_EJECTING, Environment.MEDIA_EJECTING);
Jeff Sharkey16c9c242015-04-04 21:37:20 -0700110 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700111 sStateToEnvironment.put(VolumeInfo.STATE_REMOVED, Environment.MEDIA_REMOVED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700112 sStateToEnvironment.put(VolumeInfo.STATE_BAD_REMOVAL, Environment.MEDIA_BAD_REMOVAL);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700113
114 sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
115 sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
116 sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700117 sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED_READ_ONLY, Intent.ACTION_MEDIA_MOUNTED);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700118 sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
Jeff Sharkey16c9c242015-04-04 21:37:20 -0700119 sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700120 sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700121 sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700122 }
123
124 /** vold state */
125 public final String id;
126 public final int type;
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700127 public final DiskInfo disk;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700128 public int mountFlags = 0;
129 public int mountUserId = -1;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700130 public int state = STATE_UNMOUNTED;
131 public String fsType;
132 public String fsUuid;
133 public String fsLabel;
134 public String path;
135
136 /** Framework state */
137 public final int mtpIndex;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700138 public String nickname;
139 public int userFlags = 0;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700140
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700141 public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700142 this.id = Preconditions.checkNotNull(id);
143 this.type = type;
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700144 this.disk = disk;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700145 this.mtpIndex = mtpIndex;
146 }
147
148 public VolumeInfo(Parcel parcel) {
149 id = parcel.readString();
150 type = parcel.readInt();
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700151 if (parcel.readInt() != 0) {
152 disk = DiskInfo.CREATOR.createFromParcel(parcel);
153 } else {
154 disk = null;
155 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700156 mountFlags = parcel.readInt();
157 mountUserId = parcel.readInt();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700158 state = parcel.readInt();
159 fsType = parcel.readString();
160 fsUuid = parcel.readString();
161 fsLabel = parcel.readString();
162 path = parcel.readString();
163 mtpIndex = parcel.readInt();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700164 nickname = parcel.readString();
165 userFlags = parcel.readInt();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700166 }
167
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700168 public static @NonNull String getEnvironmentForState(int state) {
169 final String envState = sStateToEnvironment.get(state);
170 if (envState != null) {
171 return envState;
172 } else {
173 return Environment.MEDIA_UNKNOWN;
174 }
175 }
176
177 public static @Nullable String getBroadcastForEnvironment(String envState) {
178 return sEnvironmentToBroadcast.get(envState);
179 }
180
181 public static @Nullable String getBroadcastForState(int state) {
182 return getBroadcastForEnvironment(getEnvironmentForState(state));
183 }
184
Jeff Sharkeye2d45be2015-04-15 17:14:12 -0700185 public static @NonNull Comparator<VolumeInfo> getDescriptionComparator() {
186 return sDescriptionComparator;
187 }
188
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700189 public @NonNull String getId() {
190 return id;
191 }
192
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700193 public @Nullable DiskInfo getDisk() {
194 return disk;
195 }
196
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700197 public @Nullable String getDiskId() {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700198 return (disk != null) ? disk.id : null;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700199 }
200
201 public int getType() {
202 return type;
203 }
204
205 public int getState() {
206 return state;
207 }
208
209 public @Nullable String getFsUuid() {
210 return fsUuid;
211 }
212
213 public @Nullable String getNickname() {
214 return nickname;
215 }
216
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700217 public int getMountUserId() {
218 return mountUserId;
219 }
220
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700221 public @Nullable String getDescription() {
222 if (ID_PRIVATE_INTERNAL.equals(id)) {
223 return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700224 } else if (!TextUtils.isEmpty(nickname)) {
225 return nickname;
226 } else if (!TextUtils.isEmpty(fsLabel)) {
227 return fsLabel;
228 } else {
229 return null;
230 }
231 }
232
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700233 public boolean isMountedReadable() {
234 return state == STATE_MOUNTED || state == STATE_MOUNTED_READ_ONLY;
235 }
236
237 public boolean isMountedWritable() {
238 return state == STATE_MOUNTED;
239 }
240
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700241 public boolean isPrimary() {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700242 return (mountFlags & MOUNT_FLAG_PRIMARY) != 0;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700243 }
244
245 public boolean isVisible() {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700246 return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700247 }
248
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700249 public boolean isInited() {
250 return (userFlags & USER_FLAG_INITED) != 0;
251 }
252
253 public boolean isSnoozed() {
254 return (userFlags & USER_FLAG_SNOOZED) != 0;
255 }
256
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700257 public boolean isVisibleToUser(int userId) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700258 if (type == TYPE_PUBLIC && userId == this.mountUserId) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700259 return isVisible();
260 } else if (type == TYPE_EMULATED) {
261 return isVisible();
262 } else {
263 return false;
264 }
265 }
266
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700267 public File getPath() {
268 return new File(path);
269 }
270
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700271 public File getPathForUser(int userId) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700272 if (path == null) {
273 return null;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700274 } else if (type == TYPE_PUBLIC && userId == this.mountUserId) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700275 return new File(path);
276 } else if (type == TYPE_EMULATED) {
277 return new File(path, Integer.toString(userId));
278 } else {
279 return null;
280 }
281 }
282
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700283 /**
284 * Path which is accessible to apps holding
285 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
286 */
287 public File getInternalPathForUser(int userId) {
288 if (type == TYPE_PUBLIC) {
289 // TODO: plumb through cleaner path from vold
290 return new File(path.replace("/storage/", "/mnt/media_rw/"));
291 } else {
292 return getPathForUser(userId);
293 }
294 }
295
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700296 public StorageVolume buildStorageVolume(Context context, int userId) {
297 final boolean removable;
298 final boolean emulated;
299 final boolean allowMassStorage = false;
300 final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700301 final String envState = getEnvironmentForState(state);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700302
303 File userPath = getPathForUser(userId);
304 if (userPath == null) {
305 userPath = new File("/dev/null");
306 }
307
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700308 String description = getDescription();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700309 if (description == null) {
310 description = context.getString(android.R.string.unknownName);
311 }
312
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700313 long mtpReserveSize = 0;
314 long maxFileSize = 0;
315
316 if (type == TYPE_EMULATED) {
317 emulated = true;
318 mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
319
320 if (ID_EMULATED_INTERNAL.equals(id)) {
321 removable = false;
322 } else {
323 removable = true;
324 }
325
326 } else if (type == TYPE_PUBLIC) {
327 emulated = false;
328 removable = true;
329
330 if ("vfat".equals(fsType)) {
331 maxFileSize = 4294967295L;
332 }
333
334 } else {
335 throw new IllegalStateException("Unexpected volume type " + type);
336 }
337
338 return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
339 emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
340 fsUuid, envState);
341 }
342
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700343 // TODO: avoid this layering violation
344 private static final String DOCUMENT_AUTHORITY = "com.android.externalstorage.documents";
345 private static final String DOCUMENT_ROOT_PRIMARY_EMULATED = "primary";
346
347 /**
348 * Build an intent to browse the contents of this volume. Only valid for
349 * {@link #TYPE_EMULATED} or {@link #TYPE_PUBLIC}.
350 */
351 public Intent buildBrowseIntent() {
352 final Uri uri;
353 if (type == VolumeInfo.TYPE_PUBLIC) {
354 uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
355 } else if (VolumeInfo.ID_EMULATED_INTERNAL.equals(id)) {
356 uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
357 DOCUMENT_ROOT_PRIMARY_EMULATED);
358 } else if (type == VolumeInfo.TYPE_EMULATED) {
359 // TODO: build intent once supported
360 uri = null;
361 } else {
362 throw new IllegalArgumentException();
363 }
364
365 final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
366 intent.addCategory(Intent.CATEGORY_DEFAULT);
367 intent.setData(uri);
368 return intent;
369 }
370
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700371 @Override
372 public String toString() {
373 final CharArrayWriter writer = new CharArrayWriter();
374 dump(new IndentingPrintWriter(writer, " ", 80));
375 return writer.toString();
376 }
377
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700378 public void dump(IndentingPrintWriter pw) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700379 pw.println("VolumeInfo{" + id + "}:");
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700380 pw.increaseIndent();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700381 pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700382 pw.printPair("diskId", getDiskId());
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700383 pw.printPair("mountFlags", DebugUtils.flagsToString(getClass(), "MOUNT_FLAG_", mountFlags));
384 pw.printPair("mountUserId", mountUserId);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700385 pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
386 pw.println();
387 pw.printPair("fsType", fsType);
388 pw.printPair("fsUuid", fsUuid);
389 pw.printPair("fsLabel", fsLabel);
390 pw.println();
391 pw.printPair("path", path);
392 pw.printPair("mtpIndex", mtpIndex);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700393 pw.printPair("nickname", nickname);
394 pw.printPair("userFlags", DebugUtils.flagsToString(getClass(), "USER_FLAG_", userFlags));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700395 pw.decreaseIndent();
396 pw.println();
397 }
398
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700399 @Override
400 public VolumeInfo clone() {
401 final Parcel temp = Parcel.obtain();
402 try {
403 writeToParcel(temp, 0);
404 temp.setDataPosition(0);
405 return CREATOR.createFromParcel(temp);
406 } finally {
407 temp.recycle();
408 }
409 }
410
Jeff Sharkeye2d45be2015-04-15 17:14:12 -0700411 @Override
412 public boolean equals(Object o) {
413 if (o instanceof VolumeInfo) {
414 return Objects.equals(id, ((VolumeInfo) o).id);
415 } else {
416 return false;
417 }
418 }
419
420 @Override
421 public int hashCode() {
422 return id.hashCode();
423 }
424
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700425 public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() {
426 @Override
427 public VolumeInfo createFromParcel(Parcel in) {
428 return new VolumeInfo(in);
429 }
430
431 @Override
432 public VolumeInfo[] newArray(int size) {
433 return new VolumeInfo[size];
434 }
435 };
436
437 @Override
438 public int describeContents() {
439 return 0;
440 }
441
442 @Override
443 public void writeToParcel(Parcel parcel, int flags) {
444 parcel.writeString(id);
445 parcel.writeInt(type);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700446 if (disk != null) {
447 parcel.writeInt(1);
448 disk.writeToParcel(parcel, flags);
449 } else {
450 parcel.writeInt(0);
451 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700452 parcel.writeInt(mountFlags);
453 parcel.writeInt(mountUserId);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700454 parcel.writeInt(state);
455 parcel.writeString(fsType);
456 parcel.writeString(fsUuid);
457 parcel.writeString(fsLabel);
458 parcel.writeString(path);
459 parcel.writeInt(mtpIndex);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700460 parcel.writeString(nickname);
461 parcel.writeInt(userFlags);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700462 }
463}