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

#include "chrome/browser/ui/app_list/search/app_search_provider.h"

#include <stddef.h>

#include <algorithm>
#include <cstring>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>

#include "ash/public/cpp/app_list/app_list_features.h"
#include "ash/public/cpp/app_list/internal_app_id_constants.h"
#include "ash/public/cpp/app_list/tokenized_string.h"
#include "ash/public/cpp/app_list/tokenized_string_match.h"
#include "base/bind.h"
#include "base/callback_list.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/extensions/gfx_utils.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_ui_util.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/session_sync_service_factory.h"
#include "chrome/browser/ui/app_list/app_list_model_updater.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/extension_app_utils.h"
#include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
#include "chrome/browser/ui/app_list/search/app_service_app_result.h"
#include "chrome/browser/ui/app_list/search/arc_app_result.h"
#include "chrome/browser/ui/app_list/search/crostini_app_result.h"
#include "chrome/browser/ui/app_list/search/extension_app_result.h"
#include "chrome/browser/ui/app_list/search/internal_app_result.h"
#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/sync/base/model_type.h"
#include "components/sync_sessions/session_sync_service.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "ui/base/l10n/l10n_util.h"

using extensions::ExtensionRegistry;

namespace {

// The minimum capacity we reserve in the Apps container which will be filled
// with extensions and ARC apps, to avoid successive reallocation.
constexpr size_t kMinimumReservedAppsContainerCapacity = 60U;

// Relevance threshold to use when Crostini has not yet been enabled. This value
// is somewhat arbitrary, but is roughly equivalent to the 'ter' in 'terminal'.
constexpr double kCrostiniTerminalRelevanceThreshold = 0.8;
// These are added to the localized values for convenience. The leading space
// is as we just append this to the localized version of 'Linux'.
constexpr char kExtraCrostiniTerminalKeywords[] = " linux terminal crostini";

// Adds |app_result| to |results| only in case no duplicate apps were already
// added. Duplicate means the same app but for different domain, Chrome and
// Android.
void MaybeAddResult(app_list::SearchProvider::Results* results,
                    std::unique_ptr<app_list::AppResult> app_result,
                    std::set<std::string>* seen_or_filtered_apps) {
  if (seen_or_filtered_apps->count(app_result->app_id()))
    return;

  seen_or_filtered_apps->insert(app_result->app_id());

  std::unordered_set<std::string> duplicate_app_ids;
  if (!extensions::util::GetEquivalentInstalledArcApps(
          app_result->profile(), app_result->app_id(), &duplicate_app_ids)) {
    results->emplace_back(std::move(app_result));
    return;
  }

  for (const auto& duplicate_app_id : duplicate_app_ids) {
    if (seen_or_filtered_apps->count(duplicate_app_id))
      return;
  }

  results->emplace_back(std::move(app_result));

  // Add duplicate ids in order to filter them if they appear down the
  // list.
  seen_or_filtered_apps->insert(duplicate_app_ids.begin(),
                                duplicate_app_ids.end());
}

// Linearly maps |score| to the range [min, max].
// |score| is assumed to be within [0.0, 1.0]; if it's greater than 1.0
// then max is returned; if it's less than 0.0, then min is returned.
float ReRange(const float score, const float min, const float max) {
  if (score >= 1.0f)
    return max;
  if (score <= 0.0f)
    return min;

  return min + score * (max - min);
}

}  // namespace

namespace app_list {

class AppSearchProvider::App {
 public:
  App(AppSearchProvider::DataSource* data_source,
      const std::string& id,
      const std::string& name,
      const base::Time& last_launch_time,
      const base::Time& install_time,
      bool installed_internally)
      : data_source_(data_source),
        id_(id),
        name_(base::UTF8ToUTF16(name)),
        last_launch_time_(last_launch_time),
        install_time_(install_time),
        installed_internally_(installed_internally) {}
  ~App() = default;

  struct CompareByLastActivityTime {
    bool operator()(const std::unique_ptr<App>& app1,
                    const std::unique_ptr<App>& app2) {
      return app1->GetLastActivityTime() > app2->GetLastActivityTime();
    }
  };

  TokenizedString* GetTokenizedIndexedName() {
    // Tokenizing a string is expensive. Don't pay the price for it at
    // construction of every App, but rather, only when needed (i.e. when the
    // query is not empty and cache the result.
    if (!tokenized_indexed_name_)
      tokenized_indexed_name_ = std::make_unique<TokenizedString>(name_);
    return tokenized_indexed_name_.get();
  }

