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 
17 package android.os.storage;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.res.Resources;
23 import android.os.Build;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.text.TextUtils;
27 import android.util.DebugUtils;
28 
29 import com.android.internal.util.IndentingPrintWriter;
30 import com.android.internal.util.Preconditions;
31 
32 import java.io.CharArrayWriter;
33 import java.util.Objects;
34 
35 /**
36  * Information about a physical disk which may contain one or more
37  * {@link VolumeInfo}.
38  *
39  * @hide
40  */
41 public class DiskInfo implements Parcelable {
42     public static final String ACTION_DISK_SCANNED =
43             "android.os.storage.action.DISK_SCANNED";
44     public static final String EXTRA_DISK_ID =
45             "android.os.storage.extra.DISK_ID";
46     public static final String EXTRA_VOLUME_COUNT =
47             "android.os.storage.extra.VOLUME_COUNT";
48 
49     public static final int FLAG_ADOPTABLE = 1 << 0;
50     public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
51     public static final int FLAG_SD = 1 << 2;
52     public static final int FLAG_USB = 1 << 3;
53 
54     public final String id;
55     @UnsupportedAppUsage
56     public final int flags;
57     @UnsupportedAppUsage
58     public long size;
59     @UnsupportedAppUsage
60     public String label;
61     /** Hacky; don't rely on this count */
62     public int volumeCount;
63     public String sysPath;
64 
DiskInfo(String id, int flags)65     public DiskInfo(String id, int flags) {
66         this.id = Preconditions.checkNotNull(id);
67         this.flags = flags;
68     }
69 
70     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
DiskInfo(Parcel parcel)71     public DiskInfo(Parcel parcel) {
72         id = parcel.readString();
73         flags = parcel.readInt();
74         size = parcel.readLong();
75         label = parcel.readString();
76         volumeCount = parcel.readInt();
77         sysPath = parcel.readString();
78     }
79 
80     @UnsupportedAppUsage
getId()81     public @NonNull String getId() {
82         return id;
83     }
84 
isInteresting(String label)85     private boolean isInteresting(String label) {
86         if (TextUtils.isEmpty(label)) {
87             return false;
88         }
89         if (label.equalsIgnoreCase("ata")) {
90             return false;
91         }
92         if (label.toLowerCase().contains("generic")) {
93             return false;
94         }
95         if (label.toLowerCase().startsWith("usb")) {
96             return false;
97         }
98         if (label.toLowerCase().startsWith("multiple")) {
99             return false;
100         }
101         return true;
102     }
103 
104     @UnsupportedAppUsage
getDescription()105     public @Nullable String getDescription() {
106         final Resources res = Resources.getSystem();
107         if ((flags & FLAG_SD) != 0) {
108             if (isInteresting(label)) {
109                 return res.getString(com.android.internal.R.string.storage_sd_card_label, label);
110             } else {
111                 return res.getString(com.android.internal.R.string.storage_sd_card);
112             }
113         } else if ((flags & FLAG_USB) != 0) {
114             if (isInteresting(label)) {
115                 return res.getString(com.android.internal.R.string.storage_usb_drive_label, label);
116             } else {
117                 return res.getString(com.android.internal.R.string.storage_usb_drive);
118             }
119         } else {
120             return null;
121         }
122     }
123 
getShortDescription()124     public @Nullable String getShortDescription() {
125         final Resources res = Resources.getSystem();
126         if (isSd()) {
127             return res.getString(com.android.internal.R.string.storage_sd_card);
128         } else if (isUsb()) {
129             return res.getString(com.android.internal.R.string.storage_usb_drive);
130         } else {
131             return null;
132         }
133     }
134 
135     @UnsupportedAppUsage
isAdoptable()136     public boolean isAdoptable() {
137         return (flags & FLAG_ADOPTABLE) != 0;
138     }
139 
140     @UnsupportedAppUsage
isDefaultPrimary()141     public boolean isDefaultPrimary() {
142         return (flags & FLAG_DEFAULT_PRIMARY) != 0;
143     }
144 
145     @UnsupportedAppUsage
isSd()146     public boolean isSd() {
147         return (flags & FLAG_SD) != 0;
148     }
149 
150     @UnsupportedAppUsage
isUsb()151     public boolean isUsb() {
152         return (flags & FLAG_USB) != 0;
153     }
154 
155     @Override
toString()156     public String toString() {
157         final CharArrayWriter writer = new CharArrayWriter();
158         dump(new IndentingPrintWriter(writer, "    ", 80));
159         return writer.toString();
160     }
161 
dump(IndentingPrintWriter pw)162     public void dump(IndentingPrintWriter pw) {
163         pw.println("DiskInfo{" + id + "}:");
164         pw.increaseIndent();
165         pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
166         pw.printPair("size", size);
167         pw.printPair("label", label);
168         pw.println();
169         pw.printPair("sysPath", sysPath);
170         pw.decreaseIndent();
171         pw.println();
172     }
173 
174     @Override
clone()175     public DiskInfo clone() {
176         final Parcel temp = Parcel.obtain();
177         try {
178             writeToParcel(temp, 0);
179             temp.setDataPosition(0);
180             return CREATOR.createFromParcel(temp);
181         } finally {
182             temp.recycle();
183         }
184     }
185 
186     @Override
equals(Object o)187     public boolean equals(Object o) {
188         if (o instanceof DiskInfo) {
189             return Objects.equals(id, ((DiskInfo) o).id);
190         } else {
191             return false;
192         }
193     }
194 
195     @Override
hashCode()196     public int hashCode() {
197         return id.hashCode();
198     }
199 
200     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
201     public static final @android.annotation.NonNull Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() {
202         @Override
203         public DiskInfo createFromParcel(Parcel in) {
204             return new DiskInfo(in);
205         }
206 
207         @Override
208         public DiskInfo[] newArray(int size) {
209             return new DiskInfo[size];
210         }
211     };
212 
213     @Override
describeContents()214     public int describeContents() {
215         return 0;
216     }
217 
218     @Override
writeToParcel(Parcel parcel, int flags)219     public void writeToParcel(Parcel parcel, int flags) {
220         parcel.writeString(id);
221         parcel.writeInt(this.flags);
222         parcel.writeLong(size);
223         parcel.writeString(label);
224         parcel.writeInt(volumeCount);
225         parcel.writeString(sysPath);
226     }
227 }
228