Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <algorithm> | |
| 6 #include <string> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/memory/ptr_util.h" | |
| 10 #include "base/threading/thread_task_runner_handle.h" | |
| 11 #include "components/offline_content/core/offline_content_aggregator.h" | |
| 12 #include "components/offline_content/core/offline_item.h" | |
| 13 | |
| 14 namespace offline_content { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // Helper method to determine whether or not |observers| contains |observer|. | |
| 19 bool VectorContains( | |
| 20 const std::vector<OfflineContentProvider::Observer*>& observers, | |
| 21 OfflineContentProvider::Observer* observer) { | |
| 22 const auto& it = std::find(observers.cbegin(), observers.cend(), observer); | |
| 23 return it != observers.end(); | |
| 24 } | |
| 25 | |
| 26 // Helper method to remove |observer| from |observers|. | |
| 27 void RemoveFromVector(std::vector<OfflineContentProvider::Observer*>& observers, | |
| 28 OfflineContentProvider::Observer* observer) { | |
| 29 auto it = std::find(observers.begin(), observers.end(), observer); | |
| 30 if (it != observers.end()) | |
| 31 observers.erase(it); | |
| 32 } | |
| 33 | |
| 34 } // namespace | |
| 35 | |
| 36 OfflineContentAggregator::OfflineContentAggregator() | |
| 37 : sent_on_items_available_(false), weak_ptr_factory_(this) {} | |
| 38 | |
| 39 OfflineContentAggregator::~OfflineContentAggregator() = default; | |
| 40 | |
| 41 void OfflineContentAggregator::RegisterProvider( | |
| 42 const std::string& name_space, | |
| 43 OfflineContentProvider* provider) { | |
| 44 // Validate that this is the first OfflineContentProvider registered that is | |
| 45 // associated with |name_space|. | |
| 46 DCHECK(providers_.find(name_space) == providers_.end()); | |
| 47 DCHECK(pending_actions_.find(name_space) == pending_actions_.end()); | |
|
fgorski
2017/02/14 22:17:55
did you consider adding: DCHECK(provider); ?
David Trainor- moved to gerrit
2017/02/22 01:23:12
Ah good call done!
| |
| 48 | |
| 49 providers_[name_space] = provider; | |
| 50 provider->AddObserver(this); | |
| 51 } | |
| 52 | |
| 53 void OfflineContentAggregator::UnregisterProvider( | |
| 54 const std::string& name_space) { | |
| 55 auto it = providers_.find(name_space); | |
| 56 DCHECK(it != providers_.end()); | |
| 57 | |
| 58 it->second->RemoveObserver(this); | |
| 59 | |
| 60 providers_.erase(it); | |
| 61 pending_actions_.erase(name_space); | |
| 62 } | |
| 63 | |
| 64 bool OfflineContentAggregator::AreItemsAvailable() { | |
| 65 return sent_on_items_available_; | |
| 66 } | |
| 67 | |
| 68 void OfflineContentAggregator::OpenItem(const ContentId& id) { | |
| 69 auto it = providers_.find(id.name_space); | |
| 70 | |
| 71 if (it == providers_.end()) | |
| 72 return; | |
| 73 | |
| 74 pending_actions_[id.name_space].push_back(base::Bind( | |
| 75 &OfflineContentProvider::OpenItem, base::Unretained(it->second), id)); | |
|
fgorski
2017/02/14 22:17:55
I feel a little uncomfortable about this one.
Is t
David Trainor- moved to gerrit
2017/02/22 01:23:12
Ended up checking if the entry was removed from th
| |
| 76 FlushPendingActionsIfReady(it->second); | |
|
fgorski
2017/02/14 22:17:55
Did you consider alternative approach:
* run if pr
David Trainor- moved to gerrit
2017/02/22 01:23:11
Yeah that makes sense. Will change.
| |
| 77 } | |
| 78 | |
| 79 void OfflineContentAggregator::RemoveItem(const ContentId& id) { | |
| 80 auto it = providers_.find(id.name_space); | |
| 81 | |
| 82 if (it == providers_.end()) | |
| 83 return; | |
| 84 | |
| 85 pending_actions_[id.name_space].push_back(base::Bind( | |
| 86 &OfflineContentProvider::RemoveItem, base::Unretained(it->second), id)); | |
| 87 FlushPendingActionsIfReady(it->second); | |
| 88 } | |
| 89 | |
| 90 void OfflineContentAggregator::CancelDownload(const ContentId& id) { | |
| 91 auto it = providers_.find(id.name_space); | |
| 92 | |
| 93 if (it == providers_.end()) | |
| 94 return; | |
| 95 | |
| 96 pending_actions_[id.name_space].push_back( | |
| 97 base::Bind(&OfflineContentProvider::CancelDownload, | |
| 98 base::Unretained(it->second), id)); | |
| 99 FlushPendingActionsIfReady(it->second); | |
| 100 } | |
| 101 | |
| 102 void OfflineContentAggregator::PauseDownload(const ContentId& id) { | |
| 103 auto it = providers_.find(id.name_space); | |
| 104 | |
| 105 if (it == providers_.end()) | |
| 106 return; | |
| 107 | |
| 108 pending_actions_[id.name_space].push_back( | |
| 109 base::Bind(&OfflineContentProvider::PauseDownload, | |
| 110 base::Unretained(it->second), id)); | |
| 111 FlushPendingActionsIfReady(it->second); | |
| 112 } | |
| 113 | |
| 114 void OfflineContentAggregator::ResumeDownload(const ContentId& id) { | |
| 115 auto it = providers_.find(id.name_space); | |
| 116 | |
| 117 if (it == providers_.end()) | |
| 118 return; | |
| 119 | |
| 120 pending_actions_[id.name_space].push_back( | |
| 121 base::Bind(&OfflineContentProvider::ResumeDownload, | |
| 122 base::Unretained(it->second), id)); | |
| 123 FlushPendingActionsIfReady(it->second); | |
| 124 } | |
| 125 | |
| 126 OfflineItem* OfflineContentAggregator::GetItemById(const ContentId& id) { | |
|
fgorski
2017/02/14 22:17:55
should this be a const OfflineItem*?
David Trainor- moved to gerrit
2017/02/22 01:23:12
Done.
| |
| 127 auto it = providers_.find(id.name_space); | |
| 128 | |
| 129 if (it == providers_.end() || !it->second->AreItemsAvailable()) | |
| 130 return nullptr; | |
| 131 | |
| 132 return it->second->GetItemById(id); | |
| 133 } | |
| 134 | |
| 135 OfflineContentProvider::OfflineItemList | |
| 136 OfflineContentAggregator::GetAllItems() { | |
| 137 OfflineItemList items; | |
| 138 for (auto& it : providers_) { | |
| 139 if (!it.second->AreItemsAvailable()) | |
| 140 continue; | |
| 141 | |
| 142 OfflineItemList provider_items = it.second->GetAllItems(); | |
| 143 items.insert(items.end(), provider_items.begin(), provider_items.end()); | |
| 144 } | |
| 145 | |
| 146 return items; | |
| 147 } | |
| 148 | |
| 149 void OfflineContentAggregator::AddObserver( | |
| 150 OfflineContentProvider::Observer* observer) { | |
| 151 DCHECK(observer); | |
| 152 if (observers_.HasObserver(observer)) | |
| 153 return; | |
| 154 | |
| 155 observers_.AddObserver(observer); | |
| 156 | |
| 157 if (sent_on_items_available_) { | |
| 158 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 159 FROM_HERE, | |
| 160 base::Bind(&OfflineContentAggregator::CheckAndNotifyItemsAvailable, | |
| 161 weak_ptr_factory_.GetWeakPtr())); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void OfflineContentAggregator::RemoveObserver( | |
| 166 OfflineContentProvider::Observer* observer) { | |
| 167 DCHECK(observer); | |
| 168 if (!observers_.HasObserver(observer)) | |
| 169 return; | |
| 170 | |
| 171 RemoveFromVector(signaled_observers_, observer); | |
| 172 observers_.RemoveObserver(observer); | |
| 173 } | |
| 174 | |
| 175 void OfflineContentAggregator::OnItemsAvailable( | |
| 176 OfflineContentProvider* provider) { | |
| 177 // Flush any pending actions that should be mirrored to the provider. | |
| 178 FlushPendingActionsIfReady(provider); | |
|
fgorski
2017/02/14 22:17:55
Why did you choose to flush first and then inform
David Trainor- moved to gerrit
2017/02/22 01:23:12
Will document in the header. Let me know if you w
| |
| 179 | |
| 180 // Some observers might already be under the impression that this class was | |
| 181 // initialized. Just treat this as an OnItemsAdded and notify those observers | |
| 182 // of the new items. | |
| 183 if (signaled_observers_.size() > 0) { | |
| 184 OfflineItemList items = provider->GetAllItems(); | |
| 185 if (items.size() > 0) { | |
| 186 for (auto& observer : signaled_observers_) { | |
| 187 observer->OnItemsAdded(items); | |
| 188 } | |
| 189 } | |
|
qinmin
2017/02/14 07:37:20
can we just early return here?
David Trainor- moved to gerrit
2017/02/22 01:23:12
No I don't think so :(. We still need to notify t
| |
| 190 } | |
| 191 | |
| 192 // Check if there were any observers who haven't been told that this class is | |
| 193 // initialized yet. If so, notify them now. | |
| 194 CheckAndNotifyItemsAvailable(); | |
| 195 } | |
| 196 | |
| 197 void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) { | |
| 198 for (auto& observer : observers_) | |
| 199 observer.OnItemsAdded(items); | |
| 200 } | |
| 201 | |
| 202 void OfflineContentAggregator::OnItemRemoved(const ContentId& id) { | |
| 203 for (auto& observer : observers_) | |
| 204 observer.OnItemRemoved(id); | |
| 205 } | |
| 206 | |
| 207 void OfflineContentAggregator::OnItemUpdated(const OfflineItem& item) { | |
| 208 for (auto& observer : observers_) | |
| 209 observer.OnItemUpdated(item); | |
| 210 } | |
| 211 | |
| 212 void OfflineContentAggregator::CheckAndNotifyItemsAvailable() { | |
| 213 if (providers_.size() == 0) | |
| 214 return; | |
| 215 | |
| 216 // If we haven't sent out the initialization message yet, make sure all | |
| 217 // underlying OfflineContentProviders are ready before notifying observers | |
| 218 // that we're ready to send items. | |
| 219 if (!sent_on_items_available_) { | |
| 220 for (auto& it : providers_) { | |
| 221 if (!it.second->AreItemsAvailable()) | |
| 222 return; | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 // Notify all observers who haven't been told about the initialization that we | |
| 227 // are initialized. Track the observers so that we don't notify them again. | |
| 228 for (auto& observer : observers_) { | |
| 229 if (!VectorContains(signaled_observers_, &observer)) { | |
| 230 observer.OnItemsAvailable(this); | |
| 231 signaled_observers_.push_back(&observer); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 // Track that we've told the world that we are initialized. | |
| 236 sent_on_items_available_ = true; | |
| 237 } | |
| 238 | |
| 239 void OfflineContentAggregator::FlushPendingActionsIfReady( | |
| 240 OfflineContentProvider* provider) { | |
| 241 if (!provider->AreItemsAvailable()) | |
| 242 return; | |
| 243 | |
| 244 // Find the actions that correspond to the provider. Requires a reverse | |
| 245 // lookup. | |
| 246 for (auto& it : providers_) { | |
| 247 if (it.second == provider) { | |
| 248 // Flush all of the actions to the provider. | |
| 249 for (auto& action : pending_actions_[it.first]) | |
| 250 action.Run(); | |
| 251 pending_actions_[it.first].clear(); | |
| 252 return; | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 } // namespace offline_content | |
| OLD | NEW |