blob: 1897171b5e5477856bb7076ae6e30845a9af4bcc [file] [log] [blame]
Evan Laird058c8ae2018-01-12 14:26:10 -05001/*
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 translationX = getWidth();
92 float contentStart = getPaddingStart();
93 int childCount = getChildCount();
94 // Underflow === don't show content until that index
95 int firstUnderflowIndex = -1;
96 android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
97
98 //TODO: Dots
99 for (int i = childCount - 1; i >= 0; i--) {
100 View child = getChildAt(i);
101 if (!(child instanceof StatusBarIconView)) {
102 continue;
103 }
104
105 ViewState childState = getViewStateFromChild(child);
106 if (childState == null ) {
107 continue;
108 }
109
110 // Rely on StatusBarIcon for truth about visibility
111 if (!((StatusBarIconView) child).getStatusBarIcon().visible) {
112 childState.hidden = true;
113 continue;
114 }
115
116 childState.xTranslation = translationX - child.getWidth();
117
118 if (childState.xTranslation < contentStart) {
119 if (firstUnderflowIndex == -1) {
120 firstUnderflowIndex = i;
121 }
122 }
123
124 translationX -= child.getWidth();
125 }
126
127 if (firstUnderflowIndex != -1) {
128 for (int i = 0; i <= firstUnderflowIndex; i++) {
129 View child = getChildAt(i);
130 ViewState vs = getViewStateFromChild(child);
131 if (vs != null) {
132 vs.hidden = true;
133 }
134 }
135 }
136 }
137
138 private void applyIconStates() {
139 for (int i = 0; i < getChildCount(); i++) {
140 View child = getChildAt(i);
141 ViewState vs = getViewStateFromChild(child);
142 if (vs != null) {
143 vs.applyToView(child);
144 }
145 }
146 }
147
148 private void resetViewStates() {
149 for (int i = 0; i < getChildCount(); i++) {
150 View child = getChildAt(i);
151 ViewState vs = getViewStateFromChild(child);
152 if (vs == null) {
153 continue;
154 }
155
156 vs.initFrom(child);
157 vs.alpha = 1.0f;
158 if (child instanceof StatusBarIconView) {
159 vs.hidden = !((StatusBarIconView)child).getStatusBarIcon().visible;
160 } else {
161 vs.hidden = false;
162 }
163 }
164 }
165
166 private static @Nullable ViewState getViewStateFromChild(View child) {
167 return (ViewState) child.getTag(R.id.status_bar_view_state_tag);
168 }
169}