Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: chrome/browser/ui/ash/chrome_launcher_prefs.cc

Issue 2055553004: arc: Support pinned apps across Arc-enabled and Arc-disabled platforms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased, comments addressed, removed item_pinned_by_policy Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" 5 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <set>
10 10
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h" 13 #include "base/values.h"
14 #include "chrome/browser/app_mode/app_mode_utils.h" 14 #include "chrome/browser/app_mode/app_mode_utils.h"
15 #include "chrome/browser/chromeos/arc/arc_auth_service.h" 15 #include "chrome/browser/chromeos/arc/arc_auth_service.h"
16 #include "chrome/browser/chromeos/arc/arc_support_host.h" 16 #include "chrome/browser/chromeos/arc/arc_support_host.h"
17 #include "chrome/browser/prefs/pref_service_syncable_util.h" 17 #include "chrome/browser/prefs/pref_service_syncable_util.h"
18 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
19 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
18 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" 20 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
19 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h" 21 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
20 #include "chrome/common/extensions/extension_constants.h" 22 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/pref_names.h" 23 #include "chrome/common/pref_names.h"
22 #include "components/pref_registry/pref_registry_syncable.h" 24 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "components/prefs/pref_service.h" 25 #include "components/prefs/pref_service.h"
24 #include "components/prefs/scoped_user_pref_update.h" 26 #include "components/prefs/scoped_user_pref_update.h"
25 #include "components/syncable_prefs/pref_service_syncable.h" 27 #include "components/syncable_prefs/pref_service_syncable.h"
28 #include "sync/api/string_ordinal.h"
26 #include "ui/display/display.h" 29 #include "ui/display/display.h"
27 #include "ui/display/screen.h" 30 #include "ui/display/screen.h"
28 31
29 namespace ash { 32 namespace ash {
33 namespace launcher {
30 34
31 namespace { 35 namespace {
32 36
33 // App ID of default pinned apps. 37 // App ID of default pinned apps.
34 const char* kDefaultPinnedApps[] = { 38 const char* kDefaultPinnedApps[] = {
35 extension_misc::kGmailAppId, 39 extension_misc::kGmailAppId,
36 extension_misc::kGoogleDocAppId, 40 extension_misc::kGoogleDocAppId,
37 extension_misc::kYoutubeAppId, 41 extension_misc::kYoutubeAppId,
38 }; 42 };
39 43
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 // If no user-set value exists at |local_path|, the value from |synced_path| is 200 // If no user-set value exists at |local_path|, the value from |synced_path| is
197 // copied to |local_path|. 201 // copied to |local_path|.
198 void PropagatePrefToLocalIfNotSet( 202 void PropagatePrefToLocalIfNotSet(
199 syncable_prefs::PrefServiceSyncable* pref_service, 203 syncable_prefs::PrefServiceSyncable* pref_service,
200 const char* local_path, 204 const char* local_path,
201 const char* synced_path) { 205 const char* synced_path) {
202 if (!pref_service->FindPreference(local_path)->HasUserSetting()) 206 if (!pref_service->FindPreference(local_path)->HasUserSetting())
203 pref_service->SetString(local_path, pref_service->GetString(synced_path)); 207 pref_service->SetString(local_path, pref_service->GetString(synced_path));
204 } 208 }
205 209
210 struct PinInfo {
211 PinInfo(const std::string& app_id, const syncer::StringOrdinal& item_ordinal)
212 : app_id(app_id), item_ordinal(item_ordinal) {}
213
214 std::string app_id;
215 syncer::StringOrdinal item_ordinal;
216 };
217
218 struct ComparePinInfo {
219 bool operator()(const PinInfo& pin1, const PinInfo& pin2) {
220 return pin1.item_ordinal.LessThan(pin2.item_ordinal);
221 }
222 };
223
224 // Helper class to keep apps in order of appearance and to provide fast way
225 // to check if app exists in the list.
226 class AppList {
xiyuan 2016/06/14 21:42:50 nit: Can we get a better name? AppList collides wi
khmel 2016/06/15 17:01:20 Agree, quite confusing :)
227 public:
228 AppList() {}
229 ~AppList() {}
stevenjb 2016/06/14 22:44:09 nit: In a file local helper class, we can omit the
khmel 2016/06/15 17:01:20 Done.
230
231 bool HasApp(const std::string& app_id) const {
232 return app_set_.find(app_id) != app_set_.end();
233 }
234
235 void AddApp(const std::string& app_id) {
236 if (HasApp(app_id))
237 return;
238 app_list_.push_back(app_id);
239 app_set_.insert(app_id);
240 }
241
242 const std::vector<std::string>& app_list() const { return app_list_; }
243
244 private:
245 std::vector<std::string> app_list_;
246 std::set<std::string> app_set_;
247
248 DISALLOW_COPY_AND_ASSIGN(AppList);
xiyuan 2016/06/15 17:26:25 Why removing this?
khmel 2016/06/15 17:29:14 As Steven recommended in comment above. I would pe
xiyuan 2016/06/15 17:30:22 I see. Never mind then. I am fine either way.
stevenjb 2016/06/15 17:53:52 I forget whether we can use DISALLOW without an ex
khmel 2016/06/15 18:26:22 I tested, we still need CTOR for DISALLOW, so skip
249 };
250
206 } // namespace 251 } // namespace
207 252
208 const char kPinnedAppsPrefAppIDPath[] = "id"; 253 const char kPinnedAppsPrefAppIDPath[] = "id";
209 const char kPinnedAppsPrefPinnedByPolicy[] = "pinned_by_policy"; 254 const char kPinnedAppsPrefPinnedByPolicy[] = "pinned_by_policy";
210 const char kPinnedAppsPlaceholder[] = "AppShelfIDPlaceholder--------"; 255 const char kPinnedAppsPlaceholder[] = "AppShelfIDPlaceholder--------";
211 256
212 const char kShelfAutoHideBehaviorAlways[] = "Always"; 257 const char kShelfAutoHideBehaviorAlways[] = "Always";
213 const char kShelfAutoHideBehaviorNever[] = "Never"; 258 const char kShelfAutoHideBehaviorNever[] = "Never";
214 259
215 const char kShelfAlignmentBottom[] = "Bottom"; 260 const char kShelfAlignmentBottom[] = "Bottom";
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 return; 342 return;
298 343
299 SetPerDisplayPref(prefs, display_id, prefs::kShelfAlignment, value); 344 SetPerDisplayPref(prefs, display_id, prefs::kShelfAlignment, value);
300 if (display_id == display::Screen::GetScreen()->GetPrimaryDisplay().id()) { 345 if (display_id == display::Screen::GetScreen()->GetPrimaryDisplay().id()) {
301 // See comment in |kShelfAlignment| as to why we consider two prefs. 346 // See comment in |kShelfAlignment| as to why we consider two prefs.
302 prefs->SetString(prefs::kShelfAlignmentLocal, value); 347 prefs->SetString(prefs::kShelfAlignmentLocal, value);
303 prefs->SetString(prefs::kShelfAlignment, value); 348 prefs->SetString(prefs::kShelfAlignment, value);
304 } 349 }
305 } 350 }
306 351
307 std::vector<std::string> GetPinnedAppsFromPrefs( 352 // Helper that extracts app list from policy preferences.
308 const PrefService* prefs, 353 void GetAppsPinnedByPolicy(const PrefService* prefs,
309 const LauncherControllerHelper* helper) { 354 const LauncherControllerHelper* helper,
310 // Adding the app list item to the list of items requires that the ID is not 355 AppList* apps) {
311 // a valid and known ID for the extension system. The ID was constructed that 356 DCHECK(apps);
312 // way - but just to make sure... 357 DCHECK(apps->app_list().empty());
313 DCHECK(!helper->IsValidIDForCurrentUser(kPinnedAppsPlaceholder));
314 358
315 std::vector<std::string> apps;
316 const auto* pinned = prefs->GetList(prefs::kPinnedLauncherApps);
317 const auto* policy = prefs->GetList(prefs::kPolicyPinnedLauncherApps); 359 const auto* policy = prefs->GetList(prefs::kPolicyPinnedLauncherApps);
318 360 if (!policy)
319 // Get the sanitized preference value for the index of the Chrome app icon. 361 return;
320 const size_t chrome_icon_index = std::max<size_t>(
321 0, std::min<size_t>(pinned->GetSize(),
322 prefs->GetInteger(prefs::kShelfChromeIconIndex)));
323
324 // Check if Chrome is in either of the the preferences lists.
325 std::unique_ptr<base::Value> chrome_app(
326 ash::CreateAppDict(extension_misc::kChromeAppId));
327 bool chrome_listed =
328 (pinned->Find(*chrome_app.get()) != pinned->end() ||
329 (policy && policy->Find(*chrome_app.get()) != policy->end()));
330 362
331 // Obtain here all ids of ARC apps because it takes linear time, and getting 363 // Obtain here all ids of ARC apps because it takes linear time, and getting
332 // them in the loop bellow would lead to quadratic complexity. 364 // them in the loop bellow would lead to quadratic complexity.
333 const ArcAppListPrefs* const arc_app_list_pref = helper->GetArcAppListPrefs(); 365 const ArcAppListPrefs* const arc_app_list_pref = helper->GetArcAppListPrefs();
334 const std::vector<std::string> all_arc_app_ids( 366 const std::vector<std::string> all_arc_app_ids(
335 arc_app_list_pref ? arc_app_list_pref->GetAppIds() 367 arc_app_list_pref ? arc_app_list_pref->GetAppIds()
336 : std::vector<std::string>()); 368 : std::vector<std::string>());
337 369
338 std::string app_id; 370 std::string app_id;
339 for (size_t i = 0; policy && (i < policy->GetSize()); ++i) { 371 for (size_t i = 0; i < policy->GetSize(); ++i) {
340 const base::DictionaryValue* dictionary = nullptr; 372 const base::DictionaryValue* dictionary = nullptr;
341 if (policy->GetDictionary(i, &dictionary) && 373 if (policy->GetDictionary(i, &dictionary) &&
342 dictionary->GetString(kPinnedAppsPrefAppIDPath, &app_id) && 374 dictionary->GetString(kPinnedAppsPrefAppIDPath, &app_id)) {
343 std::find(apps.begin(), apps.end(), app_id) == apps.end()) {
344 if (IsAppIdArcPackage(app_id)) { 375 if (IsAppIdArcPackage(app_id)) {
345 if (!arc_app_list_pref) 376 if (!arc_app_list_pref)
346 continue; 377 continue;
347 378
348 // We are dealing with package name, not with 32 characters ID. 379 // We are dealing with package name, not with 32 characters ID.
349 const std::string& arc_package = app_id; 380 const std::string& arc_package = app_id;
350 const std::vector<std::string> activities = GetActivitiesForPackage( 381 const std::vector<std::string> activities = GetActivitiesForPackage(
351 arc_package, all_arc_app_ids, *arc_app_list_pref); 382 arc_package, all_arc_app_ids, *arc_app_list_pref);
352 for (const auto& activity : activities) { 383 for (const auto& activity : activities) {
353 const std::string arc_app_id = 384 const std::string arc_app_id =
354 ArcAppListPrefs::GetAppId(arc_package, activity); 385 ArcAppListPrefs::GetAppId(arc_package, activity);
355 if (helper->IsValidIDForCurrentUser(arc_app_id)) 386 if (helper->IsValidIDForCurrentUser(arc_app_id))
356 apps.push_back(arc_app_id); 387 apps->AddApp(arc_app_id);
357 } 388 }
358 } else if (helper->IsValidIDForCurrentUser(app_id)) { 389 } else if (helper->IsValidIDForCurrentUser(app_id)) {
359 apps.push_back(app_id); 390 apps->AddApp(app_id);
360 } 391 }
361 } 392 }
362 } 393 }
394 }
stevenjb 2016/06/14 22:44:08 nit: This could be a member of AppList.
khmel 2016/06/15 17:01:19 Done.
363 395
396 std::vector<std::string> GetPinnedAppsFromPrefsLegacy(
397 const PrefService* prefs,
398 const LauncherControllerHelper* helper) {
399 // Adding the app list item to the list of items requires that the ID is not
400 // a valid and known ID for the extension system. The ID was constructed that
401 // way - but just to make sure...
402 DCHECK(!helper->IsValidIDForCurrentUser(kPinnedAppsPlaceholder));
403
404 const auto* pinned = prefs->GetList(prefs::kPinnedLauncherApps);
stevenjb 2016/06/14 22:44:09 nit: pinned_apps
khmel 2016/06/15 17:01:20 Done.
405
406 // Get the sanitized preference value for the index of the Chrome app icon.
407 const size_t chrome_icon_index = std::max<size_t>(
408 0, std::min<size_t>(pinned->GetSize(),
409 prefs->GetInteger(prefs::kShelfChromeIconIndex)));
410
411 // Check if Chrome is in either of the the preferences lists.
412 std::unique_ptr<base::Value> chrome_app(
413 CreateAppDict(extension_misc::kChromeAppId));
414
415 AppList apps;
416 GetAppsPinnedByPolicy(prefs, helper, &apps);
417
418 std::string app_id;
364 for (size_t i = 0; i < pinned->GetSize(); ++i) { 419 for (size_t i = 0; i < pinned->GetSize(); ++i) {
365 // We need to position the chrome icon relative to its place in the pinned 420 // We need to position the chrome icon relative to its place in the pinned
366 // preference list - even if an item of that list isn't shown yet. 421 // preference list - even if an item of that list isn't shown yet.
367 if (i == chrome_icon_index && !chrome_listed) { 422 if (i == chrome_icon_index)
368 apps.push_back(extension_misc::kChromeAppId); 423 apps.AddApp(extension_misc::kChromeAppId);
369 chrome_listed = true;
370 }
371 bool pinned_by_policy = false; 424 bool pinned_by_policy = false;
372 const base::DictionaryValue* dictionary = nullptr; 425 const base::DictionaryValue* dictionary = nullptr;
373 if (pinned->GetDictionary(i, &dictionary) && 426 if (pinned->GetDictionary(i, &dictionary) &&
374 dictionary->GetString(kPinnedAppsPrefAppIDPath, &app_id) && 427 dictionary->GetString(kPinnedAppsPrefAppIDPath, &app_id) &&
428 app_id != kPinnedAppsPlaceholder &&
375 helper->IsValidIDForCurrentUser(app_id) && 429 helper->IsValidIDForCurrentUser(app_id) &&
376 std::find(apps.begin(), apps.end(), app_id) == apps.end() &&
377 (!dictionary->GetBoolean(kPinnedAppsPrefPinnedByPolicy, 430 (!dictionary->GetBoolean(kPinnedAppsPrefPinnedByPolicy,
378 &pinned_by_policy) || 431 &pinned_by_policy) ||
379 !pinned_by_policy)) { 432 !pinned_by_policy)) {
380 apps.push_back(app_id); 433 apps.AddApp(app_id);
381 } 434 }
stevenjb 2016/06/14 22:44:09 nit: This would be a bit clearer as: const base::
khmel 2016/06/15 17:01:20 Done.
382 } 435 }
383 436
384 if (arc::ArcAuthService::IsAllowedForProfile(helper->profile()) &&
385 helper->IsValidIDForCurrentUser(ArcSupportHost::kHostAppId)) {
386 apps.push_back(ArcSupportHost::kHostAppId);
387 }
388
389 // If not added yet, the chrome item will be the last item in the list. 437 // If not added yet, the chrome item will be the last item in the list.
390 if (!chrome_listed) 438 apps.AddApp(extension_misc::kChromeAppId);
391 apps.push_back(extension_misc::kChromeAppId); 439 return apps.app_list();
392
393 // If not added yet, place the app list item at the beginning of the list.
394 if (std::find(apps.begin(), apps.end(), kPinnedAppsPlaceholder) == apps.end())
395 apps.insert(apps.begin(), kPinnedAppsPlaceholder);
396
397 return apps;
398 } 440 }
399 441
400 // static 442 // static
401 std::unique_ptr<ChromeLauncherPrefsObserver> 443 std::unique_ptr<ChromeLauncherPrefsObserver>
402 ChromeLauncherPrefsObserver::CreateIfNecessary(Profile* profile) { 444 ChromeLauncherPrefsObserver::CreateIfNecessary(Profile* profile) {
403 syncable_prefs::PrefServiceSyncable* prefs = 445 syncable_prefs::PrefServiceSyncable* prefs =
404 PrefServiceSyncableFromProfile(profile); 446 PrefServiceSyncableFromProfile(profile);
405 if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() || 447 if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
406 !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal) 448 !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)
407 ->HasUserSetting()) { 449 ->HasUserSetting()) {
(...skipping 10 matching lines...) Expand all
418 syncable_prefs::PrefServiceSyncable* prefs) 460 syncable_prefs::PrefServiceSyncable* prefs)
419 : prefs_(prefs) { 461 : prefs_(prefs) {
420 // This causes OnIsSyncingChanged to be called when the value of 462 // This causes OnIsSyncingChanged to be called when the value of
421 // PrefService::IsSyncing() changes. 463 // PrefService::IsSyncing() changes.
422 prefs_->AddObserver(this); 464 prefs_->AddObserver(this);
423 } 465 }
424 466
425 void ChromeLauncherPrefsObserver::OnIsSyncingChanged() { 467 void ChromeLauncherPrefsObserver::OnIsSyncingChanged() {
426 // If prefs have synced, copy the values from |synced_path| to |local_path| 468 // If prefs have synced, copy the values from |synced_path| to |local_path|
427 // if the local values haven't already been set. 469 // if the local values haven't already been set.
428 if (prefs_->IsSyncing()) { 470 if (prefs_->IsSyncing()) {
stevenjb 2016/06/14 22:44:09 nit: invert + early exit (and modify comment)
khmel 2016/06/15 17:01:20 Done.
429 PropagatePrefToLocalIfNotSet(prefs_, prefs::kShelfAlignmentLocal, 471 PropagatePrefToLocalIfNotSet(prefs_, prefs::kShelfAlignmentLocal,
430 prefs::kShelfAlignment); 472 prefs::kShelfAlignment);
431 PropagatePrefToLocalIfNotSet(prefs_, prefs::kShelfAutoHideBehaviorLocal, 473 PropagatePrefToLocalIfNotSet(prefs_, prefs::kShelfAutoHideBehaviorLocal,
432 prefs::kShelfAutoHideBehavior); 474 prefs::kShelfAutoHideBehavior);
433 prefs_->RemoveObserver(this); 475 prefs_->RemoveObserver(this);
434 } 476 }
435 } 477 }
436 478
479 // Helper to create pin position that stays before any synced app, even if
480 // app is not currently visbile on a device.
481 syncer::StringOrdinal CreateFirstPinPosition(Profile* profile) {
stevenjb 2016/06/14 22:44:09 nit: GetFirstPinPosition s/create/get/ in the comm
khmel 2016/06/15 17:01:20 Done.
482 syncer::StringOrdinal position;
483 app_list::AppListSyncableService* app_service =
484 app_list::AppListSyncableServiceFactory::GetForProfile(profile);
485 for (const auto& sync_peer : app_service->sync_items()) {
486 if (!sync_peer.second->item_pin_ordinal.IsValid())
487 continue;
488 if (!position.IsValid() ||
489 sync_peer.second->item_pin_ordinal.LessThan(position)) {
490 position = sync_peer.second->item_pin_ordinal;
491 }
492 }
493
494 return position.IsValid() ? position.CreateBefore()
495 : syncer::StringOrdinal::CreateInitialOrdinal();
496 }
497
498 // Helper to creates pin position that stays before any synced app, even if
499 // app is not currently visbile on a device.
500 syncer::StringOrdinal CreateLastPinPosition(Profile* profile) {
stevenjb 2016/06/14 22:44:09 Ditto
khmel 2016/06/15 17:01:20 Done.
501 syncer::StringOrdinal position;
502 app_list::AppListSyncableService* app_service =
503 app_list::AppListSyncableServiceFactory::GetForProfile(profile);
504 for (const auto& sync_peer : app_service->sync_items()) {
505 if (!sync_peer.second->item_pin_ordinal.IsValid())
506 continue;
507 if (!position.IsValid() ||
508 sync_peer.second->item_pin_ordinal.GreaterThan(position)) {
509 position = sync_peer.second->item_pin_ordinal;
510 }
511 }
512
513 return position.IsValid() ? position.CreateAfter()
514 : syncer::StringOrdinal::CreateInitialOrdinal();
515 }
516
517 std::vector<std::string> ImportLegacyPinnedApps(
518 const PrefService* prefs,
519 LauncherControllerHelper* helper,
520 const AppList& policy_apps) {
521 std::vector<std::string> legacy_pins =
522 GetPinnedAppsFromPrefsLegacy(prefs, helper);
523 DCHECK(!legacy_pins.empty());
524
525 app_list::AppListSyncableService* app_service =
526 app_list::AppListSyncableServiceFactory::GetForProfile(helper->profile());
527
528 syncer::StringOrdinal last_position =
529 syncer::StringOrdinal::CreateInitialOrdinal();
530 // Convert to sync item record.
531 for (const auto& app_id : legacy_pins) {
532 DCHECK_NE(kPinnedAppsPlaceholder, app_id);
533 app_service->SetPinPosition(app_id, last_position);
534 last_position = last_position.CreateAfter();
535 }
536
537 // Now process default apps.
538 for (size_t i = 0; i < arraysize(kDefaultPinnedApps); ++i) {
539 const std::string& app_id = kDefaultPinnedApps[i];
540 // Check if it is already imported.
541 if (app_service->GetPinPosition(app_id).IsValid())
542 continue;
543 // Check if it is present but not in legacy pin.
544 if (helper->IsValidIDForCurrentUser(app_id))
545 continue;
546 app_service->SetPinPosition(app_id, last_position);
547 last_position = last_position.CreateAfter();
548 }
549
550 return legacy_pins;
551 }
552
553 std::vector<std::string> GetPinnedAppsFromPrefs(
554 const PrefService* prefs,
555 LauncherControllerHelper* helper) {
556 app_list::AppListSyncableService* app_service =
557 app_list::AppListSyncableServiceFactory::GetForProfile(helper->profile());
558 // Some unit tests may not have it.
559 if (!app_service)
560 return std::vector<std::string>();
561
562 std::vector<PinInfo> pin_infos;
563
564 AppList policy_apps;
565 GetAppsPinnedByPolicy(prefs, helper, &policy_apps);
566
567 // Empty pins indicates that sync based pin model is used for the first
568 // time. In normal workflow we have at least Chrome browser pin info.
569 bool first_run = true;
570
571 for (const auto& sync_peer : app_service->sync_items()) {
572 if (!sync_peer.second->item_pin_ordinal.IsValid())
573 continue;
574
575 first_run = false;
576 // Don't include apps that currently do not exist on device.
577 if (sync_peer.first != extension_misc::kChromeAppId &&
578 !helper->IsValidIDForCurrentUser(sync_peer.first)) {
579 continue;
580 }
581
582 pin_infos.push_back(
583 PinInfo(sync_peer.first, sync_peer.second->item_pin_ordinal));
584 }
585
586 if (first_run) {
587 // We need to import legacy pins model and convert it to sync based
588 // model.
589 return ImportLegacyPinnedApps(prefs, helper, policy_apps);
590 }
591
592 // Sort pins according their ordinals.
593 std::sort(pin_infos.begin(), pin_infos.end(), ComparePinInfo());
594
595 // Now insert Chrome browser app if needed.
596 syncer::StringOrdinal chrome_position =
597 app_service->GetPinPosition(extension_misc::kChromeAppId);
598 if (!chrome_position.IsValid()) {
599 chrome_position = CreateFirstPinPosition(helper->profile());
600 pin_infos.insert(pin_infos.begin(),
601 PinInfo(extension_misc::kChromeAppId, chrome_position));
602 app_service->SetPinPosition(extension_misc::kChromeAppId, chrome_position);
603 }
604
605 // Policy apps must preserve order of appearance and be first app in the list.
606 // Validate that there have a correct position and fix if needed.
stevenjb 2016/06/14 22:44:08 s/there/they/
khmel 2016/06/15 17:01:20 Done.
607 size_t shelf_index = 0;
608 for (const auto& app_id : policy_apps.app_list()) {
xiyuan 2016/06/14 21:42:50 Would this be enforced every time? If a user moves
stevenjb 2016/06/14 22:44:09 If we put the policy pinned apps in front every ti
khmel 2016/06/15 17:01:19 This is was done for unmovable pinned by policy ap
609 if (app_id == kPinnedAppsPlaceholder)
610 continue;
611 if (app_id == extension_misc::kChromeAppId)
612 continue;
613
614 // Chrome browser app has right to appear between pinned by policy apps.
615 if (shelf_index < pin_infos.size() &&
616 pin_infos[shelf_index].app_id == extension_misc::kChromeAppId) {
617 ++shelf_index;
618 }
619
620 const bool need_position_item = shelf_index >= pin_infos.size() ||
621 app_id != pin_infos[shelf_index].app_id;
622 if (need_position_item) {
623 // Remove existing app that breaks the order from the list.
624 if (shelf_index < pin_infos.size()) {
625 pin_infos.erase(
626 std::remove_if(pin_infos.begin() + shelf_index + 1, pin_infos.end(),
627 [app_id](const PinInfo& pin_info) {
628 return (pin_info.app_id == app_id);
629 }),
630 pin_infos.end());
631 }
632
633 syncer::StringOrdinal new_shelf_ordinal;
634 if (shelf_index == 0) {
635 // First app.
636 new_shelf_ordinal = pin_infos.empty()
637 ? syncer::StringOrdinal::CreateInitialOrdinal()
638 : pin_infos.front().item_ordinal.CreateBefore();
639 } else if (shelf_index == pin_infos.size()) {
640 new_shelf_ordinal = pin_infos.back().item_ordinal.CreateAfter();
641 } else {
642 new_shelf_ordinal =
643 pin_infos[shelf_index - 1].item_ordinal.CreateBetween(
644 pin_infos[shelf_index].item_ordinal);
645 }
646 pin_infos.insert(pin_infos.begin() + shelf_index,
647 PinInfo(app_id, new_shelf_ordinal));
648 app_service->SetPinPosition(app_id, new_shelf_ordinal);
649 }
650 ++shelf_index;
651 }
652
653 if (arc::ArcAuthService::IsAllowedForProfile(helper->profile()) &&
654 helper->IsValidIDForCurrentUser(ArcSupportHost::kHostAppId)) {
655 if (!app_service->GetSyncItem(ArcSupportHost::kHostAppId)) {
656 const syncer::StringOrdinal arc_host_position =
657 CreateLastPinPosition(helper->profile());
658 pin_infos.insert(pin_infos.begin(),
659 PinInfo(ArcSupportHost::kHostAppId, arc_host_position));
660 app_service->SetPinPosition(ArcSupportHost::kHostAppId,
661 arc_host_position);
662 }
663 }
664
665 // Convert to string array.
666 std::vector<std::string> pins(pin_infos.size());
667 for (size_t i = 0; i < pin_infos.size(); ++i)
668 pins[i] = pin_infos[i].app_id;
669
670 return pins;
671 }
672
673 void RemovePinPosition(Profile* profile, const std::string& app_id) {
674 DCHECK(profile);
675 DCHECK(!app_id.empty());
676 app_list::AppListSyncableService* app_service =
677 app_list::AppListSyncableServiceFactory::GetForProfile(profile);
678 app_service->SetPinPosition(app_id, syncer::StringOrdinal());
679 }
680
681 void SetPinPosition(Profile* profile,
682 const std::string& app_id,
683 const std::string& app_id_before,
684 const std::string& app_id_after) {
685 DCHECK(profile);
686 DCHECK(!app_id.empty());
687 DCHECK_NE(app_id, app_id_before);
688 DCHECK_NE(app_id, app_id_after);
689 DCHECK(app_id_before.empty() || app_id_before != app_id_after);
690
691 app_list::AppListSyncableService* app_service =
692 app_list::AppListSyncableServiceFactory::GetForProfile(profile);
693 // Some unit tests may not have this service.
694 if (!app_service)
695 return;
696
697 syncer::StringOrdinal position_before =
698 app_id_before.empty() ? syncer::StringOrdinal()
699 : app_service->GetPinPosition(app_id_before);
700 syncer::StringOrdinal position_after =
701 app_id_after.empty() ? syncer::StringOrdinal()
702 : app_service->GetPinPosition(app_id_after);
703
704 syncer::StringOrdinal pin_position;
705 if (position_before.IsValid() && position_after.IsValid())
706 pin_position = position_before.CreateBetween(position_after);
707 else if (position_before.IsValid())
708 pin_position = position_before.CreateAfter();
709 else if (position_after.IsValid())
710 pin_position = position_after.CreateBefore();
711 else
712 pin_position = syncer::StringOrdinal::CreateInitialOrdinal();
713 app_service->SetPinPosition(app_id, pin_position);
714 }
715
716 } // namespace launcher
437 } // namespace ash 717 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698