StatusIconContainer.java revision 6303613b216dd56a58033b8e00ef718dce1d7e02
1/* 2 * Copyright (C) 2017 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/** 18 * A container for Status bar system icons. Limits the number of system icons and handles overflow 19 * similar to NotificationIconController. Can be used to layout nested StatusIconContainers 20 * 21 * Children are expected to be of type StatusBarIconView. 22 */ 23package com.android.systemui.statusbar.phone; 24 25import android.annotation.Nullable; 26import android.content.Context; 27import android.util.ArrayMap; 28import android.util.AttributeSet; 29 30import android.view.View; 31import com.android.keyguard.AlphaOptimizedLinearLayout; 32import com.android.systemui.R; 33import com.android.systemui.statusbar.StatusBarIconView; 34import com.android.systemui.statusbar.stack.ViewState; 35 36public class StatusIconContainer extends AlphaOptimizedLinearLayout { 37 38 private static final String TAG = "StatusIconContainer"; 39 private static final int MAX_ICONS = 5; 40 private static final int MAX_DOTS = 3; 41 42 public StatusIconContainer(Context context, AttributeSet attrs) { 43 super(context, attrs); 44 } 45 46 @Override 47 protected void onLayout(boolean changed, int l, int t, int r, int b) { 48 float midY = getHeight() / 2.0f; 49 50 // Layout all child views so that we can move them around later 51 for (int i = 0; i < getChildCount(); i++) { 52 View child = getChildAt(i); 53 int width = child.getMeasuredWidth(); 54 int height = child.getMeasuredHeight(); 55 int top = (int) (midY - height / 2.0f); 56 child.layout(0, top, width, top + height); 57 } 58 59 resetViewStates(); 60 calculateIconTranslations(); 61 applyIconStates(); 62 } 63 64 @Override 65 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 66 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 67 final int count = getChildCount(); 68 // Measure all children so that they report the correct width 69 for (int i = 0; i < count; i++) { 70 measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); 71 } 72 } 73 74 @Override 75 public void onViewAdded(View child) { 76 super.onViewAdded(child); 77 ViewState vs = new ViewState(); 78 child.setTag(R.id.status_bar_view_state_tag, vs); 79 } 80 81 @Override 82 public void onViewRemoved(View child) { 83 super.onViewRemoved(child); 84 child.setTag(R.id.status_bar_view_state_tag, null); 85 } 86 87 /** 88 * Layout is happening from end -> start 89 */ 90 private void calculateIconTranslations() { 91 float width = getWidth(); 92 float translationX = width; 93 float contentStart = getPaddingStart(); 94 int childCount = getChildCount(); 95 // Underflow === don't show content until that index 96 int firstUnderflowIndex = -1; 97 android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX); 98 99 //TODO: Dots 100 for (int i = childCount - 1; i >= 0; i--) { 101 View child = getChildAt(i); 102 if (!(child instanceof StatusBarIconView)) { 103 continue; 104 } 105 106 ViewState childState = getViewStateFromChild(child); 107 if (childState == null ) { 108 continue; 109 } 110 111 // Rely on StatusBarIcon for truth about visibility 112 if (!((StatusBarIconView) child).getStatusBarIcon().visible) { 113 childState.hidden = true; 114 continue; 115 } 116 117 childState.xTranslation = translationX - child.getWidth(); 118 119 if (childState.xTranslation < contentStart) { 120 if (firstUnderflowIndex == -1) { 121 firstUnderflowIndex = i; 122 } 123 } 124 125 translationX -= child.getWidth(); 126 } 127 128 if (firstUnderflowIndex != -1) { 129 for (int i = 0; i <= firstUnderflowIndex; i++) { 130 View child = getChildAt(i); 131 ViewState vs = getViewStateFromChild(child); 132 if (vs != null) { 133 vs.hidden = true; 134 } 135 } 136 } 137 138 // Stole this from NotificationIconContainer. Not optimal but keeps the layout logic clean 139 if (isLayoutRtl()) { 140 for (int i = 0; i < childCount; i++) { 141 View child = getChildAt(i); 142 ViewState state = getViewStateFromChild(child); 143 state.xTranslation = width - state.xTranslation - child.getWidth(); 144 } 145 } 146 } 147 148 private void applyIconStates() { 149 for (int i = 0; i < getChildCount(); i++) { 150 View child = getChildAt(i); 151 ViewState vs = getViewStateFromChild(child); 152 if (vs != null) { 153 vs.applyToView(child); 154 } 155 } 156 } 157 158 private void resetViewStates() { 159 for (int i = 0; i < getChildCount(); i++) { 160 View child = getChildAt(i); 161 ViewState vs = getViewStateFromChild(child); 162 if (vs == null) { 163 continue; 164 } 165 166 vs.initFrom(child); 167 vs.alpha = 1.0f; 168 if (child instanceof StatusBarIconView) { 169 vs.hidden = !((StatusBarIconView)child).getStatusBarIcon().visible; 170 } else { 171 vs.hidden = false; 172 } 173 } 174 } 175 176 private static @Nullable ViewState getViewStateFromChild(View child) { 177 return (ViewState) child.getTag(R.id.status_bar_view_state_tag); 178 } 179} 180