  base::Time GetLastActivityTime() const {
    if (!last_launch_time_.is_null())
      return last_launch_time_;
    if (!installed_internally_)
      return install_time_;
    return base::Time();
  }

  bool MatchSearchableText(const TokenizedString& query) {
    if (searchable_text_.empty())
      return false;
    if (!tokenized_indexed_searchable_text_) {
      tokenized_indexed_searchable_text_ =
          std::make_unique<TokenizedString>(searchable_text_);
    }
    TokenizedStringMatch match;
    match.Calculate(query, *tokenized_indexed_searchable_text_);
    return match.relevance() > relevance_threshold();
  }

  AppSearchProvider::DataSource* data_source() { return data_source_; }
  const std::string& id() const { return id_; }
  const base::string16& name() const { return name_; }
  const base::Time& last_launch_time() const { return last_launch_time_; }
  const base::Time& install_time() const { return install_time_; }

  bool recommendable() const { return recommendable_; }
  void set_recommendable(bool recommendable) { recommendable_ = recommendable; }

  bool searchable() const { return searchable_; }
  void set_searchable(bool searchable) { searchable_ = searchable; }

  const base::string16& searchable_text() const { return searchable_text_; }
  void set_searchable_text(const base::string16& searchable_text) {
    searchable_text_ = searchable_text;
  }

  // Relevance must exceed the threshold to appear as a search result. Exact
  // matches are always surfaced.
  float relevance_threshold() const { return relevance_threshold_; }
  void set_relevance_threshold(float threshold) {
    relevance_threshold_ = threshold;
  }

  bool installed_internally() const { return installed_internally_; }

 private:
  AppSearchProvider::DataSource* data_source_;
  std::unique_ptr<TokenizedString> tokenized_indexed_name_;
  std::unique_ptr<TokenizedString> tokenized_indexed_searchable_text_;
  const std::string id_;
  const base::string16 name_;
  const base::Time last_launch_time_;
  const base::Time install_time_;
  bool recommendable_ = true;
  bool searchable_ = true;
  base::string16 searchable_text_;
  float relevance_threshold_ = 0.f;
  // Set to true in case app was installed internally, by sync, policy or as a
  // default app.
  const bool installed_internally_;

  DISALLOW_COPY_AND_ASSIGN(App);
};

class AppSearchProvider::DataSource {
 public:
  DataSource(Profile* profile, AppSearchProvider* owner)
      : profile_(profile),
        owner_(owner) {}
  virtual ~DataSource() {}

  virtual void AddApps(Apps* apps) = 0;

  virtual std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) = 0;

 protected:
  Profile* profile() { return profile_; }
  AppSearchProvider* owner() { return owner_; }

 private:
  // Unowned pointers.
  Profile* profile_;
  AppSearchProvider* owner_;

  DISALLOW_COPY_AND_ASSIGN(DataSource);
};

namespace {

class AppServiceDataSource : public AppSearchProvider::DataSource {
 public:
  AppServiceDataSource(Profile* profile, AppSearchProvider* owner)
      : AppSearchProvider::DataSource(profile, owner) {
    // TODO(crbug.com/826982): observe the cache for apps being installed and
    // uninstalled, and in the callback, call RefreshAppsAndUpdateResultsXxx().
  }

  ~AppServiceDataSource() override = default;

  // AppSearchProvider::DataSource overrides:
  void AddApps(AppSearchProvider::Apps* apps_vector) override {
    apps::AppServiceProxy* proxy = apps::AppServiceProxy::Get(profile());
    if (!proxy) {
      return;
    }
    proxy->Cache().ForEachApp(
        [this, apps_vector](const apps::AppUpdate& update) {
          if (update.ShowInSearch() != apps::mojom::OptionalBool::kTrue) {
            return;
          }

          // TODO(crbug.com/826982): add the "can load in incognito" concept to
          // the App Service and use it here, similar to ExtensionDataSource.

          apps_vector->emplace_back(std::make_unique<AppSearchProvider::App>(
              this, update.AppId(),
              // TODO(crbug.com/826982): add the "short name" concept to the App
              // Service, and use it here.
              update.Name(),
              // TODO(crbug.com/826982): add the "last launch time" and "install
              // time" concepts to the App Service, and use them here.
              base::Time(), base::Time(),
              // TODO(crbug.com/826982): add the "installed internally" concept
              // to the App Service, and use it here.
              true));
        });
  }

