1 /* 2 * Copyright (C) 2021 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 com.android.providers.media; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.os.UserHandle; 22 import android.os.storage.StorageVolume; 23 import android.provider.MediaStore; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import java.io.File; 29 import java.util.Objects; 30 31 /** 32 * MediaVolume is a MediaProvider-internal representation of a storage volume. 33 * 34 * Before MediaVolume, volumes inside MediaProvider were represented by their name; 35 * but now that MediaProvider handles volumes on behalf on multiple users, the name of a volume 36 * might no longer be unique. So MediaVolume holds both a name and a user. The user may be 37 * null on volumes without an owner (eg public volumes). 38 * 39 * In addition to that, we keep the path and ID of the volume cached in here as well 40 * for easy access. 41 */ 42 public final class MediaVolume implements Parcelable { 43 /** 44 * Name of the volume. 45 */ 46 private final @NonNull String mName; 47 48 /** 49 * User to which the volume belongs to; might be null in case of public volumes. 50 */ 51 private final @Nullable UserHandle mUser; 52 53 /** 54 * Path on which the volume is mounted. 55 */ 56 private final @Nullable File mPath; 57 58 /** 59 * Unique ID of the volume; eg "external;0" 60 */ 61 private final @Nullable String mId; 62 getName()63 public @NonNull String getName() { 64 return mName; 65 } 66 getUser()67 public @Nullable UserHandle getUser() { 68 return mUser; 69 } 70 getPath()71 public @Nullable File getPath() { 72 return mPath; 73 } 74 getId()75 public @Nullable String getId() { 76 return mId; 77 } 78 MediaVolume(@onNull String name, UserHandle user, File path, String id)79 private MediaVolume (@NonNull String name, UserHandle user, File path, String id) { 80 this.mName = name; 81 this.mUser = user; 82 this.mPath = path; 83 this.mId = id; 84 } 85 MediaVolume(Parcel in)86 private MediaVolume (Parcel in) { 87 this.mName = in.readString(); 88 this.mUser = in.readParcelable(null); 89 this.mPath = new File(in.readString()); 90 this.mId = in.readString(); 91 } 92 93 @Override equals(Object obj)94 public boolean equals(Object obj) { 95 if (this == obj) return true; 96 if (obj == null || getClass() != obj.getClass()) return false; 97 MediaVolume that = (MediaVolume) obj; 98 return Objects.equals(mName, that.mName) && 99 Objects.equals(mUser, that.mUser) && 100 Objects.equals(mPath, that.mPath) && 101 Objects.equals(mId, that.mId); 102 } 103 104 @Override hashCode()105 public int hashCode() { 106 return Objects.hash(mName, mUser, mPath, mId); 107 } 108 isVisibleToUser(UserHandle user)109 public boolean isVisibleToUser(UserHandle user) { 110 return mUser == null || user.equals(mUser); 111 } 112 113 @NonNull fromStorageVolume(StorageVolume storageVolume)114 public static MediaVolume fromStorageVolume(StorageVolume storageVolume) { 115 String name = storageVolume.getMediaStoreVolumeName(); 116 UserHandle user = storageVolume.getOwner(); 117 File path = storageVolume.getDirectory(); 118 String id = storageVolume.getId(); 119 return new MediaVolume(name, user, path, id); 120 } 121 fromInternal()122 public static MediaVolume fromInternal() { 123 String name = MediaStore.VOLUME_INTERNAL; 124 125 return new MediaVolume(name, null, null, null); 126 } 127 128 @Override describeContents()129 public int describeContents() { 130 return 0; 131 } 132 133 @Override writeToParcel(Parcel dest, int flags)134 public void writeToParcel(Parcel dest, int flags) { 135 dest.writeString(mName); 136 dest.writeParcelable(mUser, flags); 137 dest.writeString(mPath.toString()); 138 dest.writeString(mId); 139 } 140 141 @Override toString()142 public String toString() { 143 return "MediaVolume name: [" + mName + "] id: [" + mId + "] user: [" + mUser + "] path: [" 144 + mPath + "]"; 145 } 146 147 public static final @android.annotation.NonNull Creator<MediaVolume> CREATOR 148 = new Creator<MediaVolume>() { 149 @Override 150 public MediaVolume createFromParcel(Parcel in) { 151 return new MediaVolume(in); 152 } 153 154 @Override 155 public MediaVolume[] newArray(int size) { 156 return new MediaVolume[size]; 157 } 158 }; 159 } 160