PowerSource

import Foundation
import IOKit.ps
enum PowerState {
  case ac
  case battery
  case unknown
}
/// A convenience wrapper for an IOKit power source.
final class PowerSource {
  let info = IOPSCopyPowerSourcesInfo().takeRetainedValue()
  let sources: Array<CFTypeRef>
  init() {
    sources = IOPSCopyPowerSourcesList(info).takeRetainedValue() as Array
  }
  func hasBattery() -> Bool {
    return !sources.isEmpty
  }
  /// Returns the current power source capacity. Apple-defined power sources will return this value
  /// as a percentage.
  func getCurrentCapacity() -> Int? {
    if let source = sources.first {
      let description =
        IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject]
      if let level = description[kIOPSCurrentCapacityKey] as? Int {
        return level
      }
    }
    return nil
  }
  /// Returns whether the device is drawing battery power or connected to an external power source.
  func getPowerState() -> PowerState {
    if let source = sources.first {
      let description =
        IOPSGetPowerSourceDescription(info, source).takeUnretainedValue() as! [String: AnyObject]
      if let state = description[kIOPSPowerSourceStateKey] as? String {
        switch state {
        case kIOPSACPowerValue:
          return .ac
        case kIOPSBatteryPowerValue:
          return .battery
        default:
          return .unknown
        }
      }
    }
    return .unknown
  }
}
protocol PowerSourceStateChangeDelegate: AnyObject {
  func didChangePowerSourceState()
}
/// A listener for system power source state change events. Notifies the delegate on each event.
final class PowerSourceStateChangeHandler {
  private var runLoopSource: CFRunLoopSource?
  weak var delegate: PowerSourceStateChangeDelegate?
  init() {
    let context = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
    self.runLoopSource = IOPSNotificationCreateRunLoopSource(
      { (context: UnsafeMutableRawPointer?) in
        let unownedSelf = Unmanaged<PowerSourceStateChangeHandler>.fromOpaque(
          UnsafeRawPointer(context!)
        ).takeUnretainedValue()
        unownedSelf.delegate?.didChangePowerSourceState()
      }, context
    ).takeRetainedValue()
    CFRunLoopAddSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode)
  }
  deinit {
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self.runLoopSource, .defaultMode)
  }
}


AppDelegate

class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    return true
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
  private let powerSource = PowerSource()
  private let stateChangeHandler = PowerSourceStateChangeHandler()
  private var eventSink: FlutterEventSink?
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.displayIfNeeded()
    self.setFrame(windowFrame, display: true)
    // Register battery method channel.
    let registrar = flutterViewController.registrar(forPlugin: "BatteryLevel")
    let batteryChannel = FlutterMethodChannel(
      name: "samples.flutter.io/battery",
      binaryMessenger: registrar.messenger)
    batteryChannel.setMethodCallHandler { [powerSource = self.powerSource] (call, result) in
      switch call.method {
      case "getBatteryLevel":
        guard powerSource.hasBattery() else {
          result(
            FlutterError(
              code: "NO_BATTERY",
              message: "Device does not have a battery",
              details: nil))
          return
        }
        guard let level = powerSource.getCurrentCapacity() else {
          result(
            FlutterError(
              code: "UNAVAILABLE",
              message: "Battery info unavailable",
              details: nil))
          return
        }
        result(level)
      default:
        result(FlutterMethodNotImplemented)
      }
    }
    // Register charging event channel.
    let chargingChannel = FlutterEventChannel(
      name: "samples.flutter.io/charging",
      binaryMessenger: registrar.messenger)
    chargingChannel.setStreamHandler(self)
    RegisterGeneratedPlugins(registry: flutterViewController)
    super.awakeFromNib()
  }
  /// Emit a power status event to the registered event sink.
  func emitPowerStatusEvent() {
    if let sink = self.eventSink {
      switch self.powerSource.getPowerState() {
      case .ac:
        sink("charging")
      case .battery:
        sink("discharging")
      case .unknown:
        sink("UNAVAILABLE")
      }
    }
  }
}
extension MainFlutterWindow: FlutterStreamHandler {
    -> FlutterError?
  {
    self.eventSink = events
    self.emitPowerStatusEvent()
    self.stateChangeHandler.delegate = self
    return nil
  }
  func onCancel(withArguments arguments: Any?) -> FlutterError? {
    self.stateChangeHandler.delegate = nil
    self.eventSink = nil
    return nil
  }
}
extension MainFlutterWindow: PowerSourceStateChangeDelegate {
  func didChangePowerSourceState() {
    self.emitPowerStatusEvent()
  }
}


import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    super.awakeFromNib()
  }
}


import Cocoa
import FlutterMacOS
/**
 The main application window.
 Performs Flutter app initialization, and handles channel method calls over the
 `samples.flutter.io/platform_view` channel.
*/
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    RegisterMethodChannel(registry: flutterViewController)
    super.awakeFromNib()
  }
  func RegisterMethodChannel(registry: FlutterPluginRegistry) {
    let registrar = registry.registrar(forPlugin: "platform_view")
    let channel = FlutterMethodChannel(name: "samples.flutter.io/platform_view",
                                       binaryMessenger: registrar.messenger)
    channel.setMethodCallHandler({ (call, result) in
      if (call.method == "switchView") {
        let count = call.arguments as! Int
        let controller: NSViewController = PlatformViewController(
          withCount: count,
          onClose: { platformViewController in
            result(platformViewController.count)
          }
        )
        self.contentViewController?.presentAsSheet(controller)
      }
    })
  }
}


PlatformViewController

import Cocoa
/**
`ViewControllers` in the xib can inherit from this class to communicate with
the flutter view for this application. ViewControllers that inherit from this
class should be displayed as a popover or modal, with a button that binds to
the IBAction `pop()`.
To get the value of the popover during close, pass a callback function as
the `dispose` parameter. The callback passed will have access to the
`PlatformViewController` and all of it's properties at close so that the `count`
can be passed back through the message channel if needed.
*/
class PlatformViewController: NSViewController {
    var count: Int = 0
    var dispose: ((PlatformViewController)->())?
    var labelText: String {
      get {
        return "Button tapped \(self.count) time\(self.count != 1 ? "s" : "")."
      }
    }
    override func viewDidLoad() {
      super.viewDidLoad()
      self.label.stringValue = labelText
    }
    public required init?(coder aDecoder: NSCoder) {
      self.count = 0
      self.dispose = nil
      super.init(coder: aDecoder)
    }
    init(withCount count: Int, onClose dispose: ((PlatformViewController)->())?) {
      self.count = count
      self.dispose = dispose
      super.init(nibName: nil, bundle: nil)
    }
      self.count += 1
      self.label.stringValue = labelText
    }
}


AppDelegate

import UIKit
import Flutter
enum ChannelName {
  static let battery = "samples.flutter.io/battery"
  static let charging = "samples.flutter.io/charging"
}
enum BatteryState {
  static let charging = "charging"
  static let discharging = "discharging"
}
enum MyFlutterErrorCode {
  static let unavailable = "UNAVAILABLE"
}
  private var eventSink: FlutterEventSink?
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    guard let controller = window?.rootViewController as? FlutterViewController else {
      fatalError("rootViewController is not type FlutterViewController")
    }
    let batteryChannel = FlutterMethodChannel(name: ChannelName.battery,
                                              binaryMessenger: controller.binaryMessenger)
    batteryChannel.setMethodCallHandler({
      [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
      guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
      }
      self?.receiveBatteryLevel(result: result)
    })
    let chargingChannel = FlutterEventChannel(name: ChannelName.charging,
                                              binaryMessenger: controller.binaryMessenger)
    chargingChannel.setStreamHandler(self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  private func receiveBatteryLevel(result: FlutterResult) {
    let device = UIDevice.current
    device.isBatteryMonitoringEnabled = true
    guard device.batteryState != .unknown  else {
      result(FlutterError(code: MyFlutterErrorCode.unavailable,
                          message: "Battery info unavailable",
                          details: nil))
      return
    }
    result(Int(device.batteryLevel * 100))
  }
  public func onListen(withArguments arguments: Any?,
    sendBatteryStateEvent()
  }
  private func sendBatteryStateEvent() {
    guard let eventSink = eventSink else {
      return
    }
    switch UIDevice.current.batteryState {
    case .full:
      eventSink(BatteryState.charging)
    case .charging:
      eventSink(BatteryState.charging)
    case .unplugged:
      eventSink(BatteryState.discharging)
    default:
      eventSink(FlutterError(code: MyFlutterErrorCode.unavailable,
                             message: "Charging status unavailable",
                             details: nil))
    }
  }
  public func onCancel(withArguments arguments: Any?) -> FlutterError? {
    NotificationCenter.default.removeObserver(self)
    eventSink = nil
    return nil
  }
}


  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}


NativeViewController

import Foundation
import AppKit
protocol NativeViewControllerDelegate: NSObjectProtocol {
    func didTapIncrementButton()
}
/**
The code behind a native view to be displayed in the `MainFlutterViewController`
as an embed segue. If any storyboard view inherits from this class definition,
it should contain a function to handle for `handleIncrement`
*/
class NativeViewController: NSViewController {
  var count: Int?
  var labelText: String {
    get {
      let count = self.count ?? 0
      return "Flutter button tapped \(count) time\(count == 1 ? "" : "s")"
    }
  }
  var delegate: NativeViewControllerDelegate?
    self.delegate?.didTapIncrementButton()
  }
  override func viewDidLoad() {
    super.viewDidLoad()
    setState(for: 0)
  }
  func didReceiveIncrement() {
    setState(for: (self.count ?? 0) + 1)
  }
  func setState(for count: Int) {
    self.count = count
    self.incrementLabel.stringValue = labelText
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
/**
The window that is automatically generated when `flutter create --target=macos`
on a project. `MainFlutterWindow` uses a FlutterViewController as it's content
view controller by default.
*/
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let windowFrame = self.frame
    let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
    // `flutter create --target=macos` uses this class (`self`) as an entrypoint
    // for drawing on a surface. The line below intercepts that and uses
    // the storyboard from `Main.storyboard`.
    self.contentViewController = storyboard.instantiateController(withIdentifier: "MainViewController") as! NSViewController
    self.setFrame(windowFrame, display: true)
    super.awakeFromNib()
  }
}


