Home | History | Annotate | Download | only in impl
      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    */
     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 
     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
     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
     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
    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   private 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     /** The Ui slot into which a given button desires to be placed. */
    158     public abstract int getSlot();
    159 
    160     /**
    161      * Returns an integer used to determine which button is chosen for a slot when multiple buttons
    162      * desire to be placed in the same slot. Follows from the natural ordering of integers, i.e. a
    163      * lower slotOrder results in the button being chosen.
    164      */
    165     public abstract int getSlotOrder();
    166 
    167     /**
    168      * Returns an integer used to determine the order in which buttons that weren't chosen for their
    169      * desired slot are placed into the Ui. Follows from the natural ordering of integers, i.e. a
    170      * lower conflictOrder results in the button being chosen.
    171      */
    172     public abstract int getConflictOrder();
    173 
    174     static Builder builder(int slot) {
    175       return new AutoValue_MappedButtonConfig_MappingInfo.Builder()
    176           .setSlot(slot)
    177           .setSlotOrder(Integer.MAX_VALUE)
    178           .setConflictOrder(Integer.MAX_VALUE);
    179     }
    180 
    181     /** Class used to build instances of {@link MappingInfo}. */
    182     @AutoValue.Builder
    183     abstract static class Builder {
    184       public abstract Builder setSlot(int slot);
    185 
    186       public abstract Builder setSlotOrder(int slotOrder);
    187 
    188       public abstract Builder setConflictOrder(int conflictOrder);
    189 
    190       public abstract MappingInfo build();
    191     }
    192   }
    193 }
    194