0

arc: add LaunchAppShortcutItem API and apply in ArcAppContextMenu

Changes:
Design doc: go/arc-app-shortcuts

Launch app shortcut has to be called by Android's LauncherApps'
startShortcut API. Thus provide a mojo API to do the work.

Bug: 803291
Test: tested on device with ag/3997639
Change-Id: Idece1c44836a9e43932b700b81d128883c15666d
Reviewed-on: https://chromium-review.googlesource.com/1041574
Commit-Queue: Qiang Xu <warx@google.com>
Reviewed-by: Luis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: Yury Khmel <khmel@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556106}
This commit is contained in:
Qiang Xu
2018-05-04 17:45:11 +00:00
committed by Commit Bot
parent 5cea78b92f
commit 0148a64a2c
8 changed files with 111 additions and 27 deletions

@@ -480,6 +480,11 @@ TEST_P(AppContextMenuTest, ArcMenu) {
EXPECT_EQ(base::StringPrintf("ShortLabel %d", i), EXPECT_EQ(base::StringPrintf("ShortLabel %d", i),
base::UTF16ToUTF8(menu->GetLabelAt(i + index))); base::UTF16ToUTF8(menu->GetLabelAt(i + index)));
} }
// Test launching app shortcut item.
EXPECT_EQ(0, arc_test.app_instance()->launch_app_shortcut_item_count());
menu->ActivatedAt(menu->GetItemCount() - 1);
EXPECT_EQ(1, arc_test.app_instance()->launch_app_shortcut_item_count());
} }
// This makes all apps non-ready. // This makes all apps non-ready.

