Merge "Update DownloadRequest API" am: fa42eea98f

am: 5e7c98bb6a

Change-Id: Ie5a323b8a0c96f7a7f63eea1b0163bb7e5bf4ea7
This commit is contained in:
Hall Liu
2017-07-06 02:10:30 +00:00
committed by android-build-merger
4 changed files with 125 additions and 47 deletions

View File

@@ -93,19 +93,21 @@ public class MbmsDownloadManager {
/**
* Integer extra indicating the result code of the download. One of
* {@link #RESULT_SUCCESSFUL}, {@link #RESULT_EXPIRED}, or {@link #RESULT_CANCELLED}.
* TODO: Not systemapi.
*/
public static final String EXTRA_RESULT = "android.telephony.mbms.extra.RESULT";
/**
* Extra containing the {@link android.telephony.mbms.FileInfo} for which the download result
* is for. Must not be null.
* TODO: future systemapi (here and and all extras) except the two for the app intent
* TODO: Not systemapi.
*/
public static final String EXTRA_FILE_INFO = "android.telephony.mbms.extra.FILE_INFO";
/**
* Extra containing the {@link DownloadRequest} for which the download result or file
* descriptor request is for. Must not be null.
* TODO: future systemapi (here and and all extras) except the three for the app intent
*/
public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST";
@@ -180,6 +182,7 @@ public class MbmsDownloadManager {
* {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)}.
* Will always be set to a non-null value if {@link #EXTRA_RESULT} is set to
* {@link #RESULT_SUCCESSFUL}.
* TODO: Not systemapi.
*/
public static final String EXTRA_COMPLETED_FILE_URI =
"android.telephony.mbms.extra.COMPLETED_FILE_URI";
@@ -554,7 +557,7 @@ public class MbmsDownloadManager {
private File getDownloadRequestTokenPath(DownloadRequest request) {
File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForService(mContext,
request.getFileServiceInfo());
request.getFileServiceId());
String downloadTokenFileName = request.getHash()
+ MbmsDownloadReceiver.DOWNLOAD_TOKEN_SUFFIX;
return new File(tempFileLocation, downloadTokenFileName);

View File

@@ -21,7 +21,14 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -35,24 +42,52 @@ import java.util.Objects;
public class DownloadRequest implements Parcelable {
// Version code used to keep token calculation consistent.
private static final int CURRENT_VERSION = 1;
private static final String LOG_TAG = "MbmsDownloadRequest";
/**
* Maximum permissible length for the app's download-completion intent, when serialized via
* {@link Intent#toUri(int)}.
*/
public static final int MAX_APP_INTENT_SIZE = 50000;
/**
* Maximum permissible length for the app's destination path, when serialized via
* {@link Uri#toString()}.
*/
public static final int MAX_DESTINATION_URI_SIZE = 50000;
/** @hide */
private static class OpaqueDataContainer implements Serializable {
private final String destinationUri;
private final String appIntent;
private final int version;
public OpaqueDataContainer(String destinationUri, String appIntent, int version) {
this.destinationUri = destinationUri;
this.appIntent = appIntent;
this.version = version;
}
}
public static class Builder {
private int id;
private FileServiceInfo serviceInfo;
private String fileServiceId;
private Uri source;
private Uri dest;
private int subscriptionId;
private String appIntent;
private int version = CURRENT_VERSION;
public Builder setId(int id) {
this.id = id;
public Builder setServiceInfo(FileServiceInfo serviceInfo) {
fileServiceId = serviceInfo.getServiceId();
return this;
}
public Builder setServiceInfo(FileServiceInfo serviceInfo) {
this.serviceInfo = serviceInfo;
/**
* @hide
* TODO: systemapi
*/
public Builder setServiceId(String serviceId) {
fileServiceId = serviceId;
return this;
}
@@ -62,6 +97,10 @@ public class DownloadRequest implements Parcelable {
}
public Builder setDest(Uri dest) {
if (dest.toString().length() > MAX_DESTINATION_URI_SIZE) {
throw new IllegalArgumentException("Destination uri must not exceed length " +
MAX_DESTINATION_URI_SIZE);
}
this.dest = dest;
return this;
}
@@ -73,33 +112,53 @@ public class DownloadRequest implements Parcelable {
public Builder setAppIntent(Intent intent) {
this.appIntent = intent.toUri(0);
if (this.appIntent.length() > MAX_APP_INTENT_SIZE) {
throw new IllegalArgumentException("App intent must not exceed length " +
MAX_APP_INTENT_SIZE);
}
return this;
}
public Builder setVersion(int version) {
this.version = version;
/**
* For use by middleware only
* TODO: systemapi
* @hide
*/
public Builder setOpaqueData(byte[] data) {
try {
ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(data));
OpaqueDataContainer dataContainer = (OpaqueDataContainer) stream.readObject();
version = dataContainer.version;
appIntent = dataContainer.appIntent;
dest = Uri.parse(dataContainer.destinationUri);
} catch (IOException e) {
// Really should never happen
Log.e(LOG_TAG, "Got IOException trying to parse opaque data");
throw new IllegalArgumentException(e);
} catch (ClassNotFoundException e) {
Log.e(LOG_TAG, "Got ClassNotFoundException trying to parse opaque data");
throw new IllegalArgumentException(e);
}
return this;
}
public DownloadRequest build() {
return new DownloadRequest(id, serviceInfo, source, dest,
return new DownloadRequest(fileServiceId, source, dest,
subscriptionId, appIntent, version);
}
}
private final int downloadId;
private final FileServiceInfo fileServiceInfo;
private final String fileServiceId;
private final Uri sourceUri;
private final Uri destinationUri;
private final int subscriptionId;
private final String serializedResultIntentForApp;
private final int version;
private DownloadRequest(int id, FileServiceInfo serviceInfo,
private DownloadRequest(String fileServiceId,
Uri source, Uri dest,
int sub, String appIntent, int version) {
downloadId = id;
fileServiceInfo = serviceInfo;
this.fileServiceId = fileServiceId;
sourceUri = source;
destinationUri = dest;
subscriptionId = sub;
@@ -112,8 +171,7 @@ public class DownloadRequest implements Parcelable {
}
private DownloadRequest(DownloadRequest dr) {
downloadId = dr.downloadId;
fileServiceInfo = dr.fileServiceInfo;
fileServiceId = dr.fileServiceId;
sourceUri = dr.sourceUri;
destinationUri = dr.destinationUri;
subscriptionId = dr.subscriptionId;
@@ -122,8 +180,7 @@ public class DownloadRequest implements Parcelable {
}
private DownloadRequest(Parcel in) {
downloadId = in.readInt();
fileServiceInfo = in.readParcelable(getClass().getClassLoader());
fileServiceId = in.readString();
sourceUri = in.readParcelable(getClass().getClassLoader());
destinationUri = in.readParcelable(getClass().getClassLoader());
subscriptionId = in.readInt();
@@ -136,8 +193,7 @@ public class DownloadRequest implements Parcelable {
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(downloadId);
out.writeParcelable(fileServiceInfo, flags);
out.writeString(fileServiceId);
out.writeParcelable(sourceUri, flags);
out.writeParcelable(destinationUri, flags);
out.writeInt(subscriptionId);
@@ -145,12 +201,8 @@ public class DownloadRequest implements Parcelable {
out.writeInt(version);
}
public int getDownloadId() {
return downloadId;
}
public FileServiceInfo getFileServiceInfo() {
return fileServiceInfo;
public String getFileServiceId() {
return fileServiceId;
}
public Uri getSourceUri() {
@@ -173,6 +225,27 @@ public class DownloadRequest implements Parcelable {
}
}
/**
* @hide
* TODO: systemapi
*/
public byte[] getOpaqueData() {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(byteArrayOutputStream);
OpaqueDataContainer container = new OpaqueDataContainer(
destinationUri.toString(), serializedResultIntentForApp, version);
stream.writeObject(container);
stream.flush();
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
// Really should never happen
Log.e(LOG_TAG, "Got IOException trying to serialize opaque data");
return null;
}
}
/** @hide */
public int getVersion() {
return version;
}
@@ -228,10 +301,9 @@ public class DownloadRequest implements Parcelable {
return false;
}
DownloadRequest request = (DownloadRequest) o;
return downloadId == request.downloadId &&
subscriptionId == request.subscriptionId &&
return subscriptionId == request.subscriptionId &&
version == request.version &&
Objects.equals(fileServiceInfo, request.fileServiceInfo) &&
Objects.equals(fileServiceId, request.fileServiceId) &&
Objects.equals(sourceUri, request.sourceUri) &&
Objects.equals(destinationUri, request.destinationUri) &&
Objects.equals(serializedResultIntentForApp, request.serializedResultIntentForApp);
@@ -239,7 +311,7 @@ public class DownloadRequest implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(downloadId, fileServiceInfo, sourceUri, destinationUri,
return Objects.hash(fileServiceId, sourceUri, destinationUri,
subscriptionId, serializedResultIntentForApp, version);
}
}

View File

@@ -83,7 +83,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
public static final int RESULT_DOWNLOAD_FINALIZATION_ERROR = 4;
/**
* Indicates that the manager weas unable to generate one or more of the requested file
* Indicates that the manager was unable to generate one or more of the requested file
* descriptors.
* This is a non-fatal result code -- some file descriptors may still be generated, but there
* is no guarantee that they will be the same number as requested.
@@ -149,7 +149,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
DownloadRequest request = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_REQUEST);
String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX;
File expectedTokenFile = new File(
MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceInfo()),
MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceId()),
expectedTokenFileName);
if (!expectedTokenFile.exists()) {
Log.w(LOG_TAG, "Supplied download request does not match a token that we have. " +
@@ -201,22 +201,24 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
Uri destinationUri = request.getDestinationUri();
Uri finalTempFile = intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FINAL_URI);
if (!verifyTempFilePath(context, request.getFileServiceInfo(), finalTempFile)) {
if (!verifyTempFilePath(context, request.getFileServiceId(), finalTempFile)) {
Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile);
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
return;
}
String relativePath = calculateDestinationFileRelativePath(request,
(FileInfo) intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FILE_INFO));
FileInfo completedFileInfo =
(FileInfo) intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FILE_INFO);
String relativePath = calculateDestinationFileRelativePath(request, completedFileInfo);
Uri finalFileLocation = moveTempFile(finalTempFile, destinationUri, relativePath);
if (finalFileLocation == null) {
Log.w(LOG_TAG, "Failed to move temp file to final destination");
// TODO: how do we notify the app of this?
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
return;
}
intentForApp.putExtra(MbmsDownloadManager.EXTRA_COMPLETED_FILE_URI, finalFileLocation);
intentForApp.putExtra(MbmsDownloadManager.EXTRA_FILE_INFO, completedFileInfo);
context.sendBroadcast(intentForApp);
setResultCode(RESULT_OK);
@@ -235,7 +237,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
for (Uri tempFileUri : tempFiles) {
if (verifyTempFilePath(context, request.getFileServiceInfo(), tempFileUri)) {
if (verifyTempFilePath(context, request.getFileServiceId(), tempFileUri)) {
File tempFile = new File(tempFileUri.getSchemeSpecificPart());
tempFile.delete();
}
@@ -276,7 +278,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
private ArrayList<UriPathPair> generateFreshTempFiles(Context context,
FileServiceInfo serviceInfo,
int freshFdCount) {
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo);
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context,
serviceInfo.getServiceId());
if (!tempFileDir.exists()) {
tempFileDir.mkdirs();
}
@@ -327,7 +330,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
ArrayList<UriPathPair> result = new ArrayList<>(pausedFiles.size());
for (Uri fileUri : pausedFiles) {
if (!verifyTempFilePath(context, serviceInfo, fileUri)) {
if (!verifyTempFilePath(context, serviceInfo.getServiceId(), fileUri)) {
Log.w(LOG_TAG, "Supplied file " + fileUri + " is not a valid temp file to resume");
setResultCode(RESULT_TEMP_FILE_GENERATION_ERROR);
continue;
@@ -351,7 +354,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
private void cleanupTempFiles(Context context, Intent intent) {
FileServiceInfo serviceInfo =
intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO);
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo);
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context,
serviceInfo.getServiceId());
List<Uri> filesInUse =
intent.getParcelableArrayListExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE);
File[] filesToDelete = tempFileDir.listFiles(new FileFilter() {
@@ -439,7 +443,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
return null;
}
private static boolean verifyTempFilePath(Context context, FileServiceInfo serviceInfo,
private static boolean verifyTempFilePath(Context context, String serviceId,
Uri filePath) {
if (!ContentResolver.SCHEME_FILE.equals(filePath.getScheme())) {
Log.w(LOG_TAG, "Uri " + filePath + " does not have a file scheme");
@@ -454,7 +458,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
if (!MbmsUtils.isContainedIn(
MbmsUtils.getEmbmsTempFileDirForService(context, serviceInfo), tempFile)) {
MbmsUtils.getEmbmsTempFileDirForService(context, serviceId), tempFile)) {
return false;
}

View File

@@ -89,10 +89,9 @@ public class MbmsUtils {
/**
* Returns a File linked to the directory used to store temp files for this file service
*/
public static File getEmbmsTempFileDirForService(Context context, FileServiceInfo serviceInfo) {
public static File getEmbmsTempFileDirForService(Context context, String serviceId) {
File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
String tempFileDirName = String.valueOf(serviceInfo.getServiceId());
return new File(embmsTempFileDir, tempFileDirName);
return new File(embmsTempFileDir, serviceId);
}
}