Commit 1b775321 authored by Xiqi Ruan's avatar Xiqi Ruan Committed by Commit Bot

cros: Per-App time limit change will direct to FL app

If Family Link is not installed, open Play store instead.

Bug: 1056458
Change-Id: I31e3356fbe9efba93fd75e9f786d9b84ecc87655
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2135383
Commit-Queue: Xiqi Ruan <xiqiruan@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarAga Wronska <agawronska@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#762011}
parent 2adff7cc
......@@ -16,6 +16,14 @@
namespace chromeos {
// static
const char ChildUserService::kFamilyLinkHelperAppPackageName[] =
"com.google.android.apps.kids.familylinkhelper";
// static
const char ChildUserService::kFamilyLinkHelperAppPlayStoreURL[] =
"https://play.google.com/store/apps/"
"details?id=com.google.android.apps.kids.familylinkhelper";
ChildUserService::TestApi::TestApi(ChildUserService* service)
: service_(service) {}
......
......@@ -53,6 +53,11 @@ class ChildUserService : public KeyedService,
ChildUserService* const service_;
};
// Family Link helper(for child and teens) is an app available to supervised
// users and the companion app of Family Link app(for parents).
static const char kFamilyLinkHelperAppPackageName[];
static const char kFamilyLinkHelperAppPlayStoreURL[];
explicit ChildUserService(content::BrowserContext* context);
ChildUserService(const ChildUserService&) = delete;
ChildUserService& operator=(const ChildUserService&) = delete;
......
......@@ -98,6 +98,12 @@ void AppServiceWrapper::ResumeApp(const AppId& app_id) {
GetAppProxy()->UnpauseApps(apps);
}
void AppServiceWrapper::LaunchApp(const std::string& app_service_id) {
GetAppProxy()->Launch(app_service_id, ui::EventFlags::EF_NONE,
apps::mojom::LaunchSource::kFromParentalControls,
display::kDefaultDisplayId);
}
std::vector<AppId> AppServiceWrapper::GetInstalledApps() const {
std::vector<AppId> installed_apps;
GetAppCache().ForEachApp([&installed_apps](const apps::AppUpdate& update) {
......@@ -157,6 +163,10 @@ std::string AppServiceWrapper::GetAppServiceId(const AppId& app_id) const {
return AppServiceIdFromAppId(app_id, profile_);
}
bool AppServiceWrapper::IsAppInstalled(const std::string& app_id) {
return GetAppCache().GetAppType(app_id) != apps::mojom::AppType::kUnknown;
}
AppId AppServiceWrapper::AppIdFromAppServiceId(
const std::string& app_service_id,
apps::mojom::AppType app_type) const {
......
......@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_SERVICE_WRAPPER_H_
#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_SERVICE_WRAPPER_H_
#include <string>
#include <vector>
#include "base/callback_forward.h"
......@@ -105,6 +106,10 @@ class AppServiceWrapper : public apps::AppRegistryCache::Observer,
// will be removed from the icon.
void ResumeApp(const AppId& app_id);
// Launches app identified by |app_service_id| with no event flags explicitly
// and default display id.
void LaunchApp(const std::string& app_service_id);
// Returns installed apps that are relevant for Per-App Time Limits feature.
// Installed apps of unsupported types will not be included.
std::vector<AppId> GetInstalledApps() const;
......@@ -125,6 +130,9 @@ class AppServiceWrapper : public apps::AppRegistryCache::Observer,
// It does not make sense to call it for other apps.
std::string GetAppServiceId(const AppId& app_id) const;
// Return true if the App with |app_service_id| is installed.
bool IsAppInstalled(const std::string& app_service_id);
// Returns AppId from |app_service_id| and |app_type|.
AppId AppIdFromAppServiceId(const std::string& app_service_id,
apps::mojom::AppType app_type) const;
......
......@@ -15,6 +15,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/child_accounts/child_user_service.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_time_limit_utils.h"
......@@ -26,6 +27,7 @@
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
......@@ -152,58 +154,6 @@ std::string GetNotificationIdFor(const std::string& app_name,
return base::StrCat({notification_id, app_name});
}
void ShowNotificationForApp(const std::string& app_name,
AppNotification notification,
base::Optional<base::TimeDelta> time_limit,
Profile* profile,
base::Optional<gfx::ImageSkia> icon) {
DCHECK(notification == AppNotification::kFiveMinutes ||
notification == AppNotification::kOneMinute ||
notification == AppNotification::kTimeLimitChanged ||
notification == AppNotification::kBlocked ||
notification == AppNotification::kAvailable);
DCHECK(notification == AppNotification::kTimeLimitChanged ||
notification == AppNotification::kBlocked ||
notification == AppNotification::kAvailable || time_limit.has_value());
// Alright we have all the messages that we want.
const base::string16 app_name_16 = base::UTF8ToUTF16(app_name);
const base::string16 title =
GetNotificationTitleFor(app_name_16, notification);
const base::string16 message =
GetNotificationMessageFor(app_name_16, notification, time_limit);
// Family link display source.
const base::string16 notification_source =
l10n_util::GetStringUTF16(IDS_TIME_LIMIT_NOTIFICATION_DISPLAY_SOURCE);
std::string notification_id = GetNotificationIdFor(app_name, notification);
std::unique_ptr<message_center::Notification> message_center_notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
message, notification_source, GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kFamilyLinkSourceId),
message_center::RichNotificationData(),
base::MakeRefCounted<message_center::NotificationDelegate>(),
ash::kNotificationSupervisedUserIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
if (icon.has_value())
message_center_notification->set_icon(gfx::Image(icon.value()));
auto* notification_display_service =
NotificationDisplayService::GetForProfile(profile);
if (!notification_display_service)
return;
notification_display_service->Display(NotificationHandler::Type::TRANSIENT,
*message_center_notification,
/*metadata=*/nullptr);
}
} // namespace
AppTimeController::TestApi::TestApi(AppTimeController* controller)
......@@ -429,8 +379,9 @@ void AppTimeController::ShowAppTimeLimitNotification(
int size_hint_in_dp = 48;
app_service_wrapper_->GetAppIcon(
app_id, size_hint_in_dp,
base::BindOnce(&ShowNotificationForApp, app_name, notification,
time_limit, profile_));
base::BindOnce(&AppTimeController::ShowNotificationForApp,
weak_ptr_factory_.GetWeakPtr(), app_name, notification,
time_limit));
}
void AppTimeController::OnAppLimitReached(const AppId& app_id,
......@@ -564,5 +515,77 @@ bool AppTimeController::HasTimeCrossedResetBoundary() const {
return now < last_limits_reset_time_ || now >= kDay + last_limits_reset_time_;
}
void AppTimeController::OpenFamilyLinkApp() {
const std::string app_id = arc::ArcPackageNameToAppId(
chromeos::ChildUserService::kFamilyLinkHelperAppPackageName, profile_);
if (app_service_wrapper_->IsAppInstalled(app_id)) {
// Launch Family Link Help app since it is available.
app_service_wrapper_->LaunchApp(app_id);
return;
}
// No Family Link Help app installed, so try to launch Play Store to Family
// Link Help app install page.
arc::LaunchPlayStoreWithUrl(
chromeos::ChildUserService::kFamilyLinkHelperAppPlayStoreURL);
}
void AppTimeController::ShowNotificationForApp(
const std::string& app_name,
AppNotification notification,
base::Optional<base::TimeDelta> time_limit,
base::Optional<gfx::ImageSkia> icon) {
DCHECK(notification == AppNotification::kFiveMinutes ||
notification == AppNotification::kOneMinute ||
notification == AppNotification::kTimeLimitChanged ||
notification == AppNotification::kBlocked ||
notification == AppNotification::kAvailable);
DCHECK(notification == AppNotification::kTimeLimitChanged ||
notification == AppNotification::kBlocked ||
notification == AppNotification::kAvailable || time_limit.has_value());
// Alright we have all the messages that we want.
const base::string16 app_name_16 = base::UTF8ToUTF16(app_name);
const base::string16 title =
GetNotificationTitleFor(app_name_16, notification);
const base::string16 message =
GetNotificationMessageFor(app_name_16, notification, time_limit);
// Family link display source.
const base::string16 notification_source =
l10n_util::GetStringUTF16(IDS_TIME_LIMIT_NOTIFICATION_DISPLAY_SOURCE);
std::string notification_id = GetNotificationIdFor(app_name, notification);
std::unique_ptr<message_center::Notification> message_center_notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
message, notification_source, GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT,
kFamilyLinkSourceId),
message_center::RichNotificationData(),
notification == AppNotification::kTimeLimitChanged
? base::MakeRefCounted<
message_center::HandleNotificationClickDelegate>(
base::BindRepeating(&AppTimeController::OpenFamilyLinkApp,
weak_ptr_factory_.GetWeakPtr()))
: base::MakeRefCounted<message_center::NotificationDelegate>(),
ash::kNotificationSupervisedUserIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
if (icon.has_value())
message_center_notification->set_icon(gfx::Image(icon.value()));
auto* notification_display_service =
NotificationDisplayService::GetForProfile(profile_);
if (!notification_display_service)
return;
notification_display_service->Display(NotificationHandler::Type::TRANSIENT,
*message_center_notification,
/*metadata=*/nullptr);
}
} // namespace app_time
} // namespace chromeos
......@@ -8,6 +8,7 @@
#include <memory>
#include <string>
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
......@@ -28,6 +29,10 @@ namespace base {
class OneShotTimer;
} // namespace base
namespace gfx {
class ImageSkia;
} // namespace gfx
namespace chromeos {
namespace app_time {
......@@ -140,6 +145,12 @@ class AppTimeController : public SystemClockClient::Observer,
// Called when the system time or timezone may have changed.
bool HasTimeCrossedResetBoundary() const;
void OpenFamilyLinkApp();
void ShowNotificationForApp(const std::string& app_name,
AppNotification notification,
base::Optional<base::TimeDelta> time_limit,
base::Optional<gfx::ImageSkia> icon);
// Profile
Profile* const profile_;
......@@ -165,6 +176,8 @@ class AppTimeController : public SystemClockClient::Observer,
// Metrics information to be recorded for PerAppTimeLimits.
int patl_policy_update_count_ = 0;
int apps_with_limit_ = 0;
base::WeakPtrFactory<AppTimeController> weak_ptr_factory_{this};
};
} // namespace app_time
......
......@@ -9,6 +9,7 @@
#include "base/values.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/chromeos/child_accounts/child_user_service.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
......@@ -26,13 +27,6 @@
namespace chromeos {
namespace settings {
const char kFamilyLinkHelperAppPackageName[] =
"com.google.android.apps.kids.familylinkhelper";
const char kFamilyLinkChildHelperAppPlayStoreURL[] =
"https://play.google.com/store/apps/"
"details?id=com.google.android.apps.kids.familylinkhelper";
const char kFamilyLinkSiteURL[] = "https://families.google.com/families";
ParentalControlsHandler::ParentalControlsHandler(Profile* profile)
......@@ -72,8 +66,8 @@ void ParentalControlsHandler::HandleLaunchFamilyLinkSettings(
apps::AppServiceProxyFactory::GetForProfile(profile_);
apps::AppRegistryCache& registry = proxy->AppRegistryCache();
const std::string app_id =
arc::ArcPackageNameToAppId(kFamilyLinkHelperAppPackageName, profile_);
const std::string app_id = arc::ArcPackageNameToAppId(
chromeos::ChildUserService::kFamilyLinkHelperAppPackageName, profile_);
if (registry.GetAppType(app_id) != apps::mojom::AppType::kUnknown) {
// Launch FLH app since it is available.
proxy->Launch(app_id, ui::EventFlags::EF_NONE,
......@@ -84,7 +78,8 @@ void ParentalControlsHandler::HandleLaunchFamilyLinkSettings(
// No FLH app installed, so try to launch Play Store to FLH app install page.
// If there is no Play Store available LaunchPlayStoreWithUrl() will return
// false.
if (arc::LaunchPlayStoreWithUrl(kFamilyLinkChildHelperAppPlayStoreURL)) {
if (arc::LaunchPlayStoreWithUrl(
chromeos::ChildUserService::kFamilyLinkHelperAppPlayStoreURL)) {
return;
}
// As a last resort, launch browser to the family link site.
......
......@@ -178,7 +178,8 @@ enum LaunchSource {
kFromAppListQueryContextMenu = 4, // Query-dependent results; context menu.
kFromAppListRecommendation = 5, // Query-less recommendations (smaller
// icons).
kFromParentalControls = 6, // Parental Controls Settings Section.
kFromParentalControls = 6, // Parental Controls Settings Section and
// Per App time notification.
kFromShelf = 7, // Shelf.
kFromFileManager = 8, // FileManager.
kFromLink = 9, // Left-licking on links in the browser.
......
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