blob: cd9d54a8d216ad06dcce2fde6d7940a8e714286d [file] [log] [blame]
// Copyright 2021 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/files/drive_search_provider.h"
#include <cmath>
#include "ash/public/cpp/app_list/app_list_types.h"
#include "base/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ash/drive/drive_integration_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/search/files/file_result.h"
#include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
namespace app_list {
namespace {
using chromeos::string_matching::TokenizedString;
constexpr char kDriveSearchSchema[] = "drive_search://";
constexpr int kMaxResults = 10;
// Outcome of a call to DriveSearchProvider::Start. These values persist to
// logs. Entries should not be renumbered and numeric values should never be
// reused.
enum class Status {
kOk = 0,
kDriveUnavailable = 1,
kFileError = 2,
kMaxValue = kFileError,
};
void LogStatus(Status status) {
UMA_HISTOGRAM_ENUMERATION("Apps.AppList.DriveSearchProvider.Status", status);
}
} // namespace
DriveSearchProvider::DriveSearchProvider(Profile* profile)
: profile_(profile),
drive_service_(
drive::DriveIntegrationServiceFactory::GetForProfile(profile)) {
DCHECK(profile_);
DCHECK(drive_service_);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
DriveSearchProvider::~DriveSearchProvider() = default;
ash::AppListSearchResultType DriveSearchProvider::ResultType() {
return ash::AppListSearchResultType::kDriveSearch;
}
void DriveSearchProvider::Start(const std::u16string& query) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
query_start_time_ = base::TimeTicks::Now();
// Clear results and cancel any outgoing requests.
ClearResultsSilently();
weak_factory_.InvalidateWeakPtrs();
// This provider does not handle zero-state.
if (query.empty())
return;
if (!drive_service_ || !drive_service_->is_enabled()) {
LogStatus(Status::kDriveUnavailable);
return;
}
last_query_ = query;
last_tokenized_query_.emplace(query, TokenizedString::Mode::kWords);
// New scores will be assigned for sorting purposes so use the default
// SortField. The SortDirection does nothing in this case.
drive_service_->SearchDriveByFileName(
base::UTF16ToUTF8(query), kMaxResults,
drivefs::mojom::QueryParameters::SortField::kNone,
drivefs::mojom::QueryParameters::SortDirection::kAscending,
drivefs::mojom::QueryParameters::QuerySource::kLocalOnly,
base::BindOnce(&DriveSearchProvider::SetSearchResults,
weak_factory_.GetWeakPtr()));
}
void DriveSearchProvider::SetSearchResults(
drive::FileError error,
std::vector<drivefs::mojom::QueryItemPtr> items) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (error != drive::FileError::FILE_ERROR_OK) {
LogStatus(Status::kFileError);
return;
}
SearchProvider::Results results;
for (const auto& item : items) {
if (item->metadata->type ==
drivefs::mojom::FileMetadata::Type::kDirectory) {
const auto type = item->metadata->shared
? FileResult::Type::kSharedDirectory
: FileResult::Type::kDirectory;
results.emplace_back(MakeResult(item->path, type));
} else {
results.emplace_back(MakeResult(item->path, FileResult::Type::kFile));
}
}
SwapResults(&results);
LogStatus(Status::kOk);
UMA_HISTOGRAM_TIMES("Apps.AppList.DriveSearchProvider.Latency",
base::TimeTicks::Now() - query_start_time_);
}
std::unique_ptr<FileResult> DriveSearchProvider::MakeResult(
const base::FilePath& path,
FileResult::Type type) {
// Strip leading separators so that the path can be reparented.
// TODO(crbug.com/1154513): Remove this step once the drive backend returns
// results in relative path format.
DCHECK(!path.value().empty());
const base::FilePath relative_path =
!path.value().empty() && base::FilePath::IsSeparator(path.value()[0])
? base::FilePath(path.value().substr(1))
: path;
// Reparent the file path into the user's DriveFS mount.
DCHECK(!relative_path.IsAbsolute());
const base::FilePath& reparented_path =
drive_service_->GetMountPointPath().Append(relative_path.value());
const double relevance =
FileResult::CalculateRelevance(last_tokenized_query_, reparented_path);
return std::make_unique<FileResult>(
kDriveSearchSchema, reparented_path,
ash::AppListSearchResultType::kDriveSearch, last_query_, relevance, type,
profile_);
}
} // namespace app_list