blob: c876c3228eb87487b5f019a88c65a9d0ec44caaa [file] [log] [blame]
/*
* Copyright (C) 2015 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.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
public class StatusBarIconList {
private ArrayList<Slot> mSlots = new ArrayList<>();
public StatusBarIconList(String[] slots) {
final int N = slots.length;
for (int i=0; i < N; i++) {
mSlots.add(new Slot(slots[i], null));
}
}
public int getSlotIndex(String slot) {
final int N = mSlots.size();
for (int i=0; i<N; i++) {
Slot item = mSlots.get(i);
if (item.getName().equals(slot)) {
return i;
}
}
// Auto insert new items at the beginning.
mSlots.add(0, new Slot(slot, null));
return 0;
}
protected ArrayList<Slot> getSlots() {
return new ArrayList<>(mSlots);
}
protected Slot getSlot(String name) {
return mSlots.get(getSlotIndex(name));
}
public int size() {
return mSlots.size();
}
public void setIcon(int index, @NonNull StatusBarIconHolder holder) {
mSlots.get(index).addHolder(holder);
}
public void removeIcon(int index, int tag) {
mSlots.get(index).removeForTag(tag);
}
public String getSlotName(int index) {
return mSlots.get(index).getName();
}
public StatusBarIconHolder getIcon(int index, int tag) {
return mSlots.get(index).getHolderForTag(tag);
}
public int getViewIndex(int slotIndex, int tag) {
int count = 0;
for (int i = 0; i < slotIndex; i++) {
Slot item = mSlots.get(i);
if (item.hasIconsInSlot()) {
count += item.numberOfIcons();
}
}
Slot viewItem = mSlots.get(slotIndex);
return count + viewItem.viewIndexOffsetForTag(tag);
}
public void dump(PrintWriter pw) {
pw.println("StatusBarIconList state:");
final int N = mSlots.size();
pw.println(" icon slots: " + N);
for (int i=0; i<N; i++) {
pw.printf(" %2d:%s\n", i, mSlots.get(i).toString());
}
}
public static class Slot {
private final String mName;
private StatusBarIconHolder mHolder;
/**
* Only used if multiple icons are added to the same slot.
*
* If there are mSubSlots, then these are structured like:
* [ First item | (the rest) ]
*
* The tricky thing to keep in mind here is that the list [mHolder, mSubSlots] is ordered
* ascending, but for view logic we should go backwards through the list. I.e., the first
* element (mHolder) should be the highest index, because higher priority items go to the
* right of lower priority items
*/
private ArrayList<StatusBarIconHolder> mSubSlots;
public Slot(String name, StatusBarIconHolder iconHolder) {
mName = name;
mHolder = iconHolder;
}
public String getName() {
return mName;
}
@Nullable
public StatusBarIconHolder getHolderForTag(int tag) {
if (tag == TAG_PRIMARY) {
return mHolder;
}
if (mSubSlots != null) {
for (StatusBarIconHolder holder : mSubSlots) {
if (holder.getTag() == tag) {
return holder;
}
}
}
return null;
}
public void addHolder(StatusBarIconHolder holder) {
int tag = holder.getTag();
if (tag == TAG_PRIMARY) {
mHolder = holder;
} else {
setSubSlot(holder, tag);
}
}
public void removeForTag(int tag) {
if (tag == TAG_PRIMARY) {
mHolder = null;
} else {
int index = getIndexForTag(tag);
if (index != -1) {
mSubSlots.remove(index);
}
}
}
@VisibleForTesting
public void clear() {
mHolder = null;
if (mSubSlots != null) {
mSubSlots = null;
}
}
private void setSubSlot(StatusBarIconHolder holder, int tag) {
if (mSubSlots == null) {
mSubSlots = new ArrayList<>();
mSubSlots.add(holder);
return;
}
if (getIndexForTag(tag) != -1) {
// Holder exists for tag; no-op
return;
}
// These holders get added to the end. Confused yet?
mSubSlots.add(holder);
}
private int getIndexForTag(int tag) {
for (int i = 0; i < mSubSlots.size(); i++) {
StatusBarIconHolder h = mSubSlots.get(i);
if (h.getTag() == tag) {
return i;
}
}
return -1;
}
public boolean hasIconsInSlot() {
if (mHolder != null) return true;
if (mSubSlots == null) return false;
return mSubSlots.size() > 0;
}
public int numberOfIcons() {
int num = mHolder == null ? 0 : 1;
if (mSubSlots == null) return num;
return num + mSubSlots.size();
}
/**
* View index is inverted from regular index, because they are laid out back-to-front
* @param tag the tag of the holder being viewed
* @return (1 + mSubSlots.size() - indexOfTag)
*/
public int viewIndexOffsetForTag(int tag) {
if (mSubSlots == null) {
return 0;
}
int subSlots = mSubSlots.size();
if (tag == TAG_PRIMARY) {
return subSlots;
}
return subSlots - getIndexForTag(tag) - 1;
}
/**
* Build a list of the {@link StatusBarIconHolder}s in the same order they appear in their
* view group. This provides a safe list that can be iterated and inserted into its group.
*
* @return all holders contained here, in view order
*/
public List<StatusBarIconHolder> getHolderListInViewOrder() {
ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
if (mSubSlots != null) {
for (int i = mSubSlots.size() - 1; i >= 0; i--) {
holders.add(mSubSlots.get(i));
}
}
if (mHolder != null) {
holders.add(mHolder);
}
return holders;
}
/**
* Build a list of the {@link StatusBarIconHolder}s in the same order.
* This provides a safe list that can be iterated and inserted into its group.
*
* @return all holders contained here
*/
public List<StatusBarIconHolder> getHolderList() {
ArrayList<StatusBarIconHolder> holders = new ArrayList<>();
if (mHolder != null) {
holders.add(mHolder);
}
if (mSubSlots != null) {
holders.addAll(mSubSlots);
}
return holders;
}
@Override
public String toString() {
return String.format("(%s) %s", mName, subSlotsString());
}
private String subSlotsString() {
if (mSubSlots == null) {
return "";
}
return "" + mSubSlots.size() + " subSlots";
}
}
}