chromium/chrome/browser/ash/app_list/search/app_search_data_source.h

// 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.

#ifndef CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_SEARCH_DATA_SOURCE_H_
#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_SEARCH_DATA_SOURCE_H_

#include <memory>
#include <string>
#include <vector>

#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/apps/app_service/app_service_proxy_forward.h"
#include "chrome/browser/ash/app_list/search/search_provider.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/icon_cache.h"

class AppListControllerDelegate;
class Profile;

namespace apps {
class AppUpdate;
}  // namespace apps

namespace base {
class Clock;
}

namespace app_list {

class AppResult;

// Aggregates and tracks information about installed apps relevant to launcher
// search. It's an abstraction on top of AppService that app search providers
// can use to generate search results for different queries.
class AppSearchDataSource : public apps::AppRegistryCache::Observer {
 public:
  AppSearchDataSource(Profile* profile,
                      AppListControllerDelegate* list_controller,
                      base::Clock* clock);

  AppSearchDataSource(const AppSearchDataSource&) = delete;
  AppSearchDataSource& operator=(const AppSearchDataSource&) = delete;

  ~AppSearchDataSource() override;

  // Registers a callback to be run when the set of cached apps changes. Search
  // providers can use this to update their ppublished results when apps get
  // updated.
  // Returns a subscription which keeps `callback` registered. To unregister the
  // callback, let the subscription object go out of scope.
  base::CallbackListSubscription SubscribeToAppUpdates(
      const base::RepeatingClosure& callback);

  // Immediately update the app info cache if it's not fresh.
  void RefreshIfNeeded();

  // Returns app recommendations (zero-state search results).
  SearchProvider::Results GetRecommendations();

  // Returns app results that match `query`. It uses exact matching algorithm.
  SearchProvider::Results GetExactMatches(const std::u16string& query);

  // Returns app results that match `query`. It uses fuzzy matching algorithm.
  SearchProvider::Results GetFuzzyMatches(const std::u16string& query);

  // apps::AppRegistryCache::Observer overrides:
  void OnAppUpdate(const apps::AppUpdate& update) override;
  void OnAppRegistryCacheWillBeDestroyed(
      apps::AppRegistryCache* cache) override;

 private:
  class AppInfo;

  std::unique_ptr<AppResult> CreateResult(const std::string& app_id,
                                          bool is_recommended);

  // Updates cached app info to match current app states in app service.
  void Refresh();

  // Schedules asynchronous `Refresh()` if one is not already scheduled.
  // Called when apps get updated. The refresh is asynchronous to avoid
  // repeatedly calling `Refresh()` during batch updates in app service.
  void ScheduleRefresh();

  const raw_ptr<Profile, DanglingUntriaged> profile_;
  const raw_ptr<AppListControllerDelegate> list_controller_;
  const raw_ptr<base::Clock> clock_;

  base::CallbackListSubscription foreign_session_updated_subscription_;

  // The AppSearchDataSource seems like one (but not the only) good place to
  // add an App Service icon caching wrapper, because (1) the AppSearchProvider
  // destroys and creates multiple search results in a short period of time,
  // while the user is typing, so will clearly benefit from a cache, and (2)
  // there is an obvious point in time when the cache can be emptied: the user
  // will obviously stop typing (so stop triggering LoadIcon requests) when the
  // search box view closes.
  //
  // There are reasons to have more than one icon caching layer. See the
  // comments for the apps::IconCache::GarbageCollectionPolicy enum.
  apps::IconCache icon_cache_;

  std::vector<std::unique_ptr<AppInfo>> apps_;

  base::RepeatingClosureList app_updates_callback_list_;

  base::ScopedObservation<apps::AppRegistryCache,
                          apps::AppRegistryCache::Observer>
      app_registry_cache_observer_{this};

  // Weak ptr factory for `ScheduleRefresh()` tasks - used to track and easily
  // cancel scheduled tasks.
  base::WeakPtrFactory<AppSearchDataSource> refresh_apps_factory_{this};
};

}  // namespace app_list

#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_SEARCH_DATA_SOURCE_H_