1# Copyright 2014 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"""Finds iOS browsers that can be controlled by telemetry."""
6
7import logging
8import re
9
10from telemetry.core import platform
11from telemetry.internal.backends.chrome import ios_browser_backend
12from telemetry.internal.backends.chrome_inspector import inspector_backend
13from telemetry.internal.browser import browser
14from telemetry.internal.browser import possible_browser
15from telemetry.internal.platform import ios_device
16from telemetry.internal.platform import ios_platform_backend
17
18
19# Key matches output from ios-webkit-debug-proxy and the value is a readable
20# description of the browser.
21IOS_BROWSERS = {'CriOS': 'ios-chrome', 'Version': 'ios-safari'}
22DEVICE_LIST_URL = 'http://127.0.0.1:9221/json'
23IOS_WEBKIT_DEBUG_PROXY = 'ios_webkit_debug_proxy'
24
25
26class PossibleIOSBrowser(possible_browser.PossibleBrowser):
27
28  """A running iOS browser instance."""
29  def __init__(self, browser_type, _):
30    super(PossibleIOSBrowser, self).__init__(browser_type, 'ios', True)
31
32  # TODO(baxley): Implement the following methods for iOS.
33  def Create(self, finder_options):
34    browser_backend = ios_browser_backend.IosBrowserBackend(
35        self._platform_backend, finder_options.browser_options)
36    return browser.Browser(
37        browser_backend, self._platform_backend, self._credentials_path)
38
39  def SupportsOptions(self, finder_options):
40    #TODO(baxley): Implement me.
41    return True
42
43  def UpdateExecutableIfNeeded(self):
44    #TODO(baxley): Implement me.
45    pass
46
47  def _InitPlatformIfNeeded(self):
48    if self._platform:
49      return
50
51    self._platform_backend = ios_platform_backend.IosPlatformBackend()
52    self._platform = platform.Platform(self._platform_backend)
53
54def SelectDefaultBrowser(_):
55  return None  # TODO(baxley): Implement me.
56
57
58def CanFindAvailableBrowsers():
59  # TODO(baxley): Add support for all platforms possible. Probably Linux,
60  # probably not Windows.
61  return platform.GetHostPlatform().GetOSName() == 'mac'
62
63
64def FindAllBrowserTypes(_):
65  return IOS_BROWSERS.values()
66
67
68def FindAllAvailableBrowsers(finder_options, device):
69  """Find all running iOS browsers on connected devices."""
70  if not isinstance(device, ios_device.IOSDevice):
71    return []
72
73  if not CanFindAvailableBrowsers():
74    return []
75
76  options = finder_options.browser_options
77
78  options.browser_type = 'ios-chrome'
79  host = platform.GetHostPlatform()
80  backend = ios_browser_backend.IosBrowserBackend(host, options)
81  # TODO(baxley): Use idevice to wake up device or log debug statement.
82  if not host.IsApplicationRunning(IOS_WEBKIT_DEBUG_PROXY):
83    host.LaunchApplication(IOS_WEBKIT_DEBUG_PROXY)
84    if not host.IsApplicationRunning(IOS_WEBKIT_DEBUG_PROXY):
85      return []
86
87  device_urls = backend.GetDeviceUrls()
88  if not device_urls:
89    logging.debug('Could not find any devices over %s.'
90                  % IOS_WEBKIT_DEBUG_PROXY)
91    return []
92
93  debug_urls = backend.GetWebSocketDebuggerUrls(device_urls)
94
95  # Get the userAgent for each UIWebView to find the browsers.
96  browser_pattern = (r'\)\s(%s)\/(\d+[\.\d]*)\sMobile'
97                     % '|'.join(IOS_BROWSERS.keys()))
98  browser_types = set()
99  for url in debug_urls:
100    context = {'webSocketDebuggerUrl': url, 'id': 1}
101    try:
102      inspector = inspector_backend.InspectorBackend(
103          backend.app, backend.devtools_client, context)
104      res = inspector.EvaluateJavaScript("navigator.userAgent")
105    finally:
106      inspector.Disconnect()
107    match_browsers = re.search(browser_pattern, res)
108    if match_browsers:
109      browser_types.add(match_browsers.group(1))
110
111  browsers = []
112  for browser_type in browser_types:
113    browsers.append(PossibleIOSBrowser(IOS_BROWSERS[browser_type],
114                                       finder_options))
115  return list(browsers)
116