Commit 7bb2e7bc authored by khmel's avatar khmel Committed by Commit bot

arc: Handle ARC events in MD Settings

This provides handling ARC events.
TURN ON button should be available in case ARC is disabled and unmanaged.
Once ARC is enabled TURN ON button is hidden and APPS section is shown.
APPS section shows link to ARC Settings app once Settings app appears in
the system. While Settings app is not registered tehn link to ARC Settings
is hidden. In case user click on ARC Settings link and Settings app is not
ready yet (ARC is still booting) then Settings app is started in deferred
mode (spinning animation on shelf). Disabling ARC hides APPS section and
TURN ON button is active again.

BUG=720173, b/37523579, b/29244888
TEST=Browser test extended, manually on device for managed/unmanaged
     cases.
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2873853002
Cr-Commit-Position: refs/heads/master@{#471206}
parent a3079e2f
...@@ -8,7 +8,13 @@ ...@@ -8,7 +8,13 @@
*/ */
/** /**
* @typedef {{appReady: boolean}} * Type definition of AndroidAppsInfo entry. |playStoreEnabled| indicates that
* Play Store is enabled. |settingsAppAvailable| indicates that Android settings
* app is registered in the system.
* @typedef {{
* playStoreEnabled: boolean,
* settingsAppAvailable: boolean,
* }}
* @see chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc * @see chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
*/ */
var AndroidAppsInfo; var AndroidAppsInfo;
......
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
<cr-policy-pref-indicator pref="[[prefs.arc.enabled]]" <cr-policy-pref-indicator pref="[[prefs.arc.enabled]]"
icon-aria-label="$i18n{androidAppsPageTitle}"> icon-aria-label="$i18n{androidAppsPageTitle}">
</cr-policy-pref-indicator> </cr-policy-pref-indicator>
<template is="dom-if" if="[[androidAppsInfo_.appReady]]"> <template is="dom-if" if="[[androidAppsInfo_.playStoreEnabled]]">
<button class="subpage-arrow" is="paper-icon-button-light" <button class="subpage-arrow" is="paper-icon-button-light"
aria-label="$i18n{androidAppsPageTitle}" aria-label="$i18n{androidAppsPageTitle}"
aria-describedby="secondaryText"> aria-describedby="secondaryText">
</button> </button>
</template> </template>
<template is="dom-if" if="[[!androidAppsInfo_.appReady]]"> <template is="dom-if" if="[[!androidAppsInfo_.playStoreEnabled]]">
<div class="separator"></div> <div class="separator"></div>
<paper-button id="enable" class="secondary-button" <paper-button id="enable" class="secondary-button"
on-tap="onEnableTap_" on-tap="onEnableTap_"
......
...@@ -38,17 +38,26 @@ Polymer({ ...@@ -38,17 +38,26 @@ Polymer({
/** @private {?settings.AndroidAppsBrowserProxy} */ /** @private {?settings.AndroidAppsBrowserProxy} */
browserProxy_: null, browserProxy_: null,
/** @private {?WebUIListener} */
listener_: null,
/** @override */ /** @override */
created: function() { created: function() {
this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance(); this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance();
}, },
/** @override */ /** @override */
ready: function() { attached: function() {
cr.addWebUIListener( this.listener_ = cr.addWebUIListener(
'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this)); 'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this));
this.browserProxy_.requestAndroidAppsInfo(); this.browserProxy_.requestAndroidAppsInfo();
}, },
/** @override */
detached: function() {
cr.removeWebUIListener(this.listener_);
},
/** /**
* @param {AndroidAppsInfo} info * @param {AndroidAppsInfo} info
* @private * @private
...@@ -68,7 +77,7 @@ Polymer({ ...@@ -68,7 +77,7 @@ Polymer({
/** @private */ /** @private */
onSubpageTap_: function() { onSubpageTap_: function() {
if (this.androidAppsInfo_.appReady) if (this.androidAppsInfo_.playStoreEnabled)
settings.navigateTo(settings.Route.ANDROID_APPS_DETAILS); settings.navigateTo(settings.Route.ANDROID_APPS_DETAILS);
}, },
}); });
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<div id="manageApps" class="settings-box first" <div id="manageApps" class="settings-box first"
on-keydown="onManageAndroidAppsKeydown_" on-keydown="onManageAndroidAppsKeydown_"
on-tap="onManageAndroidAppsTap_" actionable on-tap="onManageAndroidAppsTap_" actionable
hidden="[[!androidAppsInfo_.appReady]]"> hidden="[[!androidAppsInfo.settingsAppAvailable]]">
<div class="start"> <div class="start">
<div>$i18n{androidAppsManageApps}</div> <div>$i18n{androidAppsManageApps}</div>
</div> </div>
......
...@@ -17,7 +17,10 @@ Polymer({ ...@@ -17,7 +17,10 @@ Polymer({
prefs: Object, prefs: Object,
/** @private {!AndroidAppsInfo|undefined} */ /** @private {!AndroidAppsInfo|undefined} */
androidAppsInfo: Object, androidAppsInfo: {
type: Object,
observer: 'onAndroidAppsInfoUpdate_',
},
/** @private */ /** @private */
dialogBody_: { dialogBody_: {
...@@ -38,6 +41,14 @@ Polymer({ ...@@ -38,6 +41,14 @@ Polymer({
this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance(); this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance();
}, },
/**
* @private
*/
onAndroidAppsInfoUpdate_: function() {
if (!this.androidAppsInfo.playStoreEnabled)
settings.navigateToPreviousRoute();
},
/** /**
* @param {Event} event * @param {Event} event
* @private * @private
......
...@@ -14,7 +14,10 @@ namespace chromeos { ...@@ -14,7 +14,10 @@ namespace chromeos {
namespace settings { namespace settings {
AndroidAppsHandler::AndroidAppsHandler(Profile* profile) AndroidAppsHandler::AndroidAppsHandler(Profile* profile)
: arc_prefs_observer_(this), profile_(profile), weak_ptr_factory_(this) {} : arc_prefs_observer_(this),
arc_session_manager_observer_(this),
profile_(profile),
weak_ptr_factory_(this) {}
AndroidAppsHandler::~AndroidAppsHandler() {} AndroidAppsHandler::~AndroidAppsHandler() {}
...@@ -31,12 +34,16 @@ void AndroidAppsHandler::RegisterMessages() { ...@@ -31,12 +34,16 @@ void AndroidAppsHandler::RegisterMessages() {
void AndroidAppsHandler::OnJavascriptAllowed() { void AndroidAppsHandler::OnJavascriptAllowed() {
ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_); ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
if (arc_prefs) if (arc_prefs) {
arc_prefs_observer_.Add(arc_prefs); arc_prefs_observer_.Add(arc_prefs);
// arc::ArcSessionManager is assosiated with primary profile.
arc_session_manager_observer_.Add(arc::ArcSessionManager::Get());
}
} }
void AndroidAppsHandler::OnJavascriptDisallowed() { void AndroidAppsHandler::OnJavascriptDisallowed() {
arc_prefs_observer_.RemoveAll(); arc_prefs_observer_.RemoveAll();
arc_session_manager_observer_.RemoveAll();
} }
void AndroidAppsHandler::OnAppRegistered( void AndroidAppsHandler::OnAppRegistered(
...@@ -49,27 +56,24 @@ void AndroidAppsHandler::OnAppRemoved(const std::string& app_id) { ...@@ -49,27 +56,24 @@ void AndroidAppsHandler::OnAppRemoved(const std::string& app_id) {
OnAppChanged(app_id); OnAppChanged(app_id);
} }
void AndroidAppsHandler::OnAppReadyChanged(const std::string& app_id,
bool ready) {
OnAppChanged(app_id);
}
void AndroidAppsHandler::OnAppChanged(const std::string& app_id) { void AndroidAppsHandler::OnAppChanged(const std::string& app_id) {
if (app_id != arc::kSettingsAppId) if (app_id != arc::kSettingsAppId)
return; return;
SendAndroidAppsInfo(); SendAndroidAppsInfo();
} }
void AndroidAppsHandler::OnArcPlayStoreEnabledChanged(bool enabled) {
SendAndroidAppsInfo();
}
std::unique_ptr<base::DictionaryValue> std::unique_ptr<base::DictionaryValue>
AndroidAppsHandler::BuildAndroidAppsInfo() { AndroidAppsHandler::BuildAndroidAppsInfo() {
std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue); std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue);
bool app_ready = false; info->SetBoolean("playStoreEnabled",
if (arc::IsArcPlayStoreEnabledForProfile(profile_)) { arc::IsArcPlayStoreEnabledForProfile(profile_));
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = info->SetBoolean(
ArcAppListPrefs::Get(profile_)->GetApp(arc::kSettingsAppId); "settingsAppAvailable",
app_ready = app_info && app_info->ready; ArcAppListPrefs::Get(profile_)->IsRegistered(arc::kSettingsAppId));
}
info->SetBoolean("appReady", app_ready);
return info; return info;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "chrome/browser/chromeos/arc/arc_session_manager.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
...@@ -23,7 +24,8 @@ namespace chromeos { ...@@ -23,7 +24,8 @@ namespace chromeos {
namespace settings { namespace settings {
class AndroidAppsHandler : public ::settings::SettingsPageUIHandler, class AndroidAppsHandler : public ::settings::SettingsPageUIHandler,
public ArcAppListPrefs::Observer { public ArcAppListPrefs::Observer,
public arc::ArcSessionManager::Observer {
public: public:
explicit AndroidAppsHandler(Profile* profile); explicit AndroidAppsHandler(Profile* profile);
~AndroidAppsHandler() override; ~AndroidAppsHandler() override;
...@@ -34,11 +36,13 @@ class AndroidAppsHandler : public ::settings::SettingsPageUIHandler, ...@@ -34,11 +36,13 @@ class AndroidAppsHandler : public ::settings::SettingsPageUIHandler,
void OnJavascriptDisallowed() override; void OnJavascriptDisallowed() override;
// ArcAppListPrefs::Observer // ArcAppListPrefs::Observer
void OnAppReadyChanged(const std::string& app_id, bool ready) override;
void OnAppRemoved(const std::string& app_id) override; void OnAppRemoved(const std::string& app_id) override;
void OnAppRegistered(const std::string& app_id, void OnAppRegistered(const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) override; const ArcAppListPrefs::AppInfo& app_info) override;
// arc::ArcSessionManager::Observer:
void OnArcPlayStoreEnabledChanged(bool enabled) override;
private: private:
std::unique_ptr<base::DictionaryValue> BuildAndroidAppsInfo(); std::unique_ptr<base::DictionaryValue> BuildAndroidAppsInfo();
void OnAppChanged(const std::string& app_id); void OnAppChanged(const std::string& app_id);
...@@ -48,6 +52,8 @@ class AndroidAppsHandler : public ::settings::SettingsPageUIHandler, ...@@ -48,6 +52,8 @@ class AndroidAppsHandler : public ::settings::SettingsPageUIHandler,
ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer> ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
arc_prefs_observer_; arc_prefs_observer_;
ScopedObserver<arc::ArcSessionManager, arc::ArcSessionManager::Observer>
arc_session_manager_observer_;
Profile* profile_; // unowned Profile* profile_; // unowned
base::WeakPtrFactory<AndroidAppsHandler> weak_ptr_factory_; base::WeakPtrFactory<AndroidAppsHandler> weak_ptr_factory_;
......
...@@ -20,7 +20,7 @@ TestAndroidAppsBrowserProxy.prototype = { ...@@ -20,7 +20,7 @@ TestAndroidAppsBrowserProxy.prototype = {
/** @override */ /** @override */
requestAndroidAppsInfo: function() { requestAndroidAppsInfo: function() {
this.methodCalled('requestAndroidAppsInfo'); this.methodCalled('requestAndroidAppsInfo');
cr.webUIListenerCallback('android-apps-info-update', {appReady: false}); this.setAndroidAppsState(false, false);
}, },
/** override */ /** override */
...@@ -28,10 +28,14 @@ TestAndroidAppsBrowserProxy.prototype = { ...@@ -28,10 +28,14 @@ TestAndroidAppsBrowserProxy.prototype = {
this.methodCalled('showAndroidAppsSettings'); this.methodCalled('showAndroidAppsSettings');
}, },
setAppReady: function(ready) { setAndroidAppsState: function(playStoreEnabled, settingsAppAvailable) {
// We need to make sure to pass a new object here, otherwise the property // We need to make sure to pass a new object here, otherwise the property
// change event may not get fired in the listener. // change event may not get fired in the listener.
cr.webUIListenerCallback('android-apps-info-update', {appReady: ready}); var appsInfo = {
playStoreEnabled: playStoreEnabled,
settingsAppAvailable: settingsAppAvailable,
};
cr.webUIListenerCallback('android-apps-info-update', appsInfo);
}, },
}; };
...@@ -62,7 +66,7 @@ suite('AndroidAppsPageTests', function() { ...@@ -62,7 +66,7 @@ suite('AndroidAppsPageTests', function() {
return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo') return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
.then(function() { .then(function() {
androidAppsBrowserProxy.setAppReady(false); androidAppsBrowserProxy.setAndroidAppsState(false, false);
}); });
}); });
...@@ -75,7 +79,7 @@ suite('AndroidAppsPageTests', function() { ...@@ -75,7 +79,7 @@ suite('AndroidAppsPageTests', function() {
Polymer.dom.flush(); Polymer.dom.flush();
assertTrue(androidAppsPage.prefs.arc.enabled.value); assertTrue(androidAppsPage.prefs.arc.enabled.value);
androidAppsBrowserProxy.setAppReady(true); androidAppsBrowserProxy.setAndroidAppsState(true, false);
Polymer.dom.flush(); Polymer.dom.flush();
assertTrue(!!androidAppsPage.$$('.subpage-arrow')); assertTrue(!!androidAppsPage.$$('.subpage-arrow'));
}); });
...@@ -84,11 +88,25 @@ suite('AndroidAppsPageTests', function() { ...@@ -84,11 +88,25 @@ suite('AndroidAppsPageTests', function() {
suite('SubPage', function() { suite('SubPage', function() {
var subpage; var subpage;
/**
* Returns a new promise that resolves after a window 'popstate' event.
* @return {!Promise}
*/
function whenPopState() {
return new Promise(function(resolve) {
window.addEventListener('popstate', function callback() {
window.removeEventListener('popstate', callback);
resolve();
});
});
}
setup(function() { setup(function() {
androidAppsPage.prefs = {arc: {enabled: {value: true}}}; androidAppsPage.prefs = {arc: {enabled: {value: true}}};
return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo') return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
.then(function() { .then(function() {
androidAppsBrowserProxy.setAppReady(true); settings.navigateTo(settings.Route.ANDROID_APPS);
androidAppsBrowserProxy.setAndroidAppsState(true, false);
MockInteractions.tap(androidAppsPage.$$('#android-apps')); MockInteractions.tap(androidAppsPage.$$('#android-apps'));
Polymer.dom.flush(); Polymer.dom.flush();
subpage = androidAppsPage.$$('settings-android-apps-subpage'); subpage = androidAppsPage.$$('settings-android-apps-subpage');
...@@ -97,8 +115,19 @@ suite('AndroidAppsPageTests', function() { ...@@ -97,8 +115,19 @@ suite('AndroidAppsPageTests', function() {
}); });
test('Sanity', function() { test('Sanity', function() {
assertTrue(!!subpage.$$('#manageApps'));
assertTrue(!!subpage.$$('#remove')); assertTrue(!!subpage.$$('#remove'));
assertTrue(!!subpage.$$('#manageApps'));
});
test('ManageAppsUpdate', function() {
var manageApps = subpage.$$('#manageApps');
assertTrue(manageApps.hidden);
androidAppsBrowserProxy.setAndroidAppsState(true, true);
Polymer.dom.flush();
assertFalse(manageApps.hidden);
androidAppsBrowserProxy.setAndroidAppsState(true, false);
Polymer.dom.flush();
assertTrue(manageApps.hidden);
}); });
test('Disable', function() { test('Disable', function() {
...@@ -108,10 +137,22 @@ suite('AndroidAppsPageTests', function() { ...@@ -108,10 +137,22 @@ suite('AndroidAppsPageTests', function() {
var remove = subpage.$$('#remove'); var remove = subpage.$$('#remove');
assertTrue(!!remove); assertTrue(!!remove);
MockInteractions.tap(remove);
subpage.onRemoveTap_();
Polymer.dom.flush(); Polymer.dom.flush();
assertTrue(dialog.open); assertTrue(dialog.open);
dialog.close();
});
test('HideOnDisable', function() {
assertEquals(settings.getCurrentRoute(),
settings.Route.ANDROID_APPS_DETAILS);
androidAppsBrowserProxy.setAndroidAppsState(false, false);
Polymer.dom.flush();
return whenPopState().then(function() {
assertEquals(settings.getCurrentRoute(),
settings.Route.ANDROID_APPS);
});
}); });
}); });
...@@ -129,7 +170,7 @@ suite('AndroidAppsPageTests', function() { ...@@ -129,7 +170,7 @@ suite('AndroidAppsPageTests', function() {
}; };
return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo') return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
.then(function() { .then(function() {
androidAppsBrowserProxy.setAppReady(true); androidAppsBrowserProxy.setAndroidAppsState(true, true);
MockInteractions.tap(androidAppsPage.$$('#android-apps')); MockInteractions.tap(androidAppsPage.$$('#android-apps'));
Polymer.dom.flush(); Polymer.dom.flush();
subpage = androidAppsPage.$$('settings-android-apps-subpage'); subpage = androidAppsPage.$$('settings-android-apps-subpage');
......
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