1 package org.robolectric.shadows; 2 3 import android.os.Build; 4 import android.os.Build.VERSION_CODES; 5 import android.util.EventLog; 6 import java.util.ArrayList; 7 import java.util.Collection; 8 import java.util.List; 9 import org.robolectric.RuntimeEnvironment; 10 import org.robolectric.annotation.Implementation; 11 import org.robolectric.annotation.Implements; 12 import org.robolectric.annotation.Resetter; 13 import org.robolectric.shadow.api.Shadow; 14 15 @Implements(EventLog.class) 16 public class ShadowEventLog { 17 18 /** 19 * Constant written to the log if the parameter is null. 20 * 21 * <p>This matches how the real android code handles nulls. 22 */ 23 static final String NULL_PLACE_HOLDER = "NULL"; 24 25 @Implements(EventLog.Event.class) 26 public static class ShadowEvent { 27 28 private Object data; 29 private int tag; 30 private int processId; 31 private int threadId; 32 private long timeNanos; 33 34 @Implementation getData()35 protected Object getData() { 36 return data; 37 } 38 39 @Implementation getTag()40 protected int getTag() { 41 return tag; 42 } 43 44 @Implementation getProcessId()45 protected int getProcessId() { 46 return processId; 47 } 48 49 @Implementation getThreadId()50 protected int getThreadId() { 51 return threadId; 52 } 53 54 @Implementation getTimeNanos()55 protected long getTimeNanos() { 56 return timeNanos; 57 } 58 } 59 60 private static final List<EventLog.Event> events = new ArrayList<>(); 61 62 /** Class to build {@link EventLog.Event} */ 63 public static class EventBuilder { 64 65 private final Object data; 66 private final int tag; 67 private int processId = ShadowProcess.myPid(); 68 private int threadId = ShadowProcess.myTid(); 69 private long timeNanos = System.nanoTime(); 70 EventBuilder(int tag, Object data)71 public EventBuilder(int tag, Object data) { 72 this.tag = tag; 73 this.data = data; 74 } 75 setProcessId(int processId)76 public EventBuilder setProcessId(int processId) { 77 this.processId = processId; 78 return this; 79 } 80 setThreadId(int threadId)81 public EventBuilder setThreadId(int threadId) { 82 this.threadId = threadId; 83 return this; 84 } 85 setTimeNanos(long timeNanos)86 public EventBuilder setTimeNanos(long timeNanos) { 87 this.timeNanos = timeNanos; 88 return this; 89 } 90 build()91 public EventLog.Event build() { 92 EventLog.Event event; 93 if (RuntimeEnvironment.getApiLevel() >= Build.VERSION_CODES.N) { 94 // Prefer a real factory method over reflection for construction. 95 event = EventLog.Event.fromBytes(new byte[0]); 96 } else { 97 event = Shadow.newInstanceOf(EventLog.Event.class); 98 } 99 ShadowEvent shadowEvent = Shadow.extract(event); 100 shadowEvent.data = data; 101 shadowEvent.tag = tag; 102 shadowEvent.processId = processId; 103 shadowEvent.threadId = threadId; 104 shadowEvent.timeNanos = timeNanos; 105 return event; 106 } 107 } 108 109 /** Add event to {@link EventLog}. */ addEvent(EventLog.Event event)110 public static void addEvent(EventLog.Event event) { 111 events.add(event); 112 } 113 114 @Resetter clearAll()115 public static void clearAll() { 116 events.clear(); 117 } 118 119 /** Writes an event log message, returning an approximation of the bytes written. */ 120 @Implementation writeEvent(int tag, String str)121 protected static int writeEvent(int tag, String str) { 122 if (str == null) { 123 str = NULL_PLACE_HOLDER; 124 } 125 addEvent(new EventBuilder(tag, str).build()); 126 return Integer.BYTES + str.length(); 127 } 128 129 /** Writes an event log message, returning an approximation of the bytes written. */ 130 @Implementation writeEvent(int tag, Object... list)131 protected static int writeEvent(int tag, Object... list) { 132 if (list == null) { 133 // This matches how the real android code handles nulls 134 return writeEvent(tag, (String) null); 135 } 136 addEvent(new EventBuilder(tag, list).build()); 137 return Integer.BYTES + list.length * Integer.BYTES; 138 } 139 140 /** Writes an event log message, returning an approximation of the bytes written. */ 141 @Implementation writeEvent(int tag, int value)142 protected static int writeEvent(int tag, int value) { 143 addEvent(new EventBuilder(tag, value).build()); 144 return Integer.BYTES + Integer.BYTES; 145 } 146 147 /** Writes an event log message, returning an approximation of the bytes written. */ 148 @Implementation(minSdk = VERSION_CODES.M) writeEvent(int tag, float value)149 protected static int writeEvent(int tag, float value) { 150 addEvent(new EventBuilder(tag, value).build()); 151 return Integer.BYTES + Float.BYTES; 152 } 153 154 /** Writes an event log message, returning an approximation of the bytes written. */ 155 @Implementation writeEvent(int tag, long value)156 protected static int writeEvent(int tag, long value) { 157 addEvent(new EventBuilder(tag, value).build()); 158 return Integer.BYTES + Long.BYTES; 159 } 160 161 @Implementation readEvents(int[] tags, Collection<EventLog.Event> output)162 protected static void readEvents(int[] tags, Collection<EventLog.Event> output) { 163 for (EventLog.Event event : events) { 164 for (int tag : tags) { 165 if (tag == event.getTag()) { 166 output.add(event); 167 break; 168 } 169 } 170 } 171 } 172 } 173