File: holding_space_persistence_delegate.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (201 lines) | stat: -rw-r--r-- 7,078 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.h"

#include <algorithm>

#include "ash/constants/ash_features.h"
#include "ash/public/cpp/holding_space/holding_space_constants.h"
#include "ash/public/cpp/holding_space/holding_space_file.h"
#include "ash/public/cpp/holding_space/holding_space_image.h"
#include "ash/public/cpp/holding_space/holding_space_item.h"
#include "ash/public/cpp/holding_space/holding_space_progress.h"
#include "ash/public/cpp/holding_space/holding_space_util.h"
#include "base/containers/contains.h"
#include "chrome/browser/ash/file_manager/path_util.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/scoped_user_pref_update.h"

namespace ash {

namespace {

// Returns whether the item should be ignored by the holding space model. This
// returns true if the item is not supported in the current context, but may
// be otherwise supported. For example, returns true for ARC file system
// backed items in a secondary user profile.
bool ShouldIgnoreItem(Profile* profile, const HoldingSpaceItem* item) {
  return file_manager::util::GetAndroidFilesPath().IsParent(
             item->file().file_path) &&
         !ProfileHelper::IsPrimaryProfile(profile);
}

}  // namespace

// static
constexpr char HoldingSpacePersistenceDelegate::kPersistencePath[];

HoldingSpacePersistenceDelegate::HoldingSpacePersistenceDelegate(
    HoldingSpaceKeyedService* service,
    HoldingSpaceModel* model,
    ThumbnailLoader* thumbnail_loader,
    PersistenceRestoredCallback persistence_restored_callback)
    : HoldingSpaceKeyedServiceDelegate(service, model),
      thumbnail_loader_(thumbnail_loader),
      persistence_restored_callback_(std::move(persistence_restored_callback)) {
}

HoldingSpacePersistenceDelegate::~HoldingSpacePersistenceDelegate() = default;

// static
void HoldingSpacePersistenceDelegate::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterListPref(kPersistencePath);
}

void HoldingSpacePersistenceDelegate::Init() {
  // We expect that the associated profile is already ready when we are being
  // initialized. That being the case, we can immediately proceed to restore
  // the holding space model from persistence storage.
  RestoreModelFromPersistence();
}

void HoldingSpacePersistenceDelegate::OnHoldingSpaceItemsAdded(
    const std::vector<const HoldingSpaceItem*>& items) {
  if (is_restoring_persistence()) {
    return;
  }

  // Write the new finalized `items` to persistent storage.
  ScopedListPrefUpdate update(profile()->GetPrefs(), kPersistencePath);
  for (const HoldingSpaceItem* item : items) {
    if (item->progress().IsComplete()) {
      update->Append(item->Serialize());
    }
  }
}

void HoldingSpacePersistenceDelegate::OnHoldingSpaceItemsRemoved(
    const std::vector<const HoldingSpaceItem*>& items) {
  if (is_restoring_persistence()) {
    return;
  }

  // Remove the `items` from persistent storage.
  ScopedListPrefUpdate update(profile()->GetPrefs(), kPersistencePath);
  update->EraseIf([&items](const base::Value& persisted_item) {
    const std::string& persisted_item_id =
        HoldingSpaceItem::DeserializeId(persisted_item.GetDict());
    return base::Contains(items, persisted_item_id, &HoldingSpaceItem::id);
  });
}

void HoldingSpacePersistenceDelegate::OnHoldingSpaceItemUpdated(
    const HoldingSpaceItem* item,
    const HoldingSpaceItemUpdatedFields& updated_fields) {
  if (is_restoring_persistence()) {
    return;
  }

  // Only finalized items are persisted.
  if (!item->progress().IsComplete()) {
    return;
  }

  // Attempt to find the finalized `item` in persistent storage.
  ScopedListPrefUpdate update(profile()->GetPrefs(), kPersistencePath);
  base::Value::List& list = update.Get();
  auto item_it = std::ranges::find(
      list, item->id(), [](const base::Value& persisted_item) {
        return HoldingSpaceItem::DeserializeId(persisted_item.GetDict());
      });

  // If the finalized `item` already exists in persistent storage, update it.
  if (item_it != list.end()) {
    *item_it = base::Value(item->Serialize());
    return;
  }

  // If the finalized `item` did not previously exist in persistent storage,
  // insert it at the appropriate index.
  item_it = list.begin();
  for (const auto& candidate_item : model()->items()) {
    if (candidate_item.get() == item) {
      list.Insert(item_it, base::Value(item->Serialize()));
      return;
    }
    if (candidate_item->progress().IsComplete()) {
      ++item_it;
    }
  }

  // The finalized `item` should exist in the model and be handled above.
  NOTREACHED();
}

void HoldingSpacePersistenceDelegate::RestoreModelFromPersistence() {
  DCHECK(model()->items().empty());

  // Remove items from persistent storage that should not be restored to the
  // in-memory holding space model.
  MaybeRemoveItemsFromPersistence();

  const base::Value::List& persisted_holding_space_items =
      profile()->GetPrefs()->GetList(kPersistencePath);

  // If persistent storage is empty we can immediately notify the callback of
  // persistence restoration completion and quit early.
  std::vector<std::unique_ptr<HoldingSpaceItem>> restored_items;
  if (persisted_holding_space_items.empty()) {
    std::move(persistence_restored_callback_).Run(std::move(restored_items));
    return;
  }

  for (const auto& persisted_holding_space_item :
       persisted_holding_space_items) {
    std::unique_ptr<HoldingSpaceItem> holding_space_item =
        HoldingSpaceItem::Deserialize(
            persisted_holding_space_item.GetDict(),
            base::BindOnce(&holding_space_util::ResolveImage,
                           base::Unretained(thumbnail_loader_)));

    if (!ShouldIgnoreItem(profile(), holding_space_item.get())) {
      restored_items.push_back(std::move(holding_space_item));
    }
  }

  // Notify completion of persistence restoration.
  std::move(persistence_restored_callback_).Run(std::move(restored_items));
}

void HoldingSpacePersistenceDelegate::MaybeRemoveItemsFromPersistence() {
  CHECK(is_restoring_persistence());

  const auto known_types = holding_space_util::GetAllItemTypes();

  const bool remove_suggestion_items =
      !features::IsHoldingSpaceSuggestionsEnabled();

  ScopedListPrefUpdate update(profile()->GetPrefs(), kPersistencePath);
  update->EraseIf([&](const base::Value& persisted_item) {
    auto type = HoldingSpaceItem::DeserializeType(persisted_item.GetDict());

    // Remove items associated with unknown `type`s.
    if (!base::Contains(known_types, type)) {
      return true;
    }

    // Remove items associated with disabled features.
    if (remove_suggestion_items && HoldingSpaceItem::IsSuggestionType(type)) {
      return true;
    }

    return false;
  });
}

}  // namespace ash