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