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