MainViewController

import Foundation
import AppKit
import FlutterMacOS
/**
The code behind a storyboard view which splits a flutter view and a macOS view.
*/
class MainViewController: NSViewController, NativeViewControllerDelegate {
  static let emptyString: String = ""
  static let ping: String = "ping"
  static let channel: String = "increment"
  var nativeViewController: NativeViewController?
  var flutterViewController: FlutterViewController?
  var messageChannel: FlutterBasicMessageChannel?
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    if segue.identifier == "NativeViewControllerSegue" {
      self.nativeViewController = segue.destinationController as? NativeViewController
      // Since`MainViewController` owns the platform channel, but not the
      // UI elements that trigger an action, those UI elements need a reference
      // to this controller to send messages on the platform channel.
      self.nativeViewController?.delegate = self
    }
    if segue.identifier == "FlutterViewControllerSegue" {
      self.flutterViewController = segue.destinationController as? FlutterViewController
      RegisterMethodChannel(registry: self.flutterViewController!)
      weak var weakSelf = self
      messageChannel?.setMessageHandler({ (message, reply) in
        // Dispatch an event, incrementing the counter in this case, when *any*
        // message is received.
        // Depending on the order of initialization, the nativeViewController
        // might not be initialized until this point.
        weakSelf?.nativeViewController?.didReceiveIncrement()
        reply(MainViewController.emptyString)
      })
    }
  }
  func RegisterMethodChannel(registry: FlutterPluginRegistry) {
    let registrar = registry.registrar(forPlugin: "")
    messageChannel = FlutterBasicMessageChannel(
      name: MainViewController.channel,
      binaryMessenger: registrar.messenger,
      codec: FlutterStringCodec.sharedInstance())
  }
  // Call in any instance where `ping` is to be sent through the `increment`
  // channel.
  func didTapIncrementButton() {
    self.messageChannel?.sendMessage(MainViewController.ping)
  }
}


IntegrationTestPlugin

import FlutterMacOS
public class IntegrationTestPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(
      name: "plugins.flutter.io/integration_test",
      binaryMessenger: registrar.messenger)
    let instance = IntegrationTestPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }
    switch call.method {
    case "allTestsFinished":
      result(nil)
    default:
      result(FlutterMethodNotImplemented)
    }
  }
}


AppDelegate

import UIKit
import Flutter
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}


import Cocoa
import FlutterMacOS
class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    return true
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS

class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)

    RegisterGeneratedPlugins(registry: flutterViewController)

    super.awakeFromNib()
  }
}


AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {
  func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
  }
}


ViewController

import UIKit
import Flutter
import FlutterPluginRegistrant
class ViewController: UIViewController {
  var flutterEngine : FlutterEngine?;
  // Boiler-plate add-to-app demo. Not integration tested anywhere.
  override func viewDidLoad() {
    super.viewDidLoad()
    let button = UIButton(type:UIButton.ButtonType.custom)
    button.addTarget(self, action: #selector(handleButtonAction), for: .touchUpInside)
    button.setTitle("Press me", for: UIControl.State.normal)
    button.frame = CGRect(x: 80.0, y: 210.0, width: 160.0, height: 40.0)
    button.backgroundColor = UIColor.blue
    self.view.addSubview(button)
    self.flutterEngine = FlutterEngine(name: "io.flutter", project: nil);
  }
    if let flutterEngine = flutterEngine as? FlutterEngine {
      GeneratedPluginRegistrant.register(with: flutterEngine);
      let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil);
      self.present(flutterViewController, animated: false, completion: nil)
    }
  }
}


SceneDelegate

import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}


AppDelegate

class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    return true
  }
}


ContentView

//
//  ContentView.swift
//  watch Extension
//
//  Created by Georg Wechslberger on 08.04.20.
//
import SwiftUI
struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


ExtensionDelegate

//
//  ExtensionDelegate.swift
//  watch Extension
//
//  Created by Georg Wechslberger on 08.04.20.
//
import WatchKit
class ExtensionDelegate: NSObject, WKExtensionDelegate {
    func applicationDidFinishLaunching() {
        // Perform any final initialization of your application.
    }
    func applicationDidBecomeActive() {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
    func applicationWillResignActive() {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, etc.
    }
    func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
        // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
        for task in backgroundTasks {
            // Use a switch statement to check the task type
            switch task {
            case let backgroundTask as WKApplicationRefreshBackgroundTask:
                // Be sure to complete the background task once you’re done.
                backgroundTask.setTaskCompletedWithSnapshot(false)
            case let snapshotTask as WKSnapshotRefreshBackgroundTask:
                // Snapshot tasks have a unique completion call, make sure to set your expiration date
                snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
            case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
                // Be sure to complete the connectivity task once you’re done.
                connectivityTask.setTaskCompletedWithSnapshot(false)
            case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
                // Be sure to complete the URL session task once you’re done.
                urlSessionTask.setTaskCompletedWithSnapshot(false)
            case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
                // Be sure to complete the relevant-shortcut task once you're done.
                relevantShortcutTask.setTaskCompletedWithSnapshot(false)
            case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
                // Be sure to complete the intent-did-run task once you're done.
                intentDidRunTask.setTaskCompletedWithSnapshot(false)
            default:
                // make sure to complete unhandled task types
                task.setTaskCompletedWithSnapshot(false)
            }
        }
    }
}


HostingController

//
//  HostingController.swift
//  watch Extension
//
//  Created by Georg Wechslberger on 08.04.20.
//
import WatchKit
import Foundation
import SwiftUI
class HostingController: WKHostingController<ContentView> {
    override var body: ContentView {
        return ContentView()
    }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
let DATE: UInt8 = 128
let PAIR: UInt8 = 129
class Pair {
  let first: Any?
  let second: Any?
  init(first: Any?, second: Any?) {
    self.first = first
    self.second = second
  }
}
class ExtendedWriter: FlutterStandardWriter {
  override func writeValue(_ value: Any) {
    if let date = value as? Date {
      self.writeByte(DATE)
      let time = date.timeIntervalSince1970
      var ms = Int64(time * 1000.0)
      self.writeBytes(&ms, length: UInt(MemoryLayout<Int64>.size))
    } else if let pair = value as? Pair {
      self.writeByte(PAIR)
      self.writeValue(pair.first!)
      self.writeValue(pair.second!)
    } else {
      super.writeValue(value)
    }
  }
}
class ExtendedReader: FlutterStandardReader {
  override func readValue(ofType type: UInt8) -> Any? {
    if type == DATE {
      var ms: Int64 = 0
      self.readBytes(&ms, length: UInt(MemoryLayout<Int64>.size))
      let time: Double = Double(ms) / 1000.0
      return NSDate(timeIntervalSince1970: time)
    } else if type == PAIR {
      return Pair(first: self.readValue(), second: self.readValue())
    } else {
      return super.readValue(ofType: type)
    }
  }
}
class ExtendedReaderWriter: FlutterStandardReaderWriter {
  override func reader(with data: Data) -> FlutterStandardReader {
    return ExtendedReader(data: data)
  }
  override func writer(with data: NSMutableData) -> FlutterStandardWriter {
    return ExtendedWriter(data: data)
  }
}
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    let registrar = flutterViewController.registrar(forPlugin: "channel-integration-test")
    setupMessagingHandshakeOnChannel(
      FlutterBasicMessageChannel(
        name: "binary-msg",
        binaryMessenger: registrar.messenger,
        codec: FlutterBinaryCodec.sharedInstance()))
    setupMessagingHandshakeOnChannel(
      FlutterBasicMessageChannel(
        name: "string-msg",
        binaryMessenger: registrar.messenger,
        codec: FlutterStringCodec.sharedInstance()))
    setupMessagingHandshakeOnChannel(
      FlutterBasicMessageChannel(
        name: "json-msg",
        binaryMessenger: registrar.messenger,
        codec: FlutterJSONMessageCodec.sharedInstance()))
    setupMessagingHandshakeOnChannel(
      FlutterBasicMessageChannel(
        name: "std-msg",
        binaryMessenger: registrar.messenger,
        codec: FlutterStandardMessageCodec(readerWriter: ExtendedReaderWriter())))
    setupMethodHandshakeOnChannel(
      FlutterMethodChannel(
        name: "json-method",
        binaryMessenger: registrar.messenger,
        codec: FlutterJSONMethodCodec.sharedInstance()))
    setupMethodHandshakeOnChannel(
      FlutterMethodChannel(
        name: "std-method",
        binaryMessenger: registrar.messenger,
        codec: FlutterStandardMethodCodec(readerWriter: ExtendedReaderWriter())))
    FlutterBasicMessageChannel(
      name: "std-echo", binaryMessenger: registrar.messenger,
      codec: FlutterStandardMessageCodec.sharedInstance()
    ).setMessageHandler { message, reply in
      reply(message)
    }
    super.awakeFromNib()
  }
  func setupMessagingHandshakeOnChannel(_ channel: FlutterBasicMessageChannel) {
    channel.setMessageHandler { message, reply in
      channel.sendMessage(message) { messageReply in
        channel.sendMessage(messageReply)
        reply(message)
      }
    }
  }
  func setupMethodHandshakeOnChannel(_ channel: FlutterMethodChannel) {
    channel.setMethodCallHandler { call, result in
      if call.method == "success" {
        channel.invokeMethod(call.method, arguments: call.arguments) { value in
          channel.invokeMethod(call.method, arguments: value)
          result(call.arguments)
        }
      } else if call.method == "error" {
        channel.invokeMethod(call.method, arguments: call.arguments) { value in
          let error = value as! FlutterError
          channel.invokeMethod(call.method, arguments: error.details)
          result(error)
        }
      } else {
        channel.invokeMethod(call.method, arguments: call.arguments) { value in
          channel.invokeMethod(call.method, arguments: nil)
          result(FlutterMethodNotImplemented)
        }
      }
    }
  }
}


