• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.support.v4.util.ArrayMap;
21 import android.util.ArraySet;
22 import com.android.dialer.common.Assert;
23 import com.android.incallui.incall.protocol.InCallButtonIds;
24 import com.android.incallui.incall.protocol.InCallButtonIdsExtension;
25 import com.google.auto.value.AutoValue;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Set;
33 import javax.annotation.concurrent.Immutable;
34 
35 /**
36  * Determines logical button slot and ordering based on a provided mapping.
37  *
38  * <p>The provided mapping is declared with the following pieces of information: key, the {@link
39  * InCallButtonIds} for which the mapping applies; {@link MappingInfo#getSlot()}, the arbitrarily
40  * indexed slot into which the InCallButtonId desires to be placed; {@link
41  * MappingInfo#getSlotOrder()}, the slotOrder, used to choose the correct InCallButtonId when
42  * multiple desire to be placed in the same slot; and {@link MappingInfo#getConflictOrder()}, the
43  * conflictOrder, used to determine the overall order for InCallButtonIds that weren't chosen for
44  * their desired slot.
45  */
46 @Immutable
47 final class MappedButtonConfig {
48 
49   @NonNull private final Map<Integer, MappingInfo> mapping;
50   @NonNull private final List<Integer> orderedMappedSlots;
51 
52   /**
53    * Creates this MappedButtonConfig with the given mapping of {@link InCallButtonIds} to their
54    * corresponding slots and order.
55    *
56    * @param mapping the mapping.
57    */
MappedButtonConfig(@onNull Map<Integer, MappingInfo> mapping)58   public MappedButtonConfig(@NonNull Map<Integer, MappingInfo> mapping) {
59     this.mapping = new ArrayMap<>();
60     this.mapping.putAll(Assert.isNotNull(mapping));
61     this.orderedMappedSlots = findOrderedMappedSlots();
62   }
63 
findOrderedMappedSlots()64   private List<Integer> findOrderedMappedSlots() {
65     Set<Integer> slots = new ArraySet<>();
66     for (Entry<Integer, MappingInfo> entry : mapping.entrySet()) {
67       slots.add(entry.getValue().getSlot());
68     }
69     List<Integer> orderedSlots = new ArrayList<>(slots);
70     Collections.sort(orderedSlots);
71     return orderedSlots;
72   }
73 
74   /** Returns an immutable list of the slots for which this class has button mapping. */
75   @NonNull
getOrderedMappedSlots()76   public List<Integer> getOrderedMappedSlots() {
77     if (mapping.isEmpty()) {
78       return Collections.emptyList();
79     }
80     return Collections.unmodifiableList(orderedMappedSlots);
81   }
82 
83   /**
84    * Returns a list of {@link InCallButtonIds} that are configured to be placed in the given ui
85    * slot. The slot can be based from any index, as long as it matches the provided mapping.
86    */
87   @NonNull
getButtonsForSlot(int slot)88   public List<Integer> getButtonsForSlot(int slot) {
89     List<Integer> buttons = new ArrayList<>();
90     for (Entry<Integer, MappingInfo> entry : mapping.entrySet()) {
91       if (entry.getValue().getSlot() == slot) {
92         buttons.add(entry.getKey());
93       }
94     }
95     return buttons;
96   }
97 
98   /**
99    * Returns a {@link Comparator} capable of ordering {@link InCallButtonIds} that are configured to
100    * be placed in the same slot. InCallButtonIds are sorted based on the natural ordering of {@link
101    * MappingInfo#getSlotOrder()}.
102    *
103    * <p>Note: the returned Comparator's compare method will throw an {@link
104    * IllegalArgumentException} if called with InCallButtonIds that have no configuration or are not
105    * to be placed in the same slot.
106    */
107   @NonNull
getSlotComparator()108   public Comparator<Integer> getSlotComparator() {
109     return new Comparator<Integer>() {
110       @Override
111       public int compare(Integer lhs, Integer rhs) {
112         MappingInfo lhsInfo = lookupMappingInfo(lhs);
113         MappingInfo rhsInfo = lookupMappingInfo(rhs);
114         if (lhsInfo.getSlot() != rhsInfo.getSlot()) {
115           throw new IllegalArgumentException("lhs and rhs don't go in the same slot");
116         }
117         return lhsInfo.getSlotOrder() - rhsInfo.getSlotOrder();
118       }
119     };
120   }
121 
122   /**
123    * Returns a {@link Comparator} capable of ordering {@link InCallButtonIds} by their conflict
124    * score. This comparator should be used when multiple InCallButtonIds could have been shown in
125    * the same slot. InCallButtonIds are sorted based on the natural ordering of {@link
126    * MappingInfo#getConflictOrder()}.
127    *
128    * <p>Note: the returned Comparator's compare method will throw an {@link
129    * IllegalArgumentException} if called with InCallButtonIds that have no configuration.
130    */
131   @NonNull
132   public Comparator<Integer> getConflictComparator() {
133     return new Comparator<Integer>() {
134       @Override
135       public int compare(Integer lhs, Integer rhs) {
136         MappingInfo lhsInfo = lookupMappingInfo(lhs);
137         MappingInfo rhsInfo = lookupMappingInfo(rhs);
138         return lhsInfo.getConflictOrder() - rhsInfo.getConflictOrder();
139       }
140     };
141   }
142 
143   @NonNull
144   public MappingInfo lookupMappingInfo(@InCallButtonIds int button) {
145     MappingInfo info = mapping.get(button);
146     if (info == null) {
147       throw new IllegalArgumentException(
148           "Unknown InCallButtonId: " + InCallButtonIdsExtension.toString(button));
149     }
150     return info;
151   }
152 
153   /** Holds information about button mapping. */
154   @AutoValue
155   abstract static class MappingInfo {
156 
157     public static final int NO_MUTUALLY_EXCLUSIVE_BUTTON_SET = -1;
158 
159     /** The Ui slot into which a given button desires to be placed. */
160     public abstract int getSlot();
161 
162     /**
163      * Returns an integer used to determine which button is chosen for a slot when multiple buttons
164      * desire to be placed in the same slot. Follows from the natural ordering of integers, i.e. a
165      * lower slotOrder results in the button being chosen.
166      */
167     public abstract int getSlotOrder();
168 
169     /**
170      * Returns an integer used to determine the order in which buttons that weren't chosen for their
171      * desired slot are placed into the Ui. Follows from the natural ordering of integers, i.e. a
172      * lower conflictOrder results in the button being chosen.
173      */
174     public abstract int getConflictOrder();
175 
176     /**
177      * Returns an integer representing a button for which the given button conflicts. Defaults to
178      * {@link NO_MUTUALLY_EXCLUSIVE_BUTTON_SET}.
179      *
180      * <p>If the mutually exclusive button is chosen, the associated button should never be chosen.
181      */
182     public abstract @InCallButtonIds int getMutuallyExclusiveButton();
183 
184     static Builder builder(int slot) {
185       return new AutoValue_MappedButtonConfig_MappingInfo.Builder()
186           .setSlot(slot)
187           .setSlotOrder(Integer.MAX_VALUE)
188           .setConflictOrder(Integer.MAX_VALUE)
189           .setMutuallyExclusiveButton(NO_MUTUALLY_EXCLUSIVE_BUTTON_SET);
190     }
191 
192     /** Class used to build instances of {@link MappingInfo}. */
193     @AutoValue.Builder
194     abstract static class Builder {
195       public abstract Builder setSlot(int slot);
196 
197       public abstract Builder setSlotOrder(int slotOrder);
198 
199       public abstract Builder setConflictOrder(int conflictOrder);
200 
201       public abstract Builder setMutuallyExclusiveButton(@InCallButtonIds int button);
202 
203       public abstract MappingInfo build();
204     }
205   }
206 }
207