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

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

Issue 2726423002: Fix DownloadNotificationService foreground state (Closed)
Patch Set: Created 3 years, 9 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
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698