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