import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    RegisterMethodChannel(registry: flutterViewController)
    super.awakeFromNib()
  }
  func RegisterMethodChannel(registry: FlutterPluginRegistry) {
    let registrar = registry.registrar(forPlugin: "flavors")
    let channel = FlutterMethodChannel(name: "flavor",
                                       binaryMessenger: registrar.messenger)
    channel.setMethodCallHandler({ (call, result) in
      let flavor = Bundle.main.infoDictionary?["Flavor"] as? String
      result(flavor)
    })
  }
}


import Cocoa
import FlutterMacOS
extension NSWindow {
  var titlebarHeight: CGFloat {
    frame.height - contentRect(forFrameRect: frame).height
  }
}
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterMethodChannel(registry: flutterViewController)
    RegisterGeneratedPlugins(registry: flutterViewController)
    super.awakeFromNib()
  }
    func RegisterMethodChannel(registry: FlutterPluginRegistry) {
    let registrar = registry.registrar(forPlugin: "resize")
    let channel = FlutterMethodChannel(name: "samples.flutter.dev/resize",
                                       binaryMessenger: registrar.messenger)
    channel.setMethodCallHandler({ (call, result) in
      if call.method == "resize" {
        if let args = call.arguments as? Dictionary<String, Any>,
          let width = args["width"] as? Double,
          var height = args["height"] as? Double {
          height += self.titlebarHeight
          let currentFrame: NSRect = self.frame
          let nextFrame: NSRect = NSMakeRect(
            currentFrame.minX - (width - currentFrame.width) / 2,
            currentFrame.minY - (height - currentFrame.height) / 2,
            width,
            height
          )
          self.setFrame(nextFrame, display: true, animate: false)
          result(true)
        } else {
          result(FlutterError.init(code: "bad args", message: nil, details: nil))
        }
      }
    })
  }
}


AppDelegate

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    super.awakeFromNib()
  }
}


import XCTest
import os
// An XCUITest to dismiss System Dialogs.
class infra_dialogUITests: XCTestCase {
    override func setUp() {
        // Stop immediately when a failure occurs.
        continueAfterFailure = false
        super.setUp()
    }
    func testDismissDialogs() {
        // Dismiss system dialogs, e.g. No SIM Card Installed
        let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
        let defaultLog = Logger()
        // If the device has low battery or bad cable, report as infra failure.
        let failureTexts = ["Low Battery", "This accessory may not be supported"]
        let buttonTexts = ["OK", "Later", "Allow", "Remind Me Later", "Close", "Dismiss"]
        // Sometimes a second dialog pops up when one is closed, so let's run 3 times.
        for _ in 0..<3 {
            for failureText in failureTexts {
                let elementQuery = springboard.staticTexts.containing(predicate)
                XCTAssertEqual(elementQuery.count, 0);
            }
            for buttonText in buttonTexts {
                let button = springboard.buttons[buttonText]
                if button.exists {
                    defaultLog.log("Found button \(buttonText, privacy: .public)")
                    defaultLog.log("\(springboard.debugDescription, privacy: .public)")
                    button.tap()
                }
            }
        }
        if springboard.buttons.count > 0 {
            defaultLog.log("Unexpected SpringBoard button found")
            defaultLog.log("\(springboard.debugDescription, privacy: .public)")
        }
    }
}


import Cocoa
import FlutterMacOS

class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController.init()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)

    RegisterGeneratedPlugins(registry: flutterViewController)

    super.awakeFromNib()
  }
}


s

infix operator •: AdditionPrecedence
func • (a: Int, b: Int) -> Int {
  return a * b
}
func g(a: Int) -> Int{
  return a + 1
}
let i = g(a: 1 • 2)


import Swift

var s: [Int] = [1, 2, 3, 4]

func f() {
  for i in 0..<4 {
    print(s[i])
  }
}

f()


Package

// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
  name: "nanopb",
  products: [
    .library(
      name: "nanopb",
      targets: ["nanopb"]
    )
  ],

  targets: [
    .target(
      name: "nanopb",
      path: ".",
      sources: [
        "pb.h",
        "pb_common.h",
        "pb_common.c",
        "pb_decode.h",
        "pb_decode.c",
        "pb_encode.h",
        "pb_encode.c"
      ],
      publicHeadersPath: "spm_headers",
      cSettings: [
        .define("PB_FIELD_32BIT", to: "1"),
        .define("PB_NO_PACKED_STRUCTS", to: "1"),
        .define("PB_ENABLE_MALLOC", to: "1"),
      ]
    ),
    .testTarget(
      name: "swift-test",
      dependencies: [
        "nanopb",
      ],
      path: "spm-test/swift",
      cSettings: [
        .headerSearchPath("../"),
        .define("PB_FIELD_32BIT", to: "1"),
        .define("PB_NO_PACKED_STRUCTS", to: "1"),
        .define("PB_ENABLE_MALLOC", to: "1"),
      ]
    ),
    .testTarget(
      name: "objc-test",
      dependencies: [
        "nanopb",
      ],
      path: "spm-test/objc",
      cSettings: [
        .headerSearchPath("../"),
        .define("PB_FIELD_32BIT", to: "1"),
        .define("PB_NO_PACKED_STRUCTS", to: "1"),
        .define("PB_ENABLE_MALLOC", to: "1"),
      ]
    )
  ]
)


main

import nanopb


Package

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "OCHamcrest",
    platforms: [
        .macOS(.v10_10),
        .iOS(.v9),
        .tvOS(.v9),
        .watchOS(.v2)
    ],
    products: [
        .library(
            name: "OCHamcrest",
            targets: ["OCHamcrest"]
        ),
    ],
    targets: [
        .target(
            name: "OCHamcrest",
            path: "Source",
            exclude: [
                "Tests",
                "Tests-Info.plist",
                "MakeDistribution.sh",
                "makeXCFramework.sh",
                "OCHamcrest-Info.plist",
                "XcodeWarnings.xcconfig",
            ],
            publicHeadersPath: "include",
            cSettings: [
                CSetting.headerSearchPath("./Core/Helpers"),
                CSetting.headerSearchPath("./Core/Helpers/ReturnValueGetters"),
                CSetting.headerSearchPath("./Core/Helpers/TestFailureReporters"),
            ]
        ),
    ]
)


// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "Example",
    products: [
        .library(
            name: "Example",
            targets: ["Example"]),
    ],
    // begin-snippet: swiftpm-declare-dependencies
    dependencies: [
        .package(
            url: "https://github.com/hamcrest/OCHamcrest",
            .upToNextMajor(from: "9.0.0")
        ),
    ],
    // end-snippet
    targets: [
        .target(
            name: "Example",
            dependencies: [],
            publicHeadersPath: "./"
        ),
        // begin-snippet: swiftpm-use-dependencies
        .testTarget(
            name: "ExampleTests",
            dependencies: [
                "Example",
                "OCHamcrest",
            ]
        ),
        // end-snippet
    ]
)


GPBSwiftTests

