| 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);
|
| +}
|
|
|