Merge "Wire up non-visible volumes, more states."
This commit is contained in:
@@ -505,6 +505,16 @@ public class StorageManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
|
||||
return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
|
||||
return findVolumeById(privateVol.getId().replace("private", "emulated"));
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public @NonNull List<VolumeInfo> getVolumes() {
|
||||
return getVolumes(0);
|
||||
@@ -523,10 +533,9 @@ public class StorageManager {
|
||||
public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
|
||||
String descrip = vol.getDescription();
|
||||
|
||||
if (vol.diskId != null) {
|
||||
final DiskInfo disk = findDiskById(vol.diskId);
|
||||
if (disk != null && TextUtils.isEmpty(descrip)) {
|
||||
descrip = disk.getDescription();
|
||||
if (vol.disk != null) {
|
||||
if (TextUtils.isEmpty(descrip)) {
|
||||
descrip = vol.disk.getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,23 +101,27 @@ public class VolumeInfo implements Parcelable {
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_CHECKING, Environment.MEDIA_CHECKING);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, Environment.MEDIA_MOUNTED_READ_ONLY);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_EJECTING, Environment.MEDIA_EJECTING);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_REMOVED, Environment.MEDIA_REMOVED);
|
||||
sStateToEnvironment.put(VolumeInfo.STATE_BAD_REMOVAL, Environment.MEDIA_BAD_REMOVAL);
|
||||
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED_READ_ONLY, Intent.ACTION_MEDIA_MOUNTED);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED);
|
||||
sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL);
|
||||
}
|
||||
|
||||
/** vold state */
|
||||
public final String id;
|
||||
public final int type;
|
||||
public final String diskId;
|
||||
public final DiskInfo disk;
|
||||
public int mountFlags = 0;
|
||||
public int mountUserId = -1;
|
||||
public int state = STATE_UNMOUNTED;
|
||||
@@ -131,17 +135,21 @@ public class VolumeInfo implements Parcelable {
|
||||
public String nickname;
|
||||
public int userFlags = 0;
|
||||
|
||||
public VolumeInfo(String id, int type, String diskId, int mtpIndex) {
|
||||
public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) {
|
||||
this.id = Preconditions.checkNotNull(id);
|
||||
this.type = type;
|
||||
this.diskId = diskId;
|
||||
this.disk = disk;
|
||||
this.mtpIndex = mtpIndex;
|
||||
}
|
||||
|
||||
public VolumeInfo(Parcel parcel) {
|
||||
id = parcel.readString();
|
||||
type = parcel.readInt();
|
||||
diskId = parcel.readString();
|
||||
if (parcel.readInt() != 0) {
|
||||
disk = DiskInfo.CREATOR.createFromParcel(parcel);
|
||||
} else {
|
||||
disk = null;
|
||||
}
|
||||
mountFlags = parcel.readInt();
|
||||
mountUserId = parcel.readInt();
|
||||
state = parcel.readInt();
|
||||
@@ -179,8 +187,12 @@ public class VolumeInfo implements Parcelable {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable DiskInfo getDisk() {
|
||||
return disk;
|
||||
}
|
||||
|
||||
public @Nullable String getDiskId() {
|
||||
return diskId;
|
||||
return (disk != null) ? disk.id : null;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
@@ -199,6 +211,10 @@ public class VolumeInfo implements Parcelable {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public int getMountUserId() {
|
||||
return mountUserId;
|
||||
}
|
||||
|
||||
public @Nullable String getDescription() {
|
||||
if (ID_PRIVATE_INTERNAL.equals(id)) {
|
||||
return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
|
||||
@@ -211,6 +227,14 @@ public class VolumeInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMountedReadable() {
|
||||
return state == STATE_MOUNTED || state == STATE_MOUNTED_READ_ONLY;
|
||||
}
|
||||
|
||||
public boolean isMountedWritable() {
|
||||
return state == STATE_MOUNTED;
|
||||
}
|
||||
|
||||
public boolean isPrimary() {
|
||||
return (mountFlags & MOUNT_FLAG_PRIMARY) != 0;
|
||||
}
|
||||
@@ -253,6 +277,19 @@ public class VolumeInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Path which is accessible to apps holding
|
||||
* {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
|
||||
*/
|
||||
public File getInternalPathForUser(int userId) {
|
||||
if (type == TYPE_PUBLIC) {
|
||||
// TODO: plumb through cleaner path from vold
|
||||
return new File(path.replace("/storage/", "/mnt/media_rw/"));
|
||||
} else {
|
||||
return getPathForUser(userId);
|
||||
}
|
||||
}
|
||||
|
||||
public StorageVolume buildStorageVolume(Context context, int userId) {
|
||||
final boolean removable;
|
||||
final boolean emulated;
|
||||
@@ -339,7 +376,7 @@ public class VolumeInfo implements Parcelable {
|
||||
pw.println("VolumeInfo{" + id + "}:");
|
||||
pw.increaseIndent();
|
||||
pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
|
||||
pw.printPair("diskId", diskId);
|
||||
pw.printPair("diskId", getDiskId());
|
||||
pw.printPair("mountFlags", DebugUtils.flagsToString(getClass(), "MOUNT_FLAG_", mountFlags));
|
||||
pw.printPair("mountUserId", mountUserId);
|
||||
pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
|
||||
@@ -403,7 +440,12 @@ public class VolumeInfo implements Parcelable {
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeString(id);
|
||||
parcel.writeInt(type);
|
||||
parcel.writeString(diskId);
|
||||
if (disk != null) {
|
||||
parcel.writeInt(1);
|
||||
disk.writeToParcel(parcel, flags);
|
||||
} else {
|
||||
parcel.writeInt(0);
|
||||
}
|
||||
parcel.writeInt(mountFlags);
|
||||
parcel.writeInt(mountUserId);
|
||||
parcel.writeInt(state);
|
||||
|
||||
@@ -361,7 +361,7 @@ public class PackageHelper {
|
||||
VolumeInfo bestCandidate = null;
|
||||
long bestCandidateAvailBytes = Long.MIN_VALUE;
|
||||
for (VolumeInfo vol : storageManager.getVolumes()) {
|
||||
if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.state == VolumeInfo.STATE_MOUNTED) {
|
||||
if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
|
||||
final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
|
||||
if (availBytes >= sizeBytes) {
|
||||
allCandidates.add(vol.fsUuid);
|
||||
|
||||
@@ -26,34 +26,35 @@ import android.database.MatrixCursor.RowBuilder;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Environment;
|
||||
import android.os.FileObserver;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.ParcelFileDescriptor.OnCloseListener;
|
||||
import android.os.UserHandle;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.provider.DocumentsProvider;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Maps;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ExternalStorageProvider extends DocumentsProvider {
|
||||
@@ -80,6 +81,8 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
public int flags;
|
||||
public String title;
|
||||
public String docId;
|
||||
public File visiblePath;
|
||||
public File path;
|
||||
}
|
||||
|
||||
private static final String ROOT_ID_PRIMARY_EMULATED = "primary";
|
||||
@@ -90,26 +93,17 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
private final Object mRootsLock = new Object();
|
||||
|
||||
@GuardedBy("mRootsLock")
|
||||
private ArrayList<RootInfo> mRoots;
|
||||
@GuardedBy("mRootsLock")
|
||||
private HashMap<String, RootInfo> mIdToRoot;
|
||||
@GuardedBy("mRootsLock")
|
||||
private HashMap<String, File> mIdToPath;
|
||||
private ArrayMap<String, RootInfo> mRoots = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mObservers")
|
||||
private Map<File, DirectoryObserver> mObservers = Maps.newHashMap();
|
||||
private ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>();
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
|
||||
mHandler = new Handler();
|
||||
|
||||
mRoots = Lists.newArrayList();
|
||||
mIdToRoot = Maps.newHashMap();
|
||||
mIdToPath = Maps.newHashMap();
|
||||
|
||||
updateVolumes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -121,52 +115,53 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
|
||||
private void updateVolumesLocked() {
|
||||
mRoots.clear();
|
||||
mIdToPath.clear();
|
||||
mIdToRoot.clear();
|
||||
|
||||
final StorageVolume[] volumes = mStorageManager.getVolumeList();
|
||||
for (StorageVolume volume : volumes) {
|
||||
final boolean mounted = Environment.MEDIA_MOUNTED.equals(volume.getState())
|
||||
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(volume.getState());
|
||||
if (!mounted) continue;
|
||||
final int userId = UserHandle.myUserId();
|
||||
final List<VolumeInfo> volumes = mStorageManager.getVolumes();
|
||||
for (VolumeInfo volume : volumes) {
|
||||
if (!volume.isMountedReadable()) continue;
|
||||
|
||||
final String rootId;
|
||||
if (volume.isPrimary() && volume.isEmulated()) {
|
||||
if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
|
||||
rootId = ROOT_ID_PRIMARY_EMULATED;
|
||||
} else if (volume.getUuid() != null) {
|
||||
rootId = volume.getUuid();
|
||||
} else if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
|
||||
final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
|
||||
rootId = privateVol.getFsUuid();
|
||||
} else if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
|
||||
rootId = volume.getFsUuid();
|
||||
} else {
|
||||
Log.d(TAG, "Missing UUID for " + volume.getPath() + "; skipping");
|
||||
// Unsupported volume; ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mIdToPath.containsKey(rootId)) {
|
||||
Log.w(TAG, "Duplicate UUID " + rootId + "; skipping");
|
||||
if (TextUtils.isEmpty(rootId)) {
|
||||
Log.d(TAG, "Missing UUID for " + volume.getId() + "; skipping");
|
||||
continue;
|
||||
}
|
||||
if (mRoots.containsKey(rootId)) {
|
||||
Log.w(TAG, "Duplicate UUID " + rootId + " for " + volume.getId() + "; skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final File path = volume.getPathFile();
|
||||
mIdToPath.put(rootId, path);
|
||||
|
||||
final RootInfo root = new RootInfo();
|
||||
mRoots.put(rootId, root);
|
||||
|
||||
root.rootId = rootId;
|
||||
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
|
||||
| Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
|
||||
if (ROOT_ID_PRIMARY_EMULATED.equals(rootId)) {
|
||||
root.title = getContext().getString(R.string.root_internal_storage);
|
||||
} else {
|
||||
final String userLabel = volume.getUserLabel();
|
||||
if (!TextUtils.isEmpty(userLabel)) {
|
||||
root.title = userLabel;
|
||||
} else {
|
||||
root.title = volume.getDescription(getContext());
|
||||
}
|
||||
root.title = mStorageManager.getBestVolumeDescription(volume);
|
||||
}
|
||||
if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
|
||||
root.flags |= Root.FLAG_HAS_SETTINGS;
|
||||
}
|
||||
root.docId = getDocIdForFile(path);
|
||||
mRoots.add(root);
|
||||
mIdToRoot.put(rootId, root);
|
||||
root.visiblePath = volume.getPathForUser(userId);
|
||||
root.path = volume.getInternalPathForUser(userId);
|
||||
root.docId = getDocIdForFile(root.path);
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
@@ -190,23 +185,26 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
String path = file.getAbsolutePath();
|
||||
|
||||
// Find the most-specific root path
|
||||
Map.Entry<String, File> mostSpecific = null;
|
||||
String mostSpecificId = null;
|
||||
String mostSpecificPath = null;
|
||||
synchronized (mRootsLock) {
|
||||
for (Map.Entry<String, File> root : mIdToPath.entrySet()) {
|
||||
final String rootPath = root.getValue().getPath();
|
||||
if (path.startsWith(rootPath) && (mostSpecific == null
|
||||
|| rootPath.length() > mostSpecific.getValue().getPath().length())) {
|
||||
mostSpecific = root;
|
||||
for (int i = 0; i < mRoots.size(); i++) {
|
||||
final String rootId = mRoots.keyAt(i);
|
||||
final String rootPath = mRoots.valueAt(i).path.getAbsolutePath();
|
||||
if (path.startsWith(rootPath) && (mostSpecificPath == null
|
||||
|| rootPath.length() > mostSpecificPath.length())) {
|
||||
mostSpecificId = rootId;
|
||||
mostSpecificPath = rootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mostSpecific == null) {
|
||||
if (mostSpecificPath == null) {
|
||||
throw new FileNotFoundException("Failed to find root that contains " + path);
|
||||
}
|
||||
|
||||
// Start at first char of path under root
|
||||
final String rootPath = mostSpecific.getValue().getPath();
|
||||
final String rootPath = mostSpecificPath;
|
||||
if (rootPath.equals(path)) {
|
||||
path = "";
|
||||
} else if (rootPath.endsWith("/")) {
|
||||
@@ -215,21 +213,30 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
path = path.substring(rootPath.length() + 1);
|
||||
}
|
||||
|
||||
return mostSpecific.getKey() + ':' + path;
|
||||
return mostSpecificId + ':' + path;
|
||||
}
|
||||
|
||||
private File getFileForDocId(String docId) throws FileNotFoundException {
|
||||
return getFileForDocId(docId, false);
|
||||
}
|
||||
|
||||
private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
|
||||
final int splitIndex = docId.indexOf(':', 1);
|
||||
final String tag = docId.substring(0, splitIndex);
|
||||
final String path = docId.substring(splitIndex + 1);
|
||||
|
||||
File target;
|
||||
RootInfo root;
|
||||
synchronized (mRootsLock) {
|
||||
target = mIdToPath.get(tag);
|
||||
root = mRoots.get(tag);
|
||||
}
|
||||
if (target == null) {
|
||||
if (root == null) {
|
||||
throw new FileNotFoundException("No root for " + tag);
|
||||
}
|
||||
|
||||
File target = visible ? root.visiblePath : root.path;
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
if (!target.exists()) {
|
||||
target.mkdirs();
|
||||
}
|
||||
@@ -286,16 +293,13 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
|
||||
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
|
||||
synchronized (mRootsLock) {
|
||||
for (String rootId : mIdToPath.keySet()) {
|
||||
final RootInfo root = mIdToRoot.get(rootId);
|
||||
final File path = mIdToPath.get(rootId);
|
||||
|
||||
for (RootInfo root : mRoots.values()) {
|
||||
final RowBuilder row = result.newRow();
|
||||
row.add(Root.COLUMN_ROOT_ID, root.rootId);
|
||||
row.add(Root.COLUMN_FLAGS, root.flags);
|
||||
row.add(Root.COLUMN_TITLE, root.title);
|
||||
row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
|
||||
row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
|
||||
row.add(Root.COLUMN_AVAILABLE_BYTES, root.path.getFreeSpace());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -464,7 +468,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
|
||||
final File parent;
|
||||
synchronized (mRootsLock) {
|
||||
parent = mIdToPath.get(rootId);
|
||||
parent = mRoots.get(rootId).path;
|
||||
}
|
||||
|
||||
final LinkedList<File> pending = new LinkedList<File>();
|
||||
@@ -494,8 +498,10 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
String documentId, String mode, CancellationSignal signal)
|
||||
throws FileNotFoundException {
|
||||
final File file = getFileForDocId(documentId);
|
||||
final File visibleFile = getFileForDocId(documentId, true);
|
||||
|
||||
final int pfdMode = ParcelFileDescriptor.parseMode(mode);
|
||||
if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY) {
|
||||
if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) {
|
||||
return ParcelFileDescriptor.open(file, pfdMode);
|
||||
} else {
|
||||
try {
|
||||
@@ -505,7 +511,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
public void onClose(IOException e) {
|
||||
final Intent intent = new Intent(
|
||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
intent.setData(Uri.fromFile(file));
|
||||
intent.setData(Uri.fromFile(visibleFile));
|
||||
getContext().sendBroadcast(intent);
|
||||
}
|
||||
});
|
||||
@@ -523,6 +529,27 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
||||
return DocumentsContract.openImageThumbnail(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
|
||||
synchronized (mRootsLock) {
|
||||
for (int i = 0; i < mRoots.size(); i++) {
|
||||
final RootInfo root = mRoots.valueAt(i);
|
||||
pw.println("Root{" + root.rootId + "}:");
|
||||
pw.increaseIndent();
|
||||
pw.printPair("flags", DebugUtils.flagsToString(Root.class, "FLAG_", root.flags));
|
||||
pw.println();
|
||||
pw.printPair("title", root.title);
|
||||
pw.printPair("docId", root.docId);
|
||||
pw.println();
|
||||
pw.printPair("path", root.path);
|
||||
pw.printPair("visiblePath", root.visiblePath);
|
||||
pw.decreaseIndent();
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTypeForFile(File file) {
|
||||
if (file.isDirectory()) {
|
||||
return Document.MIME_TYPE_DIR;
|
||||
|
||||
@@ -60,7 +60,7 @@ public class StorageNotification extends SystemUI {
|
||||
// Avoid kicking notifications when getting early metadata before
|
||||
// mounted. If already mounted, we're being kicked because of a
|
||||
// nickname or init'ed change.
|
||||
if (vol.getState() == VolumeInfo.STATE_MOUNTED) {
|
||||
if (vol.isMountedReadable()) {
|
||||
onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,7 @@ public class StorageNotification extends SystemUI {
|
||||
onVolumeChecking(vol);
|
||||
break;
|
||||
case VolumeInfo.STATE_MOUNTED:
|
||||
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
||||
onVolumeMounted(vol);
|
||||
break;
|
||||
case VolumeInfo.STATE_FORMATTING:
|
||||
@@ -136,7 +137,7 @@ public class StorageNotification extends SystemUI {
|
||||
}
|
||||
|
||||
private void onVolumeChecking(VolumeInfo vol) {
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.ext_media_checking_notification_title, disk.getDescription());
|
||||
final CharSequence text = mContext.getString(
|
||||
@@ -156,7 +157,7 @@ public class StorageNotification extends SystemUI {
|
||||
// Don't annoy when user dismissed in past
|
||||
if (vol.isSnoozed()) return;
|
||||
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final Notification notif;
|
||||
if (disk.isAdoptable() && !vol.isInited()) {
|
||||
final CharSequence title = disk.getDescription();
|
||||
@@ -198,7 +199,7 @@ public class StorageNotification extends SystemUI {
|
||||
}
|
||||
|
||||
private void onVolumeEjecting(VolumeInfo vol) {
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.ext_media_unmounting_notification_title, disk.getDescription());
|
||||
final CharSequence text = mContext.getString(
|
||||
@@ -215,7 +216,7 @@ public class StorageNotification extends SystemUI {
|
||||
}
|
||||
|
||||
private void onVolumeUnmountable(VolumeInfo vol) {
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.ext_media_unmountable_notification_title, disk.getDescription());
|
||||
final CharSequence text = mContext.getString(
|
||||
@@ -236,7 +237,7 @@ public class StorageNotification extends SystemUI {
|
||||
return;
|
||||
}
|
||||
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.ext_media_nomedia_notification_title, disk.getDescription());
|
||||
final CharSequence text = mContext.getString(
|
||||
@@ -256,7 +257,7 @@ public class StorageNotification extends SystemUI {
|
||||
return;
|
||||
}
|
||||
|
||||
final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
|
||||
final DiskInfo disk = vol.getDisk();
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.ext_media_badremoval_notification_title, disk.getDescription());
|
||||
final CharSequence text = mContext.getString(
|
||||
|
||||
@@ -103,7 +103,6 @@ import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -688,12 +687,12 @@ class MountService extends IMountService.Stub
|
||||
synchronized (mVolumes) {
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
final VolumeInfo vol = mVolumes.valueAt(i);
|
||||
if (vol.isVisibleToUser(userId) && vol.state == VolumeInfo.STATE_MOUNTED) {
|
||||
if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
|
||||
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
|
||||
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
|
||||
|
||||
mCallbacks.notifyStorageStateChanged(userVol.getPath(),
|
||||
Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED);
|
||||
final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
|
||||
mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
|
||||
}
|
||||
}
|
||||
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
|
||||
@@ -822,13 +821,13 @@ class MountService extends IMountService.Stub
|
||||
break;
|
||||
}
|
||||
case VoldResponseCode.DISK_LABEL_CHANGED: {
|
||||
if (cooked.length != 3) break;
|
||||
final DiskInfo disk = mDisks.get(cooked[1]);
|
||||
if (disk != null) {
|
||||
disk.label = cooked[2];
|
||||
}
|
||||
if (disk.label != null) {
|
||||
disk.label = disk.label.trim();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 2; i < cooked.length; i++) {
|
||||
builder.append(cooked[i]).append(' ');
|
||||
}
|
||||
disk.label = builder.toString().trim();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -848,8 +847,9 @@ class MountService extends IMountService.Stub
|
||||
final String id = cooked[1];
|
||||
final int type = Integer.parseInt(cooked[2]);
|
||||
final String diskId = (cooked.length == 4) ? cooked[3] : null;
|
||||
final DiskInfo disk = mDisks.get(diskId);
|
||||
final int mtpIndex = allocateMtpIndex(id);
|
||||
final VolumeInfo vol = new VolumeInfo(id, type, diskId, mtpIndex);
|
||||
final VolumeInfo vol = new VolumeInfo(id, type, disk, mtpIndex);
|
||||
mVolumes.put(id, vol);
|
||||
onVolumeCreatedLocked(vol);
|
||||
break;
|
||||
@@ -885,10 +885,13 @@ class MountService extends IMountService.Stub
|
||||
break;
|
||||
}
|
||||
case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
|
||||
if (cooked.length != 3) break;
|
||||
final VolumeInfo vol = mVolumes.get(cooked[1]);
|
||||
if (vol != null) {
|
||||
vol.fsLabel = cooked[2];
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 2; i < cooked.length; i++) {
|
||||
builder.append(cooked[i]).append(' ');
|
||||
}
|
||||
vol.fsLabel = builder.toString().trim();
|
||||
}
|
||||
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
|
||||
break;
|
||||
@@ -1351,7 +1354,7 @@ class MountService extends IMountService.Stub
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
final VolumeInfo vol = mVolumes.valueAt(i);
|
||||
if (vol.isPrimary() && vol.state == VolumeInfo.STATE_MOUNTED) {
|
||||
if (vol.isPrimary() && vol.isMountedWritable()) {
|
||||
// Cool beans, we have a mounted primary volume
|
||||
return;
|
||||
}
|
||||
@@ -2711,9 +2714,47 @@ class MountService extends IMountService.Stub
|
||||
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
|
||||
|
||||
for (String arg : args) {
|
||||
if ("--clear-metadata".equals(arg)) {
|
||||
synchronized (mLock) {
|
||||
mMetadata.clear();
|
||||
writeMetadataLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
|
||||
synchronized (mLock) {
|
||||
pw.println("Disks:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mDisks.size(); i++) {
|
||||
final DiskInfo disk = mDisks.valueAt(i);
|
||||
disk.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("Volumes:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
final VolumeInfo vol = mVolumes.valueAt(i);
|
||||
if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
|
||||
vol.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("Metadata:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mMetadata.size(); i++) {
|
||||
final VolumeMetadata meta = mMetadata.valueAt(i);
|
||||
meta.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
synchronized (mObbMounts) {
|
||||
pw.println();
|
||||
pw.println("mObbMounts:");
|
||||
pw.increaseIndent();
|
||||
final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
|
||||
@@ -2743,36 +2784,6 @@ class MountService extends IMountService.Stub
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
pw.println();
|
||||
pw.println("Disks:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mDisks.size(); i++) {
|
||||
final DiskInfo disk = mDisks.valueAt(i);
|
||||
disk.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("Volumes:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
final VolumeInfo vol = mVolumes.valueAt(i);
|
||||
if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
|
||||
vol.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("Metadata:");
|
||||
pw.increaseIndent();
|
||||
for (int i = 0; i < mMetadata.size(); i++) {
|
||||
final VolumeMetadata meta = mMetadata.valueAt(i);
|
||||
meta.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
pw.println();
|
||||
pw.println("mConnection:");
|
||||
pw.increaseIndent();
|
||||
|
||||
Reference in New Issue
Block a user