  std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) override {
    return std::make_unique<AppServiceAppResult>(
        profile(), app_id, list_controller, is_recommended);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(AppServiceDataSource);
};

class ExtensionDataSource : public AppSearchProvider::DataSource,
                            public extensions::ExtensionRegistryObserver {
 public:
  ExtensionDataSource(Profile* profile, AppSearchProvider* owner)
      : AppSearchProvider::DataSource(profile, owner),
        extension_registry_observer_(this) {
    extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
  }
  ~ExtensionDataSource() override {}

  // AppSearchProvider::DataSource overrides:
  void AddApps(AppSearchProvider::Apps* apps) override {
    ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
    AddApps(apps, registry->enabled_extensions());
    AddApps(apps, registry->disabled_extensions());
    AddApps(apps, registry->terminated_extensions());
  }

  std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) override {
    return std::make_unique<ExtensionAppResult>(
        profile(), app_id, list_controller, is_recommended);
  }

  // extensions::ExtensionRegistryObserver overrides:
  void OnExtensionLoaded(content::BrowserContext* browser_context,
                         const extensions::Extension* extension) override {
    owner()->RefreshAppsAndUpdateResultsDeferred();
  }

  void OnExtensionUninstalled(content::BrowserContext* browser_context,
                              const extensions::Extension* extension,
                              extensions::UninstallReason reason) override {
    owner()->RefreshAppsAndUpdateResults();
  }

 private:
  void AddApps(AppSearchProvider::Apps* apps,
               const extensions::ExtensionSet& extensions) {
    extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(
        profile());
    for (const auto& it : extensions) {
      const extensions::Extension* extension = it.get();

      if (!app_list::ShouldShowInLauncher(extension, profile())) {
        continue;
      }

      if (profile()->IsOffTheRecord() &&
          !extensions::util::CanLoadInIncognito(extension, profile())) {
        continue;
      }

      apps->emplace_back(std::make_unique<AppSearchProvider::App>(
          this, extension->id(), extension->short_name(),
          prefs->GetLastLaunchTime(extension->id()),
          prefs->GetInstallTime(extension->id()),
          extension->was_installed_by_default() ||
              extension->was_installed_by_oem() ||
              extensions::Manifest::IsComponentLocation(
                  extension->location()) ||
              extensions::Manifest::IsPolicyLocation(extension->location())));
    }
  }

  ScopedObserver<extensions::ExtensionRegistry,
                 extensions::ExtensionRegistryObserver>
      extension_registry_observer_;

  DISALLOW_COPY_AND_ASSIGN(ExtensionDataSource);
};

class ArcDataSource : public AppSearchProvider::DataSource,
                      public ArcAppListPrefs::Observer {
 public:
  ArcDataSource(Profile* profile, AppSearchProvider* owner)
      : AppSearchProvider::DataSource(profile, owner) {
    ArcAppListPrefs::Get(profile)->AddObserver(this);
  }

  ~ArcDataSource() override {
    ArcAppListPrefs::Get(profile())->RemoveObserver(this);
  }

  // AppSearchProvider::DataSource overrides:
  void AddApps(AppSearchProvider::Apps* apps) override {
    ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile());
    CHECK(arc_prefs);

    const std::vector<std::string> app_ids = arc_prefs->GetAppIds();
    for (const auto& app_id : app_ids) {
      std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
          arc_prefs->GetApp(app_id);
      if (!app_info) {
        NOTREACHED();
        continue;
      }

      if (!app_info->show_in_launcher)
        continue;

      apps->emplace_back(std::make_unique<AppSearchProvider::App>(
          this, app_id, app_info->name, app_info->last_launch_time,
          app_info->install_time,
          arc_prefs->IsDefault(app_id) ||
              arc_prefs->IsControlledByPolicy(app_info->package_name)));
    }
  }

  std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) override {
    return std::make_unique<ArcAppResult>(profile(), app_id, list_controller,
                                          is_recommended);
  }

  // ArcAppListPrefs::Observer overrides:
  void OnAppRegistered(const std::string& app_id,
                       const ArcAppListPrefs::AppInfo& app_info) override {
    owner()->RefreshAppsAndUpdateResultsDeferred();
  }

  void OnAppStatesChanged(const std::string& app_id,
                          const ArcAppListPrefs::AppInfo& app_info) override {
    owner()->RefreshAppsAndUpdateResultsDeferred();
  }

  void OnAppRemoved(const std::string& id) override {
    owner()->RefreshAppsAndUpdateResults();
  }

  void OnAppNameUpdated(const std::string& id,
                        const std::string& name) override {
    owner()->RefreshAppsAndUpdateResultsDeferred();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ArcDataSource);
};

