Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java

Issue 848803002: Upstream DownloadManagerService (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add findbugs warnings Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.download;
6
7 import android.app.Activity;
8 import android.app.AlertDialog;
9 import android.app.DownloadManager;
10 import android.content.Context;
11 import android.content.DialogInterface;
12 import android.content.Intent;
13 import android.content.pm.PackageManager;
14 import android.content.pm.ResolveInfo;
15 import android.net.Uri;
16 import android.os.AsyncTask;
17 import android.os.Environment;
18 import android.os.ParcelFileDescriptor;
19 import android.provider.Browser;
20 import android.support.v4.util.LongSparseArray;
21 import android.text.TextUtils;
22 import android.util.Log;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.widget.TextView;
26
27 import org.apache.http.HttpResponse;
28 import org.apache.http.client.ClientProtocolException;
29 import org.apache.http.client.HttpClient;
30 import org.apache.http.client.methods.HttpPost;
31 import org.apache.http.entity.StringEntity;
32 import org.apache.http.impl.client.DefaultHttpClient;
33 import org.chromium.base.ApplicationStatus;
34 import org.chromium.base.VisibleForTesting;
35 import org.chromium.chrome.R;
36 import org.chromium.chrome.browser.ChromiumApplication;
37 import org.chromium.content.browser.DownloadInfo;
38 import org.xmlpull.v1.XmlPullParser;
39 import org.xmlpull.v1.XmlPullParserException;
40 import org.xmlpull.v1.XmlPullParserFactory;
41
42 import java.io.File;
43 import java.io.FileInputStream;
44 import java.io.FileNotFoundException;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.HashMap;
50 import java.util.List;
51 import java.util.Map;
52
53 /**
54 * This class handles OMA downloads according to the steps described in
55 * http://xml.coverpages.org/OMA-Download-OTA-V10-20020620.pdf:
56 * 1. Receives a download descriptor xml file.
57 * 2. Parses all the contents.
58 * 3. Checks device capability to see if it is able to handle the content.
59 * 4. Find the objectURI value from the download descriptor and prompt user with
60 * a dialog to proceed with the download.
61 * 5. On positive confirmation, sends a request to the download manager.
62 * 6. Once the download is completed, sends a message to the server if installNo tifyURI
63 * is present in the download descriptor.
64 * 7. Prompts user with a dialog to open the NextURL specified in the download d escriptor.
65 * If steps 2 - 6 fails, a warning dialog will be prompted to the user to let hi m
66 * know the error. Steps 6-7 will be executed afterwards.
67 * If installNotifyURI is present in the download descriptor, the downloaded con tent will
68 * be saved to the app directory first. If step 6 completes successfully, the co ntent will
69 * be moved to the public external storage. Otherwise, it will be removed from t he device.
70 */
71 public class OMADownloadHandler {
72 private static final String TAG = "OMADownloadHandler";
73
74 // MIME types for OMA downloads.
75 public static final String OMA_DOWNLOAD_DESCRIPTOR_MIME = "application/vnd.o ma.dd+xml";
76 public static final String OMA_DRM_MESSAGE_MIME = "application/vnd.oma.drm.m essage";
77 public static final String OMA_DRM_CONTENT_MIME = "application/vnd.oma.drm.c ontent";
78 public static final String OMA_DRM_RIGHTS_MIME = "application/vnd.oma.drm.ri ghts+wbxml";
79
80 // Valid download descriptor attributes.
81 protected static final String OMA_TYPE = "type";
82 protected static final String OMA_SIZE = "size";
83 protected static final String OMA_OBJECT_URI = "objectURI";
84 protected static final String OMA_INSTALL_NOTIFY_URI = "installNotifyURI";
85 protected static final String OMA_NEXT_URL = "nextURL";
86 protected static final String OMA_DD_VERSION = "DDVersion";
87 protected static final String OMA_NAME = "name";
88 protected static final String OMA_DESCRIPTION = "description";
89 protected static final String OMA_VENDOR = "vendor";
90 protected static final String OMA_INFO_URL = "infoURL";
91 protected static final String OMA_ICON_URI = "iconURI";
92 protected static final String OMA_INSTALL_PARAM = "installParam";
93
94 // Error message to send to the notification server.
95 private static final String DOWNLOAD_STATUS_SUCCESS = "900 Success \n\r";
96 private static final String DOWNLOAD_STATUS_INSUFFICIENT_MEMORY =
97 "901 insufficient memory \n\r";
98 private static final String DOWNLOAD_STATUS_USER_CANCELLED = "902 User Cance lled \n\r";
99 private static final String DOWNLOAD_STATUS_LOSS_OF_SERVICE = "903 Loss of S ervice \n\r";
100 private static final String DOWNLOAD_STATUS_ATTRIBUTE_MISMATCH = "905 Attrib ute mismatch \n\r";
101 private static final String DOWNLOAD_STATUS_INVALID_DESCRIPTOR = "906 Invali d descriptor \n\r";
102 private static final String DOWNLOAD_STATUS_INVALID_DDVERSION = "951 Invalid DDVersion \n\r";
103 private static final String DOWNLOAD_STATUS_DEVICE_ABORTED = "952 Device Abo rted \n\r";
104 private static final String DOWNLOAD_STATUS_NON_ACCEPTABLE_CONTENT =
105 "953 Non-Acceptable Content \n\r";
106 private static final String DOWNLOAD_STATUS_LOADER_ERROR = "954 Loader Error \n\r";
107
108 private final Context mContext;
109 private final LongSparseArray<OMAInfo> mPendingOMADownloads =
110 new LongSparseArray<OMAInfo>();
111
112 /**
113 * Information about the OMA content. The object is parsed from the download
114 * descriptor. There can be multiple MIME types for the object.
115 */
116 @VisibleForTesting
117 protected static class OMAInfo {
118 private final Map<String, String> mDescription;
119 private final List<String> mTypes;
120
121 OMAInfo() {
122 mDescription = new HashMap<String, String>();
123 mTypes = new ArrayList<String>();
124 }
125
126 /**
127 * Inserts an attribute-value pair about the OMA content. If the attribu te already
128 * exists, the new value will replace the old one. For MIME type, it wil l be appended
129 * to the existing MIME types.
130 *
131 * @param attribute The attribute to be inserted.
132 * @param value The new value of the attribute.
133 */
134 void addAttributeValue(String attribute, String value) {
135 if (attribute.equals(OMA_TYPE)) {
136 mTypes.add(value);
137 } else {
138 // TODO(qinmin): Handle duplicate attributes
139 mDescription.put(attribute, value);
140 }
141 }
142
143 /**
144 * Gets the value for an attribute.
145 *
146 * @param attribute The attribute to be retrieved.
147 * @return value of the attribute.
148 */
149 String getValue(String attribute) {
150 return mDescription.get(attribute);
151 }
152
153 /**
154 * Checks whether the value is empty for an attribute.
155 *
156 * @param attribute The attribute to be retrieved.
157 * @return true if it is empty, or false otherwise.
158 */
159 boolean isValueEmpty(String attribute) {
160 return TextUtils.isEmpty(getValue(attribute));
161 }
162
163 /**
164 * Gets the list of MIME types of the OMA content.
165 *
166 * @return List of MIME types.
167 */
168 List<String> getTypes() {
169 return mTypes;
170 }
171
172 /**
173 * Checks whether the information about the OMA content is empty.
174 *
175 * @return true if all attributes are empty, or false otherwise.
176 */
177 boolean isEmpty() {
178 return mDescription.isEmpty() && mTypes.isEmpty();
179 }
180
181 /**
182 * Gets the DRM MIME type of this object.
183 *
184 * @return the DRM MIME type if it is found, or null otherwise.
185 */
186 String getDrmType() {
187 for (String type : mTypes) {
188 if (type.equalsIgnoreCase(OMA_DRM_MESSAGE_MIME)
189 || type.equalsIgnoreCase(OMA_DRM_CONTENT_MIME)) {
190 return type;
191 }
192 }
193 return null;
194 }
195 }
196
197 public OMADownloadHandler(Context context) {
198 mContext = context;
199 }
200
201 /**
202 * Starts handling the OMA download.
203 *
204 * @param downloadInfo The information about the download.
205 * @param downloadId The unique identifier maintained by the Android Downloa dManager.
206 */
207 public void handleOMADownload(DownloadInfo downloadInfo, long downloadId) {
208 OMAParserTask task = new OMAParserTask(downloadInfo, downloadId);
209 task.execute();
210 }
211
212 /**
213 * Async task to parse an OMA download descriptor.
214 */
215 private class OMAParserTask extends AsyncTask<Void, Void, OMAInfo> {
216 private final DownloadInfo mDownloadInfo;
217 private final long mDownloadId;
218 public OMAParserTask(DownloadInfo downloadInfo, long downloadId) {
219 mDownloadInfo = downloadInfo;
220 mDownloadId = downloadId;
221 }
222
223 @Override
224 public OMAInfo doInBackground(Void...voids) {
225 OMAInfo omaInfo = null;
226 final DownloadManager manager =
227 (DownloadManager) mContext.getSystemService(Context.DOWNLOAD _SERVICE);
228 try {
229 ParcelFileDescriptor fd = manager.openDownloadedFile(mDownloadId );
230 if (fd == null) return null;
231 omaInfo = parseDownloadDescriptor(new FileInputStream(fd.getFile Descriptor()));
232 fd.close();
233 } catch (FileNotFoundException e) {
234 Log.w(TAG, "File not found.", e);
235 } catch (IOException e) {
236 Log.w(TAG, "Cannot read file.", e);
237 }
238 return omaInfo;
239 }
240
241 @Override
242 protected void onPostExecute(OMAInfo omaInfo) {
243 if (omaInfo == null) return;
244 // Send notification if required attributes are missing.
245 if (omaInfo.getTypes().isEmpty() || getSize(omaInfo) <= 0
246 || omaInfo.isValueEmpty(OMA_OBJECT_URI)) {
247 sendNotification(omaInfo, mDownloadInfo, DOWNLOAD_STATUS_INVALID _DESCRIPTOR);
248 return;
249 }
250 // Check version. Null version are treated as 1.0.
251 String version = omaInfo.getValue(OMA_DD_VERSION);
252 if (version != null && !version.startsWith("1.")) {
253 sendNotification(omaInfo, mDownloadInfo, DOWNLOAD_STATUS_INVALID _DDVERSION);
254 return;
255 }
256 // Check device capabilities.
257 if (Environment.getExternalStorageDirectory().getUsableSpace() < get Size(omaInfo)) {
258 showDownloadWarningDialog(
259 R.string.oma_download_insufficient_memory,
260 omaInfo, mDownloadInfo, DOWNLOAD_STATUS_INSUFFICIENT_MEM ORY);
261 return;
262 }
263 if (getOpennableType(mContext.getPackageManager(), omaInfo) == null) {
264 showDownloadWarningDialog(
265 R.string.oma_download_non_acceptable_content,
266 omaInfo, mDownloadInfo, DOWNLOAD_STATUS_NON_ACCEPTABLE_C ONTENT);
267 return;
268 }
269 showOMAInfoDialog(mDownloadId, mDownloadInfo, omaInfo);
270 }
271 }
272
273 /**
274 * Called when the content is successfully downloaded by the Android Downloa dManager.
275 *
276 * @param downloadInfo The information about the download.
277 * @param notifyURI The previously saved installNotifyURI attribute.
278 */
279 public void onDownloadCompleted(DownloadInfo downloadInfo, String notifyURI) {
280 long downloadId = (long) downloadInfo.getDownloadId();
281 OMAInfo omaInfo = mPendingOMADownloads.get(downloadId);
282 if (omaInfo == null) {
283 omaInfo = new OMAInfo();
284 omaInfo.addAttributeValue(OMA_INSTALL_NOTIFY_URI, notifyURI);
285 }
286 sendInstallNotificationAndNextStep(omaInfo, downloadInfo, DOWNLOAD_STATU S_SUCCESS);
287 mPendingOMADownloads.remove(downloadId);
288 }
289
290 /**
291 * Called when android DownloadManager fails to download the content.
292 *
293 * @param downloadInfo The information about the download.
294 * @param reason The reason of failure.
295 * @param notifyURI The previously saved installNotifyURI attribute.
296 */
297 public void onDownloadFailed(DownloadInfo downloadInfo, int reason, String n otifyURI) {
298 String status = DOWNLOAD_STATUS_DEVICE_ABORTED;
299 switch (reason) {
300 case DownloadManager.ERROR_CANNOT_RESUME:
301 status = DOWNLOAD_STATUS_LOSS_OF_SERVICE;
302 break;
303 case DownloadManager.ERROR_HTTP_DATA_ERROR:
304 case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
305 case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
306 status = DOWNLOAD_STATUS_LOADER_ERROR;
307 break;
308 case DownloadManager.ERROR_INSUFFICIENT_SPACE:
309 status = DOWNLOAD_STATUS_INSUFFICIENT_MEMORY;
310 break;
311 default:
312 break;
313 }
314 long downloadId = (long) downloadInfo.getDownloadId();
315 OMAInfo omaInfo = mPendingOMADownloads.get(downloadId);
316 if (omaInfo == null) {
317 // Just send the notification in this case.
318 omaInfo = new OMAInfo();
319 omaInfo.addAttributeValue(OMA_INSTALL_NOTIFY_URI, notifyURI);
320 sendInstallNotificationAndNextStep(omaInfo, downloadInfo, status);
321 return;
322 }
323 showDownloadWarningDialog(
324 R.string.oma_download_failed, omaInfo, downloadInfo, status);
325 mPendingOMADownloads.remove(downloadId);
326 }
327
328 /**
329 * Sends the install notification and then opens the nextURL if they are pro vided.
330 * If the install notification is sent, nextURL will be opened after the ser ver
331 * response is received.
332 *
333 * @param omaInfo Information about the OMA content.
334 * @param downloadInfo Information about the download.
335 * @param statusMessage The message to send to the notification server.
336 */
337 private void sendInstallNotificationAndNextStep(
338 OMAInfo omaInfo, DownloadInfo downloadInfo, String statusMessage) {
339 if (!sendNotification(omaInfo, downloadInfo, statusMessage)) {
340 showNextUrlDialog(omaInfo);
341 }
342 }
343
344 /**
345 * Sends the install notification to the server.
346 *
347 * @param omaInfo Information about the OMA content.
348 * @param downloadInfo Information about the download.
349 * @param statusMessage The message to send to the notification server.
350 * @return true if the notification ise sent, or false otherwise.
351 */
352 private boolean sendNotification(
353 OMAInfo omaInfo, DownloadInfo downloadInfo, String statusMessage) {
354 if (omaInfo == null) return false;
355 if (omaInfo.isValueEmpty(OMA_INSTALL_NOTIFY_URI)) return false;
356 PostStatusTask task = new PostStatusTask(omaInfo, downloadInfo, statusMe ssage);
357 task.execute();
358 return true;
359 }
360
361 /**
362 * Shows the OMA information to the user and ask whether user want to procee d.
363 *
364 * @param downloadId The unique identifier maintained by the Android Downloa dManager.
365 * @param downloadInfo Information about the download.
366 * @param omaInfo Information about the OMA content.
367 */
368 private void showOMAInfoDialog(
369 final long downloadId, final DownloadInfo downloadInfo, final OMAInf o omaInfo) {
370 LayoutInflater inflater =
371 (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLAT ER_SERVICE);
372 View v = inflater.inflate(R.layout.confirm_oma_download, null);
373
374 TextView textView = (TextView) v.findViewById(R.id.oma_download_name);
375 textView.setText(omaInfo.getValue(OMA_NAME));
376 textView = (TextView) v.findViewById(R.id.oma_download_vendor);
377 textView.setText(omaInfo.getValue(OMA_VENDOR));
378 textView = (TextView) v.findViewById(R.id.oma_download_size);
379 textView.setText(omaInfo.getValue(OMA_SIZE));
380 textView = (TextView) v.findViewById(R.id.oma_download_type);
381 textView.setText(getOpennableType(mContext.getPackageManager(), omaInfo) );
382 textView = (TextView) v.findViewById(R.id.oma_download_description);
383 textView.setText(omaInfo.getValue(OMA_DESCRIPTION));
384
385 DialogInterface.OnClickListener clickListener = new DialogInterface.OnCl ickListener() {
386 @Override
387 public void onClick(DialogInterface dialog, int which) {
388 if (which == AlertDialog.BUTTON_POSITIVE) {
389 downloadOMAContent(downloadId, downloadInfo, omaInfo);
390 } else {
391 sendInstallNotificationAndNextStep(
392 omaInfo, downloadInfo, DOWNLOAD_STATUS_USER_CANCELLE D);
393 }
394 }
395 };
396 new AlertDialog.Builder(ApplicationStatus.getLastTrackedFocusedActivity( ))
397 .setTitle(R.string.proceed_oma_download_message)
398 .setPositiveButton(R.string.ok, clickListener)
399 .setNegativeButton(R.string.cancel, clickListener)
400 .setView(v)
401 .setCancelable(false)
402 .show();
403 }
404
405 /**
406 * Shows a warning dialog indicating that download has failed. When user con firms
407 * the warning, a message will be sent to the notification server to inform about the
408 * error.
409 *
410 * @param titleId The resource identifier for the title.
411 * @param omaInfo Information about the OMA content.
412 * @param downloadInfo Information about the download.
413 * @param statusMessage Message to be sent to the notification server.
414 */
415 private void showDownloadWarningDialog(
416 int titleId, final OMAInfo omaInfo, final DownloadInfo downloadInfo,
417 final String statusMessage) {
418 DialogInterface.OnClickListener clickListener = new DialogInterface.OnCl ickListener() {
419 @Override
420 public void onClick(DialogInterface dialog, int which) {
421 if (which == AlertDialog.BUTTON_POSITIVE) {
422 sendInstallNotificationAndNextStep(omaInfo, downloadInfo, st atusMessage);
423 }
424 }
425 };
426 new AlertDialog.Builder(ApplicationStatus.getLastTrackedFocusedActivity( ))
427 .setTitle(titleId)
428 .setPositiveButton(R.string.ok, clickListener)
429 .setCancelable(false)
430 .show();
431 }
432
433 /**
434 * Shows a dialog to ask whether user wants to open the nextURL.
435 *
436 * @param omaInfo Information about the OMA content.
437 */
438 private void showNextUrlDialog(OMAInfo omaInfo) {
439 if (omaInfo.isValueEmpty(OMA_NEXT_URL)) {
440 return;
441 }
442 final String nextUrl = omaInfo.getValue(OMA_NEXT_URL);
443 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
444 Context.LAYOUT_INFLATER_SERVICE);
445 View v = inflater.inflate(R.layout.next_url_post_oma_download, null);
446 TextView textView = (TextView) v.findViewById(R.id.oma_download_next_url );
447 textView.setText(nextUrl);
448 final Activity activity = ApplicationStatus.getLastTrackedFocusedActivit y();
449 DialogInterface.OnClickListener clickListener = new DialogInterface.OnCl ickListener() {
450 @Override
451 public void onClick(DialogInterface dialog, int which) {
452 if (which == AlertDialog.BUTTON_POSITIVE) {
453 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(nex tUrl));
454 intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPa ckageName());
455 intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
456 intent.setPackage(mContext.getPackageName());
457 activity.startActivity(intent);
458 }
459 }
460 };
461 new AlertDialog.Builder(activity)
462 .setTitle(R.string.open_url_post_oma_download)
463 .setPositiveButton(R.string.ok, clickListener)
464 .setNegativeButton(R.string.cancel, clickListener)
465 .setView(v)
466 .setCancelable(false)
467 .show();
468 }
469
470 /**
471 * Returns the first MIME type in the OMA download that can be opened on the device.
472 *
473 * @param pm PackageManger for the current context.
474 * @param omaInfo Information about the OMA content.
475 * @return the MIME type can be opened by the device.
476 */
477 static String getOpennableType(PackageManager pm, OMAInfo omaInfo) {
478 if (omaInfo.isValueEmpty(OMA_OBJECT_URI)) {
479 return null;
480 }
481 Intent intent = new Intent(Intent.ACTION_VIEW);
482 Uri uri = Uri.parse(omaInfo.getValue(OMA_OBJECT_URI));
483 for (String type : omaInfo.getTypes()) {
484 if (!type.equalsIgnoreCase(OMA_DRM_MESSAGE_MIME)
485 && !type.equalsIgnoreCase(OMA_DRM_CONTENT_MIME)
486 && !type.equalsIgnoreCase(OMA_DOWNLOAD_DESCRIPTOR_MIME)
487 && !type.equalsIgnoreCase(OMA_DRM_RIGHTS_MIME)) {
488 intent.setDataAndType(uri, type);
489 ResolveInfo resolveInfo = pm.resolveActivity(intent,
490 PackageManager.MATCH_DEFAULT_ONLY);
491 if (resolveInfo != null) {
492 return type;
493 }
494 }
495 }
496 return null;
497 }
498
499 /**
500 * Parses the input stream and returns the OMA information.
501 *
502 * @param is The input stream to the parser.
503 * @return OMA information about the download content, or null if an error i s found.
504 */
505 @VisibleForTesting
506 static OMAInfo parseDownloadDescriptor(InputStream is) {
507 try {
508 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
509 factory.setNamespaceAware(true);
510 XmlPullParser parser = factory.newPullParser();
511 parser.setInput(is, null);
512 int eventType = parser.getEventType();
513 String currentAttribute = null;
514 OMAInfo info = new OMAInfo();
515 StringBuilder sb = null;
516 List<String> attributeList = new ArrayList<String>(Arrays.asList(
517 OMA_TYPE, OMA_SIZE, OMA_OBJECT_URI, OMA_INSTALL_NOTIFY_URI, OMA_NEXT_URL,
518 OMA_DD_VERSION, OMA_NAME, OMA_DESCRIPTION, OMA_VENDOR, OMA_I NFO_URL,
519 OMA_ICON_URI, OMA_INSTALL_PARAM));
520 while (eventType != XmlPullParser.END_DOCUMENT) {
521 if (eventType == XmlPullParser.START_DOCUMENT) {
522 if (!info.isEmpty()) return null;
523 } else if (eventType == XmlPullParser.START_TAG) {
524 String tagName = parser.getName();
525 if (attributeList.contains(tagName)) {
526 if (currentAttribute != null) {
527 Log.w(TAG, "Nested attributes was found in the downl oad descriptor");
528 return null;
529 }
530 sb = new StringBuilder();
531 currentAttribute = tagName;
532 }
533 } else if (eventType == XmlPullParser.END_TAG) {
534 if (currentAttribute != null) {
535 if (!currentAttribute.equals(parser.getName())) {
536 Log.w(TAG, "Nested attributes was found in the downl oad descriptor");
537 return null;
538 }
539 info.addAttributeValue(currentAttribute, sb.toString().t rim());
540 currentAttribute = null;
541 sb = null;
542 }
543 } else if (eventType == XmlPullParser.TEXT) {
544 if (currentAttribute != null) {
545 sb.append(parser.getText());
546 }
547 }
548 eventType = parser.next();
549 }
550 return info;
551 } catch (XmlPullParserException e) {
552 Log.w(TAG, "Failed to parse download descriptor.", e);
553 return null;
554 } catch (IOException e) {
555 Log.w(TAG, "Failed to read download descriptor.", e);
556 return null;
557 }
558 }
559
560 /**
561 * Returns the size of the OMA content.
562 *
563 * @param omaInfo OMA information about the download content
564 * @return size in bytes or 0 if the omaInfo doesn't contain size info.
565 */
566 @VisibleForTesting
567 protected static long getSize(OMAInfo omaInfo) {
568 String sizeString = omaInfo.getValue(OMA_SIZE);
569 try {
570 long size = sizeString == null ? 0 : Long.parseLong(sizeString.repla ce(",", ""));
571 return size;
572 } catch (NumberFormatException e) {
573 Log.w(TAG, "Cannot parse size information.", e);
574 }
575 return 0;
576 }
577
578 /**
579 * Enqueue a download request to the DownloadManager and starts downloading the OMA content.
580 *
581 * @param downloadId The unique identifier maintained by the Android Downloa dManager.
582 * @param downloadInfo Information about the download.
583 * @param omaInfo Information about the OMA content.
584 */
585 private void downloadOMAContent(long downloadId, DownloadInfo downloadInfo, OMAInfo omaInfo) {
586 if (omaInfo == null) return;
587 String mimeType = omaInfo.getDrmType();
588 if (mimeType == null) {
589 mimeType = getOpennableType(mContext.getPackageManager(), omaInfo);
590 }
591 DownloadInfo newInfo = DownloadInfo.Builder.fromDownloadInfo(downloadInf o)
592 .setFileName(omaInfo.getValue(OMA_NAME))
593 .setUrl(omaInfo.getValue(OMA_OBJECT_URI))
594 .setMimeType(mimeType)
595 .setDownloadId((int) downloadId)
596 .setDescription(omaInfo.getValue(OMA_DESCRIPTION))
597 .setContentLength(getSize(omaInfo))
598 .build();
599 // If installNotifyURI is not empty, the downloaded content cannot
600 // be used until the PostStatusTask gets a 200-series response.
601 // Don't show complete notification until that happens.
602 DownloadManagerService.getDownloadManagerService(mContext)
603 .enqueueDownloadManagerRequest(
604 newInfo, omaInfo.isValueEmpty(OMA_INSTALL_NOTIFY_URI));
605 mPendingOMADownloads.put(downloadId, omaInfo);
606 }
607
608 /**
609 * Checks if an OMA download is currently pending.
610 *
611 * @param downloadId Download identifier.
612 * @return true if the download is in progress, or false otherwise.
613 */
614 public boolean isPendingOMADownload(long downloadId) {
615 return mPendingOMADownloads.get(downloadId) != null;
616 }
617
618 /**
619 * Updates the download information with the new download Id.
620 *
621 * @param downloadInfo Information about the download.
622 * @param newDownloadId New download Id from the DownloadManager.
623 * @return the new download information with the new Id.
624 */
625 public DownloadInfo updateDownloadInfo(DownloadInfo downloadInfo, long newDo wnloadId) {
626 long oldDownloadId = (long) downloadInfo.getDownloadId();
627 OMAInfo omaInfo = mPendingOMADownloads.get(oldDownloadId);
628 mPendingOMADownloads.remove(oldDownloadId);
629 mPendingOMADownloads.put(newDownloadId, omaInfo);
630 return DownloadInfo.Builder.fromDownloadInfo(downloadInfo)
631 .setDownloadId((int) newDownloadId)
632 .build();
633 }
634
635 /**
636 * Returns the installation notification URI for the OMA download.
637 *
638 * @param downloadId Download Identifier.
639 * @return String containing the installNotifyURI.
640 */
641 public String getInstallNotifyInfo(long downloadId) {
642 OMAInfo omaInfo = mPendingOMADownloads.get(downloadId);
643 return omaInfo.getValue(OMA_INSTALL_NOTIFY_URI);
644 }
645
646 /**
647 * This class is responsible for posting the status message to the notificat ion server.
648 */
649 private class PostStatusTask extends AsyncTask<Void, Void, Boolean> {
650 private static final String TAG = "PostStatusTask";
651 private final OMAInfo mOMAInfo;
652 private final DownloadInfo mDownloadInfo;
653 private final String mStatusMessage;
654
655 public PostStatusTask(
656 OMAInfo omaInfo, DownloadInfo downloadInfo, String statusMessage ) {
657 mOMAInfo = omaInfo;
658 mDownloadInfo = downloadInfo;
659 mStatusMessage = statusMessage;
660 }
661
662 @Override
663 protected Boolean doInBackground(Void...voids) {
664 HttpClient httpClient = new DefaultHttpClient();
665 HttpPost httpPost = new HttpPost(mOMAInfo.getValue(OMA_INSTALL_NOTIF Y_URI));
666
667 try {
668 String userAgent = mDownloadInfo.getUserAgent();
669 if (TextUtils.isEmpty(userAgent)) {
670 userAgent = ChromiumApplication.getBrowserUserAgent();
671 }
672 httpPost.setHeader("Accept", "*/*");
673 httpPost.setHeader("User-Agent", userAgent);
674 httpPost.setHeader("Cookie", mDownloadInfo.getCookie());
675 httpPost.setEntity(new StringEntity(mStatusMessage));
676
677 // Execute HTTP Post Request
678 HttpResponse response = httpClient.execute(httpPost);
679
680 byte[] responseBody;
681 int responseCode = response.getStatusLine().getStatusCode();
682 if (responseCode == 200 || responseCode == -1) {
683 return true;
684 }
685 return false;
686 } catch (ClientProtocolException e) {
687 Log.w(TAG, "Invalid protocol detected.", e);
688 } catch (IOException e) {
689 Log.w(TAG, "Cannot connect to server.", e);
690 } catch (IllegalStateException e) {
691 Log.w(TAG, "Cannot connect to server.", e);
692 }
693 return false;
694 }
695
696 @Override
697 protected void onPostExecute(Boolean success) {
698 DownloadManager manager =
699 (DownloadManager) mContext.getSystemService(Context.DOWNLOAD _SERVICE);
700 if (success) {
701 String path = mDownloadInfo.getFilePath();
702 if (!TextUtils.isEmpty(path)) {
703 // Move the downloaded content from the app directory to pub lic directory.
704 File fromFile = new File(path);
705 String fileName = fromFile.getName();
706 File toFile = new File(Environment.getExternalStoragePublicD irectory(
707 Environment.DIRECTORY_DOWNLOADS), fileName);
708 if (fromFile.renameTo(toFile)) {
709 manager.addCompletedDownload(
710 fileName, mDownloadInfo.getDescription(), false,
711 mDownloadInfo.getMimeType(), toFile.getPath(),
712 mDownloadInfo.getContentLength(), true);
713 } else if (fromFile.delete()) {
714 Log.w(TAG, "Failed to rename the file.");
715 return;
716 } else {
717 Log.w(TAG, "Failed to rename and delete the file.");
718 }
719 }
720 showNextUrlDialog(mOMAInfo);
721 } else if (mDownloadInfo.getDownloadId() > 0) {
722 // Remove the downloaded content.
723 manager.remove(mDownloadInfo.getDownloadId());
724 }
725 }
726 }
727 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698