• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 package com.android.settings.network.helper;
17 
18 import android.os.ParcelUuid;
19 import android.util.Log;
20 
21 import androidx.annotation.Keep;
22 import androidx.annotation.VisibleForTesting;
23 
24 import com.android.settings.network.helper.SubscriptionAnnotation;
25 
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.function.UnaryOperator;
32 import java.util.stream.Collectors;
33 
34 /**
35  * A UnaryOperator for converting a list of SubscriptionAnnotation into
36  * another list of SubscriptionAnnotation based on group UUID.
37  * Only one SubscriptionAnnotation with entries with same (valid) group UUID would be kept.
38  *
39  * Here's an example when applying this operation as a finisher of SelectableSubscriptions:
40  *
41  * Callable<SubscriptionAnnotation> callable = (new SelectableSubscriptions(context, true))
42  *         .addFinisher(new SubscriptionGrouping());
43  *
44  * List<SubscriptionAnnotation> result = ExecutorService.submit(callable).get()
45  */
46 public class SubscriptionGrouping
47         implements UnaryOperator<List<SubscriptionAnnotation>> {
48     private static final String LOG_TAG = "SubscriptionGrouping";
49 
50     // implementation of UnaryOperator
apply(List<SubscriptionAnnotation> listOfSubscriptions)51     public List<SubscriptionAnnotation> apply(List<SubscriptionAnnotation> listOfSubscriptions) {
52         Log.d(LOG_TAG, "Grouping " + listOfSubscriptions);
53 
54         // group by GUID
55         Map<ParcelUuid, List<SubscriptionAnnotation>> groupedSubInfoList =
56                 listOfSubscriptions.stream()
57                 .filter(Objects::nonNull)
58                 .collect(Collectors.groupingBy(subAnno -> getGroupUuid(subAnno)));
59 
60         // select best one from subscription(s) within the same group
61         groupedSubInfoList.replaceAll((uuid, annoList) -> {
62             if ((uuid == SubscriptionAnnotation.EMPTY_UUID) || (annoList.size() <= 1)) {
63                 return annoList;
64             }
65             return Collections.singletonList(selectBestFromList(annoList));
66         });
67 
68         // build a stream of subscriptions
69         return groupedSubInfoList.values()
70                 .stream().flatMap(List::stream).collect(Collectors.toList());
71     }
72 
73     @Keep
74     @VisibleForTesting
getGroupUuid(SubscriptionAnnotation subAnno)75     protected ParcelUuid getGroupUuid(SubscriptionAnnotation subAnno) {
76         ParcelUuid groupUuid = subAnno.getGroupUuid();
77         return (groupUuid == null) ? SubscriptionAnnotation.EMPTY_UUID : groupUuid;
78     }
79 
selectBestFromList(List<SubscriptionAnnotation> annoList)80     protected SubscriptionAnnotation selectBestFromList(List<SubscriptionAnnotation> annoList) {
81         Comparator<SubscriptionAnnotation> annoSelector = (anno1, anno2) -> {
82             if (anno1.isDisplayAllowed() != anno2.isDisplayAllowed()) {
83                 return anno1.isDisplayAllowed() ? -1 : 1;
84             }
85             if (anno1.isActive() != anno2.isActive()) {
86                 return anno1.isActive() ? -1 : 1;
87             }
88             if (anno1.isExisted() != anno2.isExisted()) {
89                 return anno1.isExisted() ? -1 : 1;
90             }
91             return 0;
92         };
93         annoSelector = annoSelector
94                 // eSIM in front of pSIM
95                 .thenComparingInt(anno -> -anno.getType())
96                 // maintain the ordering given within constructor
97                 .thenComparingInt(anno -> annoList.indexOf(anno));
98         return annoList.stream().sorted(annoSelector).findFirst().orElse(null);
99     }
100 }
101