// Protocol Buffers - Google's data interchange format
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
import Foundation
import XCTest
// Test some usage of the ObjC library from Swift.
class GPBBridgeTests: XCTestCase {
  func testProto2Basics() {
    let msg = Message2()
    let msg2 = Message2()
    let msg3 = Message2_OptionalGroup()
    msg.optionalInt32 = 100
    msg.optionalString = "abc"
    msg.optionalEnum = .Bar
    msg2.optionalString = "other"
    msg.optionalMessage = msg2
    msg3.a = 200
    msg.optionalGroup = msg3
    msg.repeatedInt32Array.addValue(300)
    msg.repeatedInt32Array.addValue(301)
    msg.repeatedStringArray.addObject("mno")
    msg.repeatedStringArray.addObject("pqr")
    msg.repeatedEnumArray.addValue(Message2_Enum.Bar.rawValue)
    msg.repeatedEnumArray.addValue(Message2_Enum.Baz.rawValue)
    msg.mapInt32Int32.setValue(400, forKey:500)
    msg.mapInt32Int32.setValue(401, forKey:501)
    msg.mapStringString.setObject("foo", forKey:"bar")
    msg.mapStringString.setObject("abc", forKey:"xyz")
    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
    msg.mapInt32Enum.setValue(Message2_Enum.Baz.rawValue, forKey:601)
    // Check has*.
    XCTAssertTrue(msg.hasOptionalInt32)
    XCTAssertTrue(msg.hasOptionalString)
    XCTAssertTrue(msg.hasOptionalEnum)
    XCTAssertTrue(msg2.hasOptionalString)
    XCTAssertTrue(msg.hasOptionalMessage)
    XCTAssertTrue(msg3.hasA)
    XCTAssertTrue(msg.hasOptionalGroup)
    XCTAssertFalse(msg.hasOptionalInt64)
    XCTAssertFalse(msg.hasOptionalFloat)
    // Check values.
    XCTAssertEqual(msg.optionalInt32, Int32(100))
    XCTAssertEqual(msg.optionalString, "abc")
    XCTAssertEqual(msg2.optionalString, "other")
    XCTAssertTrue(msg.optionalMessage === msg2)
    XCTAssertEqual(msg.optionalEnum, Message2_Enum.Bar)
    XCTAssertEqual(msg3.a, Int32(200))
    XCTAssertTrue(msg.optionalGroup === msg3)
    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2))
    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue)
    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue)
    XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
    var intValue: Int32 = 0;
    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
    XCTAssertEqual(intValue, Int32(400))
    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
    XCTAssertEqual(intValue, Int32(401))
    XCTAssertEqual(msg.mapStringString.count, Int(2))
    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
    XCTAssertEqual(intValue, Message2_Enum.Baz.rawValue)
    // Clearing a string with nil.
    msg2.optionalString = nil
    XCTAssertFalse(msg2.hasOptionalString)
    XCTAssertEqual(msg2.optionalString, "")
    // Clearing a message with nil.
    msg.optionalGroup = nil
    XCTAssertFalse(msg.hasOptionalGroup)
    XCTAssertTrue(msg.optionalGroup !== msg3)  // New instance
    // Clear.
    msg.clear()
    XCTAssertFalse(msg.hasOptionalInt32)
    XCTAssertFalse(msg.hasOptionalString)
    XCTAssertFalse(msg.hasOptionalEnum)
    XCTAssertFalse(msg.hasOptionalMessage)
    XCTAssertFalse(msg.hasOptionalInt64)
    XCTAssertFalse(msg.hasOptionalFloat)
    XCTAssertEqual(msg.optionalInt32, Int32(0))
    XCTAssertEqual(msg.optionalString, "")
    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
    XCTAssertEqual(msg.optionalEnum, Message2_Enum.Foo)  // Default
    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0))
    XCTAssertEqual(msg.repeatedStringArray.count, Int(0))
    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0))
    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
    XCTAssertEqual(msg.mapStringString.count, Int(0))
    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
  }
  func testProto3Basics() {
    let msg = Message3()
    let msg2 = Message3()
    msg.optionalInt32 = 100
    msg.optionalString = "abc"
    msg.optionalEnum = .Bar
    msg2.optionalString = "other"
    msg.optionalMessage = msg2
    msg.repeatedInt32Array.addValue(300)
    msg.repeatedInt32Array.addValue(301)
    msg.repeatedStringArray.addObject("mno")
    msg.repeatedStringArray.addObject("pqr")
    // "proto3" syntax lets enum get unknown values.
    msg.repeatedEnumArray.addValue(Message3_Enum.Bar.rawValue)
    msg.repeatedEnumArray.addRawValue(666)
    SetMessage3_OptionalEnum_RawValue(msg2, 666)
    msg.mapInt32Int32.setValue(400, forKey:500)
    msg.mapInt32Int32.setValue(401, forKey:501)
    msg.mapStringString.setObject("foo", forKey:"bar")
    msg.mapStringString.setObject("abc", forKey:"xyz")
    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
    // "proto3" syntax lets enum get unknown values.
    msg.mapInt32Enum.setRawValue(666, forKey:601)
    // Has only exists on for message fields.
    XCTAssertTrue(msg.hasOptionalMessage)
    XCTAssertFalse(msg2.hasOptionalMessage)
    // Check values.
    XCTAssertEqual(msg.optionalInt32, Int32(100))
    XCTAssertEqual(msg.optionalString, "abc")
    XCTAssertEqual(msg2.optionalString, "other")
    XCTAssertTrue(msg.optionalMessage === msg2)
    XCTAssertEqual(msg.optionalEnum, Message3_Enum.Bar)
    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2))
    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
    XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
    XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message3_Enum.Bar.rawValue)
    XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue)
    XCTAssertEqual(msg.repeatedEnumArray.rawValueAtIndex(1), 666)
    XCTAssertEqual(msg2.optionalEnum, Message3_Enum.GPBUnrecognizedEnumeratorValue)
    XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Int32(666))
    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
    var intValue: Int32 = 0;
    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
    XCTAssertEqual(intValue, Int32(400))
    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
    XCTAssertEqual(intValue, Int32(401))
    XCTAssertEqual(msg.mapStringString.count, Int(2))
    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
    XCTAssertEqual(intValue, Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue)
    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, rawValue:&intValue))
    XCTAssertEqual(intValue, 666)
    // Clearing a string with nil.
    msg2.optionalString = nil
    XCTAssertEqual(msg2.optionalString, "")
    // Clearing a message with nil.
    msg.optionalMessage = nil
    XCTAssertFalse(msg.hasOptionalMessage)
    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
    // Clear.
    msg.clear()
    XCTAssertFalse(msg.hasOptionalMessage)
    XCTAssertEqual(msg.optionalInt32, Int32(0))
    XCTAssertEqual(msg.optionalString, "")
    XCTAssertTrue(msg.optionalMessage !== msg2)  // New instance
    XCTAssertEqual(msg.optionalEnum, Message3_Enum.Foo)  // Default
    XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0))
    XCTAssertEqual(msg.repeatedStringArray.count, Int(0))
    XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0))
    msg2.clear()
    XCTAssertEqual(msg2.optionalEnum, Message3_Enum.Foo)  // Default
    XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Message3_Enum.Foo.rawValue)
    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
    XCTAssertEqual(msg.mapStringString.count, Int(0))
    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
  }
  func testAutoCreation() {
    let msg = Message2()
    XCTAssertFalse(msg.hasOptionalGroup)
    XCTAssertFalse(msg.hasOptionalMessage)
    // Access shouldn't result in has* but should return objects.
    let msg2 = msg.optionalGroup
    let msg3 = msg.optionalMessage.optionalMessage
    let msg4 = msg.optionalMessage
    XCTAssertNotNil(msg2)
    XCTAssertNotNil(msg3)
    XCTAssertFalse(msg.hasOptionalGroup)
    XCTAssertFalse(msg.optionalMessage.hasOptionalMessage)
    XCTAssertFalse(msg.hasOptionalMessage)
    // Setting things should trigger has* getting set.
    msg.optionalGroup.a = 10
    msg.optionalMessage.optionalMessage.optionalInt32 = 100
    XCTAssertTrue(msg.hasOptionalGroup)
    XCTAssertTrue(msg.optionalMessage.hasOptionalMessage)
    XCTAssertTrue(msg.hasOptionalMessage)
    // And they should be the same pointer as before.
    XCTAssertTrue(msg2 === msg.optionalGroup)
    XCTAssertTrue(msg3 === msg.optionalMessage.optionalMessage)
    XCTAssertTrue(msg4 === msg.optionalMessage)
    // Clear gets us new objects next time around.
    msg.clear()
    XCTAssertFalse(msg.hasOptionalGroup)
    XCTAssertFalse(msg.optionalMessage.hasOptionalMessage)
    XCTAssertFalse(msg.hasOptionalMessage)
    msg.optionalGroup.a = 20
    msg.optionalMessage.optionalMessage.optionalInt32 = 200
    XCTAssertTrue(msg.hasOptionalGroup)
    XCTAssertTrue(msg.optionalMessage.hasOptionalMessage)
    XCTAssertTrue(msg.hasOptionalMessage)
    XCTAssertTrue(msg2 !== msg.optionalGroup)
    XCTAssertTrue(msg3 !== msg.optionalMessage.optionalMessage)
    XCTAssertTrue(msg4 !== msg.optionalMessage)
    // Explicit set of a message, means autocreated object doesn't bind.
    msg.clear()
    let autoCreated = msg.optionalMessage
    XCTAssertFalse(msg.hasOptionalMessage)
    let msg5 = Message2()
    msg5.optionalInt32 = 123
    msg.optionalMessage = msg5
    XCTAssertTrue(msg.hasOptionalMessage)
    // Modifing the autocreated doesn't replaced the explicit set one.
    autoCreated.optionalInt32 = 456
    XCTAssertTrue(msg.hasOptionalMessage)
    XCTAssertTrue(msg.optionalMessage === msg5)
    XCTAssertEqual(msg.optionalMessage.optionalInt32, Int32(123))
  }
  func testProto2OneOfSupport() {
    let msg = Message2()
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
    let autoCreated = msg.oneofMessage  // Default create one.
    XCTAssertNotNil(autoCreated)
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
    msg.oneofInt32 = 10
    XCTAssertEqual(msg.oneofInt32, Int32(10))
    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32)
    msg.oneofFloat = 20.0
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(20.0))
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofFloat)
    msg.oneofEnum = .Bar
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Bar)
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofEnum)
    // Sets via the autocreated instance.
    msg.oneofMessage.optionalInt32 = 200
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200))
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage)
    // Clear the oneof.
    Message2_ClearOOneOfCase(msg)
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(110.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz)  // Default
    let autoCreated2 = msg.oneofMessage  // Default create one
    XCTAssertNotNil(autoCreated2)
    XCTAssertTrue(autoCreated2 !== autoCreated)  // New instance
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
    msg.oneofInt32 = 10
    XCTAssertEqual(msg.oneofInt32, Int32(10))
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32)
    // Confirm Message.clear() handles the oneof correctly.
    msg.clear()
    XCTAssertEqual(msg.oneofInt32, Int32(100))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
    // Sets via the autocreated instance.
    msg.oneofMessage.optionalInt32 = 300
    XCTAssertTrue(msg.oneofMessage !== autoCreated)  // New instance
    XCTAssertTrue(msg.oneofMessage !== autoCreated2)  // New instance
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300))
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage)
    // Set message to nil clears the oneof.
    msg.oneofMessage = nil
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase)
}
  func testProto3OneOfSupport() {
    let msg = Message3()
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
    let autoCreated = msg.oneofMessage  // Default create one.
    XCTAssertNotNil(autoCreated)
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
    msg.oneofInt32 = 10
    XCTAssertEqual(msg.oneofInt32, Int32(10))
    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32)
    msg.oneofFloat = 20.0
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(20.0))
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofFloat)
    msg.oneofEnum = .Bar
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Bar)
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofEnum)
    // Sets via the autocreated instance.
    msg.oneofMessage.optionalInt32 = 200
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
    XCTAssertTrue(msg.oneofMessage === autoCreated)  // Still the same
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200))
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage)
    // Clear the oneof.
    Message3_ClearOOneOfCase(msg)
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oneofFloat, Float(0.0))  // Default
    XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo)  // Default
    let autoCreated2 = msg.oneofMessage  // Default create one
    XCTAssertNotNil(autoCreated2)
    XCTAssertTrue(autoCreated2 !== autoCreated)  // New instance
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
    msg.oneofInt32 = 10
    XCTAssertEqual(msg.oneofInt32, Int32(10))
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32)
    // Confirm Message.clear() handles the oneof correctly.
    msg.clear()
    XCTAssertEqual(msg.oneofInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
    // Sets via the autocreated instance.
    msg.oneofMessage.optionalInt32 = 300
    XCTAssertTrue(msg.oneofMessage !== autoCreated)  // New instance
    XCTAssertTrue(msg.oneofMessage !== autoCreated2)  // New instance
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300))
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage)
    // Set message to nil clears the oneof.
    msg.oneofMessage = nil
    XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0))  // Default
    XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase)
  }
  func testSerialization() {
    let msg = Message2()
    msg.optionalInt32 = 100
    msg.optionalInt64 = 101
    msg.optionalGroup.a = 102
    msg.repeatedStringArray.addObject("abc")
    msg.repeatedStringArray.addObject("def")
    msg.mapInt32Int32.setValue(200, forKey:300)
    msg.mapInt32Int32.setValue(201, forKey:201)
    msg.mapStringString.setObject("foo", forKey:"bar")
    msg.mapStringString.setObject("abc", forKey:"xyz")
    let data = msg.data()
    let msg2 = Message2(data: data!, error:nil)
    XCTAssertTrue(msg2 !== msg)  // New instance
    XCTAssertEqual(msg.optionalInt32, Int32(100))
    XCTAssertEqual(msg.optionalInt64, Int64(101))
    XCTAssertEqual(msg.optionalGroup.a, Int32(102))
    XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
    XCTAssertEqual(msg.mapStringString.count, Int(2))
    XCTAssertEqual(msg2, msg)
  }
}


