Index: ios/clean/chrome/browser/ui/overlay_service/internal/overlay_scheduler.mm |
diff --git a/ios/clean/chrome/browser/ui/overlay_service/internal/overlay_scheduler.mm b/ios/clean/chrome/browser/ui/overlay_service/internal/overlay_scheduler.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1a05a4b44f55d50feb7addaaafff28f7e648a0b7 |
--- /dev/null |
+++ b/ios/clean/chrome/browser/ui/overlay_service/internal/overlay_scheduler.mm |
@@ -0,0 +1,180 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/clean/chrome/browser/ui/overlay_service/internal/overlay_scheduler.h" |
+ |
+#include <list> |
+ |
+#include "base/logging.h" |
+#import "ios/chrome/browser/web_state_list/web_state_list.h" |
+#import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" |
+#import "ios/clean/chrome/browser/ui/overlay_service/internal/browser_overlay_queue.h" |
+#import "ios/clean/chrome/browser/ui/overlay_service/internal/overlay_queue.h" |
+#import "ios/clean/chrome/browser/ui/overlay_service/internal/web_state_overlay_queue.h" |
+#import "ios/web/public/web_state/web_state.h" |
+ |
+#if !defined(__has_feature) || !__has_feature(objc_arc) |
+#error "This file requires ARC support." |
+#endif |
+ |
+DEFINE_BROWSER_USER_DATA_KEY(OverlayScheduler); |
+ |
+OverlayScheduler::OverlayScheduler(Browser* browser) |
+ : browser_(browser), observing_(false) { |
+ DCHECK(browser_); |
+ StartObservingBrowser(); |
+} |
+ |
+OverlayScheduler::~OverlayScheduler() {} |
+ |
+#pragma mark - Public |
+ |
+void OverlayScheduler::StartObservingBrowser() { |
+ if (observing_) |
+ return; |
+ BrowserOverlayQueue::CreateForBrowser(browser_); |
+ BrowserOverlayQueue::FromBrowser(browser_)->AddObserver(this); |
+ StartObservingWebStateList(&browser_->web_state_list()); |
+ observing_ = true; |
+} |
+ |
+void OverlayScheduler::StopObservingBrowser() { |
+ if (!observing_) |
+ return; |
+ BrowserOverlayQueue::FromBrowser(browser_)->RemoveObserver(this); |
+ StopObservingWebStateList(&browser_->web_state_list()); |
+ observing_ = false; |
+} |
+ |
+bool OverlayScheduler::IsShowingOverlay() const { |
+ return !overlay_queues_.empty() && |
+ overlay_queues_.front()->IsShowingOverlay(); |
+} |
+ |
+void OverlayScheduler::ReplaceVisibleOverlay( |
+ BrowserCoordinator* overlay_coordinator) { |
+ DCHECK(overlay_coordinator); |
+ DCHECK(IsShowingOverlay()); |
+ overlay_queues_.front()->ReplaceVisibleOverlay(overlay_coordinator); |
+} |
+ |
+void OverlayScheduler::CancelOverlays() { |
+ // |overlay_queues_| will be updated in OverlayQueueDidCancelOverlays(), so a |
+ // while loop is used to avoid using invalidated iterators. |
+ while (!overlay_queues_.empty()) { |
+ overlay_queues_.front()->CancelOverlays(); |
+ } |
+} |
+ |
+#pragma mark - OverlayQueueObserver |
+ |
+void OverlayScheduler::OverlayQueueDidAddOverlay(OverlayQueue* queue) { |
+ DCHECK(queue); |
+ overlay_queues_.push_back(queue); |
+ TryToStartNextOverlay(); |
+} |
+ |
+void OverlayScheduler::OverlayQueueWillReplaceVisibleOverlay( |
+ OverlayQueue* queue) { |
+ DCHECK(queue); |
+ DCHECK_EQ(overlay_queues_.front(), queue); |
+ DCHECK(queue->IsShowingOverlay()); |
+ // An OverlayQueue's visible overlay can only be replaced if it's the first |
+ // queue in the scheduler and is already showing an overlay. The queue is |
+ // added here so that its replacement overlay can be displayed when its |
+ // currently-visible overlay is stopped. |
+ overlay_queues_.push_front(queue); |
+} |
+ |
+void OverlayScheduler::OverlayQueueDidStopVisibleOverlay(OverlayQueue* queue) { |
+ DCHECK(!overlay_queues_.empty()); |
+ DCHECK_EQ(overlay_queues_.front(), queue); |
+ // Only the first queue in the scheduler can start overlays, so it is expected |
+ // that this function is only called for that queue. |
+ overlay_queues_.pop_front(); |
+ TryToStartNextOverlay(); |
+} |
+ |
+void OverlayScheduler::OverlayQueueDidCancelOverlays(OverlayQueue* queue) { |
+ DCHECK(queue); |
+ // Remove all scheduled instances of |queue| from the |overlay_queues_|. |
+ auto i = overlay_queues_.begin(); |
+ while (i != overlay_queues_.end()) { |
+ if (*i == queue) |
+ overlay_queues_.erase(i); |
+ } |
+ // If |queue| is currently showing an overlay, prepend it to |
+ // |overlay_queues_|. It will be removed when the cancelled overlay is |
+ // stopped. |
+ if (queue->IsShowingOverlay()) |
+ overlay_queues_.push_front(queue); |
+} |
+ |
+#pragma mark - WebStateListObserver |
+ |
+void OverlayScheduler::WebStateInsertedAt(WebStateList* web_state_list, |
+ web::WebState* web_state, |
+ int index) { |
+ StartObservingQueueForWebState(web_state); |
+} |
+ |
+void OverlayScheduler::WebStateDetachedAt(WebStateList* web_state_list, |
+ web::WebState* web_state, |
+ int index) { |
+ StopObservingQueueForWebState(web_state); |
+} |
+ |
+#pragma mark - |
+ |
+void OverlayScheduler::TryToStartNextOverlay() { |
+ // Early return if an overlay is already started or if there are no queued |
+ // overlays to show. |
+ if (overlay_queues_.empty() || IsShowingOverlay()) |
+ return; |
+ // If the next queue requires a WebState's content area to be shown, switch |
+ // the active WebState before starting the next overlay. |
+ OverlayQueue* queue = overlay_queues_.front(); |
+ web::WebState* web_state = queue->GetWebState(); |
+ if (web_state) { |
+ WebStateList& web_state_list = browser_->web_state_list(); |
+ int new_active_index = web_state_list.GetIndexOfWebState(web_state); |
+ DCHECK_NE(new_active_index, WebStateList::kInvalidIndex); |
+ web_state_list.ActivateWebStateAt(new_active_index); |
+ id<TabGridCommands> grid_dispatcher = |
+ static_cast<id<TabGridCommands>>(browser_->dispatcher()); |
+ [grid_dispatcher showTabGridTabAtIndex:new_active_index]; |
+ } |
+ // Start the next overlay in the first queue. |
+ queue->StartNextOverlay(); |
+} |
+ |
+void OverlayScheduler::StartObservingWebStateList( |
+ WebStateList* web_state_list) { |
+ DCHECK(web_state_list); |
+ web_state_list->AddObserver(this); |
+ for (int index = 0; index < web_state_list->count(); ++index) { |
+ StartObservingQueueForWebState(web_state_list->GetWebStateAt(index)); |
+ } |
+} |
+ |
+void OverlayScheduler::StopObservingWebStateList(WebStateList* web_state_list) { |
+ DCHECK(web_state_list); |
+ web_state_list->RemoveObserver(this); |
+ for (int index = 0; index < web_state_list->count(); ++index) { |
+ StopObservingQueueForWebState(web_state_list->GetWebStateAt(index)); |
+ } |
+} |
+ |
+void OverlayScheduler::StartObservingQueueForWebState( |
+ web::WebState* web_state) { |
+ DCHECK(web_state); |
+ WebStateOverlayQueue::CreateForWebState(web_state); |
+ WebStateOverlayQueue::FromWebState(web_state)->AddObserver(this); |
+} |
+ |
+void OverlayScheduler::StopObservingQueueForWebState(web::WebState* web_state) { |
+ DCHECK(web_state); |
+ WebStateOverlayQueue::FromWebState(web_state)->CancelOverlays(); |
+ WebStateOverlayQueue::FromWebState(web_state)->RemoveObserver(this); |
+} |