Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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.telephony.mbms; |
| 18 | |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 19 | import android.annotation.NonNull; |
Hall Liu | ff6f986 | 2017-07-28 16:37:57 -0700 | [diff] [blame] | 20 | import android.annotation.SystemApi; |
Hall Liu | 07f1843 | 2018-04-10 14:04:12 -0700 | [diff] [blame] | 21 | import android.annotation.TestApi; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 22 | import android.content.Intent; |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 23 | import android.net.Uri; |
| 24 | import android.os.Parcel; |
| 25 | import android.os.Parcelable; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 26 | import android.util.Base64; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 27 | import android.util.Log; |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 28 | |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 29 | import java.io.ByteArrayInputStream; |
| 30 | import java.io.ByteArrayOutputStream; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 31 | import java.io.Externalizable; |
| 32 | import java.io.File; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 33 | import java.io.IOException; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 34 | import java.io.ObjectInput; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 35 | import java.io.ObjectInputStream; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 36 | import java.io.ObjectOutput; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 37 | import java.io.ObjectOutputStream; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 38 | import java.net.URISyntaxException; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 39 | import java.nio.charset.StandardCharsets; |
| 40 | import java.security.MessageDigest; |
| 41 | import java.security.NoSuchAlgorithmException; |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 42 | import java.util.Objects; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 43 | |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 44 | /** |
Hall Liu | ff6f986 | 2017-07-28 16:37:57 -0700 | [diff] [blame] | 45 | * Describes a request to download files over cell-broadcast. Instances of this class should be |
| 46 | * created by the app when requesting a download, and instances of this class will be passed back |
| 47 | * to the app when the middleware updates the status of the download. |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 48 | */ |
Hall Liu | 39605ad | 2017-08-15 13:46:10 -0700 | [diff] [blame] | 49 | public final class DownloadRequest implements Parcelable { |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 50 | // Version code used to keep token calculation consistent. |
| 51 | private static final int CURRENT_VERSION = 1; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 52 | private static final String LOG_TAG = "MbmsDownloadRequest"; |
| 53 | |
Hall Liu | 39605ad | 2017-08-15 13:46:10 -0700 | [diff] [blame] | 54 | /** @hide */ |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 55 | public static final int MAX_APP_INTENT_SIZE = 50000; |
| 56 | |
Hall Liu | 39605ad | 2017-08-15 13:46:10 -0700 | [diff] [blame] | 57 | /** @hide */ |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 58 | public static final int MAX_DESTINATION_URI_SIZE = 50000; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 59 | |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 60 | /** @hide */ |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 61 | private static class SerializationDataContainer implements Externalizable { |
| 62 | private String fileServiceId; |
| 63 | private Uri source; |
| 64 | private Uri destination; |
| 65 | private int subscriptionId; |
| 66 | private String appIntent; |
| 67 | private int version; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 68 | |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 69 | public SerializationDataContainer() {} |
| 70 | |
| 71 | SerializationDataContainer(DownloadRequest request) { |
| 72 | fileServiceId = request.fileServiceId; |
| 73 | source = request.sourceUri; |
| 74 | destination = request.destinationUri; |
| 75 | subscriptionId = request.subscriptionId; |
| 76 | appIntent = request.serializedResultIntentForApp; |
| 77 | version = request.version; |
| 78 | } |
| 79 | |
| 80 | @Override |
| 81 | public void writeExternal(ObjectOutput objectOutput) throws IOException { |
| 82 | objectOutput.write(version); |
| 83 | objectOutput.writeUTF(fileServiceId); |
| 84 | objectOutput.writeUTF(source.toString()); |
| 85 | objectOutput.writeUTF(destination.toString()); |
| 86 | objectOutput.write(subscriptionId); |
| 87 | objectOutput.writeUTF(appIntent); |
| 88 | } |
| 89 | |
| 90 | @Override |
| 91 | public void readExternal(ObjectInput objectInput) throws IOException { |
| 92 | version = objectInput.read(); |
| 93 | fileServiceId = objectInput.readUTF(); |
| 94 | source = Uri.parse(objectInput.readUTF()); |
| 95 | destination = Uri.parse(objectInput.readUTF()); |
| 96 | subscriptionId = objectInput.read(); |
| 97 | appIntent = objectInput.readUTF(); |
| 98 | // Do version checks here -- future versions may have other fields. |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 99 | } |
| 100 | } |
| 101 | |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 102 | public static class Builder { |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 103 | private String fileServiceId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 104 | private Uri source; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 105 | private Uri destination; |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 106 | private int subscriptionId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 107 | private String appIntent; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 108 | private int version = CURRENT_VERSION; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 109 | |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 110 | /** |
| 111 | * Constructs a {@link Builder} from a {@link DownloadRequest} |
| 112 | * @param other The {@link DownloadRequest} from which the data for the {@link Builder} |
| 113 | * should come. |
| 114 | * @return An instance of {@link Builder} pre-populated with data from the provided |
| 115 | * {@link DownloadRequest}. |
| 116 | */ |
| 117 | public static Builder fromDownloadRequest(DownloadRequest other) { |
| 118 | Builder result = new Builder(other.sourceUri, other.destinationUri) |
| 119 | .setServiceId(other.fileServiceId) |
| 120 | .setSubscriptionId(other.subscriptionId); |
| 121 | result.appIntent = other.serializedResultIntentForApp; |
| 122 | // Version of the result is going to be the current version -- as this class gets |
| 123 | // updated, new fields will be set to default values in here. |
| 124 | return result; |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * This method constructs a new instance of {@link Builder} based on the serialized data |
| 129 | * passed in. |
| 130 | * @param data A byte array, the contents of which should have been originally obtained |
| 131 | * from {@link DownloadRequest#toByteArray()}. |
| 132 | */ |
| 133 | public static Builder fromSerializedRequest(byte[] data) { |
| 134 | Builder builder; |
| 135 | try { |
| 136 | ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(data)); |
| 137 | SerializationDataContainer dataContainer = |
| 138 | (SerializationDataContainer) stream.readObject(); |
| 139 | builder = new Builder(dataContainer.source, dataContainer.destination); |
| 140 | builder.version = dataContainer.version; |
| 141 | builder.appIntent = dataContainer.appIntent; |
| 142 | builder.fileServiceId = dataContainer.fileServiceId; |
| 143 | builder.subscriptionId = dataContainer.subscriptionId; |
| 144 | } catch (IOException e) { |
| 145 | // Really should never happen |
| 146 | Log.e(LOG_TAG, "Got IOException trying to parse opaque data"); |
| 147 | throw new IllegalArgumentException(e); |
| 148 | } catch (ClassNotFoundException e) { |
| 149 | Log.e(LOG_TAG, "Got ClassNotFoundException trying to parse opaque data"); |
| 150 | throw new IllegalArgumentException(e); |
| 151 | } |
| 152 | return builder; |
| 153 | } |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 154 | |
| 155 | /** |
| 156 | * Builds a new DownloadRequest. |
| 157 | * @param sourceUri the source URI for the DownloadRequest to be built. This URI should |
| 158 | * never be null. |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 159 | * @param destinationUri The final location for the file(s) that are to be downloaded. It |
| 160 | * must be on the same filesystem as the temp file directory set via |
| 161 | * {@link android.telephony.MbmsDownloadSession#setTempFileRootDirectory(File)}. |
| 162 | * The provided path must be a directory that exists. An |
| 163 | * {@link IllegalArgumentException} will be thrown otherwise. |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 164 | */ |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 165 | public Builder(@NonNull Uri sourceUri, @NonNull Uri destinationUri) { |
| 166 | if (sourceUri == null || destinationUri == null) { |
| 167 | throw new IllegalArgumentException("Source and destination URIs must be non-null."); |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 168 | } |
| 169 | source = sourceUri; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 170 | destination = destinationUri; |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 171 | } |
| 172 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 173 | /** |
| 174 | * Sets the service from which the download request to be built will download from. |
| 175 | * @param serviceInfo |
| 176 | * @return |
| 177 | */ |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 178 | public Builder setServiceInfo(FileServiceInfo serviceInfo) { |
| 179 | fileServiceId = serviceInfo.getServiceId(); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 180 | return this; |
| 181 | } |
| 182 | |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 183 | /** |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 184 | * Set the service ID for the download request. For use by the middleware only. |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 185 | * @hide |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 186 | */ |
Hall Liu | 39605ad | 2017-08-15 13:46:10 -0700 | [diff] [blame] | 187 | @SystemApi |
Hall Liu | 07f1843 | 2018-04-10 14:04:12 -0700 | [diff] [blame] | 188 | @TestApi |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 189 | public Builder setServiceId(String serviceId) { |
| 190 | fileServiceId = serviceId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 191 | return this; |
| 192 | } |
| 193 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 194 | /** |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 195 | * Set the subscription ID on which the file(s) should be downloaded. |
| 196 | * @param subscriptionId |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 197 | */ |
| 198 | public Builder setSubscriptionId(int subscriptionId) { |
| 199 | this.subscriptionId = subscriptionId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 200 | return this; |
| 201 | } |
| 202 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 203 | /** |
| 204 | * Set the {@link Intent} that should be sent when the download completes or fails. This |
| 205 | * should be an intent with a explicit {@link android.content.ComponentName} targeted to a |
| 206 | * {@link android.content.BroadcastReceiver} in the app's package. |
| 207 | * |
| 208 | * The middleware should not use this method. |
| 209 | * @param intent |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 210 | */ |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 211 | public Builder setAppIntent(Intent intent) { |
| 212 | this.appIntent = intent.toUri(0); |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 213 | if (this.appIntent.length() > MAX_APP_INTENT_SIZE) { |
| 214 | throw new IllegalArgumentException("App intent must not exceed length " + |
| 215 | MAX_APP_INTENT_SIZE); |
| 216 | } |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 217 | return this; |
| 218 | } |
| 219 | |
| 220 | public DownloadRequest build() { |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 221 | return new DownloadRequest(fileServiceId, source, destination, |
| 222 | subscriptionId, appIntent, version); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 223 | } |
| 224 | } |
| 225 | |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 226 | private final String fileServiceId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 227 | private final Uri sourceUri; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 228 | private final Uri destinationUri; |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 229 | private final int subscriptionId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 230 | private final String serializedResultIntentForApp; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 231 | private final int version; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 232 | |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 233 | private DownloadRequest(String fileServiceId, |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 234 | Uri source, Uri destination, int sub, |
Hall Liu | e373ee5 | 2017-09-08 18:02:38 -0700 | [diff] [blame] | 235 | String appIntent, int version) { |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 236 | this.fileServiceId = fileServiceId; |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 237 | sourceUri = source; |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 238 | subscriptionId = sub; |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 239 | destinationUri = destination; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 240 | serializedResultIntentForApp = appIntent; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 241 | this.version = version; |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 242 | } |
| 243 | |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 244 | private DownloadRequest(Parcel in) { |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 245 | fileServiceId = in.readString(); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 246 | sourceUri = in.readParcelable(getClass().getClassLoader()); |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 247 | destinationUri = in.readParcelable(getClass().getClassLoader()); |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 248 | subscriptionId = in.readInt(); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 249 | serializedResultIntentForApp = in.readString(); |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 250 | version = in.readInt(); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 251 | } |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 252 | |
| 253 | public int describeContents() { |
| 254 | return 0; |
| 255 | } |
| 256 | |
| 257 | public void writeToParcel(Parcel out, int flags) { |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 258 | out.writeString(fileServiceId); |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 259 | out.writeParcelable(sourceUri, flags); |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 260 | out.writeParcelable(destinationUri, flags); |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 261 | out.writeInt(subscriptionId); |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 262 | out.writeString(serializedResultIntentForApp); |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 263 | out.writeInt(version); |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 264 | } |
| 265 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 266 | /** |
| 267 | * @return The ID of the file service to download from. |
| 268 | */ |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 269 | public String getFileServiceId() { |
| 270 | return fileServiceId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 271 | } |
| 272 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 273 | /** |
| 274 | * @return The source URI to download from |
| 275 | */ |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 276 | public Uri getSourceUri() { |
| 277 | return sourceUri; |
| 278 | } |
| 279 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 280 | /** |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 281 | * @return The destination {@link Uri} of the downloaded file. |
| 282 | */ |
| 283 | public Uri getDestinationUri() { |
| 284 | return destinationUri; |
| 285 | } |
| 286 | |
| 287 | /** |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 288 | * @return The subscription ID on which to perform MBMS operations. |
| 289 | */ |
Hall Liu | fcbf240 | 2017-06-07 13:57:11 -0700 | [diff] [blame] | 290 | public int getSubscriptionId() { |
| 291 | return subscriptionId; |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 292 | } |
| 293 | |
Hall Liu | d5c955f | 2017-07-20 15:32:51 -0700 | [diff] [blame] | 294 | /** |
| 295 | * For internal use -- returns the intent to send to the app after download completion or |
| 296 | * failure. |
| 297 | * @hide |
| 298 | */ |
Hall Liu | 563e150c | 2017-04-25 15:04:26 -0700 | [diff] [blame] | 299 | public Intent getIntentForApp() { |
| 300 | try { |
| 301 | return Intent.parseUri(serializedResultIntentForApp, 0); |
| 302 | } catch (URISyntaxException e) { |
| 303 | return null; |
| 304 | } |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 305 | } |
| 306 | |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 307 | /** |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 308 | * This method returns a byte array that may be persisted to disk and restored to a |
| 309 | * {@link DownloadRequest}. The instance of {@link DownloadRequest} persisted by this method |
| 310 | * may be recovered via {@link Builder#fromSerializedRequest(byte[])}. |
| 311 | * @return A byte array of data to persist. |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 312 | */ |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 313 | public byte[] toByteArray() { |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 314 | try { |
| 315 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
| 316 | ObjectOutputStream stream = new ObjectOutputStream(byteArrayOutputStream); |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 317 | SerializationDataContainer container = new SerializationDataContainer(this); |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 318 | stream.writeObject(container); |
| 319 | stream.flush(); |
| 320 | return byteArrayOutputStream.toByteArray(); |
| 321 | } catch (IOException e) { |
| 322 | // Really should never happen |
| 323 | Log.e(LOG_TAG, "Got IOException trying to serialize opaque data"); |
| 324 | return null; |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | /** @hide */ |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 329 | public int getVersion() { |
| 330 | return version; |
| 331 | } |
| 332 | |
Jeff Sharkey | 9e8f83d | 2019-02-28 12:06:45 -0700 | [diff] [blame^] | 333 | public static final @android.annotation.NonNull Parcelable.Creator<DownloadRequest> CREATOR = |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 334 | new Parcelable.Creator<DownloadRequest>() { |
| 335 | public DownloadRequest createFromParcel(Parcel in) { |
| 336 | return new DownloadRequest(in); |
| 337 | } |
| 338 | public DownloadRequest[] newArray(int size) { |
| 339 | return new DownloadRequest[size]; |
| 340 | } |
| 341 | }; |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 342 | |
| 343 | /** |
Hall Liu | 39605ad | 2017-08-15 13:46:10 -0700 | [diff] [blame] | 344 | * Maximum permissible length for the app's destination path, when serialized via |
| 345 | * {@link Uri#toString()}. |
| 346 | */ |
| 347 | public static int getMaxAppIntentSize() { |
| 348 | return MAX_APP_INTENT_SIZE; |
| 349 | } |
| 350 | |
| 351 | /** |
| 352 | * Maximum permissible length for the app's download-completion intent, when serialized via |
| 353 | * {@link Intent#toUri(int)}. |
| 354 | */ |
| 355 | public static int getMaxDestinationUriSize() { |
| 356 | return MAX_DESTINATION_URI_SIZE; |
| 357 | } |
| 358 | |
| 359 | /** |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 360 | * Retrieves the hash string that should be used as the filename when storing a token for |
| 361 | * this DownloadRequest. |
| 362 | * @hide |
| 363 | */ |
| 364 | public String getHash() { |
| 365 | MessageDigest digest; |
| 366 | try { |
| 367 | digest = MessageDigest.getInstance("SHA-256"); |
| 368 | } catch (NoSuchAlgorithmException e) { |
| 369 | throw new RuntimeException("Could not get sha256 hash object"); |
| 370 | } |
| 371 | if (version >= 1) { |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 372 | // Hash the source, destination, and the app intent |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 373 | digest.update(sourceUri.toString().getBytes(StandardCharsets.UTF_8)); |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 374 | digest.update(destinationUri.toString().getBytes(StandardCharsets.UTF_8)); |
Brad Ebinger | ea737a8 | 2017-10-09 11:23:21 -0700 | [diff] [blame] | 375 | if (serializedResultIntentForApp != null) { |
| 376 | digest.update(serializedResultIntentForApp.getBytes(StandardCharsets.UTF_8)); |
| 377 | } |
Hall Liu | 2043f70 | 2017-06-19 17:20:10 -0700 | [diff] [blame] | 378 | } |
| 379 | // Add updates for future versions here |
| 380 | return Base64.encodeToString(digest.digest(), Base64.URL_SAFE | Base64.NO_WRAP); |
| 381 | } |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 382 | |
| 383 | @Override |
| 384 | public boolean equals(Object o) { |
| 385 | if (this == o) return true; |
| 386 | if (o == null) { |
| 387 | return false; |
| 388 | } |
| 389 | if (!(o instanceof DownloadRequest)) { |
| 390 | return false; |
| 391 | } |
| 392 | DownloadRequest request = (DownloadRequest) o; |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 393 | return subscriptionId == request.subscriptionId && |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 394 | version == request.version && |
Hall Liu | 3bedd88 | 2017-06-29 14:10:48 -0700 | [diff] [blame] | 395 | Objects.equals(fileServiceId, request.fileServiceId) && |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 396 | Objects.equals(sourceUri, request.sourceUri) && |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 397 | Objects.equals(destinationUri, request.destinationUri) && |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 398 | Objects.equals(serializedResultIntentForApp, request.serializedResultIntentForApp); |
| 399 | } |
| 400 | |
| 401 | @Override |
| 402 | public int hashCode() { |
Hall Liu | 5b84487 | 2018-02-06 11:36:17 -0800 | [diff] [blame] | 403 | return Objects.hash(fileServiceId, sourceUri, destinationUri, |
Hall Liu | 9f116ef | 2017-06-23 16:32:30 -0700 | [diff] [blame] | 404 | subscriptionId, serializedResultIntentForApp, version); |
| 405 | } |
Robert Greenwalt | 4dded7a | 2016-12-05 16:33:32 -0800 | [diff] [blame] | 406 | } |