import UIKit
/// Globally maps reference views to layout guides.
///
/// Usage:
/// 1.  Reference a view from a part of the UI under a specific name.
/// 2.  In a different part of the UI, request a layout guide under that name. Add the synced layout
///     guide to the UI. It will track the reference view automatically.
///
/// Details:
/// -   Referenced views and created layout guides are only weakly stored by the layout guide
///     center.
/// -   Referenced views don't have to be laid out by AutoLayout.
/// -   Referenced views and layout guides don't have to be in the same window.
  public func reference(view referenceView: UIView?, under name: String) {
    let oldReferenceView = referencedView(under: name)
    // Early return if `referenceView` is already set.
    if referenceView == oldReferenceView {
      return
    }
    oldReferenceView?.cr_onWindowCoordinatesChanged = nil
    if let referenceView = referenceView {
      referenceViews.setObject(referenceView, forKey: name as NSString)
    } else {
      referenceViews.removeObject(forKey: name as NSString)
    }
    updateGuides(named: name)
    // Schedule updates to the matching layout guides when the reference view
    // moves in its window.
    referenceView?.cr_onWindowCoordinatesChanged = { [weak self] _ in
      self?.updateGuides(named: name)
    }
  }
  /// Returns the referenced view under `name`.
  public func makeLayoutGuide(named name: String) -> UILayoutGuide {
    let layoutGuide = FrameLayoutGuide()
    layoutGuide.onDidMoveToWindow = { [weak self] _ in
      self?.updateGuides(named: name)
    }
    // Keep a weak reference to the layout guide.
    if layoutGuides[name] == nil {
      layoutGuides[name] = NSHashTable<FrameLayoutGuide>.weakObjects()
    }
    layoutGuides[name]?.add(layoutGuide)
    return layoutGuide
  }
  /// MARK: Private
  /// Weakly stores the reference views.
  private var referenceViews = NSMapTable<NSString, UIView>.strongToWeakObjects()
  /// Weakly stores the layout guides.
  private var layoutGuides = [String: NSHashTable<FrameLayoutGuide>]()
  /// Updates all available guides for the given `name`.
  private func updateGuides(named name: String) {
    // Early return if there is no reference window.
    guard let referenceView = referencedView(under: name) else { return }
    guard let referenceWindow = referenceView.window else { return }
    // Early return if there are no layout guides.
    guard let layoutGuidesForName = layoutGuides[name] else { return }
    for layoutGuide in layoutGuidesForName.allObjects {
      // Skip if there is no owning window.
      guard let owningView = layoutGuide.owningView else { continue }
      guard let owningWindow = owningView.window else { continue }
      let frameInReferenceWindow = referenceView.convert(referenceView.bounds, to: nil)
      let frameInOwningWindow = referenceWindow.convert(frameInReferenceWindow, to: owningWindow)
      let frameInOwningView = owningView.convert(frameInOwningWindow, from: nil)
      layoutGuide.constrainedFrame = frameInOwningView
    }
  }
}


UIView+WindowCoordinates

import UIKit
/// Lets any UIView communicate when its coordinates in its window change.
///
/// This is useful to know when a view moved on the screen, even when it didn't change frame in its
/// own parent.
///
/// To get notified when the view moved in its window:
///
///     let myView = UIView()
///     myView.cr_onWindowCoordinatesChanged = { view in
///       // Print the window coordinates.
///       print("\(view) moved to \(view convertRect:view.bounds toView:nil)")
///     }
///     let parentView = UIView()
///     parentView.addSubview(myView)
///     let window = UIWindow()
///     window.addSubview(parentView)  // → Calls the closure a first time.
///     parentView.frame = CGRect(x: 10, y: 20, width: 30, height: 40)  // → Calls the closure.
///
///  Even though `myView`'s frame itself was not modified in `parentView`, the closure is called, as
///  actually, `myView` moved transitively in its window.
///
    get {
      objc_getAssociatedObject(self, &UIView.OnWindowCoordinatesChangedKey) as? (UIView) -> Void
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.OnWindowCoordinatesChangedKey, newValue, .OBJC_ASSOCIATION_COPY)
      if newValue != nil {
        // Make sure UIView supports window observing.
        Self.cr_supportsWindowObserving = true
        observation = observe(\.window, options: [.initial]) { [weak self] _, _ in
          guard let self = self else { return }
          if self.window != nil {
            self.addMirrorViewInWindow()
            // Additionally, call the closure here as the view moved to a window.
            self.cr_onWindowCoordinatesChanged?(self)
          } else {
            self.removeMirrorViewInWindow()
          }
        }
      } else {
        observation = nil
      }
    }
  }
  /// MARK: Private
  /// The currently set observation of the window property.
  private var observation: NSKeyValueObservation? {
    get {
      objc_getAssociatedObject(self, &UIView.ObservationKey) as? NSKeyValueObservation
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.ObservationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
  /// Inserts a direct subview to the receiver's window, with constraints such that the mirror view
  /// always has the same window coordinates as the receiver. The mirror view calls the
  /// `onWindowCoordinatesChanged` closure when its bounds change.
  private func addMirrorViewInWindow() {
    let mirrorViewInWindow = NotifyingView()
    mirrorViewInWindow.backgroundColor = .clear
    mirrorViewInWindow.isUserInteractionEnabled = false
    mirrorViewInWindow.translatesAutoresizingMaskIntoConstraints = false
    mirrorViewInWindow.onLayoutChanged = { [weak self] _ in
      // Callback on the next turn of the run loop to wait for AutoLayout to have updated the entire
      // hierarchy. (It can happen that AutoLayout updates the mirror view before the mirrored
      // view.)
      DispatchQueue.main.async {
        guard let self = self else { return }
        self.cr_onWindowCoordinatesChanged?(self)
      }
    }
    guard let window = window else { fatalError() }
    window.insertSubview(mirrorViewInWindow, at: 0)
    NSLayoutConstraint.activate([
      mirrorViewInWindow.topAnchor.constraint(equalTo: topAnchor),
      mirrorViewInWindow.bottomAnchor.constraint(equalTo: bottomAnchor),
      mirrorViewInWindow.leadingAnchor.constraint(equalTo: leadingAnchor),
      mirrorViewInWindow.trailingAnchor.constraint(equalTo: trailingAnchor),
    ])
    self.mirrorViewInWindow = mirrorViewInWindow
  }
  /// Removes the mirror view added by a call to `addMirrorViewInWindow`.
  private func removeMirrorViewInWindow() {
    mirrorViewInWindow?.onLayoutChanged = nil
    mirrorViewInWindow?.removeFromSuperview()
    mirrorViewInWindow = nil
  }
  /// The currently set mirror view.
  private var mirrorViewInWindow: NotifyingView? {
    get {
      objc_getAssociatedObject(self, &UIView.MirrorViewInWindowKey) as? NotifyingView
    }
    set {
      objc_setAssociatedObject(
        self, &UIView.MirrorViewInWindowKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
    }
  }
  /// A simple view that calls a closure when its bounds and center changed.
  private class NotifyingView: UIView {
    var onLayoutChanged: ((UIView) -> Void)?
    override var bounds: CGRect {
      didSet {
        onLayoutChanged?(self)
      }
    }
    override var center: CGPoint {
      didSet {
        onLayoutChanged?(self)
      }
    }
  }
  /// Keys for storing associated objects.
  private static var OnWindowCoordinatesChangedKey = ""
  private static var ObservationKey = ""
  private static var MirrorViewInWindowKey = ""
}


import UIKit
/// A layout guide with two distinct additions:
/// 1.  encapsulates the KVO on its owning view's window and triggers a callback closure;
/// 2.  can be constrained to a fixed frame in its owning view coordinates.
///
/// 1. To get notified when the layout guide is added to a new window:
///
///     let layoutGuide = FrameLayoutGuide()
///     layoutGuide.onDidMoveToWindow = { guide in
///       if let window = guide.owningView?.window {
///         print("\(guide) moved to \(guide.owningView?.window)")
///       } else {
///         print("\(guide) was removed from its window")
///       }
///     }
///
///  2. To constrain a frame to the layout guide:
///
///      let layoutGuide = FrameLayoutGuide()
///      layoutGuide.constrainedFrame = CGRect(x: 10, y: 20, width: 30, height: 40)
///
///  The layout guide can then be used as an anchor to place elements related to its position.
    get {
      constrainedFrameView.frame
    }
    set {
      constrainedFrameView.frame = newValue
    }
  }
  /// MARK: Private
  /// When `owningView` changes, remove `constrainedFrameView` from the old to the new view, then
  /// reset the constraints anchoring the layout guide on `constrainedFrameView`.
  override open var owningView: UIView? {
    willSet {
      constrainedFrameView.removeFromSuperview()
    }
    didSet {
      if let owningView = owningView {
        owningView.addSubview(constrainedFrameView)
        NSLayoutConstraint.activate([
          leadingAnchor.constraint(equalTo: constrainedFrameView.leadingAnchor),
          trailingAnchor.constraint(equalTo: constrainedFrameView.trailingAnchor),
          topAnchor.constraint(equalTo: constrainedFrameView.topAnchor),
          bottomAnchor.constraint(equalTo: constrainedFrameView.bottomAnchor),
        ])
      }
    }
  }
  /// The observation of the owning view's window property. It's an optional variable because it
  /// can't be initialized before `self` is. See `init`.
  private var observation: NSKeyValueObservation?
  /// The view to inject in the owning view. Its frame will be set to `constrainedFrame`. The layout
  /// guide will anchor itself on that view.
  private let constrainedFrameView: UIView
  public override init() {
    constrainedFrameView = UIView()
    constrainedFrameView.backgroundColor = .clear
    constrainedFrameView.isUserInteractionEnabled = false
    super.init()
    // Make sure UIView supports window observing.
    UIView.cr_supportsWindowObserving = true
    // Start observing. It is not possible to initialize `observation` before `super.init()` because
    // the call to `observe(_:changeHandler:)` requires `self` to be initialized.
    // https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key-value_observing_in_swift
    observation = observe(\.owningView?.window, options: [.old, .new]) { layoutGuide, change in
      // Filter out changes where owning view changed but not the window. This can happen if a
      // layout guide is moved to a different owning view whose window is the same.
      if change.oldValue != change.newValue {
        layoutGuide.onDidMoveToWindow?(layoutGuide)
      }
    }
  }
  required init(coder aDecoder: NSCoder) {
    fatalError("Not using storyboards")
  }
}