class InternalDataSource : public AppSearchProvider::DataSource {
 public:
  InternalDataSource(Profile* profile,
                     AppSearchProvider* owner,
                     bool just_continue_reading)
      : AppSearchProvider::DataSource(profile, owner),
        just_continue_reading_(just_continue_reading) {
    sync_sessions::SessionSyncService* service =
        SessionSyncServiceFactory::GetInstance()->GetForProfile(profile);
    if (!service)
      return;
    // base::Unretained() is safe below because the subscription itself is a
    // class member field and handles destruction well.
    foreign_session_updated_subscription_ =
        service->SubscribeToForeignSessionsChanged(base::BindRepeating(
            &AppSearchProvider::RefreshAppsAndUpdateResultsDeferred,
            base::Unretained(owner)));
  }

  ~InternalDataSource() override = default;

  // AppSearchProvider::DataSource overrides:
  void AddApps(AppSearchProvider::Apps* apps) override {
    for (const auto& internal_app : GetInternalAppList(profile())) {
      if (!std::strcmp(internal_app.app_id, kInternalAppIdContinueReading)) {
        if (!app_list_features::IsContinueReadingEnabled())
          continue;

        sync_sessions::SessionSyncService* service =
            SessionSyncServiceFactory::GetInstance()->GetForProfile(profile());
        if (!service || !service->GetOpenTabsUIDelegate()) {
          continue;
        }
      } else if (just_continue_reading_) {
        continue;
      }

      apps->emplace_back(std::make_unique<AppSearchProvider::App>(
          this, internal_app.app_id,
          l10n_util::GetStringUTF8(internal_app.name_string_resource_id),
          base::Time() /* last_launch_time */, base::Time() /* install_time */,
          true /* installed_internally */));
      apps->back()->set_recommendable(internal_app.recommendable);
      apps->back()->set_searchable(internal_app.searchable);
      if (internal_app.searchable_string_resource_id != 0) {
        apps->back()->set_searchable_text(l10n_util::GetStringUTF16(
            internal_app.searchable_string_resource_id));
      }
    }
  }

  std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) override {
    return std::make_unique<InternalAppResult>(profile(), app_id,
                                               list_controller, is_recommended);
  }

 private:
  // Whether InternalDataSource provides just the kInternalAppIdContinueReading
  // app. If true, other internal apps are provided by AppServiceDataSource.
  //
  // TODO(crbug.com/826982): move the "foreign session updated subscription"
  // into the App Service? Or if, in terms of UI, "continue reading" is exposed
  // only in the app list search UI, it might make more sense to leave it in
  // this code. See also built_in_chromeos_apps.cc.
  bool just_continue_reading_;

  std::unique_ptr<base::CallbackList<void()>::Subscription>
      foreign_session_updated_subscription_;

  DISALLOW_COPY_AND_ASSIGN(InternalDataSource);
};

