chromium/ios/chrome/browser/bring_android_tabs/ui_bundled/bring_android_tabs_app_interface.mm

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/bring_android_tabs/ui_bundled/bring_android_tabs_app_interface.h"

#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "base/time/time.h"
#import "components/sync_device_info/device_info.h"
#import "ios/chrome/browser/synced_sessions/model/distant_session.h"
#import "ios/chrome/browser/synced_sessions/model/distant_tab.h"
#import "ios/chrome/browser/bring_android_tabs/ui_bundled/bring_android_tabs_test_session.h"
#import "ios/chrome/test/app/sync_test_util.h"
#import "url/gurl.h"

namespace {

void AddDistantTabWithTitleAndURLToSession(
    const std::string& title,
    const GURL& url,
    synced_sessions::DistantSession& session) {
  // Tab ID to monotonically increment for each new tab to avoid conflicts.
  static int g_next_tab_id = 1;

  auto tab = std::make_unique<synced_sessions::DistantTab>();
  tab->session_tag = session.tag;
  tab->tab_id = SessionID::FromSerializedValue(g_next_tab_id++);
  tab->title = base::UTF8ToUTF16(title);
  tab->virtual_url = url;
  session.tabs.push_back(std::move(tab));
}

// Distant session lazy getter for `g_recent_session_android_phone`. The
// `test_server` is needed for initialization purpose, but will be disregarded
// if the property is already set.
synced_sessions::DistantSession& GetRecentSessionFromAndroidPhone(
    const GURL& test_server) {
  static synced_sessions::DistantSession g_recent_session_android_phone;
  if (g_recent_session_android_phone.tag.empty()) {
    std::string sessionName("recent_session_from_android_phone");
    g_recent_session_android_phone.tag = sessionName;
    g_recent_session_android_phone.name = sessionName;
    g_recent_session_android_phone.modified_time =
        base::Time::Now() - base::Days(14) + base::Minutes(10);
    g_recent_session_android_phone.form_factor =
        syncer::DeviceInfo::FormFactor::kPhone;
    AddDistantTabWithTitleAndURLToSession("ponies",
                                          test_server.Resolve("/pony.html"),
                                          g_recent_session_android_phone);
    AddDistantTabWithTitleAndURLToSession(
        "chromium logo", test_server.Resolve("/chromium_logo_page.html"),
        g_recent_session_android_phone);
  }
  return g_recent_session_android_phone;
}

// Distant session lazy getter for `g_expired_session_android_phone`. The
// `test_server` is needed for initialization purpose, but will be disregarded
// if the property is already set.
synced_sessions::DistantSession& GetExpiredSessionFromAndroidPhone(
    const GURL& test_server) {
  static synced_sessions::DistantSession g_expired_session_android_phone;
  if (g_expired_session_android_phone.tag.empty()) {
    std::string sessionName("expired_session_from_android_phone");
    g_expired_session_android_phone.tag = sessionName;
    g_expired_session_android_phone.name = sessionName;
    g_expired_session_android_phone.modified_time =
        base::Time::Now() - base::Days(14) - base::Minutes(10);
    g_expired_session_android_phone.form_factor =
        syncer::DeviceInfo::FormFactor::kPhone;
    AddDistantTabWithTitleAndURLToSession(
        "Full Screen", test_server.Resolve("/tall_page.html"),
        g_expired_session_android_phone);
  }
  return g_expired_session_android_phone;
}

// Distant session lazy getter for `g_recent_session_desktop`. The `test_server`
// is needed for initialization purpose, but will be disregarded if the property
// is already set.
synced_sessions::DistantSession& GetRecentSessionFromDesktop(
    const GURL& test_server) {
  static synced_sessions::DistantSession g_recent_session_desktop;
  if (g_recent_session_desktop.tag.empty()) {
    std::string sessionName = "recent_session_from_desktop";
    g_recent_session_desktop.tag = sessionName;
    g_recent_session_desktop.name = sessionName;
    g_recent_session_desktop.modified_time =
        base::Time::Now() - base::Days(14) + base::Minutes(10);
    g_recent_session_desktop.form_factor =
        syncer::DeviceInfo::FormFactor::kDesktop;
    AddDistantTabWithTitleAndURLToSession(
        "Test Request Desktop/Mobile Script",
        test_server.Resolve("/user_agent_test_page.html"),
        g_recent_session_desktop);
  }
  return g_recent_session_desktop;
}

}  // namespace

#pragma mark - BringAndroidTabsAppInterface

@implementation BringAndroidTabsAppInterface

+ (void)addFakeSyncServerSession:(BringAndroidTabsTestSession)sessionType
                  fromTestServer:(NSString*)testServerHost {
  const GURL testServer = GURL(base::SysNSStringToUTF8(testServerHost));
  switch (sessionType) {
    case BringAndroidTabsTestSession::kRecentFromAndroidPhone:
      chrome_test_util::AddSessionToFakeSyncServer(
          GetRecentSessionFromAndroidPhone(testServer));
      return;
    case BringAndroidTabsTestSession::kExpiredFromAndroidPhone:
      chrome_test_util::AddSessionToFakeSyncServer(
          GetExpiredSessionFromAndroidPhone(testServer));
      return;
    case BringAndroidTabsTestSession::kRecentFromDesktop:
      chrome_test_util::AddSessionToFakeSyncServer(
          GetRecentSessionFromDesktop(testServer));
      return;
  }
}

+ (int)tabsCountForPrompt {
  const synced_sessions::DistantSession& session =
      GetRecentSessionFromAndroidPhone(GURL());
  size_t tabCount = session.tabs.size();

  // If the URL of the session tab is empty, the session itself is created at
  // the time of declaration, instead of before. That means it has not been
  // added to the fake sync server, and should not be prompted.
  if (tabCount < 1 || session.tabs[0]->virtual_url.is_empty()) {
    return 0;
  }
  return static_cast<int>(tabCount);
}

@end