UIView+WindowObserving

    get {
      return swizzled
    }
    set {
      if swizzled != newValue {
        // Swap implementations.
        guard
          let willMove1 = class_getInstanceMethod(UIView.self, #selector(willMove(toWindow:))),
          let willMove2 = class_getInstanceMethod(UIView.self, #selector(cr_willMove(toWindow:))),
          let didMove1 = class_getInstanceMethod(UIView.self, #selector(didMoveToWindow)),
          let didMove2 = class_getInstanceMethod(UIView.self, #selector(cr_didMoveToWindow)),
          // UITextField's original implementations don't call the super class implementations,
          // which breaks the interposition at the UIView level. Handle UITextField explicitly.
          let textFieldWillMove1 = class_getInstanceMethod(
            UITextField.self, #selector(willMove(toWindow:))),
          let textFieldWillMove2 = class_getInstanceMethod(
            UITextField.self, #selector(cr_willMove(toWindow:))),
          let textFieldDidMove1 = class_getInstanceMethod(
            UITextField.self, #selector(didMoveToWindow)),
          let textFieldDidMove2 = class_getInstanceMethod(
            UITextField.self, #selector(cr_didMoveToWindow))
        else {
          // If it failed here, don't change the `swizzled` state.
          return
        }
        method_exchangeImplementations(willMove1, willMove2)
        method_exchangeImplementations(didMove1, didMove2)
        method_exchangeImplementations(textFieldWillMove1, textFieldWillMove2)
        method_exchangeImplementations(textFieldDidMove1, textFieldDidMove2)
        // Change the `swizzled` state.
        swizzled = newValue
      }
    }
  }
  /// Signals that the `window` key is supported via Manual Change Notification.
  /// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-SW3
    cr_willMove(toWindow: newWindow)
    willChangeValue(forKey: "window")
  }
  /// Adds a call to the KVO `didChangeValue(forKey:)` method.
    cr_willMove(toWindow: newWindow)
    willChangeValue(forKey: "window")
  }
  /// Adds a call to the KVO `didChangeValue(forKey:)` method.
  ///
  /// This version is necessary, as UITextField's original implementation doesn't call its
  /// superclass implementation, hence escapes the interposition at the UIView level.
    cr_didMoveToWindow()
    didChangeValue(forKey: "window")
  }
}


import Foundation
import WidgetKit
/// Helper class to update timelines for WidgetKit widgets.
public final class WidgetTimelinesUpdater: NSObject {
  /// The queue onto which time-consuming work is dispatched.
  private static let queue = DispatchQueue(label: "com.google.chrome.ios.WidgetTimelinesUpdater")
  /// Updates timelines for all shared widgets.
  ///
  /// Whether or not widgets are actually updated depends on many factors
  /// governed by an OS level budgeting system. Widgets are guaranteed
  /// to be updated if the main app is in the foreground.
  ///
  /// This method is safe to call from any thread.
  public static func reloadAllTimelines() {
    queue.async {
      WidgetCenter.shared.reloadAllTimelines()
    }
  }
}


import Foundation
/// An object that stores and retrieves the widget configurations from user defaults.
public struct UserDefaultsWidgetStore {
  /// The key that the current widget configurations are stored under in the user defaults.
  private let widgetInfoKey = "com.google.chrome.ios.widgets.widget-info"
  // Use UserDefaults.standard because this information only needs to be stored and retrieved from
  // the main app.
  private let userDefaults = UserDefaults.standard
  public func storeWidgetInfo(_ info: [String]) throws {
    let encoder = JSONEncoder()
    let data = try encoder.encode(info)
    userDefaults.set(data, forKey: widgetInfoKey)
  }
  public func retrieveStoredWidgetInfo() -> Result<[String], Error> {
    guard let data = userDefaults.data(forKey: widgetInfoKey) else {
      // If there is no stored data, return an empty array.
      return .success([])
    }
    let decoder = JSONDecoder()
    return Result {
      return try decoder.decode(Array<String>.self, from: data)
    }
  }
}


import Foundation
import WidgetKit
/// Logs metrics associated with iOS 14 home screen widgets.
public final class WidgetsMetricLogger: NSObject {
  /// The queue onto which time-consuming work is dispatched.
  private static let queue = DispatchQueue(label: "com.google.chrome.ios.WidgetMetricLogger")
  // MARK: Public
  /// A callback to be called when a widget install is detected. This callback is passed the
  /// information about which widget was installed.
  ///
  /// This property must be set before the `logInstalledWidgets` method is called.
  /// Logs metrics if the user has installed or uninstalled a widget since the last check.
  ///
  /// This method should be called once per application foreground, for example in the
  /// `applicationWillEnterForeground` method.
  ///
  /// This method is safe to call from any thread.
  public static func logInstalledWidgets() {
    if #available(iOS 14, *) {
      // To avoid blocking startup, perform work on a background queue.
      queue.async {
        logInstalledWidgets(fetcher: WidgetCenter.shared, store: UserDefaultsWidgetStore())
      }
    }
  }
  // MARK: Private
  /// Logs metrics if the user has installed or uninstalled a widget since the last app launch.
  static func logInstalledWidgets(fetcher: WidgetCenter, store: UserDefaultsWidgetStore) {
    fetcher.getCurrentConfigurations { result in
      // If fetching either current or previous info fails, avoid logging anything. The next time
      // this is called, metrics will be logged.
      guard let currentWidgets = try? result.get().map({ $0.kind }) else {
        return
      }
      // Log current widgets.
      for widget in currentWidgets {
        widgetCurrentCallback?(widget)
      }
      guard let storedWidgets = try? store.retrieveStoredWidgetInfo().get() else {
        return
      }
      // Attempt to store the new configurations and verify that it is successful to avoid double
      // logging. If metrics were logged when storage failed, they would be double-logged the next
      // time this method is called.
      do {
        try store.storeWidgetInfo(currentWidgets)
      } catch {
        return
      }
      // Current widgets minus stored widgets are installations.
      var installedWidgets = currentWidgets
      for storedWidget in storedWidgets {
        if let index = installedWidgets.firstIndex(of: storedWidget) {
          installedWidgets.remove(at: index)
        }
      }
      for installedWidget in installedWidgets {
        widgetInstalledCallback?(installedWidget)
      }
      // Stored widgets minus current widgets are uninstallations.
      var uninstalledWidgets = storedWidgets
      for currentWidget in currentWidgets {
        if let index = uninstalledWidgets.firstIndex(of: currentWidget) {
          uninstalledWidgets.remove(at: index)
        }
      }
      for uninstalledWidget in uninstalledWidgets {
        widgetUninstalledCallback?(uninstalledWidget)
      }
    }
  }
}


import CoreSpotlight
import UIKit
/// Displays details of a single CSSearchableItem.
class SearchableItemDetailViewController: UIViewController {
  let item: CSSearchableItem
  init(with item: CSSearchableItem) {
    self.item = item
    super.init(nibName: nil, bundle: nil)
  }
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  enum Section: CaseIterable {
    case main
  }
  struct SearchableItemDetail: Hashable {
    let title: String  // Used as unique ID
    let value: String?
    func hash(into hasher: inout Hasher) {
      hasher.combine(title)
    }
    static func == (lhs: SearchableItemDetail, rhs: SearchableItemDetail) -> Bool {
      return lhs.title == rhs.title
    }
  }
  var dataSource: UICollectionViewDiffableDataSource<Section, SearchableItemDetail>! = nil
  var collectionView: UICollectionView! = nil
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = item.attributeSet.title ?? item.uniqueIdentifier
    configureHierarchy()
    configureDataSource()
  }
  func createLayout() -> UICollectionViewLayout {
    let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
    return UICollectionViewCompositionalLayout.list(using: config)
  }
  private func configureHierarchy() {
    collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.addSubview(collectionView)
  }
  private func configureDataSource() {
    let cellRegistration = UICollectionView.CellRegistration<
      UICollectionViewListCell, SearchableItemDetail
    > { (cell, indexPath, detail) in
      var content = cell.defaultContentConfiguration()
      content.text = detail.title
      content.secondaryText = detail.value
      cell.contentConfiguration = content
    }
    dataSource = UICollectionViewDiffableDataSource<Section, SearchableItemDetail>(
      collectionView: collectionView
    ) {
      (collectionView: UICollectionView, indexPath: IndexPath, identifier: SearchableItemDetail)
        -> UICollectionViewCell? in
      return collectionView.dequeueConfiguredReusableCell(
        using: cellRegistration, for: indexPath, item: identifier)
    }
    var snapshot = NSDiffableDataSourceSnapshot<Section, SearchableItemDetail>()
    snapshot.appendSections([SearchableItemDetailViewController.Section.main])
    snapshot.appendItems([
      SearchableItemDetail(title: "displayName", value: item.attributeSet.displayName),
      SearchableItemDetail(title: "domain", value: item.domainIdentifier),
      SearchableItemDetail(title: "title", value: item.attributeSet.title),
      SearchableItemDetail(title: "id", value: item.uniqueIdentifier),
      SearchableItemDetail(title: "URL", value: item.attributeSet.url?.absoluteString),
      SearchableItemDetail(title: "description", value: item.attributeSet.contentDescription),
      SearchableItemDetail(title: "thumbnail data", value: thumbnailDescription()),
    ])
    dataSource.apply(snapshot, animatingDifferences: false)
  }
  private func thumbnailDescription() -> String {
    guard let data = item.attributeSet.thumbnailData else {
      return "not available"
    }
    guard let image = UIImage(data: data) else {
      return "corrupt image data"
    }
  }
}


import CoreSpotlight
import UIKit
/// Controller backed by SpotlightLogger known items, with filter function.
class ItemsController {
  func filteredItems(with filter: String? = nil, limit: Int? = nil) -> [CSSearchableItem] {
    let filtered = knownItems.filter { $0.contains(filter) }
    if let limit = limit {
      return Array(filtered.prefix(through: limit))
    } else {
      return filtered
    }
  }
  private lazy var knownItems: [CSSearchableItem] = {
    return SpotlightLogger.shared().knownIndexedItems() ?? []
  }()
}
/// Displays a list of all searchable items from the spotlight logger.
class SpotlightDebuggerAllItemsViewController: UIViewController {
  enum Section: CaseIterable {
    case main
  }
  let itemsController = ItemsController()
  let searchBar = UISearchBar(frame: .zero)
  var collectionView: UICollectionView!
  var dataSource: UICollectionViewDiffableDataSource<Section, CSSearchableItem>!
  var nameFilter: String?
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = "Donated Items"
    configureHierarchy()
    configureDataSource()
    performQuery(with: nil)
  }
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    collectionView.deselectAllItems(animated: animated)
  }
}
extension UICollectionView {
  func deselectAllItems(animated: Bool) {
    guard let selectedItems = indexPathsForSelectedItems else { return }
    for indexPath in selectedItems { deselectItem(at: indexPath, animated: animated) }
  }
}
extension SpotlightDebuggerAllItemsViewController {
  func configureDataSource() {
    let cellRegistration = UICollectionView.CellRegistration<
      UICollectionViewListCell, CSSearchableItem
    > { (cell, indexPath, item) in
      var content = cell.defaultContentConfiguration()
      content.text = item.attributeSet.title
      if let data = item.attributeSet.thumbnailData {
        content.image = UIImage(data: data)
        content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
      } else {
        content.image = UIImage(systemName: "questionmark.diamond")
      }
      cell.accessories = [.disclosureIndicator()]
      cell.contentConfiguration = content
    }
    dataSource = UICollectionViewDiffableDataSource<Section, CSSearchableItem>(
      collectionView: collectionView
    ) {
      (collectionView: UICollectionView, indexPath: IndexPath, identifier: CSSearchableItem)
        -> UICollectionViewCell? in
      // Return the cell.
      return collectionView.dequeueConfiguredReusableCell(
        using: cellRegistration, for: indexPath, item: identifier)
    }
  }
  func performQuery(with filter: String?) {
    let items = itemsController.filteredItems(with: filter).sorted {
      $0.uniqueIdentifier < $1.uniqueIdentifier
    }
    var snapshot = NSDiffableDataSourceSnapshot<Section, CSSearchableItem>()
    snapshot.appendSections([.main])
    snapshot.appendItems(items)
    dataSource.apply(snapshot, animatingDifferences: true)
  }
}
extension SpotlightDebuggerAllItemsViewController {
  func createLayout() -> UICollectionViewLayout {
    let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
    return UICollectionViewCompositionalLayout.list(using: config)
  }
  func configureHierarchy() {
    view.backgroundColor = .systemBackground
    let layout = createLayout()
    let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    searchBar.translatesAutoresizingMaskIntoConstraints = false
    collectionView.backgroundColor = .systemBackground
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    collectionView.delegate = self
    view.addSubview(collectionView)
    view.addSubview(searchBar)
    let views = ["cv": collectionView, "searchBar": searchBar]
    var constraints = [NSLayoutConstraint]()
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[cv]|", options: [], metrics: nil, views: views))
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[searchBar]|", options: [], metrics: nil, views: views))
    constraints.append(
      contentsOf: NSLayoutConstraint.constraints(
        withVisualFormat: "V:[searchBar]-20-[cv]|", options: [], metrics: nil, views: views))
    constraints.append(
      searchBar.topAnchor.constraint(
        equalToSystemSpacingBelow: view.safeAreaLayoutGuide.topAnchor, multiplier: 1.0))
    NSLayoutConstraint.activate(constraints)
    self.collectionView = collectionView
    searchBar.delegate = self
  }
}
extension SpotlightDebuggerAllItemsViewController: UICollectionViewDelegate {
  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let item = self.dataSource.itemIdentifier(for: indexPath) else {
      collectionView.deselectItem(at: indexPath, animated: true)
      return
    }
    let detailViewController = SearchableItemDetailViewController(with: item)
    self.navigationController?.pushViewController(detailViewController, animated: true)
  }
}
extension SpotlightDebuggerAllItemsViewController: UISearchBarDelegate {
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    performQuery(with: searchText)
  }
}
extension CSSearchableItem {
  func contains(_ filter: String?) -> Bool {
    guard let filterText = filter else { return true }
    if filterText.isEmpty { return true }
    let lowercasedFilter = filterText.lowercased()
    return (attributeSet.title?.lowercased().contains(lowercasedFilter) ?? false)
      || (attributeSet.url?.absoluteString.lowercased().contains(lowercasedFilter) ?? false)
      || (domainIdentifier?.lowercased().contains(lowercasedFilter) ?? false)
      || uniqueIdentifier.lowercased().contains(lowercasedFilter)
  }
}


  /// Pedal title, as seen in the pedal button/row.
  public let title: String
  /// Pedal subtitle, e.g. "Settings -> Passwords"
  public let subtitle: String
  /// Describes the action performed; can be used for voiceover.
  public let hint: String
  /// The image for the Pedal.
  public let image: UIImage
  public let imageTintColor: UIColor?
  public let backgroundColor: UIColor?
  public let imageBorderColor: UIColor?
  /// Action to run when the pedal is executed.
  public let action: () -> Void
  /// Action type for metrics collection. Int-casted OmniboxPedalId
  public let type: Int
  public init(
    title: String, subtitle: String,
    accessibilityHint: String,
    image: UIImage,
    imageTintColor: UIColor?,
    backgroundColor: UIColor?,
    imageBorderColor: UIColor?,
    type: Int,
  ) {
    self.title = title
    self.subtitle = subtitle
    self.hint = accessibilityHint
    self.image = image
    self.imageTintColor = imageTintColor
    self.backgroundColor = backgroundColor
    self.imageBorderColor = imageBorderColor
    self.type = type
    self.action = action
  }
}
extension OmniboxPedalData: OmniboxIcon {
  public var iconType: OmniboxIconType {
    return .suggestionIcon
  }
  public var iconImage: UIImage? {
    return image
  }
  public var imageURL: CrURL? { return nil }
  public var iconImageTintColor: UIColor? {
    return imageTintColor
  }
  public var backgroundImageTintColor: UIColor? {
    return backgroundColor
  }
  public var borderColor: UIColor? {
    return imageBorderColor
  }
}


  }
  var body: some View {
    Button {
      state.action?()
    } label: {
      if sizeCategory < .accessibilityMedium {
        regularLayout()
      } else {
        xxlLayout()
      }
    }
    .buttonStyle(InactiveTabsButtonStyle())
  }
  /// MARK - Layouts
  /// Displays the elements mostly horizontally, for when the size category is small.
  private func xxlLayout() -> some View {
    HStack {
      leadingTextVStack {
        title()
        counter()
        subtitle()
      }
      Spacer()
      disclosure()
    }
  }
  /// MARK - Elements
  /// Displays the button title.
  private func subtitle() -> some View {
    if let daysThreshold = state.daysThreshold {
      Text(
        L10nUtils.formatString(
          messageId: IDS_IOS_INACTIVE_TABS_BUTTON_SUBTITLE,
          argument: String(daysThreshold))
      )
      .font(.footnote)
      .foregroundColor(.textSecondary)
    }
  }
  /// Displays the tabs count.
  ///
  /// If the count is larger than 99, "99+" is displayed.
  /// If the count is not set, this returns nothing.
  private func disclosure() -> some View {
    if #available(iOS 16.0, *) {
      Image(systemName: kChevronForwardSymbol)
        .foregroundColor(.textTertiary)
        .fontWeight(.semibold)
    } else {
      // fontWeight is not available on Image. Wrap it in a Text.
      Text(Image(systemName: kChevronForwardSymbol))
        .foregroundColor(.textTertiary)
        .fontWeight(.semibold)
    }
  }
  /// VStack displaying its contents from the leading edge. Textual content is also leading aligned
  /// when displayed on multiple lines.
    VStack(alignment: .leading, spacing: Dimensions.spacing) {
      content()
    }
    .multilineTextAlignment(.leading)
  }
  /// MARK - Styles
  /// Style for the main button, i.e. the top-level view.
  private struct InactiveTabsButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
      configuration.label
        .padding([.top, .bottom], Dimensions.verticalPadding)
        .padding([.leading, .trailing], Dimensions.horizontalPadding)
        .background(
          configuration.isPressed ? Color(.systemGray4) : Color.groupedSecondaryBackground
        )
        .cornerRadius(Dimensions.cornerRadius)
        .environment(\.colorScheme, .dark)
    }
  }
}


