chromium/ios/chrome/browser/push_notification/model/push_notification_client.mm

// Copyright 2022 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/push_notification/model/push_notification_client.h"

#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/browser/browser_list.h"
#import "ios/chrome/browser/shared/model/browser/browser_list_factory.h"
#import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"
#import "ios/chrome/browser/url_loading/model/url_loading_params.h"
#import "ios/public/provider/chrome/browser/user_feedback/user_feedback_sender.h"

PushNotificationClient::PushNotificationClient(
    PushNotificationClientId client_id)
    : client_id_(client_id) {}

PushNotificationClient::~PushNotificationClient() = default;

PushNotificationClientId PushNotificationClient::GetClientId() {
  return client_id_;
}

void PushNotificationClient::OnSceneActiveForegroundBrowserReady() {
  if (!urls_delayed_for_loading_.size() && !feedback_presentation_delayed_) {
    return;
  }

  // TODO(crbug.com/41497027): The notifications should probbaly be linked
  // to a specific profile, and thus this should check that the code here
  // use the correct profile.
  Browser* browser = GetSceneLevelForegroundActiveBrowser();
  CHECK(browser);

  if (feedback_presentation_delayed_) {
    id<ApplicationCommands> handler =
        static_cast<id<ApplicationCommands>>(browser->GetCommandDispatcher());
    switch (feedback_presentation_delayed_client_) {
      case PushNotificationClientId::kContent:
      case PushNotificationClientId::kSports:
        [handler
            showReportAnIssueFromViewController:browser->GetSceneState()
                                                    .window.rootViewController
                                         sender:UserFeedbackSender::
                                                    ContentNotification
                            specificProductData:feedback_data_];
        feedback_presentation_delayed_ = false;
        break;
      case PushNotificationClientId::kTips:
      case PushNotificationClientId::kCommerce:
      case PushNotificationClientId::kSafetyCheck:
        // Features do not support feedback.
        NOTREACHED_IN_MIGRATION();
        break;
    }
  }

  if (urls_delayed_for_loading_.size()) {
    for (const GURL& url : urls_delayed_for_loading_) {
      LoadUrlInNewTab(url, browser);
    }
    urls_delayed_for_loading_.clear();
  }
}

// TODO(crbug.com/41497027): Current implementation returns any Scene. Instead
// the notification should includes some way to identify the associated profile
// to use (maybe by including the gaia id of the associated profile).
Browser* PushNotificationClient::GetSceneLevelForegroundActiveBrowser() {
  ChromeBrowserState* profile = GetAnyProfile();
  if (!profile) {
    return nullptr;
  }

  std::set<Browser*> browsers =
      BrowserListFactory::GetForBrowserState(profile)->BrowsersOfType(
          BrowserList::BrowserType::kRegular);

  for (Browser* browser : browsers) {
    if (browser->GetSceneState().activationLevel ==
        SceneActivationLevelForegroundActive) {
      return browser;
    }
  }
  return nullptr;
}

void PushNotificationClient::LoadUrlInNewTab(const GURL& url) {
  Browser* browser = GetSceneLevelForegroundActiveBrowser();
  if (!browser) {
    urls_delayed_for_loading_.push_back(url);
    return;
  }

  LoadUrlInNewTab(url, browser);
}

void PushNotificationClient::LoadUrlInNewTab(const GURL& url,
                                             Browser* browser) {
  UrlLoadParams params = UrlLoadParams::InNewTab(url);
  UrlLoadingBrowserAgent::FromBrowser(browser)->Load(params);
}

void PushNotificationClient::LoadFeedbackWithPayloadAndClientId(
    NSDictionary<NSString*, NSString*>* data,
    PushNotificationClientId client) {
  Browser* browser = GetSceneLevelForegroundActiveBrowser();
  if (!browser && data) {
    feedback_presentation_delayed_client_ = client;
    feedback_presentation_delayed_ = true;
    feedback_data_ = data;
    return;
  }
}

ChromeBrowserState* PushNotificationClient::GetAnyProfile() {
  std::vector<ChromeBrowserState*> loaded_profiles =
      GetApplicationContext()->GetProfileManager()->GetLoadedProfiles();

  if (loaded_profiles.empty()) {
    return nullptr;
  }

  return loaded_profiles.back();
}