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
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_COMPONENTS_PHONEHUB_NOTIFICATION_PROCESSOR_H_
#define CHROMEOS_ASH_COMPONENTS_PHONEHUB_NOTIFICATION_PROCESSOR_H_
#include <google/protobuf/repeated_field.h>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/components/phonehub/proto/phonehub_api.pb.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "services/data_decoder/public/cpp/decode_image.h"
#include "ui/gfx/image/image.h"
namespace ash::phonehub {
using ::google::protobuf::RepeatedPtrField;
class Notification;
class NotificationManager;
// A helper class that processes inline reply-able notification protos and
// updates the notification manager with such notifications to add or remove.
// Since decoding image(s) included in every notification proto are asynchronous
// calls, this class ensures that additions and removals are scheduled and
// executed synchronously via a queue of requests without unexpected race
// conditions. Note that adding notifications requires using an image utility
// process asynchronously, but removals are carried out synchronously.
class NotificationProcessor {
public:
using DecodeImageCallback = data_decoder::DecodeImageCallback;
explicit NotificationProcessor(NotificationManager* notification_manager);
virtual ~NotificationProcessor();
NotificationProcessor(const NotificationProcessor&) = delete;
NotificationProcessor& operator=(const NotificationProcessor&) = delete;
// Removes all notifications and clears pending unfulfilled requests.
void ClearNotificationsAndPendingUpdates();
// Adds only inline reply-able notifications by extracting metadata from
// their protos and asynchronously decoding their associated images.
virtual void AddNotifications(
const std::vector<proto::Notification>& notification_protos);
// Removes notifications with |notifications_ids|.
virtual void RemoveNotifications(
const base::flat_set<int64_t>& notification_ids);
private:
friend class FakeNotificationProcessor;
friend class NotificationProcessorTest;
// Used to track which image type is being processed.
enum class NotificationImageField {
kColorIcon = 0,
kMonochromeIcon = 1,
kSharedImage = 2,
kContactImage = 3,
};
// Each notification proto will be associated with one of these structs.
// |color_icon| will always be populated, but |monochrome_icon|,
// |shared_image|, and |contact_image| may be empty.
struct NotificationImages {
NotificationImages();
~NotificationImages();
NotificationImages(const NotificationImages& other);
NotificationImages& operator=(const NotificationImages& other);
gfx::Image color_icon;
gfx::Image monochrome_icon_mask;
gfx::Image shared_image;
gfx::Image contact_image;
};
// Each image to decode will be associated with one of these structs. Each
// request in |pending_notification_requests_| may be associated to multiple
// DecodeImageRequestMetadata with more than one |notification_id|.
struct DecodeImageRequestMetadata {
DecodeImageRequestMetadata(int64_t notification_id,
NotificationImageField image_field,
const std::string& data);
int64_t notification_id;
NotificationImageField image_field;
std::string data;
};
// A delegate class that is faked out for testing purposes.
class ImageDecoderDelegate {
public:
ImageDecoderDelegate() = default;
virtual ~ImageDecoderDelegate() = default;
virtual void PerformImageDecode(
const std::string& data,
DecodeImageCallback single_image_decoded_closure);
private:
// The instance of the Data Decoder used by this ImageDecoderDelegate to
// perform any image decoding operations. The underlying service instance is
// started lazily when needed and torn down when not in use.
data_decoder::DataDecoder data_decoder_;
};
NotificationProcessor(NotificationManager* notification_manager,
std::unique_ptr<ImageDecoderDelegate> delegate);
void StartDecodingImages(
const std::vector<DecodeImageRequestMetadata>& decode_image_requests,
base::RepeatingClosure done_closure);
void OnDecodedBitmapReady(const DecodeImageRequestMetadata& request,
base::OnceClosure done_closure,
const SkBitmap& decoded_bitmap);
void OnAllImagesDecoded(
std::vector<proto::Notification> inline_replyable_notifications);
void ProcessRequestQueue();
void CompleteRequest();
void AddNotificationsAndProcessNextRequest(
const base::flat_set<Notification>& notifications);
void RemoveNotificationsAndProcessNextRequest(
base::flat_set<int64_t> removed_notification_ids);
raw_ptr<NotificationManager> notification_manager_;
base::queue<base::OnceClosure> pending_notification_requests_;
base::flat_map<int64_t, NotificationImages> id_to_images_map_;
std::unique_ptr<ImageDecoderDelegate> delegate_;
base::WeakPtrFactory<NotificationProcessor> weak_ptr_factory_{this};
};
} // namespace ash::phonehub
#endif // CHROMEOS_ASH_COMPONENTS_PHONEHUB_NOTIFICATION_PROCESSOR_H_
|