public class InactiveTabsButtonHeader: UICollectionReusableView {
  private enum Dimensions {
    /// The margin at the top of the header.
    static let topMargin: CGFloat = 12
    /// The margin on the other edges of the header.
    static let margin: CGFloat = 16
  }
  /// The state driving the SwiftUI button.
  private let buttonState = InactiveTabsButton.State()
  /// The hosting controller to map to the SwiftUI button.
  private lazy var hostingController = {
    UIHostingController(rootView: InactiveTabsButton(state: buttonState))
  }()
  /// Installs the hosting controller in the parent view controller.
    didSet {
      guard hostingController.parent != parent else { return }
      if let parent {
        parent.addChild(hostingController)
        hostingController.view.backgroundColor = .clear
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        addSubview(hostingController.view)
        hostingController.didMove(toParent: parent)
        NSLayoutConstraint.activate([
          hostingController.view.topAnchor.constraint(
            equalTo: topAnchor, constant: Dimensions.topMargin),
          hostingController.view.leadingAnchor.constraint(
            equalTo: leadingAnchor, constant: Dimensions.margin),
          hostingController.view.bottomAnchor.constraint(
            equalTo: bottomAnchor, constant: -Dimensions.margin),
          hostingController.view.trailingAnchor.constraint(
            equalTo: trailingAnchor, constant: -Dimensions.margin),
        ])
      } else {
        hostingController.willMove(toParent: nil)
        hostingController.view.removeFromSuperview()
        hostingController.removeFromParent()
      }
    }
  }
  /// The callback when the Inactive Tabs button is pressed.
    buttonState.count = count
  }
}


