/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.incallui.incall.impl; import android.support.annotation.NonNull; import android.support.v4.util.ArrayMap; import android.util.ArraySet; import com.android.dialer.common.Assert; import com.android.incallui.incall.protocol.InCallButtonIds; import com.android.incallui.incall.protocol.InCallButtonIdsExtension; import com.google.auto.value.AutoValue; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.annotation.concurrent.Immutable; /** * Determines logical button slot and ordering based on a provided mapping. * *

The provided mapping is declared with the following pieces of information: key, the {@link * InCallButtonIds} for which the mapping applies; {@link MappingInfo#getSlot()}, the arbitrarily * indexed slot into which the InCallButtonId desires to be placed; {@link * MappingInfo#getSlotOrder()}, the slotOrder, used to choose the correct InCallButtonId when * multiple desire to be placed in the same slot; and {@link MappingInfo#getConflictOrder()}, the * conflictOrder, used to determine the overall order for InCallButtonIds that weren't chosen for * their desired slot. */ @Immutable final class MappedButtonConfig { @NonNull private final Map mapping; @NonNull private final List orderedMappedSlots; /** * Creates this MappedButtonConfig with the given mapping of {@link InCallButtonIds} to their * corresponding slots and order. * * @param mapping the mapping. */ public MappedButtonConfig(@NonNull Map mapping) { this.mapping = new ArrayMap<>(); this.mapping.putAll(Assert.isNotNull(mapping)); this.orderedMappedSlots = findOrderedMappedSlots(); } private List findOrderedMappedSlots() { Set slots = new ArraySet<>(); for (Entry entry : mapping.entrySet()) { slots.add(entry.getValue().getSlot()); } List orderedSlots = new ArrayList<>(slots); Collections.sort(orderedSlots); return orderedSlots; } /** Returns an immutable list of the slots for which this class has button mapping. */ @NonNull public List getOrderedMappedSlots() { if (mapping.isEmpty()) { return Collections.emptyList(); } return Collections.unmodifiableList(orderedMappedSlots); } /** * Returns a list of {@link InCallButtonIds} that are configured to be placed in the given ui * slot. The slot can be based from any index, as long as it matches the provided mapping. */ @NonNull public List getButtonsForSlot(int slot) { List buttons = new ArrayList<>(); for (Entry entry : mapping.entrySet()) { if (entry.getValue().getSlot() == slot) { buttons.add(entry.getKey()); } } return buttons; } /** * Returns a {@link Comparator} capable of ordering {@link InCallButtonIds} that are configured to * be placed in the same slot. InCallButtonIds are sorted based on the natural ordering of {@link * MappingInfo#getSlotOrder()}. * *

Note: the returned Comparator's compare method will throw an {@link * IllegalArgumentException} if called with InCallButtonIds that have no configuration or are not * to be placed in the same slot. */ @NonNull public Comparator getSlotComparator() { return new Comparator() { @Override public int compare(Integer lhs, Integer rhs) { MappingInfo lhsInfo = lookupMappingInfo(lhs); MappingInfo rhsInfo = lookupMappingInfo(rhs); if (lhsInfo.getSlot() != rhsInfo.getSlot()) { throw new IllegalArgumentException("lhs and rhs don't go in the same slot"); } return lhsInfo.getSlotOrder() - rhsInfo.getSlotOrder(); } }; } /** * Returns a {@link Comparator} capable of ordering {@link InCallButtonIds} by their conflict * score. This comparator should be used when multiple InCallButtonIds could have been shown in * the same slot. InCallButtonIds are sorted based on the natural ordering of {@link * MappingInfo#getConflictOrder()}. * *

Note: the returned Comparator's compare method will throw an {@link * IllegalArgumentException} if called with InCallButtonIds that have no configuration. */ @NonNull public Comparator getConflictComparator() { return new Comparator() { @Override public int compare(Integer lhs, Integer rhs) { MappingInfo lhsInfo = lookupMappingInfo(lhs); MappingInfo rhsInfo = lookupMappingInfo(rhs); return lhsInfo.getConflictOrder() - rhsInfo.getConflictOrder(); } }; } @NonNull private MappingInfo lookupMappingInfo(@InCallButtonIds int button) { MappingInfo info = mapping.get(button); if (info == null) { throw new IllegalArgumentException( "Unknown InCallButtonId: " + InCallButtonIdsExtension.toString(button)); } return info; } /** Holds information about button mapping. */ @AutoValue abstract static class MappingInfo { /** The Ui slot into which a given button desires to be placed. */ public abstract int getSlot(); /** * Returns an integer used to determine which button is chosen for a slot when multiple buttons * desire to be placed in the same slot. Follows from the natural ordering of integers, i.e. a * lower slotOrder results in the button being chosen. */ public abstract int getSlotOrder(); /** * Returns an integer used to determine the order in which buttons that weren't chosen for their * desired slot are placed into the Ui. Follows from the natural ordering of integers, i.e. a * lower conflictOrder results in the button being chosen. */ public abstract int getConflictOrder(); static Builder builder(int slot) { return new AutoValue_MappedButtonConfig_MappingInfo.Builder() .setSlot(slot) .setSlotOrder(Integer.MAX_VALUE) .setConflictOrder(Integer.MAX_VALUE); } /** Class used to build instances of {@link MappingInfo}. */ @AutoValue.Builder abstract static class Builder { public abstract Builder setSlot(int slot); public abstract Builder setSlotOrder(int slotOrder); public abstract Builder setConflictOrder(int conflictOrder); public abstract MappingInfo build(); } } }