Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |