Commit 53d1a583 authored by Qiang Xu's avatar Qiang Xu Committed by Commit Bot

arc: introduce searching app shortcuts in launcher

changes:
- Add #enable-app-shortcut-search flag and develop behind it.
- Chrome side framework to support searching app shortcuts.
- Reuse GetAppShortcutItems mojo API. When specified |package_name| is empty, it
  is aimed on global query.

Video demo:
https://drive.google.com/file/d/14y70Bn0gFrZqmqJtsCS8xPLUEC0twFwh/view?usp=sharing
https://drive.google.com/file/d/1LUyzoX0dLpy3rkAx420oqznZEO9Lyyww/view?usp=sharing

Bug: 842947
Test: manual test with Android change
Change-Id: I8d6f62f12d215d464815dd4ff6c31c1e6af9e2c5
Reviewed-on: https://chromium-review.googlesource.com/1058681
Commit-Queue: Qiang Xu <warx@google.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561570}
parent 894661c0
......@@ -13,6 +13,8 @@ namespace features {
const base::Feature kEnableAnswerCard{"EnableAnswerCard",
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kEnableAppShortcutSearch{"EnableAppShortcutSearch",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnableBackgroundBlur{"EnableBackgroundBlur",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnablePlayStoreAppSearch{"EnablePlayStoreAppSearch",
......@@ -27,6 +29,10 @@ bool IsAnswerCardEnabled() {
return base::FeatureList::IsEnabled(kEnableAnswerCard);
}
bool IsAppShortcutSearchEnabled() {
return base::FeatureList::IsEnabled(kEnableAppShortcutSearch);
}
bool IsBackgroundBlurEnabled() {
return base::FeatureList::IsEnabled(kEnableBackgroundBlur);
}
......
......@@ -21,6 +21,9 @@ namespace features {
// Enables the answer card in the app list.
ASH_PUBLIC_EXPORT extern const base::Feature kEnableAnswerCard;
// Enables app shortcuts search.
ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppShortcutSearch;
// Enables background blur for the app list, lock screen, and tab switcher, also
// enables the AppsGridView mask layer. In this mode, slower devices may have
// choppier app list animations. crbug.com/765292.
......@@ -38,6 +41,7 @@ ASH_PUBLIC_EXPORT extern const base::Feature kEnableHomeLauncher;
ASH_PUBLIC_EXPORT extern const base::Feature kEnableSettingsShortcutSearch;
bool ASH_PUBLIC_EXPORT IsAnswerCardEnabled();
bool ASH_PUBLIC_EXPORT IsAppShortcutSearchEnabled();
bool ASH_PUBLIC_EXPORT IsBackgroundBlurEnabled();
bool ASH_PUBLIC_EXPORT IsPlayStoreAppSearchEnabled();
bool ASH_PUBLIC_EXPORT IsHomeLauncherEnabled();
......
......@@ -3887,6 +3887,13 @@ const FeatureEntry kFeatureEntries[] = {
ORIGIN_LIST_VALUE_TYPE(switches::kUnsafelyTreatInsecureOriginAsSecure,
"")},
#if defined(OS_CHROMEOS)
{"enable-app-shortcut-search",
flag_descriptions::kEnableAppShortcutSearchName,
flag_descriptions::kEnableAppShortcutSearchDescription, kOsCrOS,
FEATURE_VALUE_TYPE(app_list::features::kEnableAppShortcutSearch)},
#endif // OS_CHROMEOS
// NOTE: Adding a new flag requires adding a corresponding entry to enum
// "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
// Histograms" in tools/metrics/histograms/README.md (run the
......
......@@ -2794,6 +2794,11 @@ const char kDisableTabletSplitViewName[] = "Disable split view in Tablet mode";
const char kDisableTabletSplitViewDescription[] =
"Disable split view for Chrome OS tablet mode.";
const char kEnableAppShortcutSearchName[] =
"Enable app shortcut search in launcher";
const char kEnableAppShortcutSearchDescription[] =
"Enables app shortcut search in launcher";
const char kEnableBackgroundBlurName[] = "Enable background blur.";
const char kEnableBackgroundBlurDescription[] =
"Enables background blur for the Peeking Launcher and Tab Switcher.";
......@@ -2872,10 +2877,6 @@ const char kEnableZipArchiverPackerName[] = "ZIP archiver - Packer";
const char kEnableZipArchiverPackerDescription[] =
"Enable the ability to archive files on Drive in the Files app";
const char kZipArchiverUnpackerName[] = "ZIP archiver - Unpacker";
const char kZipArchiverUnpackerDescription[] =
"Enable or disable the ability to unpack archives in incognito mode";
const char kEolNotificationName[] = "Disable Device End of Life notification.";
const char kEolNotificationDescription[] =
"Disable Notifcation when Device is End of Life.";
......@@ -3106,6 +3107,10 @@ const char kWakeOnPacketsName[] = "Wake On Packets";
const char kWakeOnPacketsDescription[] =
"Enables waking the device based on the receipt of some network packets.";
const char kZipArchiverUnpackerName[] = "ZIP archiver - Unpacker";
const char kZipArchiverUnpackerDescription[] =
"Enable or disable the ability to unpack archives in incognito mode";
#endif // defined(OS_CHROMEOS)
// Random platform combinations -----------------------------------------------
......
......@@ -1718,6 +1718,9 @@ extern const char kDisableTabletAutohideTitlebarsDescription[];
extern const char kDisableTabletSplitViewName[];
extern const char kDisableTabletSplitViewDescription[];
extern const char kEnableAppShortcutSearchName[];
extern const char kEnableAppShortcutSearchDescription[];
extern const char kEnableBackgroundBlurName[];
extern const char kEnableBackgroundBlurDescription[];
......
......@@ -3529,6 +3529,10 @@ split_static_library("ui") {
"app_list/search/arc/arc_app_data_search_provider.h",
"app_list/search/arc/arc_app_data_search_result.cc",
"app_list/search/arc/arc_app_data_search_result.h",
"app_list/search/arc/arc_app_shortcut_search_result.cc",
"app_list/search/arc/arc_app_shortcut_search_result.h",
"app_list/search/arc/arc_app_shortcuts_search_provider.cc",
"app_list/search/arc/arc_app_shortcuts_search_provider.h",
"app_list/search/arc/arc_playstore_search_provider.cc",
"app_list/search/arc/arc_playstore_search_provider.h",
"app_list/search/arc/arc_playstore_search_result.cc",
......
// Copyright 2018 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/arc/arc_app_shortcut_search_result.h"
#include <string>
#include <utility>
#include "ash/public/cpp/app_list/app_list_constants.h"
#include "ash/public/cpp/app_list/app_list_types.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/arc/icon_decode_request.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/app_list_controller_delegate.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 "ui/gfx/image/image_skia_operations.h"
namespace app_list {
namespace {
constexpr char kAppShortcutSearchPrefix[] = "appshortcutsearch://";
} // namespace
ArcAppShortcutSearchResult::ArcAppShortcutSearchResult(
arc::mojom::AppShortcutItemPtr data,
Profile* profile,
AppListControllerDelegate* list_controller)
: data_(std::move(data)),
profile_(profile),
list_controller_(list_controller) {
SetTitle(base::UTF8ToUTF16(data_->short_label));
set_id(kAppShortcutSearchPrefix + GetAppId() + "/" + data_->shortcut_id);
SetDisplayType(ash::SearchResultDisplayType::kTile);
icon_decode_request_ = std::make_unique<arc::IconDecodeRequest>(
base::BindOnce(&ArcAppShortcutSearchResult::SetIcon,
base::Unretained(this)),
kGridIconDimension);
icon_decode_request_->StartWithOptions(data_->icon_png);
badge_icon_loader_ =
std::make_unique<ArcAppIconLoader>(profile_, kGridIconDimension, this);
badge_icon_loader_->FetchImage(GetAppId());
}
ArcAppShortcutSearchResult::~ArcAppShortcutSearchResult() = default;
void ArcAppShortcutSearchResult::Open(int event_flags) {
arc::LaunchAppShortcutItem(profile_, GetAppId(), data_->shortcut_id,
list_controller_->GetAppListDisplayId());
}
void ArcAppShortcutSearchResult::OnAppImageUpdated(
const std::string& app_id,
const gfx::ImageSkia& image) {
SetBadgeIcon(gfx::ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST,
gfx::Size(kAppBadgeIconSize, kAppBadgeIconSize)));
}
std::string ArcAppShortcutSearchResult::GetAppId() const {
if (!data_->package_name)
return std::string();
const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
DCHECK(arc_prefs);
return arc_prefs->GetAppIdByPackageName(data_->package_name.value());
}
} // namespace app_list
// Copyright 2018 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.
#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUT_SEARCH_RESULT_H_
#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUT_SEARCH_RESULT_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "chrome/browser/ui/app_icon_loader_delegate.h"
#include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
#include "chrome/browser/ui/app_list/search/chrome_search_result.h"
#include "components/arc/common/app.mojom.h"
#include "ui/gfx/image/image_skia.h"
class AppListControllerDelegate;
class Profile;
namespace arc {
class IconDecodeRequest;
} // namespace arc
namespace app_list {
class ArcAppShortcutSearchResult : public ChromeSearchResult,
public AppIconLoaderDelegate {
public:
ArcAppShortcutSearchResult(arc::mojom::AppShortcutItemPtr data,
Profile* profile,
AppListControllerDelegate* list_controller);
~ArcAppShortcutSearchResult() override;
// ChromeSearchResult:
void Open(int event_flags) override;
private:
// AppIconLoaderDelegate:
void OnAppImageUpdated(const std::string& app_id,
const gfx::ImageSkia& image) override;
// Gets app id of the app that publishes this app shortcut.
std::string GetAppId() const;
arc::mojom::AppShortcutItemPtr data_;
std::unique_ptr<arc::IconDecodeRequest> icon_decode_request_;
std::unique_ptr<ArcAppIconLoader> badge_icon_loader_;
Profile* const profile_; // Owned by ProfileInfo.
AppListControllerDelegate* const list_controller_; // Owned by AppListClient.
DISALLOW_COPY_AND_ASSIGN(ArcAppShortcutSearchResult);
};
} // namespace app_list
#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUT_SEARCH_RESULT_H_
// Copyright 2018 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/arc/arc_app_shortcuts_search_provider.h"
#include <memory>
#include <utility>
#include "base/i18n/string_search.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service_manager.h"
namespace app_list {
ArcAppShortcutsSearchProvider::ArcAppShortcutsSearchProvider(
Profile* profile,
AppListControllerDelegate* list_controller)
: profile_(profile),
list_controller_(list_controller),
weak_ptr_factory_(this) {}
ArcAppShortcutsSearchProvider::~ArcAppShortcutsSearchProvider() = default;
void ArcAppShortcutsSearchProvider::Start(const base::string16& query) {
arc::mojom::AppInstance* app_instance =
arc::ArcServiceManager::Get()
? ARC_GET_INSTANCE_FOR_METHOD(
arc::ArcServiceManager::Get()->arc_bridge_service()->app(),
GetAppShortcutItems)
: nullptr;
if (!app_instance || query.empty()) {
ClearResults();
return;
}
// Invalidate the weak ptr to prevent previous callback run.
weak_ptr_factory_.InvalidateWeakPtrs();
// Pass empty package name to do query for all packages.
app_instance->GetAppShortcutItems(
std::string(),
base::BindOnce(&ArcAppShortcutsSearchProvider::OnGetAppShortcutItems,
weak_ptr_factory_.GetWeakPtr(), query));
}
void ArcAppShortcutsSearchProvider::OnGetAppShortcutItems(
const base::string16& query,
std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items) {
SearchProvider::Results search_results;
base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents finder(query);
for (auto& item : shortcut_items) {
// TODO(warx): Use tokenized string match.
const base::string16& short_label = base::UTF8ToUTF16(item->short_label);
if (!finder.Search(short_label, nullptr, nullptr))
continue;
search_results.emplace_back(std::make_unique<ArcAppShortcutSearchResult>(
std::move(item), profile_, list_controller_));
DCHECK(!short_label.empty());
search_results.back()->set_relevance(query.length() / short_label.length());
}
SwapResults(&search_results);
}
} // namespace app_list
// Copyright 2018 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.
#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUTS_SEARCH_PROVIDER_H_
#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUTS_SEARCH_PROVIDER_H_
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "chrome/browser/ui/app_list/search/search_provider.h"
#include "components/arc/common/app.mojom.h"
class AppListControllerDelegate;
class Profile;
namespace app_list {
class ArcAppShortcutsSearchProvider : public SearchProvider {
public:
ArcAppShortcutsSearchProvider(Profile* profile,
AppListControllerDelegate* list_controller);
~ArcAppShortcutsSearchProvider() override;
// SearchProvider:
void Start(const base::string16& query) override;
private:
void OnGetAppShortcutItems(
const base::string16& query,
std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items);
Profile* const profile_; // Owned by ProfileInfo.
AppListControllerDelegate* const list_controller_; // Owned by AppListClient.
base::WeakPtrFactory<ArcAppShortcutsSearchProvider> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcAppShortcutsSearchProvider);
};
} // namespace app_list
#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUTS_SEARCH_PROVIDER_H_
// Copyright 2018 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/arc/arc_app_shortcuts_search_provider.h"
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/arc/icon_decode_request.h"
#include "chrome/browser/ui/app_list/app_list_test_util.h"
#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
#include "chrome/browser/ui/app_list/search/chrome_search_result.h"
#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
namespace app_list {
class ArcAppShortcutsSearchProviderTest : public AppListTestBase {
protected:
ArcAppShortcutsSearchProviderTest() = default;
~ArcAppShortcutsSearchProviderTest() override = default;
// AppListTestBase:
void SetUp() override {
AppListTestBase::SetUp();
arc_test_.SetUp(profile());
controller_ = std::make_unique<test::TestAppListControllerDelegate>();
}
void TearDown() override {
controller_.reset();
arc_test_.TearDown();
AppListTestBase::TearDown();
}
std::unique_ptr<test::TestAppListControllerDelegate> controller_;
ArcAppTest arc_test_;
private:
DISALLOW_COPY_AND_ASSIGN(ArcAppShortcutsSearchProviderTest);
};
TEST_F(ArcAppShortcutsSearchProviderTest, Basic) {
constexpr char kQuery[] = "shortlabel";
auto provider = std::make_unique<ArcAppShortcutsSearchProvider>(
profile(), controller_.get());
EXPECT_TRUE(provider->results().empty());
arc::IconDecodeRequest::DisableSafeDecodingForTesting();
provider->Start(base::UTF8ToUTF16(kQuery));
const auto& results = provider->results();
EXPECT_EQ(3u, results.size());
// Verify search results.
for (size_t i = 0; i < results.size(); ++i) {
EXPECT_EQ(base::StringPrintf("ShortLabel %zu", i),
base::UTF16ToUTF8(results[i]->title()));
EXPECT_EQ(ash::SearchResultDisplayType::kTile, results[i]->display_type());
}
}
} // namespace app_list
......@@ -16,6 +16,7 @@
#include "chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.h"
#include "chrome/browser/ui/app_list/search/app_search_provider.h"
#include "chrome/browser/ui/app_list/search/arc/arc_app_data_search_provider.h"
#include "chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h"
#include "chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h"
#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h"
#include "chrome/browser/ui/app_list/search/mixer.h"
......@@ -43,7 +44,9 @@ constexpr size_t kMaxLauncherSearchResults = 2;
// TODO(753947): Consider progressive algorithm of getting Play Store results.
constexpr size_t kMaxPlayStoreResults = 12;
// TODO(warx): Need UX spec.
constexpr size_t kMaxAppDataResults = 6;
constexpr size_t kMaxAppShortcutResults = 4;
// TODO(wutao): Need UX spec.
constexpr size_t kMaxSettingsShortcutResults = 6;
......@@ -131,6 +134,14 @@ std::unique_ptr<SearchController> CreateSearchController(
std::make_unique<SettingsShortcutProvider>(profile));
}
if (features::IsAppShortcutSearchEnabled()) {
size_t app_shortcut_group_id =
controller->AddGroup(kMaxAppShortcutResults, 1.0, kBoostOfApps);
controller->AddProvider(app_shortcut_group_id,
std::make_unique<ArcAppShortcutsSearchProvider>(
profile, list_controller));
}
return controller;
}
......
......@@ -4405,6 +4405,7 @@ test("unit_tests") {
"../browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc",
"../browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc",
"../browser/ui/app_list/search/arc/arc_app_data_search_provider_unittest.cc",
"../browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc",
"../browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc",
"../browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc",
"../browser/ui/app_list/search/settings_shortcut/settings_shortcut_provider_unittest.cc",
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Next MinVersion: 31
// Next MinVersion: 32
module arc.mojom;
......@@ -167,6 +167,9 @@ struct AppShortcutItem {
// The icon for this shortcut, decoded in the utility process.
array<uint8> icon_png;
// The package name of the publisher app.
[MinVersion=31] string? package_name;
};
// Next method ID: 18
......@@ -340,7 +343,8 @@ interface AppInstance {
// happens) is ignored, and uninstall option should appear in the UI.
[MinVersion=2] UninstallPackage@5(string package_name);
// Sends a request to ARC to get app shortcuts for app with |package_name|.
// Sends a request to ARC to get app shortcuts for app with |package_name|. If
// |package_name| is empty, it will query for all launchable activities.
[MinVersion=29] GetAppShortcutItems@23(string package_name) =>
(array<AppShortcutItem> shortcut_items);
......
......@@ -389,7 +389,7 @@ void FakeAppInstance::GetIcingGlobalQueryResults(
}
void FakeAppInstance::GetAppShortcutItems(
const std::string& pacakge_name,
const std::string& package_name,
GetAppShortcutItemsCallback callback) {
// Fake app shortcut items results.
std::vector<mojom::AppShortcutItemPtr> fake_app_shortcut_items;
......@@ -403,7 +403,8 @@ void FakeAppInstance::GetAppShortcutItems(
for (int i = 0; i < 3; ++i) {
fake_app_shortcut_items.push_back(mojom::AppShortcutItem::New(
base::StringPrintf("ShortcutId %d", i),
base::StringPrintf("ShortLabel %d", i), fake_icon_png_data));
base::StringPrintf("ShortLabel %d", i), fake_icon_png_data,
package_name.empty() ? "FakeAppPackageName" : package_name));
}
std::move(callback).Run(std::move(fake_app_shortcut_items));
......
......@@ -131,7 +131,7 @@ class FakeAppInstance : public mojom::AppInstance {
const std::string& query,
int32_t max_results,
GetIcingGlobalQueryResultsCallback callback) override;
void GetAppShortcutItems(const std::string& pacakge_name,
void GetAppShortcutItems(const std::string& package_name,
GetAppShortcutItemsCallback callback) override;
void StartPaiFlow() override;
......
......@@ -27956,6 +27956,7 @@ from previous Chrome versions.
<int value="986796748" label="AccountConsistency:enabled"/>
<int value="988981463" label="ImageCaptureAPI:enabled"/>
<int value="989062160" label="ModuleScriptsImportMetaUrl:enabled"/>
<int value="996643125" label="EnableAppShortcutSearch:disabled"/>
<int value="996701528" label="SystemKeyboardLock:enabled"/>
<int value="996797157" label="V8ContextSnapshot:enabled"/>
<int value="1000587036" label="OfflinePagesDescriptiveFailStatus:disabled"/>
......@@ -28469,6 +28470,7 @@ from previous Chrome versions.
<int value="2098907258" label="UseSurfaceLayerForVideo:disabled"/>
<int value="2101151142" label="disable-direct-write"/>
<int value="2104788328" label="use-winrt-midi-api"/>
<int value="2113804526" label="EnableAppShortcutSearch:enabled"/>
<int value="2119964154" label="enable-download-resumption"/>
<int value="2121056855" label="IncreaseInputAudioBufferSize:disabled"/>
<int value="2121550859" label="PreferHtmlOverPlugins:enabled"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment