OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.download; | 5 package org.chromium.chrome.browser.download; |
6 | 6 |
7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.app.DownloadManager; | 8 import android.app.DownloadManager; |
9 import android.app.Notification; | 9 import android.app.Notification; |
10 import android.app.NotificationManager; | 10 import android.app.NotificationManager; |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
209 return DownloadNotificationService.this; | 209 return DownloadNotificationService.this; |
210 } | 210 } |
211 } | 211 } |
212 | 212 |
213 @Override | 213 @Override |
214 public void onTaskRemoved(Intent rootIntent) { | 214 public void onTaskRemoved(Intent rootIntent) { |
215 super.onTaskRemoved(rootIntent); | 215 super.onTaskRemoved(rootIntent); |
216 // If we've lost all Activities, cancel the off the record downloads. | 216 // If we've lost all Activities, cancel the off the record downloads. |
217 if (ApplicationStatus.isEveryActivityDestroyed()) { | 217 if (ApplicationStatus.isEveryActivityDestroyed()) { |
218 cancelOffTheRecordDownloads(); | 218 cancelOffTheRecordDownloads(); |
219 hideSummaryNotificationIfNecessary(); | 219 hideSummaryNotificationIfNecessary(null); |
220 } | 220 } |
221 } | 221 } |
222 | 222 |
223 @Override | 223 @Override |
224 public void onCreate() { | 224 public void onCreate() { |
225 mContext = ContextUtils.getApplicationContext(); | 225 mContext = ContextUtils.getApplicationContext(); |
226 mNotificationManager = (NotificationManager) mContext.getSystemService( | 226 mNotificationManager = (NotificationManager) mContext.getSystemService( |
227 Context.NOTIFICATION_SERVICE); | 227 Context.NOTIFICATION_SERVICE); |
228 mSharedPrefs = ContextUtils.getAppSharedPreferences(); | 228 mSharedPrefs = ContextUtils.getAppSharedPreferences(); |
229 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ ATTEMPT_LEFT, | 229 mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ ATTEMPT_LEFT, |
230 MAX_RESUMPTION_ATTEMPT_LEFT); | 230 MAX_RESUMPTION_ATTEMPT_LEFT); |
231 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst ance(); | 231 mDownloadSharedPreferenceHelper = DownloadSharedPreferenceHelper.getInst ance(); |
232 mNextNotificationId = mSharedPrefs.getInt( | 232 mNextNotificationId = mSharedPrefs.getInt( |
233 KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); | 233 KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); |
234 } | 234 } |
235 | 235 |
236 @Override | 236 @Override |
237 public void onDestroy() { | 237 public void onDestroy() { |
238 updateNotificationsForShutdown(); | 238 updateNotificationsForShutdown(); |
239 rescheduleDownloads(); | 239 rescheduleDownloads(); |
240 super.onDestroy(); | 240 super.onDestroy(); |
241 } | 241 } |
242 | 242 |
243 @Override | 243 @Override |
244 public int onStartCommand(final Intent intent, int flags, int startId) { | 244 public int onStartCommand(final Intent intent, int flags, int startId) { |
245 if (intent == null) { | 245 if (intent == null) { |
246 updateNotificationsForShutdown(); | 246 updateNotificationsForShutdown(); |
247 handleDownloadOperation( | 247 handleDownloadOperation( |
248 new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUM E_ALL)); | 248 new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUM E_ALL)); |
249 hideSummaryNotificationIfNecessary(); | 249 hideSummaryNotificationIfNecessary(null); |
250 } else if (isDownloadOperationIntent(intent)) { | 250 } else if (isDownloadOperationIntent(intent)) { |
251 handleDownloadOperation(intent); | 251 handleDownloadOperation(intent); |
252 DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext) .cancelTask(); | 252 DownloadResumptionScheduler.getDownloadResumptionScheduler(mContext) .cancelTask(); |
253 // Limit the number of auto resumption attempts in case Chrome falls into a vicious | 253 // Limit the number of auto resumption attempts in case Chrome falls into a vicious |
254 // cycle. | 254 // cycle. |
255 if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) { | 255 if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction())) { |
256 if (mNumAutoResumptionAttemptLeft > 0) { | 256 if (mNumAutoResumptionAttemptLeft > 0) { |
257 mNumAutoResumptionAttemptLeft--; | 257 mNumAutoResumptionAttemptLeft--; |
258 updateResumptionAttemptLeft(); | 258 updateResumptionAttemptLeft(); |
259 } | 259 } |
(...skipping 23 matching lines...) Expand all Loading... | |
283 public void removeObserver(Observer observer) { | 283 public void removeObserver(Observer observer) { |
284 mObservers.removeObserver(observer); | 284 mObservers.removeObserver(observer); |
285 } | 285 } |
286 | 286 |
287 /** | 287 /** |
288 * Called when browser is killed. Schedule a resumption task and pause all t he download | 288 * Called when browser is killed. Schedule a resumption task and pause all t he download |
289 * notifications. | 289 * notifications. |
290 */ | 290 */ |
291 @VisibleForTesting | 291 @VisibleForTesting |
292 void shutdownService() { | 292 void shutdownService() { |
293 // TODO(dtrainor): Post a task to make SURE the summary notification is gone... | |
David Trainor- moved to gerrit
2017/03/03 20:11:22
I'll look into fixing this before I land the patch
David Trainor- moved to gerrit
2017/03/04 06:46:01
I believe I fixed this without the posted task.
| |
293 stopForeground(); | 294 stopForeground(); |
294 for (Observer observer : mObservers) observer.onServiceShutdownRequested (); | 295 for (Observer observer : mObservers) observer.onServiceShutdownRequested (); |
295 stopSelf(); | 296 stopSelf(); |
296 } | 297 } |
297 | 298 |
298 private void stopForegroundIfNecessary() { | 299 private void stopForegroundIfNecessary() { |
299 if (mDownloadsInProgress.size() == 0) stopForeground(); | 300 if (mDownloadsInProgress.size() == 0) stopForeground(); |
300 } | 301 } |
301 | 302 |
302 @VisibleForTesting | 303 @VisibleForTesting |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 * greater or equal to O, stop making this a foreground service. | 383 * greater or equal to O, stop making this a foreground service. |
383 * @param downloadGuid The guid of the download that has been paused or canc eled and shouldn't | 384 * @param downloadGuid The guid of the download that has been paused or canc eled and shouldn't |
384 * be tracked. | 385 * be tracked. |
385 */ | 386 */ |
386 private void stopTrackingInProgressDownload(String downloadGuid) { | 387 private void stopTrackingInProgressDownload(String downloadGuid) { |
387 mDownloadsInProgress.remove(downloadGuid); | 388 mDownloadsInProgress.remove(downloadGuid); |
388 stopForegroundIfNecessary(); | 389 stopForegroundIfNecessary(); |
389 } | 390 } |
390 | 391 |
391 /** | 392 /** |
393 * @see #hideSummaryNotificationIfNecessary(Integer) | |
394 * @param notificationIdToIgnore If not {@code null}, the id of a notificati on to ignore and | |
395 * assume is closing or about to be closed. | |
396 * @return Whether or not there are valid download notifications currently v isible. | |
397 */ | |
398 @VisibleForTesting | |
399 @TargetApi(Build.VERSION_CODES.M) | |
400 boolean hasDownloadNotifications(Integer notificationIdToIgnore) { | |
401 if (!BuildInfo.isAtLeastO()) return false; | |
qinmin
2017/03/03 20:48:40
nit: android version doesn't matter with this func
David Trainor- moved to gerrit
2017/03/04 06:46:01
I figured it's a good safety catch in case someone
| |
402 | |
403 StatusBarNotification[] notifications = mNotificationManager.getActiveNo tifications(); | |
404 for (StatusBarNotification notification : notifications) { | |
405 boolean isDownloadsGroup = TextUtils.equals(notification.getNotifica tion().getGroup(), | |
406 NotificationConstants.GROUP_DOWNLOADS); | |
407 boolean isSummaryNotification = | |
408 notification.getId() == NotificationConstants.NOTIFICATION_I D_DOWNLOAD_SUMMARY; | |
409 boolean isIgnoredNotification = notificationIdToIgnore != null | |
410 && notificationIdToIgnore == notification.getId(); | |
411 if (isDownloadsGroup && !isSummaryNotification && !isIgnoredNotifica tion) return true; | |
412 } | |
413 | |
414 return false; | |
415 } | |
416 | |
417 @VisibleForTesting | |
418 void cancelSummaryNotification() { | |
419 mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLO AD_SUMMARY); | |
420 } | |
421 | |
422 /** | |
392 * Check all current notifications and hide the summary notification if we h ave no downloads | 423 * Check all current notifications and hide the summary notification if we h ave no downloads |
393 * notifications left. On Android if the user swipes away the last download notification the | 424 * notifications left. On Android if the user swipes away the last download notification the |
394 * summary will be dismissed. But if the last downloads notification is dis missed via | 425 * summary will be dismissed. But if the last downloads notification is dis missed via |
395 * {@link NotificationManager#cancel(int)}, the summary will remain, so we n eed to check and | 426 * {@link NotificationManager#cancel(int)}, the summary will remain, so we n eed to check and |
396 * manually remove it ourselves. | 427 * manually remove it ourselves. |
428 * @param notificationIdToIgnore Cancelling a notification and querying for the current list of | |
429 * active notifications isn't synchronous. Pa ss a notification id | |
430 * here if there is a notification that should be assumed gone. | |
431 * Or pass {@code null} if no notification fit s that criteria. | |
397 */ | 432 */ |
398 @TargetApi(Build.VERSION_CODES.M) | 433 void hideSummaryNotificationIfNecessary(Integer notificationIdToIgnore) { |
399 void hideSummaryNotificationIfNecessary() { | |
400 if (!BuildInfo.isAtLeastO()) return; | 434 if (!BuildInfo.isAtLeastO()) return; |
435 if (mDownloadsInProgress.size() > 0) return; | |
401 | 436 |
402 stopForegroundIfNecessary(); | 437 stopForegroundIfNecessary(); |
403 | 438 if (hasDownloadNotifications(notificationIdToIgnore)) return; |
404 StatusBarNotification[] notifications = mNotificationManager.getActiveNo tifications(); | 439 cancelSummaryNotification(); |
405 for (StatusBarNotification notification : notifications) { | |
406 if (TextUtils.equals(notification.getNotification().getGroup(), | |
407 NotificationConstants.GROUP_DOWNLOADS) | |
408 && notification.getId() | |
409 != NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SU MMARY) { | |
410 return; | |
411 } | |
412 } | |
413 mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLO AD_SUMMARY); | |
414 | 440 |
415 // Added to shut down the service when everything is gone. | 441 // Added to shut down the service when everything is gone. |
416 // TODO(dtrainor): Make sure this makes sense. | |
417 shutdownService(); | 442 shutdownService(); |
418 } | 443 } |
419 | 444 |
420 @Override | 445 @Override |
421 public IBinder onBind(Intent intent) { | 446 public IBinder onBind(Intent intent) { |
422 return mBinder; | 447 return mBinder; |
423 } | 448 } |
424 | 449 |
425 /** | 450 /** |
426 * Helper method to update the remaining number of background resumption att empts left. | 451 * Helper method to update the remaining number of background resumption att empts left. |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
565 /** | 590 /** |
566 * Cancel a download notification. | 591 * Cancel a download notification. |
567 * @param notificationId Notification ID of the download | 592 * @param notificationId Notification ID of the download |
568 * @param downloadGuid GUID of the download. | 593 * @param downloadGuid GUID of the download. |
569 */ | 594 */ |
570 @VisibleForTesting | 595 @VisibleForTesting |
571 void cancelNotification(int notificationId, String downloadGuid) { | 596 void cancelNotification(int notificationId, String downloadGuid) { |
572 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); | 597 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); |
573 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid ); | 598 mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(downloadGuid ); |
574 stopTrackingInProgressDownload(downloadGuid); | 599 stopTrackingInProgressDownload(downloadGuid); |
575 hideSummaryNotificationIfNecessary(); | 600 hideSummaryNotificationIfNecessary(notificationId); |
576 } | 601 } |
577 | 602 |
578 /** | 603 /** |
579 * Called when a download is canceled. | 604 * Called when a download is canceled. |
580 * @param downloadGuid GUID of the download. | 605 * @param downloadGuid GUID of the download. |
581 */ | 606 */ |
582 @VisibleForTesting | 607 @VisibleForTesting |
583 public void notifyDownloadCanceled(String downloadGuid) { | 608 public void notifyDownloadCanceled(String downloadGuid) { |
584 DownloadSharedPreferenceEntry entry = | 609 DownloadSharedPreferenceEntry entry = |
585 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry (downloadGuid); | 610 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry (downloadGuid); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
818 * @param intent Intent with the download operation. | 843 * @param intent Intent with the download operation. |
819 */ | 844 */ |
820 private void handleDownloadOperation(final Intent intent) { | 845 private void handleDownloadOperation(final Intent intent) { |
821 // TODO(qinmin): Figure out how to properly handle this case. | 846 // TODO(qinmin): Figure out how to properly handle this case. |
822 boolean isOfflinePage = | 847 boolean isOfflinePage = |
823 IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFFLINE_PAGE, f alse); | 848 IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OFFLINE_PAGE, f alse); |
824 final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(i ntent); | 849 final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(i ntent); |
825 if (entry == null | 850 if (entry == null |
826 && !(isOfflinePage && TextUtils.equals(intent.getAction(), ACTIO N_DOWNLOAD_OPEN))) { | 851 && !(isOfflinePage && TextUtils.equals(intent.getAction(), ACTIO N_DOWNLOAD_OPEN))) { |
827 handleDownloadOperationForMissingNotification(intent); | 852 handleDownloadOperationForMissingNotification(intent); |
828 hideSummaryNotificationIfNecessary(); | 853 hideSummaryNotificationIfNecessary(null); |
829 return; | 854 return; |
830 } | 855 } |
831 | 856 |
832 if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) { | 857 if (ACTION_DOWNLOAD_PAUSE.equals(intent.getAction())) { |
833 // If browser process already goes away, the download should have al ready paused. Do | 858 // If browser process already goes away, the download should have al ready paused. Do |
834 // nothing in that case. | 859 // nothing in that case. |
835 if (!DownloadManagerService.hasDownloadManagerService()) { | 860 if (!DownloadManagerService.hasDownloadManagerService()) { |
836 notifyDownloadPaused(entry.downloadGuid, !entry.isOffTheRecord, false); | 861 notifyDownloadPaused(entry.downloadGuid, !entry.isOffTheRecord, false); |
837 hideSummaryNotificationIfNecessary(); | 862 hideSummaryNotificationIfNecessary(null); |
838 return; | 863 return; |
839 } | 864 } |
840 } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) { | 865 } else if (ACTION_DOWNLOAD_RESUME.equals(intent.getAction())) { |
841 // If user manually resumes a download, update the network type if i t | 866 // If user manually resumes a download, update the network type if i t |
842 // is not metered previously. | 867 // is not metered previously. |
843 boolean canDownloadWhileMetered = entry.canDownloadWhileMetered | 868 boolean canDownloadWhileMetered = entry.canDownloadWhileMetered |
844 || DownloadManagerService.isActiveNetworkMetered(mContext); | 869 || DownloadManagerService.isActiveNetworkMetered(mContext); |
845 // Update the SharedPreference entry. | 870 // Update the SharedPreference entry. |
846 mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry( | 871 mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry( |
847 new DownloadSharedPreferenceEntry(entry.notificationId, entr y.isOffTheRecord, | 872 new DownloadSharedPreferenceEntry(entry.notificationId, entr y.isOffTheRecord, |
848 canDownloadWhileMetered, entry.downloadGuid, entry.f ileName, | 873 canDownloadWhileMetered, entry.downloadGuid, entry.f ileName, |
849 entry.itemType, true)); | 874 entry.itemType, true)); |
850 } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction()) | 875 } else if (ACTION_DOWNLOAD_RESUME_ALL.equals(intent.getAction()) |
851 && (mDownloadSharedPreferenceHelper.getEntries().isEmpty() | 876 && (mDownloadSharedPreferenceHelper.getEntries().isEmpty() |
852 || DownloadManagerService.hasDownloadManagerService())) { | 877 || DownloadManagerService.hasDownloadManagerService())) { |
853 hideSummaryNotificationIfNecessary(); | 878 hideSummaryNotificationIfNecessary(null); |
854 return; | 879 return; |
855 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 880 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
856 // TODO(fgorski): Do we even need to do anything special here, befor e we launch Chrome? | 881 // TODO(fgorski): Do we even need to do anything special here, befor e we launch Chrome? |
857 } | 882 } |
858 | 883 |
859 BrowserParts parts = new EmptyBrowserParts() { | 884 BrowserParts parts = new EmptyBrowserParts() { |
860 @Override | 885 @Override |
861 public boolean shouldStartGpuProcess() { | 886 public boolean shouldStartGpuProcess() { |
862 return false; | 887 return false; |
863 } | 888 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
895 resumeAllPendingDownloads(); | 920 resumeAllPendingDownloads(); |
896 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 921 } else if (ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
897 OfflinePageDownloadBridge.openDownloadedPage( | 922 OfflinePageDownloadBridge.openDownloadedPage( |
898 IntentUtils.safeGetStringExtra(intent, EXTRA_DOW NLOAD_GUID)); | 923 IntentUtils.safeGetStringExtra(intent, EXTRA_DOW NLOAD_GUID)); |
899 } else { | 924 } else { |
900 Log.e(TAG, "Unrecognized intent action.", intent); | 925 Log.e(TAG, "Unrecognized intent action.", intent); |
901 } | 926 } |
902 if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { | 927 if (!ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) { |
903 downloadServiceDelegate.destroyServiceDelegate(); | 928 downloadServiceDelegate.destroyServiceDelegate(); |
904 } | 929 } |
905 hideSummaryNotificationIfNecessary(); | 930 |
931 hideSummaryNotificationIfNecessary(ACTION_DOWNLOAD_CANCEL.equals (intent.getAction()) | |
932 ? entry.notificationId | |
933 : null); | |
906 } | 934 } |
907 }; | 935 }; |
908 try { | 936 try { |
909 ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartu p(parts); | 937 ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartu p(parts); |
910 ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStart up(true, parts); | 938 ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStart up(true, parts); |
911 } catch (ProcessInitException e) { | 939 } catch (ProcessInitException e) { |
912 Log.e(TAG, "Unable to load native library.", e); | 940 Log.e(TAG, "Unable to load native library.", e); |
913 ChromeApplication.reportStartupErrorAndExit(e); | 941 ChromeApplication.reportStartupErrorAndExit(e); |
914 } | 942 } |
915 } | 943 } |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1085 return context.getString(R.string.remaining_duration_minutes, minute s); | 1113 return context.getString(R.string.remaining_duration_minutes, minute s); |
1086 } else if (minutes > 0) { | 1114 } else if (minutes > 0) { |
1087 return context.getString(R.string.remaining_duration_one_minute); | 1115 return context.getString(R.string.remaining_duration_one_minute); |
1088 } else if (seconds == 1) { | 1116 } else if (seconds == 1) { |
1089 return context.getString(R.string.remaining_duration_one_second); | 1117 return context.getString(R.string.remaining_duration_one_second); |
1090 } else { | 1118 } else { |
1091 return context.getString(R.string.remaining_duration_seconds, second s); | 1119 return context.getString(R.string.remaining_duration_seconds, second s); |
1092 } | 1120 } |
1093 } | 1121 } |
1094 } | 1122 } |
OLD | NEW |