class CrostiniDataSource : public AppSearchProvider::DataSource,
                           public crostini::CrostiniRegistryService::Observer {
 public:
  CrostiniDataSource(Profile* profile, AppSearchProvider* owner)
      : AppSearchProvider::DataSource(profile, owner) {
    crostini::CrostiniRegistryServiceFactory::GetForProfile(profile)
        ->AddObserver(this);
  }

  ~CrostiniDataSource() override {
    crostini::CrostiniRegistryServiceFactory::GetForProfile(profile())
        ->RemoveObserver(this);
  }

  // AppSearchProvider::DataSource overrides:
  void AddApps(AppSearchProvider::Apps* apps) override {
    crostini::CrostiniRegistryService* registry_service =
        crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
    for (const std::string& app_id : registry_service->GetRegisteredAppIds()) {
      crostini::CrostiniRegistryService::Registration registration =
          *registry_service->GetRegistration(app_id);
      if (registration.NoDisplay())
        continue;
      // Eventually it would be nice to use additional data points, for example
      // the 'Keywords' desktop entry field and the executable file name.
      apps->emplace_back(std::make_unique<AppSearchProvider::App>(
          this, app_id, registration.Name(), registration.LastLaunchTime(),
          registration.InstallTime(), false /* installed_internally */));

      if (app_id == crostini::kCrostiniTerminalId) {
        base::string16 searchable_text =
            l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINAL_APP_SEARCH_TERMS);
        searchable_text += base::UTF8ToUTF16(kExtraCrostiniTerminalKeywords);
        apps->back()->set_searchable_text(searchable_text);
        // Until it's been installed, the Terminal is hidden and requires
        // a few characters before being shown in search results.
        if (!crostini::IsCrostiniEnabled(profile())) {
          apps->back()->set_recommendable(false);
          apps->back()->set_relevance_threshold(
              kCrostiniTerminalRelevanceThreshold);
        }
      }
    }
  }

  std::unique_ptr<AppResult> CreateResult(
      const std::string& app_id,
      AppListControllerDelegate* list_controller,
      bool is_recommended) override {
    return std::make_unique<CrostiniAppResult>(profile(), app_id,
                                               list_controller, is_recommended);
  }

  // crostini::CrostiniRegistryService::Observer overrides:
  void OnRegistryUpdated(
      crostini::CrostiniRegistryService* registry_service,
      const std::vector<std::string>& updated_apps,
      const std::vector<std::string>& removed_apps,
      const std::vector<std::string>& inserted_apps) override {
    if (removed_apps.empty())
      owner()->RefreshAppsAndUpdateResultsDeferred();
    else
      owner()->RefreshAppsAndUpdateResults();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(CrostiniDataSource);
};

}  // namespace

AppSearchProvider::AppSearchProvider(Profile* profile,
                                     AppListControllerDelegate* list_controller,
                                     base::Clock* clock,
                                     AppListModelUpdater* model_updater)
    : profile_(profile),
      list_controller_(list_controller),
      model_updater_(model_updater),
      clock_(clock),
      ranker_(std::make_unique<AppSearchResultRanker>(
          profile->GetPath(),
          chromeos::ProfileHelper::IsEphemeralUserProfile(profile))),
      refresh_apps_factory_(this),
      update_results_factory_(this) {
  bool app_service_enabled =
      base::FeatureList::IsEnabled(features::kAppService);
  if (app_service_enabled) {
    data_sources_.emplace_back(
        std::make_unique<AppServiceDataSource>(profile, this));
  } else {
    data_sources_.emplace_back(
        std::make_unique<ExtensionDataSource>(profile, this));
    if (arc::IsArcAllowedForProfile(profile)) {
      data_sources_.emplace_back(
          std::make_unique<ArcDataSource>(profile, this));
    }
    if (crostini::IsCrostiniUIAllowedForProfile(profile)) {
      data_sources_.emplace_back(
          std::make_unique<CrostiniDataSource>(profile, this));
    }
  }
  data_sources_.emplace_back(
      std::make_unique<InternalDataSource>(profile, this, app_service_enabled));
}

AppSearchProvider::~AppSearchProvider() {}

void AppSearchProvider::Start(const base::string16& query) {
  query_ = query;
  const bool show_recommendations = query.empty();
  // Refresh list of apps to ensure we have the latest launch time information.
  // This will also cause the results to update.
  if (show_recommendations || apps_.empty())
    RefreshAppsAndUpdateResults();
  else
    UpdateResults();
}

void AppSearchProvider::Train(const std::string& id) {
  ranker_->Train(id);
}

void AppSearchProvider::RefreshAppsAndUpdateResults() {
  // Clear any pending requests if any.
  refresh_apps_factory_.InvalidateWeakPtrs();

  apps_.clear();
  apps_.reserve(kMinimumReservedAppsContainerCapacity);
  for (auto& data_source : data_sources_)
    data_source->AddApps(&apps_);
  UpdateResults();
}

void AppSearchProvider::RefreshAppsAndUpdateResultsDeferred() {
  // Check if request is pending.
  if (refresh_apps_factory_.HasWeakPtrs())
    return;

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE, base::BindOnce(&AppSearchProvider::RefreshAppsAndUpdateResults,
                                refresh_apps_factory_.GetWeakPtr()));
}

