Merge "create a metrics log reader for tests"

This commit is contained in:
TreeHugger Robot
2017-01-19 06:22:23 +00:00
committed by Android (Google) Code Review
47 changed files with 4032 additions and 19 deletions

View File

@@ -1,6 +1,22 @@
/*
* Copyright (C) 2017 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.internal.logging;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -14,16 +30,16 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
*/
public class LogBuilder {
private static final String TAG = "LogBuilder";
private SparseArray<Object> entries = new SparseArray();
public LogBuilder(int mainCategory) {
setCategory(mainCategory);
}
public LogBuilder setView(View view) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
return this;
/* Deserialize from the eventlog */
public LogBuilder(Object[] items) {
deserialize(items);
}
public LogBuilder setCategory(int category) {
@@ -36,16 +52,48 @@ public class LogBuilder {
return this;
}
public LogBuilder setSubtype(int subtype) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE, subtype);
return this;
}
public LogBuilder setTimestamp(long timestamp) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP, timestamp);
return this;
}
public LogBuilder setPackageName(String packageName) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, packageName);
return this;
}
public LogBuilder setCounterName(String name) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME, name);
return this;
}
public LogBuilder setCounterBucket(int bucket) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
return this;
}
public LogBuilder setCounterBucket(long bucket) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
return this;
}
public LogBuilder setCounterValue(int value) {
entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE, value);
return this;
}
/**
* @param tag From your MetricsEvent enum.
* @param value One of Integer, Long, Float, String
* @return
*/
public LogBuilder addTaggedData(int tag, Object value) {
if (!(value instanceof Integer ||
value instanceof String ||
value instanceof Long ||
value instanceof Float)) {
if (isValidValue(value)) {
throw new IllegalArgumentException(
"Value must be loggable type - int, long, float, String");
}
@@ -53,6 +101,94 @@ public class LogBuilder {
return this;
}
public boolean isValidValue(Object value) {
return !(value instanceof Integer ||
value instanceof String ||
value instanceof Long ||
value instanceof Float);
}
public Object getTaggedData(int tag) {
return entries.get(tag);
}
public int getCategory() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY);
if (obj instanceof Integer) {
return (Integer) obj;
} else {
return MetricsEvent.VIEW_UNKNOWN;
}
}
public int getType() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE);
if (obj instanceof Integer) {
return (Integer) obj;
} else {
return MetricsEvent.TYPE_UNKNOWN;
}
}
public int getSubtype() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE);
if (obj instanceof Integer) {
return (Integer) obj;
} else {
return 0;
}
}
public long getTimestamp() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP);
if (obj instanceof Long) {
return (Long) obj;
} else {
return 0;
}
}
public String getPackageName() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME);
if (obj instanceof String) {
return (String) obj;
} else {
return null;
}
}
public String getCounterName() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME);
if (obj instanceof String) {
return (String) obj;
} else {
return null;
}
}
public long getCounterBucket() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
if (obj instanceof Number) {
return ((Number) obj).longValue();
} else {
return 0L;
}
}
public boolean isLongCounterBucket() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
return obj instanceof Long;
}
public int getCounterValue() {
Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE);
if (obj instanceof Integer) {
return (Integer) obj;
} else {
return 0;
}
}
/**
* Assemble logs into structure suitable for EventLog.
*/
@@ -64,5 +200,17 @@ public class LogBuilder {
}
return out;
}
}
public void deserialize(Object[] items) {
int i = 0;
while(i < items.length) {
Object key = items[i++];
Object value = i < items.length ? items[i++] : null;
if (key instanceof Integer) {
entries.put((Integer) key, value);
} else {
Log.i(TAG, "Invalid key " + key.toString());
}
}
}
}

View File