import SwiftUI
import ios_chrome_common_ui_colors_swift
private let kPromptInnerPaddingHorizontal: CGFloat = 12
private let kPromptInnerPaddingVertical: CGFloat = 8
private let kPromptOuterPaddingHorizontal: CGFloat = 6
private let kPromptOuterPaddingVertical: CGFloat = 8
private let kPromptCornerRadius: CGFloat = 20
private let kTextVerticalSpacing: CGFloat = 12
private let kTextMinimumScaleFactor: CGFloat = 0.5
private let kSeparatorHeight: CGFloat = 1
// The view object for "Bring Android Tabs" bottom message prompt.
struct BringAndroidTabsPromptBottomMessageView: View {
  // Number of tabs brought from Android.
  let tabsCount: Int
  // Provider object for the view.
  weak var provider: BringAndroidTabsPromptBottomMessageProvider?
  var body: some View {
    HStack(alignment: .top) {
      Image(systemName: kTabsSymbol)
        .imageScale(.large)
        .padding(.top, kTextVerticalSpacing)
      VStack(alignment: .leading, spacing: kTextVerticalSpacing) {
        HStack(alignment: .top) {
          VStack(
            alignment: .leading,
            spacing: kTextVerticalSpacing - kPromptInnerPaddingVertical
          ) {
            Text(
              L10nUtils.pluralString(
                messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE,
                number: self.tabsCount)
            )
            .font(.body)
            .minimumScaleFactor(kTextMinimumScaleFactor)
            Text(
              L10nUtils.pluralString(
                messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE,
                number: self.tabsCount)
            )
            .font(.footnote)
            .foregroundColor(.textSecondary)
            .minimumScaleFactor(kTextMinimumScaleFactor)
          }
          .padding(.top, kTextVerticalSpacing - kPromptInnerPaddingVertical)
          Spacer()
          Button(action: self.close) {
            Image(systemName: kXMarkCircleFillSymbol)
              .foregroundColor(.textQuaternary)
          }
          .accessibilityIdentifier(
            kBringAndroidTabsPromptBottomMessageCloseButtonAXId)
        }
        .padding(0)
        Divider().overlay(Color.separator).frame(height: kSeparatorHeight)
        Button(action: self.review) {
          HStack {
            Text(
              L10nUtils.pluralString(
                messageId:
                  IDS_IOS_BRING_ANDROID_TABS_PROMPT_REVIEW_TABS_BUTTON_BOTTOM_MESSAGE,
                number: self.tabsCount)
            )
            .minimumScaleFactor(kTextMinimumScaleFactor)
            Spacer()
            Image(systemName: kChevronForwardSymbol)
              .foregroundColor(.textSecondary)
          }
        }
        .foregroundColor(.chromeBlue)
        .accessibilityIdentifier(
          kBringAndroidTabsPromptBottomMessageReviewButtonAXId)
      }
      .padding(.bottom, kTextVerticalSpacing)
    }
    .padding(.horizontal, kPromptInnerPaddingHorizontal)
    .padding(.vertical, kPromptInnerPaddingVertical)
    .background(Color.primaryBackground)
    .clipShape(RoundedRectangle(cornerRadius: kPromptCornerRadius))
    .environment(\.colorScheme, .dark)
    .onAppear { self.onAppear() }
    .padding(.horizontal, kPromptOuterPaddingHorizontal)
    .padding(.vertical, kPromptOuterPaddingVertical)
  }
  // MARK: - Action handlers.
  // Invoked when the view is displayed.
  func onAppear() {
    self.provider?.delegate?.bringAndroidTabsPromptViewControllerDidShow()
  }
  // Review button action handler.
  func review() {
    self.provider?.delegate?
      .bringAndroidTabsPromptViewControllerDidTapReviewButton()
    self.provider?.commandHandler?.reviewAllBringAndroidTabs()
  }
  // Close button action handler.
  func close() {
    self.provider?.delegate?.bringAndroidTabsPromptViewControllerDidDismiss(
      swiped: false)
    self.provider?.commandHandler?.dismissBringAndroidTabsPrompt()
  }
}


class BringAndroidTabsPromptBottomMessageProvider: NSObject {
  // Delegate to handle user actions and update browser models accordingly.
  weak var delegate: BringAndroidTabsPromptViewControllerDelegate?
  // Command handler to continue Bring Android Tabs user journey based on
  // command invocation.
  weak var commandHandler: BringAndroidTabsCommands?
  // Number of active tabs from Android.
  let tabsCount: Int
  init(tabsCount: Int) {
    self.tabsCount = tabsCount
  }
  // View controller that manages this view. Should be added to the view
  // hierarchy when the view is displayed or removed.
  lazy var viewController: UIViewController = {
    var viewController = UIHostingController(
      rootView: BringAndroidTabsPromptBottomMessageView(
        tabsCount: self.tabsCount, provider: self))
    // Workaround of SwiftUI/UIKit interoperality limitation that the topmost
    // view always have an opaque background.
    viewController.view.backgroundColor = UIColor.clear
    return viewController
  }()
}


class BringAndroidTabsPromptConfirmationAlertViewController:
  ConfirmationAlertViewController,  // super class
  ConfirmationAlertActionHandler,  // protocol
  UIAdaptivePresentationControllerDelegate
{
  // Delegate to handle user actions.
  weak var delegate: BringAndroidTabsPromptViewControllerDelegate?
  // Command handler to continue Bring Android Tabs user journey base on command
  // invocation.
  weak var commandHandler: BringAndroidTabsCommands?
  // Number of active tabs from Android.
  private let tabsCount: Int
  init(tabsCount: Int) {
    self.tabsCount = tabsCount
  }
  override func viewDidLoad() {
    // Configure confirmation alert properties. These properties need to be set
    // before calling the confirmation alert's `viewDidLoad`.
    self.image = UIImage(named: "bring_android_tabs_icon")
    self.imageHasFixedSize = true
    self.customSpacingBeforeImageIfNoNavigationBar = kSpacingBeforeImage
    self.customSpacingAfterImage = kSpacingAfterImage
    self.helpButtonAvailable = false
    self.showDismissBarButton = false
    self.titleString = L10nUtils.pluralString(
      messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_TITLE,
      number: self.tabsCount)
    self.titleTextStyle = .title2
    self.subtitleString = L10nUtils.pluralString(
      messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_SUBTITLE,
      number: self.tabsCount)
    self.primaryActionString = L10nUtils.pluralString(
      messageId: IDS_IOS_BRING_ANDROID_TABS_PROMPT_OPEN_TABS_BUTTON,
      number: self.tabsCount)
    self.secondaryActionString = L10nUtils.pluralString(
      messageId: IDS_IOS_BRING_ANDROID_TABS_CANCEL_BUTTON,
      number: self.tabsCount)
    self.tertiaryActionString = L10nUtils.pluralString(
      messageId:
        IDS_IOS_BRING_ANDROID_TABS_PROMPT_REVIEW_TABS_BUTTON_CONFIRMATION_ALERT,
      number: self.tabsCount)
    super.viewDidLoad()
    // Configure properties specific to the "Bring Android Tabs" prompt.
    self.actionHandler = self
    self.presentationController?.delegate = self
    self.overrideUserInterfaceStyle = .dark
    self.view.accessibilityIdentifier =
      kBringAndroidTabsPromptConfirmationAlertAXId
  }
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.delegate?.bringAndroidTabsPromptViewControllerDidShow()
  }
  // MARK: - UIAdaptivePresentationControllerDelegate
  func presentationControllerDidDismiss(_ controller: UIPresentationController) {
    self.delegate?.bringAndroidTabsPromptViewControllerDidDismiss(swiped: true)
    self.commandHandler?.dismissBringAndroidTabsPrompt()
  }
  // MARK: - ConfirmationAlertActionHandler
  func confirmationAlertPrimaryAction() {
    self.delegate?.bringAndroidTabsPromptViewControllerDidTapOpenAllButton()
    self.commandHandler?.dismissBringAndroidTabsPrompt()
  }
  func confirmationAlertSecondaryAction() {
    self.delegate?.bringAndroidTabsPromptViewControllerDidDismiss(swiped: false)
    self.commandHandler?.dismissBringAndroidTabsPrompt()
  }
  func confirmationAlertTertiaryAction() {
    self.delegate?.bringAndroidTabsPromptViewControllerDidTapReviewButton()
    self.commandHandler?.reviewAllBringAndroidTabs()
  }
}