1 /* 2 * Copyright (C) 2016 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.incallui.incall.impl; 18 19 import android.support.annotation.NonNull; 20 import com.android.dialer.common.Assert; 21 import com.android.incallui.incall.impl.MappedButtonConfig.MappingInfo; 22 import com.android.incallui.incall.protocol.InCallButtonIds; 23 import java.util.ArrayList; 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Set; 27 import javax.annotation.concurrent.Immutable; 28 29 /** 30 * Determines where logical buttons should be placed in the {@link InCallFragment} based on the 31 * provided mapping. 32 * 33 * <p>The button placement returned by a call to {@link #getButtonPlacement(int, Set)} is created as 34 * follows: one button is placed at each UI slot, using the provided mapping to resolve conflicts. 35 * Any allowed buttons that were not chosen for their desired slot are filled in at the end of the 36 * list until it becomes the proper size. 37 */ 38 @Immutable 39 final class ButtonChooser { 40 41 private final MappedButtonConfig config; 42 ButtonChooser(@onNull MappedButtonConfig config)43 public ButtonChooser(@NonNull MappedButtonConfig config) { 44 this.config = Assert.isNotNull(config); 45 } 46 47 /** 48 * Returns the buttons that should be shown in the {@link InCallFragment}, ordered appropriately. 49 * 50 * @param numUiButtons the number of ui buttons available. 51 * @param allowedButtons the {@link InCallButtonIds} that can be shown. 52 * @param disabledButtons the {@link InCallButtonIds} that can be shown but in disabled stats. 53 * @return an immutable list whose size is at most {@code numUiButtons}, containing the buttons to 54 * show. 55 */ 56 @NonNull getButtonPlacement( int numUiButtons, @NonNull Set<Integer> allowedButtons, @NonNull Set<Integer> disabledButtons)57 public List<Integer> getButtonPlacement( 58 int numUiButtons, 59 @NonNull Set<Integer> allowedButtons, 60 @NonNull Set<Integer> disabledButtons) { 61 Assert.isNotNull(allowedButtons); 62 Assert.checkArgument(numUiButtons >= 0); 63 64 if (numUiButtons == 0 || allowedButtons.isEmpty()) { 65 return Collections.emptyList(); 66 } 67 68 List<Integer> placedButtons = new ArrayList<>(); 69 List<Integer> conflicts = new ArrayList<>(); 70 placeButtonsInSlots(numUiButtons, allowedButtons, placedButtons, conflicts); 71 placeConflictsInOpenSlots( 72 numUiButtons, allowedButtons, disabledButtons, placedButtons, conflicts); 73 return Collections.unmodifiableList(placedButtons); 74 } 75 placeButtonsInSlots( int numUiButtons, @NonNull Set<Integer> allowedButtons, @NonNull List<Integer> placedButtons, @NonNull List<Integer> conflicts)76 private void placeButtonsInSlots( 77 int numUiButtons, 78 @NonNull Set<Integer> allowedButtons, 79 @NonNull List<Integer> placedButtons, 80 @NonNull List<Integer> conflicts) { 81 List<Integer> configuredSlots = config.getOrderedMappedSlots(); 82 for (int i = 0; i < configuredSlots.size() && placedButtons.size() < numUiButtons; ++i) { 83 int slotNumber = configuredSlots.get(i); 84 List<Integer> potentialButtons = config.getButtonsForSlot(slotNumber); 85 Collections.sort(potentialButtons, config.getSlotComparator()); 86 for (int j = 0; j < potentialButtons.size(); ++j) { 87 if (allowedButtons.contains(potentialButtons.get(j))) { 88 placedButtons.add(potentialButtons.get(j)); 89 conflicts.addAll(potentialButtons.subList(j + 1, potentialButtons.size())); 90 break; 91 } 92 } 93 } 94 } 95 placeConflictsInOpenSlots( int numUiButtons, @NonNull Set<Integer> allowedButtons, @NonNull Set<Integer> disabledButtons, @NonNull List<Integer> placedButtons, @NonNull List<Integer> conflicts)96 private void placeConflictsInOpenSlots( 97 int numUiButtons, 98 @NonNull Set<Integer> allowedButtons, 99 @NonNull Set<Integer> disabledButtons, 100 @NonNull List<Integer> placedButtons, 101 @NonNull List<Integer> conflicts) { 102 Collections.sort(conflicts, config.getConflictComparator()); 103 for (Integer conflict : conflicts) { 104 if (placedButtons.size() >= numUiButtons) { 105 return; 106 } 107 108 // If the conflict button is allowed but disabled, don't place it since it probably will 109 // move when it's enabled. 110 if (!allowedButtons.contains(conflict) || disabledButtons.contains(conflict)) { 111 continue; 112 } 113 114 if (isMutuallyExclusiveButtonAvailable( 115 config.lookupMappingInfo(conflict).getMutuallyExclusiveButton(), allowedButtons)) { 116 continue; 117 } 118 placedButtons.add(conflict); 119 } 120 } 121 isMutuallyExclusiveButtonAvailable( int mutuallyExclusiveButton, @NonNull Set<Integer> allowedButtons)122 private boolean isMutuallyExclusiveButtonAvailable( 123 int mutuallyExclusiveButton, @NonNull Set<Integer> allowedButtons) { 124 if (mutuallyExclusiveButton == MappingInfo.NO_MUTUALLY_EXCLUSIVE_BUTTON_SET) { 125 return false; 126 } 127 if (allowedButtons.contains(mutuallyExclusiveButton)) { 128 return true; 129 } 130 return false; 131 } 132 } 133