summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/systemui/qs/AutoSizingList.java
blob: 1195184050e3df6f54bca2823f67dc87d1a2e291 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (C) 2016 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.qs;

import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

import com.android.systemui.R;

/**
 * Similar to a ListView, but it will show only as many items as fit on screen and
 * bind those instead of scrolling.
 */
public class AutoSizingList extends LinearLayout {

    private static final String TAG = "AutoSizingList";
    private final int mItemSize;
    private final Handler mHandler;

    private ListAdapter mAdapter;
    private int mCount;
    private boolean mEnableAutoSizing;

    public AutoSizingList(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mHandler = new Handler();
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoSizingList);
        mItemSize = a.getDimensionPixelSize(R.styleable.AutoSizingList_itemHeight, 0);
        mEnableAutoSizing = a.getBoolean(R.styleable.AutoSizingList_enableAutoSizing, true);
        a.recycle();
    }

    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mDataObserver);
        }
        mAdapter = adapter;
        if (adapter != null) {
            adapter.registerDataSetObserver(mDataObserver);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int requestedHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (requestedHeight != 0) {
            int count = getItemCount(requestedHeight);
            if (mCount != count) {
                postRebindChildren();
                mCount = count;
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private int getItemCount(int requestedHeight) {
        int desiredCount = getDesiredCount();
        return mEnableAutoSizing ? Math.min(requestedHeight / mItemSize, desiredCount)
                : desiredCount;
    }

    private int getDesiredCount() {
        return mAdapter != null ? mAdapter.getCount() : 0;
    }

    private void postRebindChildren() {
        mHandler.post(mBindChildren);
    }

    private void rebindChildren() {
        if (mAdapter == null) {
            return;
        }
        for (int i = 0; i < mCount; i++) {
            View v = i < getChildCount() ? getChildAt(i) : null;
            View newView = mAdapter.getView(i, v, this);
            if (newView != v) {
                if (v != null) {
                    removeView(v);
                }
                addView(newView, i);
            }
        }
        // Ditch extra views.
        while (getChildCount() > mCount) {
            removeViewAt(getChildCount() - 1);
        }
    }

    private final Runnable mBindChildren = new Runnable() {
        @Override
        public void run() {
            rebindChildren();
        }
    };

    private final DataSetObserver mDataObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            if (mCount > getDesiredCount()) {
                mCount = getDesiredCount();
            }
            postRebindChildren();
        }

        @Override
        public void onInvalidated() {
            postRebindChildren();
        }
    };
}