huangcm
2025-04-11 48566d1cda2d109a94496c806286f47b8984166d
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * Copyright (C) 2018 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.statusbar.phone;
 
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.view.View;
 
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
 
public class ContextualButtonGroup extends ButtonDispatcher {
    private static final int INVALID_INDEX = -1;
 
    // List of pairs that contains the button and if the button was visible within this group
    private final List<ButtonData> mButtonData = new ArrayList<>();
 
    public ContextualButtonGroup(@IdRes int containerId) {
        super(containerId);
    }
 
    /**
     * Add a contextual button to the group. The order of adding increases in its priority. The
     * priority is used to determine which button should be visible when setting multiple button's
     * visibility {@see setButtonVisibility}.
     * @param button the button added to the group
     */
    public void addButton(@NonNull ContextualButton button) {
        button.attachToGroup(this);
        mButtonData.add(new ButtonData(button));
    }
 
    public ContextualButton getContextButton(@IdRes int buttonResId) {
        int index = getContextButtonIndex(buttonResId);
        if (index != INVALID_INDEX) {
            return mButtonData.get(index).button;
        }
        return null;
    }
 
    public ContextualButton getVisibleContextButton() {
        for (int i = mButtonData.size() - 1; i >= 0; --i) {
            if (mButtonData.get(i).markedVisible) {
                return mButtonData.get(i).button;
            }
        }
        return null;
    }
 
    /**
     * Set the visibility of the button by {@param buttonResId} with {@param visible}. Only one
     * button is shown at a time. The input button will only show up if it has higher priority than
     * a previous button, otherwise it will be marked as visible and shown later if all higher
     * priority buttons are invisible. Therefore hiding a button will show the next marked visible
     * button. This group's view will be visible if at least one button is visible.
     * @return if the button is visible after operation
     * @throws RuntimeException if the input id does not match any of the ids in the group
     */
    public int setButtonVisibility(@IdRes int buttonResId, boolean visible) {
        final int index = getContextButtonIndex(buttonResId);
        if (index == INVALID_INDEX) {
            throw new RuntimeException("Cannot find the button id of " + buttonResId
                    + " in context group");
        }
        setVisibility(View.INVISIBLE);
        mButtonData.get(index).markedVisible = visible;
 
        // Make all buttons invisible except the first markedVisible button
        boolean alreadyFoundVisibleButton = false;
        int i = mButtonData.size() - 1;
        for (; i >= 0; --i) {
            final ButtonData buttonData = mButtonData.get(i);
            if (!alreadyFoundVisibleButton && buttonData.markedVisible) {
                buttonData.setVisibility(View.VISIBLE);
                setVisibility(View.VISIBLE);
                alreadyFoundVisibleButton = true;
            } else {
                buttonData.setVisibility(View.INVISIBLE);
            }
        }
        return mButtonData.get(index).button.getVisibility();
    }
 
    /**
     * See if button is group visible. Group visible determines if a button can be visible when
     * higher priority buttons go invisible.
     * @param buttonResId the button to see if it is group visible
     * @return true if button is group visible
     */
    public boolean isButtonVisibleWithinGroup(@IdRes int buttonResId) {
        final int index = getContextButtonIndex(buttonResId);
        return index != INVALID_INDEX && mButtonData.get(index).markedVisible;
    }
 
    /**
     * Update all the icons that are attached to this group. This will get all the buttons to update
     * their icons for their buttons.
     */
    public void updateIcons() {
        for (ButtonData data : mButtonData) {
            data.button.updateIcon();
        }
    }
 
    public void dump(PrintWriter pw) {
        View view = getCurrentView();
        pw.println("ContextualButtonGroup {");
        pw.println("      getVisibleContextButton(): " + getVisibleContextButton());
        pw.println("      isVisible(): " + isVisible());
        pw.println("      attached(): " + (view != null && view.isAttachedToWindow()));
        pw.println("      mButtonData [ ");
        for (int i = mButtonData.size() - 1; i >= 0; --i) {
            final ButtonData data = mButtonData.get(i);
            view = data.button.getCurrentView();
            pw.println("            " + i + ": markedVisible=" + data.markedVisible
                    + " visible=" + data.button.getVisibility()
                    + " attached=" + (view != null && view.isAttachedToWindow())
                    + " alpha=" + data.button.getAlpha());
        }
        pw.println("      ]");
        pw.println("    }");
    }
 
    private int getContextButtonIndex(@IdRes int buttonResId) {
        for (int i = 0; i < mButtonData.size(); ++i) {
            if (mButtonData.get(i).button.getId() == buttonResId) {
                return i;
            }
        }
        return INVALID_INDEX;
    }
 
    private final static class ButtonData {
        ContextualButton button;
        boolean markedVisible;
 
        ButtonData(ContextualButton button) {
            this.button = button;
            this.markedVisible = false;
        }
 
        void setVisibility(int visiblity) {
            button.setVisibility(visiblity);
        }
    }
}