1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.people.data;
18 
19 import android.annotation.NonNull;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Set;
24 
25 /** An {@link EventHistory} that aggregates multiple {@link EventHistory}.  */
26 class AggregateEventHistoryImpl implements EventHistory {
27 
28     private final List<EventHistory> mEventHistoryList = new ArrayList<>();
29 
30     @NonNull
31     @Override
getEventIndex(int eventType)32     public EventIndex getEventIndex(int eventType) {
33         for (EventHistory eventHistory : mEventHistoryList) {
34             EventIndex eventIndex = eventHistory.getEventIndex(eventType);
35             if (!eventIndex.isEmpty()) {
36                 return eventIndex;
37             }
38         }
39         return EventIndex.EMPTY;
40     }
41 
42     @NonNull
43     @Override
getEventIndex(Set<Integer> eventTypes)44     public EventIndex getEventIndex(Set<Integer> eventTypes) {
45         EventIndex merged = null;
46         for (EventHistory eventHistory : mEventHistoryList) {
47             EventIndex eventIndex = eventHistory.getEventIndex(eventTypes);
48             if (merged == null) {
49                 merged = eventIndex;
50             } else if (!eventIndex.isEmpty()) {
51                 merged = EventIndex.combine(merged, eventIndex);
52             }
53         }
54         return merged != null ? merged : EventIndex.EMPTY;
55     }
56 
57     @NonNull
58     @Override
queryEvents(Set<Integer> eventTypes, long startTime, long endTime)59     public List<Event> queryEvents(Set<Integer> eventTypes, long startTime, long endTime) {
60         List<Event> results = new ArrayList<>();
61         for (EventHistory eventHistory : mEventHistoryList) {
62             EventIndex eventIndex = eventHistory.getEventIndex(eventTypes);
63             if (eventIndex.isEmpty()) {
64                 continue;
65             }
66             List<Event> queryResults = eventHistory.queryEvents(eventTypes, startTime, endTime);
67             results = combineEventLists(results, queryResults);
68         }
69         return results;
70     }
71 
addEventHistory(EventHistory eventHistory)72     void addEventHistory(EventHistory eventHistory) {
73         mEventHistoryList.add(eventHistory);
74     }
75 
76     /**
77      * Combines the sorted events (in chronological order) from the given 2 lists {@code lhs}
78      * and {@code rhs} and preserves the order.
79      */
combineEventLists(List<Event> lhs, List<Event> rhs)80     private List<Event> combineEventLists(List<Event> lhs, List<Event> rhs) {
81         List<Event> results = new ArrayList<>();
82         int i = 0, j = 0;
83         while (i < lhs.size() && j < rhs.size()) {
84             if (lhs.get(i).getTimestamp() < rhs.get(j).getTimestamp()) {
85                 results.add(lhs.get(i++));
86             } else {
87                 results.add(rhs.get(j++));
88             }
89         }
90         if (i < lhs.size()) {
91             results.addAll(lhs.subList(i, lhs.size()));
92         } else if (j < rhs.size()) {
93             results.addAll(rhs.subList(j, rhs.size()));
94         }
95         return results;
96     }
97 }
98