@@ -17,12 +17,10 @@ package com.android.internal.logging;
import android.content.Context;
import android.os.Build;
import android.util.EventLog;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Log all the things.
*
@@ -38,6 +36,10 @@ public class MetricsLogger {
throw new IllegalArgumentException("Must define metric category");
}
EventLogTags.writeSysuiViewVisibility(category, 100);
EventLogTags.writeSysuiMultiAction(
new LogBuilder(category)
.setType(MetricsEvent.TYPE_OPEN)
.serialize());
}
public static void hidden(Context context, int category) throws IllegalArgumentException {
@@ -45,6 +47,10 @@ public class MetricsLogger {
throw new IllegalArgumentException("Must define metric category");
}
EventLogTags.writeSysuiViewVisibility(category, 0);
EventLogTags.writeSysuiMultiAction(
new LogBuilder(category)
.setType(MetricsEvent.TYPE_CLOSE)
.serialize());
}
public static void visibility(Context context, int category, boolean visibile)
@@ -62,21 +68,38 @@ public class MetricsLogger {
}
public static void action(Context context, int category) {
action(context, category, "");
EventLogTags.writeSysuiAction(category, "");
EventLogTags.writeSysuiMultiAction(
new LogBuilder(category)
.setType(MetricsEvent.TYPE_ACTION)
.serialize());
}
public static void action(Context context, int category, int value) {
action(context, category, Integer.toString(value));
EventLogTags.writeSysuiAction(category, Integer.toString(value));
EventLogTags.writeSysuiMultiAction(
new LogBuilder(category)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(value)
.serialize());
}
public static void action(Context context, int category, boolean value) {
action(context, category, Boolean.toString(value));
EventLogTags.writeSysuiAction(category, Boolean.toString(value));
EventLogTags.writeSysuiMultiAction(
new LogBuilder(category)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(value ? 1 : 0)
.serialize());
}
public static void action(LogBuilder content) {
//EventLog.writeEvent(524292, content.serialize());
// Below would be the *right* way to do this, using the generated
// EventLogTags method, but that doesn't work.
if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
content.setType(MetricsEvent.TYPE_ACTION);
}
EventLogTags.writeSysuiMultiAction(content.serialize());
}
@@ -86,15 +109,30 @@ public class MetricsLogger {
throw new IllegalArgumentException("Must define metric category");
}
EventLogTags.writeSysuiAction(category, pkg);
EventLogTags.writeSysuiMultiAction(new LogBuilder(category)
.setType(MetricsEvent.TYPE_ACTION)
.setPackageName(pkg)
.serialize());
}
/** Add an integer value to the monotonically increasing counter with the given name. */
public static void count(Context context, String name, int value) {
EventLogTags.writeSysuiCount(name, value);
EventLogTags.writeSysuiMultiAction(
new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
.setCounterName(name)
.setCounterValue(value)
.serialize());
}
/** Increment the bucket with the integer label on the histogram with the given name. */
public static void histogram(Context context, String name, int bucket) {
EventLogTags.writeSysuiHistogram(name, bucket);
EventLogTags.writeSysuiMultiAction(
new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
.setCounterName(name)
.setCounterBucket(bucket)
.setCounterValue(1)
.serialize());
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2017 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.internal.logging;
import com.android.internal.logging.legacy.LegacyConversionLogger;
import com.android.internal.logging.legacy.EventLogCollector;
import java.util.Queue;
/**
* Read platform logs.
*/
public class MetricsReader {
private EventLogCollector mReader;
private Queue<LogBuilder> mEventQueue;
private long mLastEventMs;
private long mCheckpointMs;
/** Open a new session and start reading logs.
*
* Starts reading from the oldest log not already read by this reader object.
* On first invocation starts from the oldest available log ion the system.
*/
public void read(long startMs) {
EventLogCollector reader = EventLogCollector.getInstance();
LegacyConversionLogger logger = new LegacyConversionLogger();
mLastEventMs = reader.collect(logger, startMs);
mEventQueue = logger.getEvents();
}
public void checkpoint() {
read(0L);
mCheckpointMs = mLastEventMs;
mEventQueue = null;
}
public void reset() {
read(mCheckpointMs);
}
/* Does the current log session have another entry? */
public boolean hasNext() {
return mEventQueue == null ? false : !mEventQueue.isEmpty();
}
/* Next entry in the current log session. */
public LogBuilder next() {
return mEventQueue == null ? null : mEventQueue.remove();
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
/**
* Parse the Android counter event logs.
* @hide
*/
public class CounterParser extends TagParser {
private static final String TAG = "CounterParser";
private static final int EVENTLOG_TAG = 524290;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 2) {
try {
String name = ((String) operands[0]);
int value = (Integer) operands[1];
logCount(logger, name, value);
} catch (ClassCastException e) {
if (debug) {
Log.d(TAG, "unexpected operand type", e);
}
}
} else if (debug) {
Log.d(TAG, "wrong number of operands: " + operands.length);
}
}
protected void logCount(TronLogger logger, String name, int value) {
logger.incrementBy(TronCounters.TRON_AOSP_PREFIX + name, value);
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
/**
* Scan the event log for interaction metrics events.
* @hide
*/
public class EventLogCollector {
private static final String TAG = "EventLogCollector";
// TODO replace this with GoogleLogTags.TRON_HEARTBEAT
@VisibleForTesting
static final int TRON_HEARTBEAT = 208000;
private static EventLogCollector sInstance;
private final ArrayMap<Integer, TagParser> mTagParsers;
private int[] mInterestingTags;
private LogReader mLogReader;
private EventLogCollector() {
mTagParsers = new ArrayMap<>();
addParser(new SysuiViewVisibilityParser());
addParser(new SysuiActionParser());
addParser(new SysuiQueryParser());
addParser(new NotificationPanelRevealedParser());
addParser(new NotificationPanelHiddenParser());
addParser(new NotificationClickedParser());
addParser(new NotificationActionClickedParser());
addParser(new NotificationCanceledParser());
addParser(new NotificationVisibilityParser());
addParser(new NotificationAlertParser());
addParser(new NotificationExpansionParser());
addParser(new CounterParser());
addParser(new HistogramParser());
addParser(new LockscreenGestureParser());
addParser(new StatusBarStateParser());
addParser(new PowerScreenStateParser());
addParser(new SysuiMultiActionParser());
mLogReader = new LogReader();
}
public static EventLogCollector getInstance() {
if (sInstance == null) {
sInstance = new EventLogCollector();
}
return sInstance;
}
@VisibleForTesting
public void setLogReader(LogReader logReader) {
mLogReader = logReader;
}
private int[] getInterestingTags() {
if (mInterestingTags == null) {
mInterestingTags = new int[mTagParsers.size()];
for (int i = 0; i < mTagParsers.size(); i++) {
mInterestingTags[i] = mTagParsers.valueAt(i).getTag();
}
}
return mInterestingTags;
}
// I would customize ArrayMap to add put(TagParser), but ArrayMap is final.
@VisibleForTesting
void addParser(TagParser parser) {
mTagParsers.put(parser.getTag(), parser);
mInterestingTags = null;
}
public void collect(LegacyConversionLogger logger) {
collect(logger, 0L);
}
public long collect(TronLogger logger, long lastSeenEventMs) {
long lastEventMs = 0L;
final boolean debug = Util.debug();
if (debug) {
Log.d(TAG, "Eventlog Collection");
}
ArrayList<Event> events = new ArrayList<>();
try {
mLogReader.readEvents(getInterestingTags(), events);
} catch (IOException e) {
e.printStackTrace();
}
if (debug) {
Log.d(TAG, "read this many events: " + events.size());
}
for (Event event : events) {
final long millis = event.getTimeNanos() / 1000000;
if (millis > lastSeenEventMs) {
final int tag = event.getTag();
TagParser parser = mTagParsers.get(tag);
if (parser == null) {
if (debug) {
Log.d(TAG, "unknown tag: " + tag);
}
continue;
}
if (debug) {
Log.d(TAG, "parsing tag: " + tag);
}
parser.parseEvent(logger, event);
lastEventMs = Math.max(lastEventMs, millis);
} else {
if (debug) {
Log.d(TAG, "old event: " + millis + " < " + lastSeenEventMs);
}
}
}
return lastEventMs;
}
@VisibleForTesting
static class Event {
long mTimeNanos;
int mTag;
Object mData;
Event(long timeNanos, int tag, Object data) {
super();
mTimeNanos = timeNanos;
mTag = tag;
mData = data;
}
Event(EventLog.Event event) {
mTimeNanos = event.getTimeNanos();
mTag = event.getTag();
mData = event.getData();
}
public long getTimeNanos() {
return mTimeNanos;
}
public int getTag() {
return mTag;
}
public Object getData() {
return mData;
}
}
@VisibleForTesting
static class LogReader {
public void readEvents(int[] tags, Collection<Event> events) throws IOException {
// Testing in Android: the Static Final Class Strikes Back!
ArrayList<EventLog.Event> nativeEvents = new ArrayList<>();
EventLog.readEvents(tags, nativeEvents);
for (EventLog.Event nativeEvent : nativeEvents) {
Event event = new Event(nativeEvent);
events.add(event);
}
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
/**
* Parse the Android histogram event logs.
* @hide
*/
public class HistogramParser extends CounterParser {
private static final String TAG = "HistogramParser";
private static final int EVENTLOG_TAG = 524291;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
protected void logCount(TronLogger logger, String name, int value) {
logger.incrementIntHistogram("tron_varz_" + name, value);
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.os.Bundle;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
/** @hide */
public class LegacyConversionLogger implements TronLogger {
public static final String VIEW_KEY = "view";
public static final String TYPE_KEY = "type";
public static final String EVENT_KEY = "data";
public static final int TYPE_COUNTER = 1;
public static final int TYPE_HISTOGRAM = 2;
public static final int TYPE_EVENT = 3;
private final Queue<LogBuilder> mQueue;
private HashMap<String, Boolean> mConfig;
public LegacyConversionLogger() {
mQueue = new LinkedList<>();
}
public Queue<LogBuilder> getEvents() {
return mQueue;
}
@Override
public void increment(String counterName) {
LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
.setCounterName(counterName)
.setCounterValue(1);
mQueue.add(b);
}
@Override
public void incrementBy(String counterName, int value) {
LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
.setCounterName(counterName)
.setCounterValue(value);
mQueue.add(b);
}
@Override
public void incrementIntHistogram(String counterName, int bucket) {
LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
.setCounterName(counterName)
.setCounterBucket(bucket)
.setCounterValue(1);
mQueue.add(b);
}
@Override
public void incrementLongHistogram(String counterName, long bucket) {
LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
.setCounterName(counterName)
.setCounterBucket(bucket)
.setCounterValue(1);
mQueue.add(b);
}
@Override
public LogBuilder obtain() {
return new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
}
@Override
public void dispose(LogBuilder proto) {
}
@Override
public void addEvent(LogBuilder proto) {
mQueue.add(proto);
}
@Override
public boolean getConfig(String configName) {
if (mConfig != null && mConfig.containsKey(configName)) {
return mConfig.get(configName);
}
return false;
}
@Override
public void setConfig(String configName, boolean newValue) {
if (mConfig == null) {
mConfig = new HashMap<>();
}
mConfig.put(configName, newValue);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android lockscreen gesture logs.
* @hide
*/
public class LockscreenGestureParser extends TagParser {
private static final String TAG = "LockscreenGestureParser";
private static final int EVENTLOG_TAG = 36021;
// source of truth is com.android.systemui.EventLogConstants
public static final int[] GESTURE_TYPE_MAP = {
MetricsEvent.VIEW_UNKNOWN, // there is no type 0
MetricsEvent.ACTION_LS_UNLOCK, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1
MetricsEvent.ACTION_LS_SHADE, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2
MetricsEvent.ACTION_LS_HINT, // SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3
MetricsEvent.ACTION_LS_CAMERA, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4
MetricsEvent.ACTION_LS_DIALER, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5
MetricsEvent.ACTION_LS_LOCK, // SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6
MetricsEvent.ACTION_LS_NOTE, // SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7
MetricsEvent.ACTION_LS_QS, // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8
MetricsEvent.ACTION_SHADE_QS_PULL, // SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9
MetricsEvent.ACTION_SHADE_QS_TAP // SYSUI_TAP_TO_OPEN_QS = 10
};
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 1) {
try {
int type = ((Integer) operands[0]).intValue();
// ignore gesture length in operands[1]
// ignore gesture velocity in operands[2]
int category = MetricsEvent.VIEW_UNKNOWN;
if (type < GESTURE_TYPE_MAP.length) {
category = GESTURE_TYPE_MAP[type];
}
if (category != MetricsEvent.VIEW_UNKNOWN) {
LogBuilder proto = logger.obtain();
proto.setCategory(category);
proto.setType(MetricsEvent.TYPE_ACTION);
proto.setTimestamp(eventTimeMs);
logger.addEvent(proto);
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification action button interaction event logs.
* @hide
*/
public class NotificationActionClickedParser extends TagParser {
private static final String TAG = "NotificationAction";
private static final int EVENTLOG_TAG = 27521;
private final NotificationKey mKey;
public NotificationActionClickedParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 1) {
try {
if (mKey.parse((String) operands[0])) {
int index = (Integer) operands[1];
parseTimes(operands, 2);
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION);
proto.setType(MetricsEvent.TYPE_ACTION);
proto.setSubtype(index);
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
filltimes(proto);
logger.addEvent(proto);
} else if (debug) {
Log.e(TAG, "unable to parse key.");
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the new Android notification alert event logs.
* @hide
*/
public class NotificationAlertParser extends TagParser {
private static final String TAG = "NotificationAlertParser";
private static final int EVENTLOG_TAG = 27532;
@VisibleForTesting
static final int BUZZ = 0x00000001;
@VisibleForTesting
static final int BEEP = 0x00000002;
@VisibleForTesting
static final int BLINK = 0x00000004;
private final NotificationKey mKey;
public NotificationAlertParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 3) {
try {
final String keyString = (String) operands[0];
final boolean buzz = ((Integer) operands[1]) == 1;
final boolean beep = ((Integer) operands[2]) == 1;
final boolean blink = ((Integer) operands[3]) == 1;
if (mKey.parse(keyString)) {
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ALERT);
proto.setType(MetricsEvent.TYPE_OPEN);
proto.setSubtype((buzz ? BUZZ : 0) | (beep ? BEEP : 0) | (blink ? BLINK : 0));
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
filltimes(proto);
logger.addEvent(proto);
} else {
if (debug) {
Log.e(TAG, "unable to parse key: " + keyString);
}
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
return;
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification cancellation event logs.
* @hide
*/
public class NotificationCanceledParser extends TagParser {
private static final String TAG = "NotificationCanceled";
private static final int EVENTLOG_TAG = 27530;
// from com.android.server.notification.NotificationManagerService
static final int REASON_DELEGATE_CLICK = 1;
static final int REASON_DELEGATE_CANCEL = 2;
static final int REASON_DELEGATE_CANCEL_ALL = 3;
static final int REASON_PACKAGE_BANNED = 7;
static final int REASON_LISTENER_CANCEL = 10;
static final int REASON_LISTENER_CANCEL_ALL = 11;
private final NotificationKey mKey;
public NotificationCanceledParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 1) {
try {
final String keyString = (String) operands[0];
final int reason = (Integer) operands[1];
parseTimes(operands, 2);
// handle old style log
// TODO: delete once M is launched
if (operands.length < 5) {
mSinceVisibleMillis = mSinceUpdateMillis;
mSinceUpdateMillis = 0;
}
boolean intentional = true;
switch (reason) {
case REASON_DELEGATE_CANCEL:
case REASON_DELEGATE_CANCEL_ALL:
case REASON_LISTENER_CANCEL:
case REASON_LISTENER_CANCEL_ALL:
case REASON_DELEGATE_CLICK:
case REASON_PACKAGE_BANNED:
break;
default:
intentional = false;
}
if (mKey.parse(keyString)) {
if (intentional) {
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
proto.setType(MetricsEvent.TYPE_DISMISS);
proto.setSubtype(reason);
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
filltimes(proto);
logger.addEvent(proto);
}
} else if (debug) {
Log.e(TAG, "unable to parse key: " + keyString);
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification interaction event logs.
* @hide
*/
public class NotificationClickedParser extends TagParser {
private static final String TAG = "NotificationClicked";
private static final int EVENTLOG_TAG = 27520;
private final NotificationKey mKey;
public NotificationClickedParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 0) {
try {
if (mKey.parse((String) operands[0])) {
parseTimes(operands, 1);
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
proto.setType(MetricsEvent.TYPE_ACTION);
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
filltimes(proto);
logger.addEvent(proto);
} else if (debug) {
Log.e(TAG, "unable to parse key.");
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification expansion event logs.
* @hide
*/
public class NotificationExpansionParser extends TagParser {
private static final String TAG = "NotificationExpansion";
private static final int EVENTLOG_TAG = 27511;
private final NotificationKey mKey;
public NotificationExpansionParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 2) {
try {
if (mKey.parse((String) operands[0])) {
boolean byUser = ((Integer) operands[1]) == 1;
boolean expanded = ((Integer) operands[2]) == 1;
parseTimes(operands, 3);
if (!byUser || !expanded) {
return;
}
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
proto.setType(MetricsEvent.TYPE_DETAIL);
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
filltimes(proto);
logger.addEvent(proto);
} else if (debug) {
Log.e(TAG, "unable to parse key.");
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
/**
* Parse Android notification keys
* @hide
*/
public class NotificationKey {
private static final String TAG = "NotificationKey";
public int mUser;
public String mPackageName;
public int mId;
public String mTag;
public int mUid;
public boolean parse(String key) {
if (key == null) {
return false;
}
boolean debug = Util.debug();
String[] parts = key.split("\\|");
if (parts.length == 5) {
try {
mUser = Integer.valueOf(parts[0]);
mPackageName = parts[1];
mId = Integer.valueOf(parts[2]);
mTag = parts[3].equals("null") ? "" : parts[3];
mUid = Integer.valueOf(parts[4]);
return true;
} catch (NumberFormatException e) {
if (debug) {
Log.w(TAG, "could not parse notification key.", e);
}
return false;
}
}
if (debug) {
Log.w(TAG, "wrong number of parts in notification key: " + key);
}
return false;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification panel visibility event logs.
* @hide
*/
public class NotificationPanelHiddenParser extends TagParser {
private static final String TAG = "NotificationPanelHidden";
private static final int EVENTLOG_TAG = 27501;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
proto.setType(MetricsEvent.TYPE_CLOSE);
proto.setTimestamp(eventTimeMs);
logger.addEvent(proto);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android notification panel visibility event logs.
* @hide
*/
public class NotificationPanelRevealedParser extends TagParser {
private static final String TAG = "NotificationPanelRevea";
private static final int EVENTLOG_TAG = 27500;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 1) {
try {
int load = ((Integer) operands[0]).intValue();
//logger.incrementBy(TronCounters.TRON_NOTIFICATION_LOAD, load);
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
}
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
proto.setType(MetricsEvent.TYPE_OPEN);
proto.setTimestamp(eventTimeMs);
logger.addEvent(proto);
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the new Android notification visibility event logs.
* @hide
*/
public class NotificationVisibilityParser extends TagParser {
private static final String TAG = "NotificationVisibility";
private static final int EVENTLOG_TAG = 27531;
private final NotificationKey mKey;
public NotificationVisibilityParser() {
mKey = new NotificationKey();
}
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length > 1) {
try {
final String keyString = (String) operands[0];
final boolean visible = ((Integer) operands[1]) == 1;
parseTimes(operands, 2);
int index = 0;
if (operands.length > 5 && operands[5] instanceof Integer) {
index = (Integer) operands[5];
}
if (mKey.parse(keyString)) {
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
proto.setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
proto.setTimestamp(eventTimeMs);
proto.setPackageName(mKey.mPackageName);
proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
proto.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, index);
filltimes(proto);
logger.addEvent(proto);
} else {
if (debug) {
Log.e(TAG, "unable to parse key: " + keyString);
}
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
return;
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android lockscreen gesture logs.
* @hide
*/
public class PowerScreenStateParser extends TagParser {
private static final String TAG = "PowerScreenStateParser";
private static final int EVENTLOG_TAG = 2728;
// source of truth is android.view.WindowManagerPolicy, why:
// 0: on
// 1: OFF_BECAUSE_OF_ADMIN
// 2: OFF_BECAUSE_OF_USER
// 3: OFF_BECAUSE_OF_TIMEOUT
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 2) {
try {
// (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
boolean state = (((Integer) operands[0]).intValue()) == 1;
int why = ((Integer) operands[1]).intValue();
LogBuilder proto = logger.obtain();
proto.setCategory(MetricsEvent.SCREEN);
proto.setType(state ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
proto.setTimestamp(eventTimeMs);
proto.setSubtype(why);
logger.addEvent(proto);
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android lockscreen gesture logs.
* @hide
*/
public class StatusBarStateParser extends TagParser {
private static final String TAG = "StatusBarStateParser";
private static final int EVENTLOG_TAG = 36004;
// source of truth is com.android.systemui.statusbar.StatusBarState
public static final int SHADE = 0;
public static final int KEYGUARD = 1;
public static final int SHADE_LOCKED = 2;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 6) {
try {
// [state, isShowing, isOccluded, isBouncerShowing, isSecure, isCurrentlyInsecure]
int state = ((Integer) operands[0]).intValue();
boolean isBouncerShowing = (((Integer) operands[3]).intValue()) == 1;
int isSecure = ((Integer) operands[4]).intValue();
int view = MetricsEvent.LOCKSCREEN;
int type = MetricsEvent.TYPE_OPEN;
if (state == SHADE) {
type = MetricsEvent.TYPE_CLOSE;
} else if (isBouncerShowing) {
view = MetricsEvent.BOUNCER;
}
LogBuilder proto = logger.obtain();
proto.setCategory(view);
proto.setType(type);
proto.setTimestamp(eventTimeMs);
proto.setSubtype(isSecure);
logger.addEvent(proto);
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android framework sysui action logs.
* @hide
*/
public class SysuiActionParser extends TagParser {
private static final String TAG = "SysuiActionParser";
private static final int EVENTLOG_TAG = 524288;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
try {
String packageName = null;
int subType = -1;
boolean hasSubType = false;
if (operands.length > 1) {
String arg = (String) operands[1];
if (arg.equals("true")) {
hasSubType = true;
subType = 1;
} else if (arg.equals("false")) {
hasSubType = true;
subType = 0;
} else if (arg.matches("^-?\\d+$")) {
try {
subType = Integer.valueOf(arg);
hasSubType = true;
} catch (NumberFormatException e) {
}
} else {
packageName = arg;
}
}
if (operands.length > 0) {
int category = ((Integer) operands[0]).intValue();
LogBuilder proto = logger.obtain();
proto.setCategory(category);
proto.setType(MetricsEvent.TYPE_ACTION);
proto.setTimestamp(eventTimeMs);
if (packageName != null) {
proto.setPackageName(packageName);
}
if (hasSubType) {
proto.setSubtype(subType);
}
logger.addEvent(proto);
}
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* ...and one parser to rule them all.
*
* This should, at some point in the future, be the only parser.
* @hide
*/
public class SysuiMultiActionParser extends TagParser {
private static final String TAG = "SysuiMultiActionParser";
private static final int EVENTLOG_TAG = 524292;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
try {
logger.addEvent(new LogBuilder(operands).setTimestamp(eventTimeMs));
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
/**
* Parse the Android framework sysui search query logs.
* For now just treat them like actions.
* @hide
*/
public class SysuiQueryParser extends SysuiActionParser {
private static final String TAG = "SysuiQueryParser";
private static final int EVENTLOG_TAG = 524289;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Parse the Android framework sysui view visibility logs.
* @hide
*/
public class SysuiViewVisibilityParser extends TagParser {
private static final String TAG = "SysuiViewVisibility";
private static final int EVENTLOG_TAG = 524287;
@Override
public int getTag() {
return EVENTLOG_TAG;
}
@Override
public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
final boolean debug = Util.debug();
if (operands.length >= 2) {
try {
int category = ((Integer) operands[0]).intValue();
boolean visibility = ((Integer) operands[1]).intValue() != 0;
LogBuilder proto = logger.obtain();
proto.setCategory(category);
proto.setType(visibility ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
proto.setTimestamp(eventTimeMs);
logger.addEvent(proto);
} catch (ClassCastException e) {
if (debug) {
Log.e(TAG, "unexpected operand type: ", e);
}
}
} else if (debug) {
Log.w(TAG, "wrong number of operands: " + operands.length);
}
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Abstraction layer between EventLog static classes and the actual TagParsers.
* @hide
*/
public abstract class TagParser {
private static final String TAG = "TagParser";
protected int mSinceCreationMillis;
protected int mSinceUpdateMillis;
protected int mSinceVisibleMillis;
abstract int getTag();
@VisibleForTesting
abstract public void parseEvent(TronLogger logger, long eventTimeMs, Object[] objects);
/**
* Parse the event into the proto: return true if proto was modified.
*/
public void parseEvent(TronLogger logger, EventLogCollector.Event event) {
final boolean debug = Util.debug();
Object data = event.getData();
Object[] objects;
if (data instanceof Object[]) {
objects = (Object[]) data;
for (int i = 0; i < objects.length; i++) {
if (objects[i] == null) {
if (debug) {
Log.d(TAG, "unexpected null value:" + event.getTag());
}
return;
}
}
} else {
// wrap scalar objects
objects = new Object[1];
objects[0] = data;
}
parseEvent(logger, event.getTimeNanos() / 1000000, objects);
}
protected void resetTimes() {
mSinceCreationMillis = 0;
mSinceUpdateMillis = 0;
mSinceVisibleMillis = 0;
}
public void parseTimes(Object[] operands, int index) {
resetTimes();
if (operands.length > index && operands[index] instanceof Integer) {
mSinceCreationMillis = (Integer) operands[index];
}
index++;
if (operands.length > index && operands[index] instanceof Integer) {
mSinceUpdateMillis = (Integer) operands[index];
}
index++;
if (operands.length > index && operands[index] instanceof Integer) {
mSinceVisibleMillis = (Integer) operands[index];
}
}
public void filltimes(LogBuilder proto) {
if (mSinceCreationMillis != 0) {
proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS,
mSinceCreationMillis);
}
if (mSinceUpdateMillis != 0) {
proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS,
mSinceUpdateMillis);
}
if (mSinceVisibleMillis != 0) {
proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS,
mSinceVisibleMillis);
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
/**
* Names of the counters that the Tron package defines.
*
* Other counter names may be generated by AOSP code.
* @hide
*/
public class TronCounters {
static final String TRON_COLLECTIONS = "tron_collections";
static final String TRON_COLLECTION_PERIOD = "tron_collection_period_minutes";
static final String TRON_EVENTLOG_LENGTH = "tron_eventlog_horizon";
static final String TRON_NOTE_DISMISS = "tron_note_dismiss";
static final String TRON_NOTE_DISMISS_BY_USER = "tron_note_dismiss_user";
static final String TRON_NOTE_DISMISS_BY_CLICK = "tron_note_dismiss_click";
static final String TRON_NOTE_DISMISS_BY_LISTENER = "tron_note_dismiss_listener";
static final String TRON_NOTE_DISMISS_BY_BAN = "tron_note_dismiss_ban";
static final String TRON_NOTE_REVEALED = "tron_note_revealed";
static final String TRON_NOTIFICATION_LOAD = "tron_notification_load";
static final String TRON_VIEW = "tron_view";
static final String TRON_ACTION = "tron_action";
static final String TRON_DETAIL = "tron_detail";
static final String TRON_NOTE_LIFETIME = "tron_note_lifetime";
/** Append the AOSP-generated name */
static final String TRON_AOSP_PREFIX = "tron_varz_";
static final String TRON_ACTION_BAD_INT = "tron_action_bad_int";
static final String TRON_NOTE_FRESHNESS = "tron_note_freshness";
static final String TRON_NOTE_BUZZ = "tron_note_buzz";
static final String TRON_NOTE_BEEP = "tron_note_beep";
static final String TRON_NOTE_BLINK = "tron_note_blink";
static final String TRON_DISABLE = "tron_disable";
static final String TRON_LAST_HEART_AGE = "tron_last_heart_minutes";
static final String TRON_HEARTS_SEEN = "tron_hearts_seen";
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import com.android.internal.logging.LogBuilder;
/**
* An entity that knows how to log events and counters.
*/
public interface TronLogger {
/** Add one to the named counter. */
void increment(String counterName);
/** Add an arbitrary value to the named counter. */
void incrementBy(String counterName, int value);
/** Increment a specified bucket on the named histogram by one. */
void incrementIntHistogram(String counterName, int bucket);
/** Increment the specified bucket on the named histogram by one. */
void incrementLongHistogram(String counterName, long bucket);
/** Obtain a SystemUiEvent proto, must release this with dispose() or addEvent(). */
LogBuilder obtain();
void dispose(LogBuilder proto);
/** Submit an event to be logged. Logger will dispose of proto. */
void addEvent(LogBuilder proto);
/** Get a config flag. */
boolean getConfig(String configName);
/** Set a config flag. */
void setConfig(String configName, boolean newValue);
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
/**
* Created by cwren on 11/21/16.
*/
public class Util {
public static boolean debug() {
return false;
}
}

View File

@@ -1,5 +1,21 @@
/*
* Copyright (C) 2017 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.internal.logging;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import junit.framework.TestCase;
public class LogBuilderTest extends TestCase {
@@ -15,6 +31,57 @@ public class LogBuilderTest extends TestCase {
assertEquals("two", out[3]);
}
public void testSerializeDeserialize() {
int category = 10;
int type = 11;
int subtype = 12;
long timestamp = 1484669007890L;
String packageName = "com.foo.bar";
String counterName = "sheep";
int bucket = 13;
int value = 14;
LogBuilder builder = new LogBuilder(category);
builder.setType(type);
builder.setSubtype(subtype);
builder.setTimestamp(timestamp);
builder.setPackageName(packageName);
builder.setCounterName(counterName);
builder.setCounterBucket(bucket);
builder.setCounterValue(value);
builder.addTaggedData(1, "one");
builder.addTaggedData(2, "two");
Object[] out = builder.serialize();
LogBuilder parsed = new LogBuilder(out);
assertEquals(category, parsed.getCategory());
assertEquals(type, parsed.getType());
assertEquals(subtype, parsed.getSubtype());
assertEquals(timestamp, parsed.getTimestamp());
assertEquals(packageName, parsed.getPackageName());
assertEquals(counterName, parsed.getCounterName());
assertEquals(bucket, parsed.getCounterBucket());
assertEquals(value, parsed.getCounterValue());
assertEquals("one", parsed.getTaggedData(1));
assertEquals("two", parsed.getTaggedData(2));
}
public void testIntBucket() {
LogBuilder builder = new LogBuilder(0);
builder.setCounterBucket(100);
assertEquals(100, builder.getCounterBucket());
assertEquals(false, builder.isLongCounterBucket());
}
public void testLongBucket() {
long longBucket = Long.MAX_VALUE;
LogBuilder builder = new LogBuilder(0);
builder.setCounterBucket(longBucket);
assertEquals(longBucket, builder.getCounterBucket());
assertEquals(true, builder.isLongCounterBucket());
}
public void testInvalidInputThrows() {
LogBuilder builder = new LogBuilder(0);
boolean threw = false;
@@ -24,7 +91,7 @@ public class LogBuilderTest extends TestCase {
threw = true;
}
assertTrue(threw);
assertEquals(0, builder.serialize().length);
assertEquals(2, builder.serialize().length);
}
public void testValidInputTypes() {
@@ -40,4 +107,11 @@ public class LogBuilderTest extends TestCase {
assertEquals(123.0F, out[7]);
}
public void testCategoryDefault() {
LogBuilder builder = new LogBuilder(10);
Object[] out = builder.serialize();
assertEquals(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY, out[0]);
assertEquals(10, out[1]);
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class CounterParserTest extends ParserTest {
public CounterParserTest() {
mParser = new CounterParser();
}
public void testGoodData() throws Throwable {
String name = "foo";
int value = 5;
Object[] objects = new Object[2];
objects[0] = name;
objects[1] = value;
validateGoodData(name, value, objects);
}
private void validateGoodData(String name, int value, Object[] objects) {
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, times(1)).incrementBy(mNameCaptor.capture(), mCountCaptor.capture());
assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
assertEquals(value, mCountCaptor.getValue().intValue());
}
public void testMissingName() throws Throwable {
Object[] objects = new Object[1];
objects[0] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testWrongTypes() throws Throwable {
String name = "foo";
int value = 5;
Object[] objects = new Object[2];
objects[0] = value;
objects[1] = name;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreMissingInput() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreUnexpectedData() throws Throwable {
String name = "foo";
int value = 5;
Object[] objects = new Object[3];
objects[0] = name;
objects[1] = value;
objects[2] = "foo";
validateGoodData(name, value, objects);
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class HistogramParserTest extends ParserTest {
public HistogramParserTest() {
mParser = new HistogramParser();
}
public void testGoodData() throws Throwable {
String name = "foo";
int bucket = 5;
Object[] objects = new Object[2];
objects[0] = name;
objects[1] = bucket;
validateGoodData(name, bucket, objects);
}
private void validateGoodData(String name, int bucket, Object[] objects) {
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, times(1))
.incrementIntHistogram(mNameCaptor.capture(), mCountCaptor.capture());
assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
assertEquals(bucket, mCountCaptor.getValue().intValue());
}
public void testMissingName() throws Throwable {
Object[] objects = new Object[1];
objects[0] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testWrongTypes() throws Throwable {
String name = "foo";
int value = 5;
Object[] objects = new Object[2];
objects[0] = value;
objects[1] = name;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreMissingInput() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreUnexpectedData() throws Throwable {
String name = "foo";
int bucket = 5;
Object[] objects = new Object[3];
objects[0] = name;
objects[1] = bucket;
objects[2] = "foo";
validateGoodData(name, bucket, objects);
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class LockscreenGestureParserTest extends ParserTest {
public LockscreenGestureParserTest() {
mParser = new LockscreenGestureParser();
}
public void testSwipeUpUnlock() throws Throwable {
validate(MetricsEvent.ACTION_LS_UNLOCK, 1, 359, 6382);
}
public void testSwipeToShade() throws Throwable {
validate(MetricsEvent.ACTION_LS_SHADE, 2, 324, 0);
}
public void testTapLockHint() throws Throwable {
validate(MetricsEvent.ACTION_LS_HINT, 3, 0, 0);
}
public void testCamera() throws Throwable {
validate(MetricsEvent.ACTION_LS_CAMERA, 4, 223, 1756);
}
public void testDialer() throws Throwable {
validate(MetricsEvent.ACTION_LS_DIALER, 5, 163, 861);
}
public void testTapToLock() throws Throwable {
validate(MetricsEvent.ACTION_LS_LOCK, 6, 0, 0);
}
public void testTapOnNotification() throws Throwable {
validate(MetricsEvent.ACTION_LS_NOTE, 7, 0, 0);
}
public void testLockscreenQuickSettings() throws Throwable {
validate(MetricsEvent.ACTION_LS_QS, 8, 284, 3824);
}
public void testShadePullQuickSettings() throws Throwable {
validate(MetricsEvent.ACTION_SHADE_QS_PULL, 9, 175, 3444);
}
public void testShadeTapQuickSettings() throws Throwable {
validate(MetricsEvent.ACTION_SHADE_QS_TAP, 10, 0, 0);
}
private void validate(int view, int type, int len, int vel) {
int t = 1000;
Object[] objects = new Object[3];
objects[0] = type;
objects[1] = len;
objects[2] = vel;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
Object[] objects = new Object[4];
objects[0] = 1;
objects[1] = 0;
objects[2] = 0;
objects[3] = "foo";
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class NotificationActionClickedParserTest extends ParserTest {
public NotificationActionClickedParserTest() {
mParser = new NotificationActionClickedParser();
}
public void testGoodData() throws Throwable {
int t = 1000;
int index = 1;
Object[] objects = new Object[2];
objects[0] = mKey;
objects[1] = index;
validateGoodData(t, "", index, objects);
}
public void testTagged() throws Throwable {
int t = 1000;
int index = 1;
Object[] objects = new Object[2];
objects[0] = mTaggedKey;
objects[1] = index;
validateGoodData(t, mTag, index, objects);
}
private LogBuilder validateGoodData(int t, String tag, int index, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ITEM_ACTION, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, tag);
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
assertEquals(index, proto.getSubtype());
return proto;
}
public void testMissingData() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testWrongType() throws Throwable {
Object[] objects = new Object[2];
objects[0] = 2;
objects[1] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testBadKey() throws Throwable {
Object[] objects = new Object[2];
objects[0] = "foo";
objects[1] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testMncTimestamps() throws Throwable {
int t = 1000;
int index = 1;
Object[] objects = new Object[5];
objects[0] = mKey;
objects[1] = index;
objects[2] = mSinceCreationMillis;
objects[3] = mSinceUpdateMillis;
objects[4] = mSinceVisibleMillis;
LogBuilder proto = validateGoodData(t, "", index, objects);
validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
mSinceVisibleMillis);
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int index = 1;
Object[] objects = new Object[6];
objects[0] = mKey;
objects[1] = index;
objects[2] = mSinceCreationMillis;
objects[3] = mSinceUpdateMillis;
objects[4] = mSinceVisibleMillis;
objects[5] = "foo";
validateGoodData(t, "", index, objects);
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.Collections;
import java.util.List;
import org.mockito.ArgumentCaptor;
public class NotificationAlertParserTest extends ParserTest {
protected ArgumentCaptor<Boolean> mConfigCaptor;
private final int mTime = 1000;
public NotificationAlertParserTest() {
mParser = new NotificationAlertParser();
}
@Override
protected void setUp() throws Exception {
super.setUp();
mConfigCaptor = ArgumentCaptor.forClass(Boolean.class);
when(mLogger.getConfig(anyString())).thenReturn(false);
}
public void testBuzzOnly() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 1;
objects[2] = 0;
objects[3] = 0;
validateInteraction(true, false, false, objects);
}
public void testBeepOnly() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 0;
objects[2] = 1;
objects[3] = 0;
validateInteraction(false, true, false, objects);
}
public void testBlinkOnly() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 0;
objects[2] = 0;
objects[3] = 1;
validateInteraction(false, false, true, objects);
}
public void testBuzzBlink() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 1;
objects[2] = 0;
objects[3] = 1;
validateInteraction(true, false, true, objects);
}
public void testBeepBlink() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 0;
objects[2] = 1;
objects[3] = 1;
validateInteraction(false, true, true, objects);
}
public void testIgnoreExtraArgs() throws Throwable {
Object[] objects = new Object[5];
objects[0] = mTaggedKey;
objects[1] = 0;
objects[2] = 1;
objects[3] = 1;
objects[4] = "foo";
validateInteraction(false, true, true, objects);
}
private void validateInteraction(boolean buzz, boolean beep, boolean blink, Object[] objects) {
int flags = 0;
int counts = 0;
if (buzz) {
counts++;
flags |= NotificationAlertParser.BUZZ;
}
if (beep) {
counts++;
flags |= NotificationAlertParser.BEEP;
}
if (blink) {
counts++;
flags |= NotificationAlertParser.BLINK;
}
mParser.parseEvent(mLogger, mTime, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(mTime, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ALERT, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, mTag);
assertEquals(flags, proto.getSubtype());
assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.List;
public class NotificationCanceledParserTest extends ParserTest {
public NotificationCanceledParserTest() {
mParser = new NotificationCanceledParser();
}
public void testGoodProto() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[2];
objects[0] = mKey;
objects[1] = reason;
validateGoodData(t, "", reason, objects);
}
public void testTagged() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[2];
objects[0] = mTaggedKey;
objects[1] = reason;
validateGoodData(t, mTag, reason, objects);
}
private void validateGoodData(int t, String tag, int reason, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, tag);
assertEquals(MetricsEvent.TYPE_DISMISS, proto.getType());
assertEquals(reason, proto.getSubtype());
}
public void testLifetime() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = reason;
objects[2] = mSinceCreationMillis;
validateTimers(t, objects, mSinceCreationMillis, 0, 0);
}
public void testExposure() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[4];
objects[0] = mKey;
objects[1] = reason;
objects[2] = mSinceCreationMillis;
objects[3] = mSinceVisibleMillis;
validateTimers(t, objects, mSinceCreationMillis, 0, mSinceVisibleMillis);
}
public void testFreshness() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[5];
objects[0] = mKey;
objects[1] = reason;
objects[2] = mSinceCreationMillis;
objects[3] = mSinceUpdateMillis;
objects[4] = mSinceVisibleMillis;
validateTimers(t, objects, mSinceCreationMillis, mSinceUpdateMillis, mSinceVisibleMillis);
}
private void validateTimers(int t, Object[] objects, int life, int freshness, int exposure) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
validateNotificationTimes(proto, life, freshness, exposure);
}
public void verifyReason(int reason, boolean intentional, boolean important, String counter)
throws Throwable {
Object[] objects = new Object[2];
objects[0] = mKey;
objects[1] = reason;
mParser.parseEvent(mLogger, 0, objects);
if (intentional) {
verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
}
}
public void testDelegateCancel() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL,
true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
}
public void testDelegateCancelAll() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL_ALL,
true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
}
public void testListenerCancel() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL,
false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
}
public void testListenerCancelAll() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL_ALL,
false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
}
public void testDelegateClick() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_DELEGATE_CLICK,
true, true, TronCounters.TRON_NOTE_DISMISS_BY_CLICK);
}
public void testBanned() throws Throwable {
verifyReason(NotificationCanceledParser.REASON_PACKAGE_BANNED,
false, true, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
}
public void testUnknownReason() throws Throwable {
verifyReason(1001010, false, false, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
}
public void testMissingData() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testWrongType() throws Throwable {
Object[] objects = new Object[2];
objects[0] = 2;
objects[1] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testBadKey() throws Throwable {
Object[] objects = new Object[2];
objects[0] = "foo";
objects[1] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = reason;
objects[2] = "foo";
validateGoodData(t, "", reason, objects);
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class NotificationClickedParserTest extends ParserTest {
public NotificationClickedParserTest() {
mParser = new NotificationClickedParser();
}
public void testGoodData() throws Throwable {
int t = 1000;
Object[] objects = new Object[1];
objects[0] = mKey;
validateGoodData(t, "", objects);
}
public void testTagged() throws Throwable {
int t = 1000;
Object[] objects = new Object[1];
objects[0] = mTaggedKey;
validateGoodData(t, mTag, objects);
}
private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, tag);
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
assertEquals(0, proto.getSubtype());
return proto;
}
public void testMissingKey() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testWrongType() throws Throwable {
Object[] objects = new Object[1];
objects[0] = 5;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testBadKey() throws Throwable {
Object[] objects = new Object[1];
objects[0] = "foo";
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testMncTimestamps() throws Throwable {
int t = 1000;
Object[] objects = new Object[4];
objects[0] = mKey;
objects[1] = mSinceCreationMillis;
objects[2] = mSinceUpdateMillis;
objects[3] = mSinceVisibleMillis;
LogBuilder proto = validateGoodData(t, "", objects);
validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
mSinceVisibleMillis);
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
Object[] objects = new Object[5];
objects[0] = mKey;
objects[1] = mSinceCreationMillis;
objects[2] = mSinceUpdateMillis;
objects[3] = mSinceVisibleMillis;
objects[4] = "foo";
validateGoodData(t, "", objects);
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class NotificationExpansionParserTest extends ParserTest {
public NotificationExpansionParserTest() {
mParser = new NotificationExpansionParser();
}
public void testExpandedByUser() throws Throwable {
int t = 1000;
int byUser = 1;
int expanded = 1;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
validateGoodData(t, "", objects);
}
public void testTagged() throws Throwable {
int t = 1000;
int byUser = 1;
int expanded = 1;
Object[] objects = new Object[3];
objects[0] = mTaggedKey;
objects[1] = byUser;
objects[2] = expanded;
validateGoodData(t, mTag, objects);
}
private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, tag);
assertEquals(MetricsEvent.TYPE_DETAIL, proto.getType());
return proto;
}
public void testAutoExpand() throws Throwable {
int t = 1000;
int byUser = 0;
int expanded = 1;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testCollapsedByUser() throws Throwable {
int t = 1000;
int byUser = 1;
int expanded = 0;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testAutoCollapsed() throws Throwable {
int t = 1000;
int byUser = 0;
int expanded = 0;
Object[] objects = new Object[3];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testMissingData() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testWrongType() throws Throwable {
Object[] objects = new Object[3];
objects[0] = 2;
objects[1] = 5;
objects[2] = 7;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testBadKey() throws Throwable {
Object[] objects = new Object[3];
objects[0] = "foo";
objects[1] = 5;
objects[2] = 2;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
}
public void testMncTimestamps() throws Throwable {
int t = 1000;
int byUser = 1;
int expanded = 1;
Object[] objects = new Object[6];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
objects[3] = mSinceCreationMillis;
objects[4] = mSinceUpdateMillis;
objects[5] = mSinceVisibleMillis;
LogBuilder proto = validateGoodData(t, "", objects);
validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
mSinceVisibleMillis);
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int byUser = 1;
int expanded = 1;
Object[] objects = new Object[7];
objects[0] = mKey;
objects[1] = byUser;
objects[2] = expanded;
objects[3] = mSinceCreationMillis;
objects[4] = mSinceUpdateMillis;
objects[5] = mSinceVisibleMillis;
objects[6] = "foo";
validateGoodData(t, "", objects);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import android.test.InstrumentationTestCase;
public class NotificationKeyTest extends InstrumentationTestCase {
private final NotificationKey mKey;
public NotificationKeyTest() {
mKey = new NotificationKey();
}
public void testGoodKey() throws Throwable {
assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|null|10090"));
assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
assertEquals("", mKey.mTag);
assertEquals(31338, mKey.mId);
assertEquals(1, mKey.mUser);
assertEquals(10090, mKey.mUid);
}
public void testTaggedKey() throws Throwable {
assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|foo|10090"));
assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
assertEquals("foo", mKey.mTag);
assertEquals(31338, mKey.mId);
assertEquals(1, mKey.mUser);
assertEquals(10090, mKey.mUid);
}
public void testEmptyTag() throws Throwable {
assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338||10090"));
assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
assertEquals("", mKey.mTag);
assertEquals(31338, mKey.mId);
assertEquals(1, mKey.mUser);
assertEquals(10090, mKey.mUid);
}
public void testBadKeys() throws Throwable {
assertFalse(mKey.parse(null));
assertFalse(mKey.parse(""));
assertFalse(mKey.parse("foo")); // not a key
assertFalse(mKey.parse("1|com.android.example.notificationshowcase|31338|null"));
assertFalse(mKey.parse("bar|com.android.example.notificationshowcase|31338|null|10090"));
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class NotificationPanelHiddenParserTest extends ParserTest {
public NotificationPanelHiddenParserTest() {
mParser = new NotificationPanelHiddenParser();
}
public void testNoInput() throws Throwable {
int t = 1000;
Object[] objects = new Object[0];
validateGoodData(t, objects);
}
public void testIgnoreExtraneousInput() throws Throwable {
Object[] objects = new Object[1];
objects[0] = "nothing to see here";
validateGoodData(0, objects);
}
private void validateGoodData(int t, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class NotificationPanelRevealedParserTest extends ParserTest {
public NotificationPanelRevealedParserTest() {
mParser = new NotificationPanelRevealedParser();
}
public void testLollipopInput() throws Throwable {
int t = 1000;
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
}
public void testMncData() throws Throwable {
int t = 1000;
int n = 5;
Object[] objects = new Object[1];
objects[0] = Integer.valueOf(n);
validateMncData(t, n, objects);
}
private void validateMncData(int t, int n, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
}
public void testBadInput() throws Throwable {
Object[] objects = new Object[1];
objects[0] = "This is not the integer you're looking for.";
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int n = 5;
Object[] objects = new Object[2];
objects[0] = Integer.valueOf(n);
objects[1] = "foo";
validateMncData(t, n, objects);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import org.mockito.ArgumentCaptor;
public class NotificationVisibilityParserTest extends ParserTest {
private final int mCreationTime = 23124;
private final int mUpdateTime = 3412;
private final int mTime = 1000;
public NotificationVisibilityParserTest() {
mParser = new NotificationVisibilityParser();
}
public void testReveal() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 1;
objects[2] = mCreationTime;
objects[3] = mUpdateTime;
validateInteraction(true, mUpdateTime, 0, objects);
}
public void testHide() throws Throwable {
Object[] objects = new Object[4];
objects[0] = mTaggedKey;
objects[1] = 0;
objects[2] = mCreationTime;
objects[3] = mUpdateTime;
validateInteraction(false, mUpdateTime, 0, objects);
}
public void testIgnoreUnexpectedData() throws Throwable {
Object[] objects = new Object[5];
objects[0] = mTaggedKey;
objects[1] = 1;
objects[2] = mCreationTime;
objects[3] = mUpdateTime;
objects[4] = "foo";
validateInteraction(true, mUpdateTime, 0, objects);
}
public void testMarshmallowIndexData() throws Throwable {
Object[] objects = new Object[6];
objects[0] = mTaggedKey;
objects[1] = 1;
objects[2] = mCreationTime;
objects[3] = mUpdateTime;
objects[4] = 0;
objects[5] = 3;
validateInteraction(true, mUpdateTime, 3, objects);
}
private void validateInteraction(boolean visible, int freshness, int index, Object[] objects) {
mParser.parseEvent(mLogger, mTime, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(mTime, proto.getTimestamp());
assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
assertEquals(mKeyPackage, proto.getPackageName());
validateNotificationIdAndTag(proto, mId, mTag);
validateNotificationTimes(proto, mCreationTime, mUpdateTime);
assertEquals(index, proto.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
assertEquals(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE, proto.getType());
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import junit.framework.TestCase;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.OngoingStubbing;
/**
* Common functions and temporaries for parser tests.
*/
public class ParserTest extends TestCase {
@Mock
protected TronLogger mLogger;
protected TagParser mParser;
protected LogBuilder[] mProto;
protected ArgumentCaptor<LogBuilder> mProtoCaptor;
protected ArgumentCaptor<String> mNameCaptor;
protected ArgumentCaptor<Integer> mCountCaptor;
protected String mKey = "0|com.android.example.notificationshowcase|31338|null|10090";
protected String mTaggedKey = "0|com.android.example.notificationshowcase|31338|badger|10090";
protected String mKeyPackage = "com.android.example.notificationshowcase";
protected String mTag = "badger";
protected int mId = 31338;
protected int mSinceCreationMillis = 5000;
protected int mSinceUpdateMillis = 1012;
protected int mSinceVisibleMillis = 323;
public ParserTest() {
mProto = new LogBuilder[5];
for (int i = 0; i < mProto.length; i++) {
mProto[i] = new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
mProtoCaptor = ArgumentCaptor.forClass(LogBuilder.class);
mNameCaptor = ArgumentCaptor.forClass(String.class);
mCountCaptor = ArgumentCaptor.forClass(Integer.class);
OngoingStubbing<LogBuilder> stub = when(mLogger.obtain()).thenReturn(mProto[0]);
for (int i = 1; i < mProto.length; i++) {
stub.thenReturn(mProto[i]);
}
doNothing().when(mLogger).addEvent(any(LogBuilder.class));
doNothing().when(mLogger).incrementBy(anyString(), anyInt());
}
protected void validateNotificationTimes(LogBuilder proto, int life, int freshness,
int exposure) {
validateNotificationTimes(proto, life, freshness);
if (exposure != 0) {
assertEquals(exposure,
proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
} else {
assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
}
}
protected void validateNotificationTimes(LogBuilder proto, int life, int freshness) {
if (life != 0) {
assertEquals(life,
proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
} else {
assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
}
if (freshness != 0) {
assertEquals(freshness,
proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
} else {
assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
}
}
protected void validateNotificationIdAndTag(LogBuilder proto, int id, String tag) {
assertEquals(tag, proto.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
assertEquals(id, proto.getTaggedData(MetricsEvent.NOTIFICATION_ID));
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class PowerScreenStateParserTest extends ParserTest {
public PowerScreenStateParserTest() {
mParser = new PowerScreenStateParser();
}
public void testScreenOn() throws Throwable {
validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0");
}
public void testTimeout() throws Throwable {
validate(MetricsEvent.TYPE_CLOSE, 3, "0,3,0,0");
}
public void testUser() throws Throwable {
validate(MetricsEvent.TYPE_CLOSE, 2, "0,2,0,0");
}
public void testAdmin() throws Throwable {
validate(MetricsEvent.TYPE_CLOSE, 1, "0,1,0,0");
}
public void testIgnoreUnexpectedData() throws Throwable {
validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0,5");
}
private void validate(int type, int subType, String log) {
String[] parts = log.split(",");
int t = 1000;
Object[] objects = new Object[parts.length];
for (int i = 0; i < parts.length; i++) {
objects[i] = Integer.valueOf(parts[i]);
}
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(type, proto.getType());
assertEquals(MetricsEvent.SCREEN, proto.getCategory());
assertEquals(subType, proto.getSubtype());
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class StatusBarStateParserTest extends ParserTest {
public StatusBarStateParserTest() {
mParser = new StatusBarStateParser();
}
public void testLockScreen() throws Throwable {
validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 1, "1,1,0,0,1,0");
}
public void testBounce() throws Throwable {
validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "1,1,0,1,1,0");
}
public void testUnlock() throws Throwable {
validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_CLOSE, 1, "0,0,0,0,1,0");
}
public void testSecure() throws Throwable {
validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "2,1,0,1,1,0");
}
public void testInsecure() throws Throwable {
validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0");
}
public void testIgnoreUnexpectedData() throws Throwable {
validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0,5");
}
private void validate(int view, int type, int subType, String log) {
String[] parts = log.split(",");
int t = 1000;
Object[] objects = new Object[parts.length];
for (int i = 0; i < parts.length; i++) {
objects[i] = Integer.valueOf(parts[i]);
}
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(type, proto.getType());
assertEquals(subType, proto.getSubtype());
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class SysuiActionParserTest extends ParserTest {
public SysuiActionParserTest() {
mParser = new SysuiActionParser();
}
public void testGoodDatal() throws Throwable {
int t = 1000;
int view = 10;
Object[] objects = new Object[1];
objects[0] = view;
validateGoodData(t, view, objects);
}
private void validateGoodData(int t, int view, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
}
public void testGoodDataWithPackage() throws Throwable {
int t = 1000;
int view = 10;
String packageName = "com.foo";
Object[] objects = new Object[2];
objects[0] = view;
objects[1] = packageName;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(packageName, proto.getPackageName());
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
}
public void testGoodDataWithTrue() throws Throwable {
validateSubType(Boolean.toString(true), 1);
}
public void testGoodDataWithFalse() throws Throwable {
validateSubType(Boolean.toString(false), 0);
}
public void testGoodDataWithIntZero() throws Throwable {
validateSubType(Integer.toString(0), 0);
}
public void testGoodDataWithIntONe() throws Throwable {
validateSubType(Integer.toString(1), 1);
}
public void testGoodDataWithIntTwo() throws Throwable {
validateSubType(Integer.toString(2), 2);
}
public void testGoodDataWithNegativeInt() throws Throwable {
validateSubType(Integer.toString(-1), -1);
}
public void testGoodDataWithIntLarge() throws Throwable {
validateSubType(Integer.toString(120312), 120312);
}
public void testGoodDataWithNegativeIntLarge() throws Throwable {
validateSubType(Integer.toString(-120312), -120312);
}
private void validateSubType(String arg, int expectedValue) {
int t = 1000;
int view = 10;
Object[] objects = new Object[2];
objects[0] = view;
objects[1] = arg;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(expectedValue, proto.getSubtype());
assertNull(proto.getPackageName());
assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
}
public void testIgnoreMissingInput() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreWrongInputs() throws Throwable {
Object[] objects = new Object[2];
objects[0] = "nothing to see here";
objects[1] = 10;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreStringViewInput() throws Throwable {
Object[] objects = new Object[1];
objects[0] = "this is not the input you are looking for";
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int view = 10;
Object[] objects = new Object[2];
objects[0] = view;
objects[1] = "foo";
validateGoodData(t, view, objects);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class SysuiMultiActionParserTest extends ParserTest {
public SysuiMultiActionParserTest() {
mParser = new SysuiMultiActionParser();
}
public void testParseAllFields() {
int category = 10;
int type = 11;
int subtype = 12;
long timestamp = 1484669007890L;
String packageName = "com.foo.bar";
String counterName = "sheep";
int bucket = 13;
int value = 14;
LogBuilder builder = new LogBuilder(category);
builder.setType(type);
builder.setSubtype(subtype);
builder.setPackageName(packageName);
builder.setCounterName(counterName);
builder.setCounterBucket(bucket);
builder.setCounterValue(value);
builder.addTaggedData(1, "one");
builder.addTaggedData(2, "two");
Object[] out = builder.serialize();
int t = 1000;
mParser.parseEvent(mLogger, timestamp, out);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(category, proto.getCategory());
assertEquals(type, proto.getType());
assertEquals(subtype, proto.getSubtype());
assertEquals(timestamp, proto.getTimestamp());
assertEquals(packageName, proto.getPackageName());
assertEquals(counterName, proto.getCounterName());
assertEquals(bucket, proto.getCounterBucket());
assertEquals(value, proto.getCounterValue());
assertEquals("one", proto.getTaggedData(1));
assertEquals("two", proto.getTaggedData(2));
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2017 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.internal.logging.legacy;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class SysuiViewVisibilityParserTest extends ParserTest {
public SysuiViewVisibilityParserTest() {
mParser = new SysuiViewVisibilityParser();
}
public void testViewReveal() throws Throwable {
int t = 1000;
int view = 10;
Object[] objects = new Object[2];
objects[0] = view;
objects[1] = 100;
validateViewReveal(t, view, objects);
}
private void validateViewReveal(int t, int view, Object[] objects) {
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(t, proto.getTimestamp());
assertEquals(view, proto.getCategory());
assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
}
public void testViewHidden() throws Throwable {
int t = 1000;
int view = 10;
Object[] objects = new Object[2];
objects[0] = view;
objects[1] = 0;
mParser.parseEvent(mLogger, t, objects);
verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
LogBuilder proto = mProtoCaptor.getValue();
assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
}
public void testIgnoreMissingInput() throws Throwable {
Object[] objects = new Object[0];
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreStringInARgOne() throws Throwable {
Object[] objects = new Object[2];
objects[0] = "nothing to see here";
objects[1] = 100;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreStringInArgTwo() throws Throwable {
Object[] objects = new Object[2];
objects[0] = 100;
objects[1] = "nothing to see here";
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testOneInput() throws Throwable {
Object[] objects = new Object[1];
objects[0] = 100;
mParser.parseEvent(mLogger, 0, objects);
verify(mLogger, never()).addEvent((LogBuilder) anyObject());
verify(mLogger, never()).incrementBy(anyString(), anyInt());
}
public void testIgnoreUnexpectedData() throws Throwable {
int t = 1000;
int view = 10;
Object[] objects = new Object[3];
objects[0] = view;
objects[1] = 100;
objects[2] = "foo";
validateViewReveal(t, view, objects);
}
}

View File

@@ -3173,9 +3173,9 @@ message MetricsEvent {
// These values should never appear in log outputs - they are reserved for
// internal Tron use.
RESERVED_FOR_LOGBUILDER_VIEW = 757;
RESERVED_FOR_LOGBUILDER_CATEGORY = 758;
RESERVED_FOR_LOGBUILDER_TYPE = 759;
RESERVED_FOR_LOGBUILDER_CATEGORY = 757;
RESERVED_FOR_LOGBUILDER_TYPE = 758;
RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;
// ACTION: "Do not show again" was enabled in the support disclaimer and the
// user accepted
@@ -3275,16 +3275,36 @@ message MetricsEvent {
// OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
// OPEN: Settings > Apps > Default Apps > Default auto-fill app
DEFAULT_AUTO_FILL_PICKER = 792;
// ---- End O Constants, all O constants go above this line ----
// These values should never appear in log outputs - they are reserved for
// internal Tron use.
NOTIFICATION_SINCE_CREATE_MILLIS = 793;
NOTIFICATION_SINCE_VISIBLE_MILLIS = 794;
NOTIFICATION_SINCE_UPDATE_MILLIS = 795;
NOTIFICATION_ID = 796;
NOTIFICATION_TAG = 797;
NOTIFICATION_SHADE_INDEX = 798;
RESERVED_FOR_LOGBUILDER_NAME = 799;
// OPEN: QS NFC tile shown
// ACTION: QS NFC tile tapped
// CATEGORY: QUICK_SETTINGS
QS_NFC = 800;
// These values should never appear in log outputs - they are reserved for
// internal Tron use.
RESERVED_FOR_LOGBUILDER_BUCKET = 801;
RESERVED_FOR_LOGBUILDER_VALUE = 802;
RESERVED_FOR_LOGBUILDER_COUNTER = 803;
RESERVED_FOR_LOGBUILDER_HISTOGRAM = 804;
RESERVED_FOR_LOGBUILDER_TIMESTAMP = 805;
RESERVED_FOR_LOGBUILDER_PACKAGENAME = 806;
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}