@@ -88,18 +88,17 @@ bool ArcAppContextMenu::IsCommandIdEnabled(int command_id) const {
} }
void ArcAppContextMenu::ExecuteCommand(int command_id, int event_flags) { void ArcAppContextMenu::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) { if (command_id == LAUNCH_NEW) {
case LAUNCH_NEW: delegate()->ExecuteLaunchCommand(event_flags);
delegate()->ExecuteLaunchCommand(event_flags); } else if (command_id == UNINSTALL) {
break; arc::ShowArcAppUninstallDialog(profile(), controller(), app_id());
case UNINSTALL: } else if (command_id == SHOW_APP_INFO) {
arc::ShowArcAppUninstallDialog(profile(), controller(), app_id()); ShowPackageInfo();
break; } else if (command_id >= LAUNCH_APP_SHORTCUT_FIRST &&
case SHOW_APP_INFO: command_id <= LAUNCH_APP_SHORTCUT_LAST) {
ShowPackageInfo(); ExecuteLaunchAppShortcutCommand(command_id);
break; } else {
default: app_list::AppContextMenu::ExecuteCommand(command_id, event_flags);
app_list::AppContextMenu::ExecuteCommand(command_id, event_flags);
} }
} }
@@ -132,17 +131,30 @@ void ArcAppContextMenu::BuildAppShortcutsMenu(
void ArcAppContextMenu::OnGetAppShortcutItems( void ArcAppContextMenu::OnGetAppShortcutItems(
std::unique_ptr<ui::SimpleMenuModel> menu_model, std::unique_ptr<ui::SimpleMenuModel> menu_model,
GetMenuModelCallback callback, GetMenuModelCallback callback,
std::unique_ptr<arc::ArcAppShortcutItems> shortcut_items) { std::unique_ptr<arc::ArcAppShortcutItems> app_shortcut_items) {
if (shortcut_items) { app_shortcut_items_ = std::move(app_shortcut_items);
if (app_shortcut_items_) {
int command_id = LAUNCH_APP_SHORTCUT_FIRST; int command_id = LAUNCH_APP_SHORTCUT_FIRST;
DCHECK_LT(command_id + shortcut_items->size(), LAUNCH_APP_SHORTCUT_LAST); DCHECK_LT(command_id + app_shortcut_items_->size(),
for (const auto& item : *shortcut_items) LAUNCH_APP_SHORTCUT_LAST);
for (const auto& item : *app_shortcut_items_)
menu_model->AddItemWithIcon(command_id++, item.short_label, item.icon); menu_model->AddItemWithIcon(command_id++, item.short_label, item.icon);
} }
std::move(callback).Run(std::move(menu_model)); std::move(callback).Run(std::move(menu_model));
arc_app_shortcuts_request_.reset(); arc_app_shortcuts_request_.reset();
} }
void ArcAppContextMenu::ExecuteLaunchAppShortcutCommand(int command_id) {
DCHECK(command_id >= LAUNCH_APP_SHORTCUT_FIRST &&
command_id <= LAUNCH_APP_SHORTCUT_LAST);
size_t index = command_id - LAUNCH_APP_SHORTCUT_FIRST;
DCHECK(app_shortcut_items_);
DCHECK_LT(index, app_shortcut_items_->size());
arc::LaunchAppShortcutItem(profile(), app_id(),
app_shortcut_items_->at(index).shortcut_id,
controller()->GetAppListDisplayId());
}
void ArcAppContextMenu::ShowPackageInfo() { void ArcAppContextMenu::ShowPackageInfo() {
const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile()); const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile());
DCHECK(arc_prefs); DCHECK(arc_prefs);

@@ -45,10 +45,16 @@ class ArcAppContextMenu : public app_list::AppContextMenu {
void OnGetAppShortcutItems( void OnGetAppShortcutItems(
std::unique_ptr<ui::SimpleMenuModel> menu_model, std::unique_ptr<ui::SimpleMenuModel> menu_model,
GetMenuModelCallback callback, GetMenuModelCallback callback,
std::unique_ptr<arc::ArcAppShortcutItems> shortcut_items); std::unique_ptr<arc::ArcAppShortcutItems> app_shortcut_items);
// Executes launching app shortcut item.
void ExecuteLaunchAppShortcutCommand(int command_id);
void ShowPackageInfo(); void ShowPackageInfo();
// Caches the app shortcut items from OnGetAppShortcutItems().
std::unique_ptr<arc::ArcAppShortcutItems> app_shortcut_items_;
// Handles requesting app shortcuts from Android. // Handles requesting app shortcuts from Android.
std::unique_ptr<arc::ArcAppShortcutsRequest> arc_app_shortcuts_request_; std::unique_ptr<arc::ArcAppShortcutsRequest> arc_app_shortcuts_request_;

@@ -150,6 +150,15 @@ bool Launch(content::BrowserContext* context,
return true; return true;
} }
// Returns primary display id if |display_id| is invalid.
int64_t GetValidDisplayId(int64_t display_id) {
if (display_id != display::kInvalidDisplayId)
return display_id;
if (auto* screen = display::Screen::GetScreen())
return screen->GetPrimaryDisplay().id();
return display::kInvalidDisplayId;
}
} // namespace } // namespace
const char kPlayStoreAppId[] = "cnbgggchhmkkdmeppjobngjoejnihlei"; const char kPlayStoreAppId[] = "cnbgggchhmkkdmeppjobngjoejnihlei";
@@ -184,7 +193,8 @@ bool LaunchPlayStoreWithUrl(const std::string& url) {
arc::mojom::IntentHelperInstance* instance = arc::mojom::IntentHelperInstance* instance =
GET_INTENT_HELPER_INSTANCE(HandleUrl); GET_INTENT_HELPER_INSTANCE(HandleUrl);
if (!instance) { if (!instance) {
VLOG(1) << "Cannot find a mojo instance, ARC is unreachable"; VLOG(1) << "Cannot find a mojo instance, ARC is unreachable or mojom"
<< " version mismatch";
return false; return false;
} }
instance->HandleUrl(url, kPlayStorePackage); instance->HandleUrl(url, kPlayStorePackage);
@@ -212,11 +222,6 @@ bool LaunchAppWithIntent(content::BrowserContext* context,
int64_t display_id) { int64_t display_id) {
DCHECK(!launch_intent.has_value() || !launch_intent->empty()); DCHECK(!launch_intent.has_value() || !launch_intent->empty());
if (display_id == display::kInvalidDisplayId) {
if (auto* screen = display::Screen::GetScreen())
display_id = screen->GetPrimaryDisplay().id();
}
Profile* const profile = Profile::FromBrowserContext(context); Profile* const profile = Profile::FromBrowserContext(context);
// Even when ARC is not allowed for the profile, ARC apps may still show up // Even when ARC is not allowed for the profile, ARC apps may still show up
@@ -273,7 +278,7 @@ bool LaunchAppWithIntent(content::BrowserContext* context,
DCHECK(chrome_controller || !ash::Shell::HasInstance()); DCHECK(chrome_controller || !ash::Shell::HasInstance());
if (chrome_controller) { if (chrome_controller) {
chrome_controller->GetArcDeferredLauncher()->RegisterDeferredLaunch( chrome_controller->GetArcDeferredLauncher()->RegisterDeferredLaunch(
app_id, event_flags, display_id); app_id, event_flags, GetValidDisplayId(display_id));
// On some boards, ARC is booted with a restricted set of resources by // On some boards, ARC is booted with a restricted set of resources by
// default to avoid slowing down Chrome's user session restoration. // default to avoid slowing down Chrome's user session restoration.
@@ -286,7 +291,37 @@ bool LaunchAppWithIntent(content::BrowserContext* context,
} }
arc::ArcBootPhaseMonitorBridge::RecordFirstAppLaunchDelayUMA(context); arc::ArcBootPhaseMonitorBridge::RecordFirstAppLaunchDelayUMA(context);
return Launch(context, app_id, launch_intent, event_flags, display_id); return Launch(context, app_id, launch_intent, event_flags,
GetValidDisplayId(display_id));
}
bool LaunchAppShortcutItem(content::BrowserContext* context,
const std::string& app_id,
const std::string& shortcut_id,
int64_t display_id) {
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
ArcAppListPrefs::Get(context)->GetApp(app_id);
if (!app_info) {
LOG(ERROR) << "App " << app_id << " is not available.";
return false;
}
mojom::AppInstance* app_instance =
ArcServiceManager::Get()
? ARC_GET_INSTANCE_FOR_METHOD(
ArcServiceManager::Get()->arc_bridge_service()->app(),
LaunchAppShortcutItem)
: nullptr;
if (!app_instance) {
LOG(ERROR) << "Cannot find a mojo instance, ARC is unreachable or mojom"
<< " version mismatch.";
return false;
}
app_instance->LaunchAppShortcutItem(app_info->package_name, shortcut_id,
GetValidDisplayId(display_id));
return true;
} }
bool LaunchSettingsAppActivity(content::BrowserContext* context, bool LaunchSettingsAppActivity(content::BrowserContext* context,

@@ -109,6 +109,12 @@ bool LaunchAppWithIntent(content::BrowserContext* context,
int event_flags, int event_flags,
int64_t display_id); int64_t display_id);
// Launches App Shortcut that was published by Android's ShortcutManager.
bool LaunchAppShortcutItem(content::BrowserContext* context,
const std::string& app_id,
const std::string& shortcut_id,
int64_t display_id);
// Launches a specific activity within Settings app on ARC. // Launches a specific activity within Settings app on ARC.
bool LaunchSettingsAppActivity(content::BrowserContext* context, bool LaunchSettingsAppActivity(content::BrowserContext* context,
const std::string& activity, const std::string& activity,

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Next MinVersion: 30 // Next MinVersion: 31
module arc.mojom; module arc.mojom;
@@ -281,7 +281,7 @@ interface AppHost {
}; };
// TODO(lhchavez): Migrate all request/response messages to Mojo. // TODO(lhchavez): Migrate all request/response messages to Mojo.
// Next method ID: 24 // Next method ID: 25
interface AppInstance { interface AppInstance {
// DEPRECATED: Please use Init@21 instead. // DEPRECATED: Please use Init@21 instead.
InitDeprecated@0(AppHost host_ptr); InitDeprecated@0(AppHost host_ptr);
@@ -311,6 +311,11 @@ interface AppInstance {
[MinVersion=23] LaunchApp@18(string package_name, string activity, [MinVersion=23] LaunchApp@18(string package_name, string activity,
int64 display_id); int64 display_id);
// Sends a request to ARC for the Android launcher to launch the specified app
// shortcut.
[MinVersion=30] LaunchAppShortcutItem@24(
string package_name, string shortcut_id, int64 display_id);
[MinVersion=9] LaunchIntentDeprecated@12(string intent_uri, [MinVersion=9] LaunchIntentDeprecated@12(string intent_uri,
Rect? dimension_on_screen); Rect? dimension_on_screen);

@@ -74,6 +74,12 @@ void FakeAppInstance::LaunchApp(const std::string& package_name,
launch_requests_.push_back(std::make_unique<Request>(package_name, activity)); launch_requests_.push_back(std::make_unique<Request>(package_name, activity));
} }
void FakeAppInstance::LaunchAppShortcutItem(const std::string& package_name,
const std::string& shortcut_id,
int64_t display_id) {
++launch_app_shortcut_item_count_;
}
void FakeAppInstance::RequestAppIcon(const std::string& package_name, void FakeAppInstance::RequestAppIcon(const std::string& package_name,
const std::string& activity, const std::string& activity,
mojom::ScaleFactor scale_factor) { mojom::ScaleFactor scale_factor) {

@@ -88,6 +88,9 @@ class FakeAppInstance : public mojom::AppInstance {
void LaunchApp(const std::string& package_name, void LaunchApp(const std::string& package_name,
const std::string& activity, const std::string& activity,
int64_t display_id) override; int64_t display_id) override;
void LaunchAppShortcutItem(const std::string& package_name,
const std::string& shortcut_id,
int64_t display_id) override;
void RequestAppIcon(const std::string& package_name, void RequestAppIcon(const std::string& package_name,
const std::string& activity, const std::string& activity,
mojom::ScaleFactor scale_factor) override; mojom::ScaleFactor scale_factor) override;
@@ -170,6 +173,10 @@ class FakeAppInstance : public mojom::AppInstance {
int start_pai_request_count() const { return start_pai_request_count_; } int start_pai_request_count() const { return start_pai_request_count_; }
int launch_app_shortcut_item_count() const {
return launch_app_shortcut_item_count_;
}
const std::vector<std::unique_ptr<Request>>& launch_requests() const { const std::vector<std::unique_ptr<Request>>& launch_requests() const {
return launch_requests_; return launch_requests_;
} }
@@ -195,6 +202,8 @@ class FakeAppInstance : public mojom::AppInstance {
int refresh_app_list_count_ = 0; int refresh_app_list_count_ = 0;
// Number of requests to start PAI flows. // Number of requests to start PAI flows.
int start_pai_request_count_ = 0; int start_pai_request_count_ = 0;
// Keeps information about launch app shortcut requests.
int launch_app_shortcut_item_count_ = 0;
// Keeps information about launch requests. // Keeps information about launch requests.
std::vector<std::unique_ptr<Request>> launch_requests_; std::vector<std::unique_ptr<Request>> launch_requests_;
// Keeps information about launch intents. // Keeps information about launch intents.