Merge changes I17264f0e,I0581978f am: 06c8be69b9
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1902510 Change-Id: I30faa68caf5a55504b1b8cc3c9b958c308a9b120
This commit is contained in:
@@ -103,6 +103,7 @@ public class MtpDatabase implements AutoCloseable {
|
|||||||
private int mDeviceType;
|
private int mDeviceType;
|
||||||
private String mHostType;
|
private String mHostType;
|
||||||
private boolean mSkipThumbForHost = false;
|
private boolean mSkipThumbForHost = false;
|
||||||
|
private volatile boolean mHostIsWindows = false;
|
||||||
|
|
||||||
private MtpServer mServer;
|
private MtpServer mServer;
|
||||||
private MtpStorageManager mManager;
|
private MtpStorageManager mManager;
|
||||||
@@ -358,7 +359,7 @@ public class MtpDatabase implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addStorage(StorageVolume storage) {
|
public void addStorage(StorageVolume storage) {
|
||||||
MtpStorage mtpStorage = mManager.addMtpStorage(storage);
|
MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows);
|
||||||
mStorageMap.put(storage.getPath(), mtpStorage);
|
mStorageMap.put(storage.getPath(), mtpStorage);
|
||||||
if (mServer != null) {
|
if (mServer != null) {
|
||||||
mServer.addStorage(mtpStorage);
|
mServer.addStorage(mtpStorage);
|
||||||
@@ -413,6 +414,7 @@ public class MtpDatabase implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
mHostType = "";
|
mHostType = "";
|
||||||
mSkipThumbForHost = false;
|
mSkipThumbForHost = false;
|
||||||
|
mHostIsWindows = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForNative
|
@VisibleForNative
|
||||||
@@ -736,10 +738,12 @@ public class MtpDatabase implements AutoCloseable {
|
|||||||
: MtpConstants.RESPONSE_GENERAL_ERROR);
|
: MtpConstants.RESPONSE_GENERAL_ERROR);
|
||||||
case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
|
case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
|
||||||
mHostType = stringValue;
|
mHostType = stringValue;
|
||||||
|
Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
|
||||||
|
+ "=" + stringValue);
|
||||||
if (stringValue.startsWith("Android/")) {
|
if (stringValue.startsWith("Android/")) {
|
||||||
Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
|
|
||||||
+ "=" + stringValue);
|
|
||||||
mSkipThumbForHost = true;
|
mSkipThumbForHost = true;
|
||||||
|
} else if (stringValue.startsWith("Windows/")) {
|
||||||
|
mHostIsWindows = true;
|
||||||
}
|
}
|
||||||
return MtpConstants.RESPONSE_OK;
|
return MtpConstants.RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package android.mtp;
|
|||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.os.storage.StorageVolume;
|
import android.os.storage.StorageVolume;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a storage unit on an MTP device.
|
* This class represents a storage unit on an MTP device.
|
||||||
* Used only for MTP support in USB responder mode.
|
* Used only for MTP support in USB responder mode.
|
||||||
@@ -33,14 +35,16 @@ public class MtpStorage {
|
|||||||
private final boolean mRemovable;
|
private final boolean mRemovable;
|
||||||
private final long mMaxFileSize;
|
private final long mMaxFileSize;
|
||||||
private final String mVolumeName;
|
private final String mVolumeName;
|
||||||
|
private final Supplier<Boolean> mIsHostWindows;
|
||||||
|
|
||||||
public MtpStorage(StorageVolume volume, int storageId) {
|
public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) {
|
||||||
mStorageId = storageId;
|
mStorageId = storageId;
|
||||||
mPath = volume.getPath();
|
mPath = volume.getPath();
|
||||||
mDescription = volume.getDescription(null);
|
mDescription = volume.getDescription(null);
|
||||||
mRemovable = volume.isRemovable();
|
mRemovable = volume.isRemovable();
|
||||||
mMaxFileSize = volume.getMaxFileSize();
|
mMaxFileSize = volume.getMaxFileSize();
|
||||||
mVolumeName = volume.getMediaStoreVolumeName();
|
mVolumeName = volume.getMediaStoreVolumeName();
|
||||||
|
mIsHostWindows = isHostWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,4 +97,13 @@ public class MtpStorage {
|
|||||||
public String getVolumeName() {
|
public String getVolumeName() {
|
||||||
return mVolumeName;
|
return mVolumeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the mtp host of this storage is Windows.
|
||||||
|
*
|
||||||
|
* @return is host Windows
|
||||||
|
*/
|
||||||
|
public boolean isHostWindows() {
|
||||||
|
return mIsHostWindows.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ package android.mtp;
|
|||||||
|
|
||||||
import android.media.MediaFile;
|
import android.media.MediaFile;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
|
import android.os.SystemProperties;
|
||||||
import android.os.storage.StorageVolume;
|
import android.os.storage.StorageVolume;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.system.StructStat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
@@ -35,6 +39,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
|
* MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
|
||||||
@@ -199,7 +204,38 @@ public class MtpStorageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return mIsDir ? 0 : getPath().toFile().length();
|
return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private long maybeApplyTranscodeLengthWorkaround(long length) {
|
||||||
|
// Windows truncates transferred files to the size advertised in the object property.
|
||||||
|
if (mStorage.isHostWindows() && isTranscodeMtpEnabled() && isFileTranscodeSupported()) {
|
||||||
|
// If the file supports transcoding, we double the returned size to accommodate
|
||||||
|
// the increase in size from transcoding to AVC. This is the same heuristic
|
||||||
|
// applied in the FUSE daemon (MediaProvider).
|
||||||
|
return length * 2;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTranscodeMtpEnabled() {
|
||||||
|
return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFileTranscodeSupported() {
|
||||||
|
// Check if the file supports transcoding by reading the |st_nlinks| struct stat
|
||||||
|
// field. This will be > 1 if the file supports transcoding. The FUSE daemon
|
||||||
|
// sets the field accordingly to enable the MTP stack workaround some Windows OS
|
||||||
|
// MTP client bug where they ignore the size returned as part of getting the MTP
|
||||||
|
// object, see MtpServer#doGetObject.
|
||||||
|
final Path path = getPath();
|
||||||
|
try {
|
||||||
|
StructStat stat = Os.stat(path.toString());
|
||||||
|
return stat.st_nlink > 1;
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getPath() {
|
public Path getPath() {
|
||||||
@@ -420,10 +456,12 @@ public class MtpStorageManager {
|
|||||||
* @param volume Storage to add.
|
* @param volume Storage to add.
|
||||||
* @return the associated MtpStorage
|
* @return the associated MtpStorage
|
||||||
*/
|
*/
|
||||||
public synchronized MtpStorage addMtpStorage(StorageVolume volume) {
|
public synchronized MtpStorage addMtpStorage(StorageVolume volume,
|
||||||
|
Supplier<Boolean> isHostWindows) {
|
||||||
int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
|
int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
|
||||||
MtpStorage storage = new MtpStorage(volume, storageId);
|
MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows);
|
||||||
MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true);
|
MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null,
|
||||||
|
/* isDir= */ true);
|
||||||
mRoots.put(storageId, root);
|
mRoots.put(storageId, root);
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,10 +159,11 @@ public class MtpStorageManagerTest {
|
|||||||
Log.d(TAG, "sendObjectInfoChanged: " + id);
|
Log.d(TAG, "sendObjectInfoChanged: " + id);
|
||||||
objectsInfoChanged.add(id);
|
objectsInfoChanged.add(id);
|
||||||
}
|
}
|
||||||
}, null);
|
}, /* subdirectories= */ null);
|
||||||
|
|
||||||
mainMtpStorage = manager.addMtpStorage(mainStorage);
|
mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false);
|
||||||
secondaryMtpStorage = manager.addMtpStorage(secondaryStorage);
|
secondaryMtpStorage = manager.addMtpStorage(secondaryStorage,
|
||||||
|
/* isHostWindows= */ () -> false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
Reference in New Issue
Block a user