void AppSearchProvider::UpdateRecommendedResults(
    const base::flat_map<std::string, uint16_t>& id_to_app_list_index) {
  SearchProvider::Results new_results;
  std::set<std::string> seen_or_filtered_apps;
  const uint16_t apps_size = apps_.size();
  new_results.reserve(apps_size);
  const auto& ranker_scores = ranker_->Rank();

  for (auto& app : apps_) {
    // Skip apps which cannot be shown as a suggested app.
    if (!app->recommendable())
      continue;

    base::string16 title = app->name();
    if (app->id() == kInternalAppIdContinueReading) {
      if (HasRecommendableForeignTab(profile_, &title, nullptr))
        app->set_searchable_text(title);
      else
        continue;
    }

    std::unique_ptr<AppResult> result =
        app->data_source()->CreateResult(app->id(), list_controller_, true);
    result->SetTitle(title);

    // Set app->relevance based on the following criteria.
    const auto find_in_ranker = ranker_scores.find(app->id());
    const auto find_in_app_list = id_to_app_list_index.find(app->id());
    const base::Time time = app->GetLastActivityTime();

    if (app->id() == kInternalAppIdContinueReading) {
      // Case 1: if it's |kInternalAppIdContinueReading|, set relevance as 1.0
      // (always show it as the first).
      result->set_relevance(1.0);
    } else if (find_in_ranker != ranker_scores.end()) {
      // Case 2: if it's recommended by |ranker_|, set relevance as a score
      // in [0.67, 0.99].
      result->set_relevance(ReRange(find_in_ranker->second, 0.67, 0.99));
    } else if (!time.is_null()) {
      // Case 3: if it has last activity time or install time, set the relevance
      // in [0.34, 0.66] based on the time.
      result->UpdateFromLastLaunchedOrInstalledTime(clock_->Now(), time);
      result->set_relevance(ReRange(result->relevance(), 0.34, 0.66));
    } else if (find_in_app_list != id_to_app_list_index.end()) {
      // Case 4: if it's in the app_list_index, set the relevance in [0.1, 0.33]
      result->set_relevance(
          ReRange(1.0f / (1.0f + find_in_app_list->second), 0.1, 0.33));
    } else {
      // Case 5: otherwise set the relevance as 0.0f;
      result->set_relevance(0.0f);
    }

    MaybeAddResult(&new_results, std::move(result), &seen_or_filtered_apps);
  }

  SwapResults(&new_results);
  update_results_factory_.InvalidateWeakPtrs();
}

void AppSearchProvider::UpdateQueriedResults() {
  SearchProvider::Results new_results;
  std::set<std::string> seen_or_filtered_apps;
  const size_t apps_size = apps_.size();
  new_results.reserve(apps_size);

  const TokenizedString query_terms(query_);
  for (auto& app : apps_) {
    if (!app->searchable())
      continue;

    TokenizedStringMatch match;
    TokenizedString* indexed_name = app->GetTokenizedIndexedName();

    if (match.Calculate(query_terms, *indexed_name)) {
      // Exact matches should be shown even if the threshold isn't reached, e.g.
      // due to a localized name being particularly short.
      if (match.relevance() <= app->relevance_threshold() &&
          !base::EqualsCaseInsensitiveASCII(query_, app->name()) &&
          !app->MatchSearchableText(query_terms)) {
        continue;
      }
    } else if (!app->MatchSearchableText(query_terms)) {
      continue;
    }

    std::unique_ptr<AppResult> result =
        app->data_source()->CreateResult(app->id(), list_controller_, false);
    result->UpdateFromMatch(*indexed_name, match);
    MaybeAddResult(&new_results, std::move(result), &seen_or_filtered_apps);
  }

  SwapResults(&new_results);
  update_results_factory_.InvalidateWeakPtrs();
}

void AppSearchProvider::UpdateResults() {
  const bool show_recommendations = query_.empty();

  // Presort app based on last active time in order to be able to remove
  // duplicates from results.
  std::sort(apps_.begin(), apps_.end(), App::CompareByLastActivityTime());

  if (show_recommendations) {
    // Get the map of app ids to their position in the app list, and then
    // update results.
    model_updater_->GetIdToAppListIndexMap(
        base::BindOnce(&AppSearchProvider::UpdateRecommendedResults,
                       update_results_factory_.GetWeakPtr()));
  } else {
    UpdateQueriedResults();
  }
}

}  // namespace app_list
