1// Copyright 2016 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#import "ios/chrome/test/app/tab_test_util.h"
6
7#import <Foundation/Foundation.h>
8
9#import "base/mac/foundation_util.h"
10#import "ios/chrome/app/main_controller_private.h"
11#include "ios/chrome/browser/chrome_url_constants.h"
12#import "ios/chrome/browser/main/browser.h"
13#import "ios/chrome/browser/metrics/tab_usage_recorder_browser_agent.h"
14#import "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
15#include "ios/chrome/browser/system_flags.h"
16#import "ios/chrome/browser/tabs/tab_title_util.h"
17#import "ios/chrome/browser/ui/commands/browser_commands.h"
18#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
19#import "ios/chrome/browser/ui/main/scene_controller.h"
20#import "ios/chrome/browser/ui/main/scene_controller_testing.h"
21#import "ios/chrome/browser/url_loading/url_loading_params.h"
22#import "ios/chrome/browser/web_state_list/web_state_list.h"
23#import "ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h"
24#import "ios/chrome/test/app/chrome_test_util.h"
25
26#if !defined(__has_feature) || !__has_feature(objc_arc)
27#error "This file requires ARC support."
28#endif
29
30namespace chrome_test_util {
31
32namespace {
33
34// Returns the browser for the current mode.
35Browser* GetCurrentBrowser() {
36  return GetMainController().interfaceProvider.currentInterface.browser;
37}
38
39// Returns the WebStateList for the current mode. Or nullptr of there is no
40// browser.
41WebStateList* GetCurrentWebStateList() {
42  Browser* browser = GetCurrentBrowser();
43  return browser ? browser->GetWebStateList() : nullptr;
44}
45
46}  // namespace
47
48BOOL IsIncognitoMode() {
49  return GetMainController().interfaceProvider.currentInterface.incognito;
50}
51
52void OpenNewTab() {
53  @autoreleasepool {  // Make sure that all internals are deallocated.
54    OpenNewTabCommand* command = [OpenNewTabCommand command];
55    if (GetForegroundActiveSceneController().isTabSwitcherActive) {
56      // The TabGrid is currently presented.
57      Browser* browser =
58          GetForegroundActiveScene().interfaceProvider.mainInterface.browser;
59      UrlLoadParams params = UrlLoadParams::InNewTab(GURL(kChromeUINewTabURL));
60      [GetForegroundActiveSceneController() addANewTabAndPresentBrowser:browser
61                                                      withURLLoadParams:params];
62      return;
63    }
64    id<ApplicationCommands, BrowserCommands> handler =
65        chrome_test_util::HandlerForActiveBrowser();
66    [handler openURLInNewTab:command];
67  }
68}
69
70NSURL* SimulateExternalAppURLOpening() {
71  NSURL* url = [NSURL URLWithString:@"http://www.example.com"];
72  UIApplication* application = UIApplication.sharedApplication;
73  id<UIApplicationDelegate> applicationDelegate = application.delegate;
74  [applicationDelegate application:application openURL:url options:@{}];
75  return url;
76}
77
78void SimulateAddAccountFromWeb() {
79  id<ApplicationCommands, BrowserCommands> handler =
80      chrome_test_util::HandlerForActiveBrowser();
81  [handler showAddAccountFromViewController:(UIViewController*)
82                                                GetForegroundActiveScene()
83                                                    .interfaceProvider
84                                                    .mainInterface.bvc];
85}
86
87void OpenNewIncognitoTab() {
88  @autoreleasepool {  // Make sure that all internals are deallocated.
89    OpenNewTabCommand* command = [OpenNewTabCommand incognitoTabCommand];
90    if (GetForegroundActiveSceneController().isTabSwitcherActive) {
91      // The TabGrid is currently presented.
92      Browser* browser = GetForegroundActiveScene()
93                             .interfaceProvider.incognitoInterface.browser;
94      UrlLoadParams params = UrlLoadParams::InNewTab(GURL(kChromeUINewTabURL));
95      [GetForegroundActiveSceneController() addANewTabAndPresentBrowser:browser
96                                                      withURLLoadParams:params];
97      return;
98    }
99    id<ApplicationCommands, BrowserCommands> handler =
100        chrome_test_util::HandlerForActiveBrowser();
101    [handler openURLInNewTab:command];
102  }
103}
104
105web::WebState* GetCurrentWebState() {
106  WebStateList* web_state_list = GetCurrentWebStateList();
107  return web_state_list ? web_state_list->GetActiveWebState() : nullptr;
108}
109
110web::WebState* GetNextWebState() {
111  WebStateList* web_state_list = GetCurrentWebStateList();
112  if (!web_state_list || web_state_list->count() < 2)
113    return nullptr;
114  int next_index = web_state_list->active_index() + 1;
115  if (next_index >= web_state_list->count())
116    next_index = 0;
117  return web_state_list->GetWebStateAt(next_index);
118}
119
120web::WebState* GetWebStateAtIndexInCurrentMode(int index) {
121  WebStateList* web_state_list = GetCurrentWebStateList();
122  if (!web_state_list || !web_state_list->ContainsIndex(index))
123    return nullptr;
124  return web_state_list->GetWebStateAt(index);
125}
126
127NSString* GetCurrentTabTitle() {
128  return tab_util::GetTabTitle(GetCurrentWebState());
129}
130
131NSString* GetNextTabTitle() {
132  return tab_util::GetTabTitle(GetNextWebState());
133}
134
135void CloseCurrentTab() {
136  WebStateList* web_state_list = GetCurrentWebStateList();
137  if (!web_state_list ||
138      web_state_list->active_index() == WebStateList::kInvalidIndex)
139    return;
140  web_state_list->CloseWebStateAt(web_state_list->active_index(),
141                                  WebStateList::CLOSE_USER_ACTION);
142}
143
144void CloseTabAtIndex(NSUInteger index) {
145  @autoreleasepool {  // Make sure that all internals are deallocated.
146    DCHECK_LE(index, static_cast<NSUInteger>(INT_MAX));
147    GetCurrentWebStateList()->CloseWebStateAt(static_cast<int>(index),
148                                              WebStateList::CLOSE_USER_ACTION);
149  }
150}
151
152NSUInteger GetIndexOfActiveNormalTab() {
153  Browser* browser = chrome_test_util::GetForegroundActiveSceneController()
154                         .interfaceProvider.mainInterface.browser;
155  return browser->GetWebStateList()->active_index();
156}
157
158void CloseAllTabsInCurrentMode() {
159  GetCurrentWebStateList()->CloseAllWebStates(WebStateList::CLOSE_USER_ACTION);
160}
161
162void CloseAllTabs() {
163  if (GetIncognitoTabCount() && GetForegroundActiveSceneController()) {
164    Browser* browser = GetForegroundActiveSceneController()
165                           .interfaceProvider.incognitoInterface.browser;
166    DCHECK(browser);
167    browser->GetWebStateList()->CloseAllWebStates(
168        WebStateList::CLOSE_USER_ACTION);
169  }
170  if (GetMainTabCount() && GetForegroundActiveScene()) {
171    Browser* browser =
172        GetForegroundActiveScene().interfaceProvider.mainInterface.browser;
173    DCHECK(browser);
174    browser->GetWebStateList()->CloseAllWebStates(
175        WebStateList::CLOSE_USER_ACTION);
176  }
177}
178
179void SelectTabAtIndexInCurrentMode(NSUInteger index) {
180  @autoreleasepool {  // Make sure that all internals are deallocated.
181
182    WebStateList* web_state_list = GetCurrentWebStateList();
183    web_state_list->ActivateWebStateAt(static_cast<int>(index));
184  }
185}
186
187NSUInteger GetMainTabCount() {
188  return GetMainController()
189      .interfaceProvider.mainInterface.browser->GetWebStateList()
190      ->count();
191}
192
193NSUInteger GetIncognitoTabCount() {
194  return GetMainController()
195      .interfaceProvider.incognitoInterface.browser->GetWebStateList()
196      ->count();
197}
198
199BOOL ResetTabUsageRecorder() {
200  TabUsageRecorderBrowserAgent* tab_usage_recorder =
201      TabUsageRecorderBrowserAgent::FromBrowser(GetCurrentBrowser());
202  if (!tab_usage_recorder)
203    return NO;
204  tab_usage_recorder->ResetAll();
205  return YES;
206}
207
208BOOL SetCurrentTabsToBeColdStartTabs() {
209  TabUsageRecorderBrowserAgent* tab_usage_recorder =
210      TabUsageRecorderBrowserAgent::FromBrowser(GetCurrentBrowser());
211
212  if (!tab_usage_recorder)
213    return NO;
214  WebStateList* web_state_list = GetCurrentWebStateList();
215
216  std::vector<web::WebState*> web_states;
217  web_states.reserve(web_state_list->count());
218  for (int index = 0; index < web_state_list->count(); ++index) {
219    web_states.push_back(web_state_list->GetWebStateAt(index));
220  }
221  tab_usage_recorder->InitialRestoredTabs(web_state_list->GetActiveWebState(),
222                                          web_states);
223  return YES;
224}
225
226BOOL SimulateTabsBackgrounding() {
227  TabUsageRecorderBrowserAgent* tab_usage_recorder =
228      TabUsageRecorderBrowserAgent::FromBrowser(GetCurrentBrowser());
229  if (!tab_usage_recorder)
230    return NO;
231  tab_usage_recorder->AppDidEnterBackground();
232  return YES;
233}
234
235void SaveSessionImmediately() {
236  SessionRestorationBrowserAgent::FromBrowser(GetCurrentBrowser())
237      ->SaveSession(true);
238}
239
240void EvictOtherTabModelTabs() {
241  id<BrowserInterfaceProvider> provider = GetMainController().interfaceProvider;
242  Browser* otherBrowser = IsIncognitoMode()
243                              ? provider.mainInterface.browser
244                              : provider.incognitoInterface.browser;
245  // Disabling and enabling web usage will evict all web views.
246  WebUsageEnablerBrowserAgent* enabler =
247      WebUsageEnablerBrowserAgent::FromBrowser(otherBrowser);
248  DCHECK(enabler);
249  enabler->SetWebUsageEnabled(false);
250  enabler->SetWebUsageEnabled(true);
251}
252
253BOOL CloseAllNormalTabs() {
254  MainController* main_controller = GetMainController();
255  DCHECK(main_controller);
256
257  Browser* browser = main_controller.interfaceProvider.mainInterface.browser;
258  DCHECK(browser);
259  browser->GetWebStateList()->CloseAllWebStates(
260      WebStateList::CLOSE_USER_ACTION);
261  return YES;
262}
263
264BOOL CloseAllIncognitoTabs() {
265  MainController* main_controller = GetMainController();
266  DCHECK(main_controller);
267  Browser* browser =
268      GetMainController().interfaceProvider.incognitoInterface.browser;
269  DCHECK(browser);
270  browser->GetWebStateList()->CloseAllWebStates(
271      WebStateList::CLOSE_USER_ACTION);
272  return YES;
273}
274
275NSUInteger GetEvictedMainTabCount() {
276  Browser* browser =
277      GetMainController().interfaceProvider.mainInterface.browser;
278  TabUsageRecorderBrowserAgent* tab_usage_recorder =
279      TabUsageRecorderBrowserAgent::FromBrowser(browser);
280  if (!tab_usage_recorder)
281    return 0;
282  return tab_usage_recorder->EvictedTabsMapSize();
283}
284
285}  // namespace chrome_test_util
286