Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2015 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.systemui.statusbar.phone;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import com.android.internal.annotations.VisibleForTesting;
     22 import com.android.internal.statusbar.StatusBarIcon;
     23 import java.io.PrintWriter;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 
     27 import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
     28 
     29 public class StatusBarIconList {
     30     private ArrayList<Slot> mSlots = new ArrayList<>();
     31 
     32     public StatusBarIconList(String[] slots) {
     33         final int N = slots.length;
     34         for (int i=0; i < N; i++) {
     35             mSlots.add(new Slot(slots[i], null));
     36         }
     37     }
     38 
     39     public int getSlotIndex(String slot) {
     40         final int N = mSlots.size();
     41         for (int i=0; i<N; i++) {
     42             Slot item = mSlots.get(i);
     43             if (item.getName().equals(slot)) {
     44                 return i;
     45             }
     46         }
     47         // Auto insert new items at the beginning.
     48         mSlots.add(0, new Slot(slot, null));
     49         return 0;
     50     }
     51 
     52     protected ArrayList<Slot> getSlots() {
     53         return new ArrayList<>(mSlots);
     54     }
     55 
     56     protected Slot getSlot(String name) {
     57         return mSlots.get(getSlotIndex(name));
     58     }
     59 
     60     public int size() {
     61         return mSlots.size();
     62     }
     63 
     64     public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
     65         mSlots.get(index).addHolder(holder);
     66     }
     67 
     68     public void removeIcon(int index, int tag) {
     69         mSlots.get(index).removeForTag(tag);
     70     }
     71 
     72     public String getSlotName(int index) {
     73         return mSlots.get(index).getName();
     74     }
     75 
     76     public StatusBarIconHolder getIcon(int index, int tag) {
     77         return mSlots.get(index).getHolderForTag(tag);
     78     }
     79 
     80     public int getViewIndex(int slotIndex, int tag) {
     81         int count = 0;
     82         for (int i = 0; i < slotIndex; i++) {
     83             Slot item = mSlots.get(i);
     84             if (item.hasIconsInSlot()) {
     85                 count += item.numberOfIcons();
     86             }
     87         }
     88 
     89         Slot viewItem = mSlots.get(slotIndex);
     90         return count + viewItem.viewIndexOffsetForTag(tag);
     91     }
     92 
     93     public void dump(PrintWriter pw) {
     94         pw.println("StatusBarIconList state:");
     95         final int N = mSlots.size();
     96         pw.println("  icon slots: " + N);
     97         for (int i=0; i<N; i++) {
     98             pw.printf("    %2d:%s\n", i, mSlots.get(i).toString());
     99         }
    100     }
    101 
    102     public static class Slot {
    103         private final String mName;
    104         private StatusBarIconHolder mHolder;
    105         /**
    106          * Only used if multiple icons are added to the same slot.
    107          *
    108          * If there are mSubSlots, then these are structured like:
    109          *      [ First item | (the rest) ]
    110          *
    111          * The tricky thing to keep in mind here is that the list [mHolder, mSubSlots] is ordered
    112          * ascending, but for view logic we should go backwards through the list. I.e., the first
    113          * element (mHolder) should be the highest index, because higher priority items go to the
    114          * right of lower priority items
    115          */
    116         private ArrayList<StatusBarIconHolder> mSubSlots;
    117 
    118         public Slot(String name, StatusBarIconHolder iconHolder) {
    119             mName = name;
    120             mHolder = iconHolder;
    121         }
    122 
    123         public String getName() {
    124             return mName;
    125         }
    126 
    127         @Nullable
    128         public StatusBarIconHolder getHolderForTag(int tag) {
    129             if (tag == TAG_PRIMARY) {
    130                 return mHolder;
    131             }
    132 
    133             if (mSubSlots != null) {
    134                 for (StatusBarIconHolder holder : mSubSlots) {
    135                     if (holder.getTag() == tag) {
    136                         return holder;
    137                     }
    138                 }
    139             }
    140 
    141             return null;
    142         }
    143 
    144         public void addHolder(StatusBarIconHolder holder) {
    145             int tag = holder.getTag();
    146             if (tag == TAG_PRIMARY) {
    147                 mHolder = holder;
    148             } else {
    149                 setSubSlot(holder, tag);
    150             }
    151         }
    152 
    153         public void removeForTag(int tag) {
    154             if (tag == TAG_PRIMARY) {
    155                 mHolder = null;
    156             } else {
    157                 int index = getIndexForTag(tag);
    158                 if (index != -1) {
    159                     mSubSlots.remove(index);
    160                 }
    161             }
    162         }
    163 
    164         @VisibleForTesting
    165         public void clear() {
    166             mHolder = null;
    167             if (mSubSlots != null) {
    168                 mSubSlots = null;
    169             }
    170         }
    171 
    172         private void setSubSlot(StatusBarIconHolder holder, int tag) {
    173             if (mSubSlots == null) {
    174                 mSubSlots = new ArrayList<>();
    175                 mSubSlots.add(holder);
    176                 return;
    177             }
    178 
    179             if (getIndexForTag(tag) != -1) {
    180                 // Holder exists for tag; no-op
    181                 return;
    182             }
    183 
    184             // These holders get added to the end. Confused yet?
    185             mSubSlots.add(holder);
    186         }
    187 
    188         private int getIndexForTag(int tag) {
    189             for (int i = 0; i < mSubSlots.size(); i++) {
    190                 StatusBarIconHolder h = mSubSlots.get(i);
    191                 if (h.getTag() == tag) {
    192                     return i;
    193                 }
    194             }
    195 
    196             return -1;
    197         }
    198 
    199         public boolean hasIconsInSlot() {
    200             if (mHolder != null) return true;
    201             if (mSubSlots == null) return false;
    202 
    203             return mSubSlots.size() > 0;
    204         }
    205 
    206         public int numberOfIcons() {
    207             int num = mHolder == null ? 0 : 1;
    208             if (mSubSlots == null) return num;
    209 
    210             return num + mSubSlots.size();
    211         }
    212 
    213         /**
    214          * View index is inverted from regular index, because they are laid out back-to-front
    215          * @param tag the tag of the holder being viewed
    216          * @return (1 + mSubSlots.size() - indexOfTag)
    217          */
    218         public int viewIndexOffsetForTag(int tag) {
    219             if (mSubSlots == null) {
    220                 return 0;
    221             }
    222 
    223             int subSlots = mSubSlots.size();
    224             if (tag == TAG_PRIMARY) {
    225                 return subSlots;
    226             }
    227 
    228             return subSlots - getIndexForTag(tag) - 1;
    229         }
    230 
    231         /**
    232          * Build a list of the {@link StatusBarIconHolder}s in the same order they appear in their
    233          * view group. This provides a safe list that can be iterated and inserted into its group.
    234          *
    235          * @return all holders contained here, in view order
    236          */
    237         public List<StatusBarIconHolder> getHolderListInViewOrder() {
    238             ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
    239             if (mSubSlots != null) {
    240                 for (int i = mSubSlots.size() - 1; i >= 0; i--) {
    241                     holders.add(mSubSlots.get(i));
    242                 }
    243             }
    244 
    245             if (mHolder != null) {
    246                 holders.add(mHolder);
    247             }
    248 
    249             return holders;
    250         }
    251 
    252         @Override
    253         public String toString() {
    254             return String.format("(%s) %s", mName, subSlotsString());
    255         }
    256 
    257         private String subSlotsString() {
    258             if (mSubSlots == null) {
    259                 return "";
    260             }
    261 
    262             return "" + mSubSlots.size() + " subSlots";
    263         }
    264     }
    265 }
    266