1f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk/*
2f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * Copyright (C) 2017 The Android Open Source Project
3f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk *
4f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * except in compliance with the License. You may obtain a copy of the License at
6f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk *
7f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
8f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk *
9f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
10f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * KIND, either express or implied. See the License for the specific language governing
12f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk * permissions and limitations under the License.
13f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk */
14f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
15f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkpackage com.android.systemui.statusbar.policy;
16f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
17f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
18f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
19f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static com.android.internal.logging.nano.MetricsProto.MetricsEvent
20f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        .NOTIFICATION_SINCE_CREATE_MILLIS;
21f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
22f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.junit.Assert.*;
23f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.ArgumentMatchers.any;
24f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.ArgumentMatchers.argThat;
25f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.clearInvocations;
26f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.mock;
27f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.never;
28f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.times;
29f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.verify;
30f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static org.mockito.Mockito.when;
31f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
32f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport static java.lang.Thread.sleep;
33f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
34f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.metrics.LogMaker;
35b16ae4ac94f11f41d30f44bad24fbe362b5e0e55Jason Monkimport android.support.test.filters.SmallTest;
36f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.testing.AndroidTestingRunner;
37f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.testing.TestableLooper;
38f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.testing.TestableLooper.MessageHandler;
39f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.testing.TestableLooper.RunWithLooper;
40f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport android.util.Log;
41f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
42f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport com.android.internal.logging.MetricsLogger;
43f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport com.android.systemui.SysuiTestCase;
44f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
45f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport org.junit.Before;
46f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport org.junit.Test;
47f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport org.junit.runner.RunWith;
48f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkimport org.mockito.ArgumentMatcher;
49f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
50f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk@RunWith(AndroidTestingRunner.class)
51f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk@RunWithLooper
52b16ae4ac94f11f41d30f44bad24fbe362b5e0e55Jason Monk@SmallTest
53f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monkpublic class IconLoggerImplTest extends SysuiTestCase {
54f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
55f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    private MetricsLogger mMetricsLogger;
56f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    private IconLoggerImpl mIconLogger;
57f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    private TestableLooper mTestableLooper;
58f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    private MessageHandler mMessageHandler;
59f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
60f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    @Before
61f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    public void setup() {
62f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        IconLoggerImpl.MIN_LOG_INTERVAL = 5; // Low interval for testing
63f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mMetricsLogger = mock(MetricsLogger.class);
64f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper = TestableLooper.get(this);
65f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mMessageHandler = mock(MessageHandler.class);
66f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.setMessageHandler(mMessageHandler);
67f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        String[] iconArray = new String[] {
68f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                "test_icon_1",
69f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                "test_icon_2",
70f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        };
71f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mContext.getOrCreateTestableResources().addOverride(
72f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                com.android.internal.R.array.config_statusBarIcons, iconArray);
73f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger = new IconLoggerImpl(mContext, mTestableLooper.getLooper(), mMetricsLogger);
74f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        when(mMessageHandler.onMessageHandled(any())).thenReturn(true);
75f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        clearInvocations(mMetricsLogger);
76f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    }
77f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
78f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    @Test
79f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    public void testIconShown() throws InterruptedException {
80f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        // Should only get one message, for the same icon shown twice.
81f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_2");
82f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_2");
83f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
84f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        // There should be some delay before execute.
85f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
86f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMessageHandler, never()).onMessageHandled(any());
87f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
88f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
89f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
90f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMessageHandler, times(1)).onMessageHandled(any());
91f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    }
92f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
93f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    @Test
94f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    public void testIconHidden() throws InterruptedException {
95f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        // Add the icon so that it can be removed.
96f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_2");
97f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
98f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
99f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        clearInvocations(mMessageHandler);
100f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
101f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        // Should only get one message, for the same icon shown twice.
102f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconHidden("test_icon_2");
103f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconHidden("test_icon_2");
104f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
105f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        // There should be some delay before execute.
106f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
107f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMessageHandler, never()).onMessageHandled(any());
108f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
109f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
110f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
111f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMessageHandler, times(1)).onMessageHandled(any());
112f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    }
113f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
114f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    @Test
115f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    public void testLog() throws InterruptedException {
116f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_2");
117f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
118f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
119f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
120f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMetricsLogger).write(argThat(maker -> {
121f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            if (IconLoggerImpl.MIN_LOG_INTERVAL >
122f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                    (long) maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS)) {
123f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                Log.e("IconLoggerImplTest", "Invalid latency "
124f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                        + maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS));
125f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                return false;
126f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            }
127f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
128f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                Log.e("IconLoggerImplTest", "Invalid icon count "
129f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                        + maker.getTaggedData(FIELD_NUM_STATUS_ICONS));
130f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                return false;
131f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            }
132f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            return true;
133f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        }));
134f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    }
135f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
136f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    @Test
137f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    public void testBitField() throws InterruptedException {
138f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_2");
139f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
140f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
141f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
142f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMetricsLogger).write(argThat(maker -> {
143f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            if ((1 << 1) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
144f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
145f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
146f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                return false;
147f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            }
148f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            return true;
149f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        }));
150f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
151f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconShown("test_icon_1");
152f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
153f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
154f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
155f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMetricsLogger).write(argThat(maker -> {
156f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            if ((1 << 1 | 1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
157f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
158f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
159f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                return false;
160f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            }
161f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            return true;
162f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        }));
163f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
164f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mIconLogger.onIconHidden("test_icon_2");
165f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        sleep(10);
166f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        mTestableLooper.processAllMessages();
167f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk
168f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        verify(mMetricsLogger).write(argThat(maker -> {
169f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            if ((1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
170f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
171f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                        (Integer) maker.getTaggedData(FIELD_STATUS_ICONS)));
172f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk                return false;
173f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            }
174f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk            return true;
175f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk        }));
176f8c2f7bd7baf0d001a707af48b3152f26fbaeda2Jason Monk    }
177b16ae4ac94f11f41d30f44bad24fbe362b5e0e55Jason Monk}
178