blob: 06544543adc62533d3c380d3d88a1a7636942059 [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
2 * Copyright (C) 2016 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 */
16package com.android.internal.widget;
17
18import android.annotation.IdRes;
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.View;
22import android.view.ViewGroup;
23import android.widget.AdapterView;
24import android.widget.ListAdapter;
25import android.widget.ListView;
26import android.widget.HeaderViewListAdapter;
27
28import java.util.ArrayList;
29import java.util.function.Predicate;
30
31public class WatchHeaderListView extends ListView {
32 private View mTopPanel;
33
34 public WatchHeaderListView(Context context, AttributeSet attrs) {
35 super(context, attrs);
36 }
37
38 public WatchHeaderListView(Context context, AttributeSet attrs, int defStyleAttr) {
39 super(context, attrs, defStyleAttr);
40 }
41
42 public WatchHeaderListView(
43 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
44 super(context, attrs, defStyleAttr, defStyleRes);
45 }
46
47 @Override
48 protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
49 ArrayList<ListView.FixedViewInfo> headerViewInfos,
50 ArrayList<ListView.FixedViewInfo> footerViewInfos,
51 ListAdapter adapter) {
52 return new WatchHeaderListAdapter(headerViewInfos, footerViewInfos, adapter);
53 }
54
55 @Override
56 public void addView(View child, ViewGroup.LayoutParams params) {
57 if (mTopPanel == null) {
58 setTopPanel(child);
59 } else {
60 throw new IllegalStateException("WatchHeaderListView can host only one header");
61 }
62 }
63
64 public void setTopPanel(View v) {
65 mTopPanel = v;
66 wrapAdapterIfNecessary();
67 }
68
69 @Override
70 public void setAdapter(ListAdapter adapter) {
71 super.setAdapter(adapter);
72 wrapAdapterIfNecessary();
73 }
74
75 @Override
76 protected View findViewTraversal(@IdRes int id) {
77 View v = super.findViewTraversal(id);
78 if (v == null && mTopPanel != null && !mTopPanel.isRootNamespace()) {
79 return mTopPanel.findViewById(id);
80 }
81 return v;
82 }
83
84 @Override
85 protected View findViewWithTagTraversal(Object tag) {
86 View v = super.findViewWithTagTraversal(tag);
87 if (v == null && mTopPanel != null && !mTopPanel.isRootNamespace()) {
88 return mTopPanel.findViewWithTag(tag);
89 }
90 return v;
91 }
92
93 @Override
94 protected <T extends View> T findViewByPredicateTraversal(
95 Predicate<View> predicate, View childToSkip) {
96 View v = super.findViewByPredicateTraversal(predicate, childToSkip);
97 if (v == null && mTopPanel != null && mTopPanel != childToSkip
98 && !mTopPanel.isRootNamespace()) {
99 return (T) mTopPanel.findViewByPredicate(predicate);
100 }
101 return (T) v;
102 }
103
104 @Override
105 public int getHeaderViewsCount() {
106 return mTopPanel == null ? super.getHeaderViewsCount()
107 : super.getHeaderViewsCount() + (mTopPanel.getVisibility() == GONE ? 0 : 1);
108 }
109
110 private void wrapAdapterIfNecessary() {
111 ListAdapter adapter = getAdapter();
112 if (adapter != null && mTopPanel != null) {
113 if (!(adapter instanceof WatchHeaderListAdapter)) {
114 wrapHeaderListAdapterInternal();
115 }
116
117 ((WatchHeaderListAdapter) getAdapter()).setTopPanel(mTopPanel);
118 dispatchDataSetObserverOnChangedInternal();
119 }
120 }
121
122 private static class WatchHeaderListAdapter extends HeaderViewListAdapter {
123 private View mTopPanel;
124
125 public WatchHeaderListAdapter(
126 ArrayList<ListView.FixedViewInfo> headerViewInfos,
127 ArrayList<ListView.FixedViewInfo> footerViewInfos,
128 ListAdapter adapter) {
129 super(headerViewInfos, footerViewInfos, adapter);
130 }
131
132 public void setTopPanel(View v) {
133 mTopPanel = v;
134 }
135
136 private int getTopPanelCount() {
137 return (mTopPanel == null || mTopPanel.getVisibility() == GONE) ? 0 : 1;
138 }
139
140 @Override
141 public int getCount() {
142 return super.getCount() + getTopPanelCount();
143 }
144
145 @Override
146 public boolean areAllItemsEnabled() {
147 return getTopPanelCount() == 0 && super.areAllItemsEnabled();
148 }
149
150 @Override
151 public boolean isEnabled(int position) {
152 int topPanelCount = getTopPanelCount();
153 return position < topPanelCount ? false : super.isEnabled(position - topPanelCount);
154 }
155
156 @Override
157 public Object getItem(int position) {
158 int topPanelCount = getTopPanelCount();
159 return position < topPanelCount ? null : super.getItem(position - topPanelCount);
160 }
161
162 @Override
163 public long getItemId(int position) {
164 int numHeaders = getHeadersCount() + getTopPanelCount();
165 if (getWrappedAdapter() != null && position >= numHeaders) {
166 int adjPosition = position - numHeaders;
167 int adapterCount = getWrappedAdapter().getCount();
168 if (adjPosition < adapterCount) {
169 return getWrappedAdapter().getItemId(adjPosition);
170 }
171 }
172 return -1;
173 }
174
175 @Override
176 public View getView(int position, View convertView, ViewGroup parent) {
177 int topPanelCount = getTopPanelCount();
178 return position < topPanelCount
179 ? mTopPanel : super.getView(position - topPanelCount, convertView, parent);
180 }
181
182 @Override
183 public int getItemViewType(int position) {
184 int numHeaders = getHeadersCount() + getTopPanelCount();
185 if (getWrappedAdapter() != null && position >= numHeaders) {
186 int adjPosition = position - numHeaders;
187 int adapterCount = getWrappedAdapter().getCount();
188 if (adjPosition < adapterCount) {
189 return getWrappedAdapter().getItemViewType(adjPosition);
190 }
191 }
192
193 return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
194 }
195 }
196}