// Copyright 2021 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_UI_ASH_PROJECTOR_PENDING_SCREENCAST_MANAGER_H_
#define CHROME_BROWSER_UI_ASH_PROJECTOR_PENDING_SCREENCAST_MANAGER_H_
#include <map>
#include <memory>
#include "ash/webui/projector_app/projector_app_client.h"
#include "ash/webui/projector_app/projector_xhr_sender.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/ash/extensions/file_manager/scoped_suppress_drive_notifications_for_path.h"
#include "chrome/browser/ui/ash/projector/projector_drivefs_provider.h"
#include "chromeos/ash/components/drivefs/drivefs_host.h"
namespace drivefs {
namespace mojom {
class SyncingStatus;
class DriveError;
} // namespace mojom
} // namespace drivefs
namespace base {
class FilePath;
}
// A callback to notify the change of pending screencasts to
// ProjectorAppClient::Observer. The argument is the set of pending screencasts
// owned by PendingScreencastManager.
using PendingScreencastChangeCallback =
base::RepeatingCallback<void(const ash::PendingScreencastContainerSet&)>;
// A class that handles pending screencast events.
class PendingScreencastManager : drivefs::DriveFsHost::Observer {
public:
explicit PendingScreencastManager(
PendingScreencastChangeCallback pending_screencast_change_callback);
PendingScreencastManager(const PendingScreencastManager&) = delete;
PendingScreencastManager& operator=(const PendingScreencastManager&) = delete;
~PendingScreencastManager() override;
// DriveFsHost::Observer implementation.
using drivefs::DriveFsHost::Observer::GetHost;
void OnUnmounted() override;
void OnSyncingStatusUpdate(
const drivefs::mojom::SyncingStatus& status) override;
void OnError(const drivefs::mojom::DriveError& error) override;
// Returns a list of pending screencast from `pending_screencast_cache_`.
const ash::PendingScreencastContainerSet& GetPendingScreencasts() const;
// Maybe observe the current active profile.
void MaybeSwitchDriveFsObservation();
// Adds `screencast_paths` to `paths_notifications_suppressors_` and
// suppresses notification for these paths if `suppress` is true. Removes
// `screencast_paths` from `paths_notifications_suppressors_` when
// `suppress` is false.
void ToggleFileSyncingNotificationForPaths(
const std::vector<base::FilePath>& screencast_paths,
bool suppress);
// Resets (`is_active` is false) or creates (`is_active` is true) values for
// all keys stored in `paths_notifications_suppressors_`.
void OnAppActiveStatusChanged(bool is_active);
// Test only:
base::TimeTicks last_pending_screencast_change_tick() const {
return last_pending_screencast_change_tick_;
}
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner() {
return blocking_task_runner_;
}
using OnGetFileIdCallback =
base::OnceCallback<void(const base::FilePath& local_file_path,
const std::string& file_id)>;
void SetOnGetFileIdCallbackForTest(OnGetFileIdCallback callback);
using OnGetRequestBodyCallback =
base::OnceCallback<void(const std::string& file_id,
const std::string& request_body)>;
void SetOnGetRequestBodyCallbackForTest(OnGetRequestBodyCallback callback);
void SetProjectorXhrSenderForTest(
std::unique_ptr<ash::ProjectorXhrSender> xhr_sender);
private:
// Updates `pending_screencast_cache_` and notifies pending screencast change.
void OnProcessAndGenerateNewScreencastsFinished(
const base::TimeTicks task_start_tick,
const ash::PendingScreencastContainerSet& screencasts);
// Called when the `event_file` is synced to Drive. Removed completedly synced
// files from `error_syncing_files_` and `syncing_metadata_files_` cached. If
// it is a screencast metadata file, post task to update indexable text.
void OnFileSyncedCompletely(const base::FilePath& event_file);
void OnGetFileId(const base::FilePath& local_file_path,
const std::string& file_id);
// Sends a patch request to patch file metadata. `file_id` is the Drive server
// side file id.
void SendDrivePatchRequest(const std::string& file_id,
const std::string& request_body);
// TODO(b/221902328): Fix the case that user might delete files through file
// app.
// A set that caches current pending screencast.
ash::PendingScreencastContainerSet pending_screencast_cache_;
// A set of files failed to upload to Drive.
std::set<base::FilePath> error_syncing_files_;
// A set of syncing screencast metadata files, which have ".projector"
// extension. This set is used to track which metadata files are being
// uploaded so we only update the indexable text once. File is removed from
// the set after updating indexable text completed.
std::set<base::FilePath> syncing_metadata_files_;
// A callback to notify pending screencast status change.
PendingScreencastChangeCallback pending_screencast_change_callback_;
// A blocking task runner for file IO operations.
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
// The time tick when last `pending_screencast_change_callback_` was called.
// Could be null if last `pending_screencast_change_callback_` was called with
// empty screencasts set or no `pending_screencast_change_callback_` invoked
// in the current ChromeOS session.
base::TimeTicks last_pending_screencast_change_tick_;
// Not available if user never uploads a screencast during current ChromeOS
// session.
std::unique_ptr<ash::ProjectorXhrSender> xhr_sender_;
// Updates indexable text containing a lot of async steps. These callbacks are
// used in tests to verify the task quit correctly while error happens.
OnGetRequestBodyCallback on_get_request_body_;
OnGetFileIdCallback on_get_file_id_callback_;
ProjectorDriveFsProvider drive_helper_;
// A map to store `file_manager::ScopedSuppressDriveNotificationsForPath`. The
// entries get created/destroyed on calling
// `ToggleFileSyncingNotificationForPaths`, or when files whose paths are
// stored in this map are uploaded completely. All unique pointers get reset
// on app UI destroyed and re-created on app UI active.
std::map<
base::FilePath,
std::unique_ptr<file_manager::ScopedSuppressDriveNotificationsForPath>>
paths_notifications_suppressors_;
base::WeakPtrFactory<PendingScreencastManager> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_ASH_PROJECTOR_PENDING_SCREENCAST_MANAGER_H_