/* * Copyright (C) 2008 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.ddmuilib.log.event; import com.android.ddmlib.Log; import com.android.ddmlib.log.EventContainer; import com.android.ddmlib.log.EventContainer.CompareMethod; import com.android.ddmlib.log.EventContainer.EventValueType; import com.android.ddmlib.log.EventLogParser; import com.android.ddmlib.log.EventValueDescription.ValueType; import com.android.ddmlib.log.InvalidTypeException; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.event.ChartChangeEvent; import org.jfree.chart.event.ChartChangeEventType; import org.jfree.chart.event.ChartChangeListener; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.title.TextTitle; import org.jfree.data.time.Millisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.experimental.chart.swt.ChartComposite; import org.jfree.experimental.swt.SWTUtils; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.regex.Pattern; /** * Represents a custom display of one or more events. */ abstract class EventDisplay { private final static String DISPLAY_DATA_STORAGE_SEPARATOR = ":"; //$NON-NLS-1$ private final static String PID_STORAGE_SEPARATOR = ","; //$NON-NLS-1$ private final static String DESCRIPTOR_STORAGE_SEPARATOR = "$"; //$NON-NLS-1$ private final static String DESCRIPTOR_DATA_STORAGE_SEPARATOR = "!"; //$NON-NLS-1$ private final static String FILTER_VALUE_NULL = "<null>"; //$NON-NLS-1$ public final static int DISPLAY_TYPE_LOG_ALL = 0; public final static int DISPLAY_TYPE_FILTERED_LOG = 1; public final static int DISPLAY_TYPE_GRAPH = 2; public final static int DISPLAY_TYPE_SYNC = 3; public final static int DISPLAY_TYPE_SYNC_HIST = 4; public final static int DISPLAY_TYPE_SYNC_PERF = 5; private final static int EVENT_CHECK_FAILED = 0; protected final static int EVENT_CHECK_SAME_TAG = 1; protected final static int EVENT_CHECK_SAME_VALUE = 2; /** * Creates the appropriate EventDisplay subclass. * * @param type the type of display (DISPLAY_TYPE_LOG_ALL, etc) * @param name the name of the display * @return the created object */ public static EventDisplay eventDisplayFactory(int type, String name) { switch (type) { case DISPLAY_TYPE_LOG_ALL: return new DisplayLog(name); case DISPLAY_TYPE_FILTERED_LOG: return new DisplayFilteredLog(name); case DISPLAY_TYPE_SYNC: return new DisplaySync(name); case DISPLAY_TYPE_SYNC_HIST: return new DisplaySyncHistogram(name); case DISPLAY_TYPE_GRAPH: return new DisplayGraph(name); case DISPLAY_TYPE_SYNC_PERF: return new DisplaySyncPerf(name); default: throw new InvalidParameterException("Unknown Display Type " + type); //$NON-NLS-1$ } } /** * Adds event to the display. * @param event The event * @param logParser The log parser. */ abstract void newEvent(EventContainer event, EventLogParser logParser); /** * Resets the display. */ abstract void resetUI(); /** * Gets display type * * @return display type as an integer */ abstract int getDisplayType(); /** * Creates the UI for the event display. * * @param parent the parent composite. * @param logParser the current log parser. * @return the created control (which may have children). */ abstract Control createComposite(final Composite parent, EventLogParser logParser, final ILogColumnListener listener); interface ILogColumnListener { void columnResized(int index, TableColumn sourceColumn); } /** * Describes an event to be displayed. */ static class OccurrenceDisplayDescriptor { int eventTag = -1; int seriesValueIndex = -1; boolean includePid = false; int filterValueIndex = -1; CompareMethod filterCompareMethod = CompareMethod.EQUAL_TO; Object filterValue = null; OccurrenceDisplayDescriptor() { } OccurrenceDisplayDescriptor(OccurrenceDisplayDescriptor descriptor) { replaceWith(descriptor); } OccurrenceDisplayDescriptor(int eventTag) { this.eventTag = eventTag; } OccurrenceDisplayDescriptor(int eventTag, int seriesValueIndex) { this.eventTag = eventTag; this.seriesValueIndex = seriesValueIndex; } void replaceWith(OccurrenceDisplayDescriptor descriptor) { eventTag = descriptor.eventTag; seriesValueIndex = descriptor.seriesValueIndex; includePid = descriptor.includePid; filterValueIndex = descriptor.filterValueIndex; filterCompareMethod = descriptor.filterCompareMethod; filterValue = descriptor.filterValue; } /** * Loads the descriptor parameter from a storage string. The storage string must have * been generated with {@link #getStorageString()}. * * @param storageString the storage string */ final void loadFrom(String storageString) { String[] values = storageString.split(Pattern.quote(DESCRIPTOR_DATA_STORAGE_SEPARATOR)); loadFrom(values, 0); } /** * Loads the parameters from an array of strings. * * @param storageStrings the strings representing each parameter. * @param index the starting index in the array of strings. * @return the new index in the array. */ protected int loadFrom(String[] storageStrings, int index) { eventTag = Integer.parseInt(storageStrings[index++]); seriesValueIndex = Integer.parseInt(storageStrings[index++]); includePid = Boolean.parseBoolean(storageStrings[index++]); filterValueIndex = Integer.parseInt(storageStrings[index++]); try { filterCompareMethod = CompareMethod.valueOf(storageStrings[index++]); } catch (IllegalArgumentException e) { // if the name does not match any known CompareMethod, we init it to the default one filterCompareMethod = CompareMethod.EQUAL_TO; } String value = storageStrings[index++]; if (filterValueIndex != -1 && FILTER_VALUE_NULL.equals(value) == false) { filterValue = EventValueType.getObjectFromStorageString(value); } return index; } /** * Returns the storage string for the receiver. */ String getStorageString() { StringBuilder sb = new StringBuilder(); sb.append(eventTag); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(seriesValueIndex); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(Boolean.toString(includePid)); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(filterValueIndex); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(filterCompareMethod.name()); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); if (filterValue != null) { String value = EventValueType.getStorageString(filterValue); if (value != null) { sb.append(value); } else { sb.append(FILTER_VALUE_NULL); } } else { sb.append(FILTER_VALUE_NULL); } return sb.toString(); } } /** * Describes an event value to be displayed. */ static final class ValueDisplayDescriptor extends OccurrenceDisplayDescriptor { String valueName; int valueIndex = -1; ValueDisplayDescriptor() { super(); } ValueDisplayDescriptor(ValueDisplayDescriptor descriptor) { super(); replaceWith(descriptor); } ValueDisplayDescriptor(int eventTag, String valueName, int valueIndex) { super(eventTag); this.valueName = valueName; this.valueIndex = valueIndex; } ValueDisplayDescriptor(int eventTag, String valueName, int valueIndex, int seriesValueIndex) { super(eventTag, seriesValueIndex); this.valueName = valueName; this.valueIndex = valueIndex; } @Override void replaceWith(OccurrenceDisplayDescriptor descriptor) { super.replaceWith(descriptor); if (descriptor instanceof ValueDisplayDescriptor) { ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor) descriptor; valueName = valueDescriptor.valueName; valueIndex = valueDescriptor.valueIndex; } } /** * Loads the parameters from an array of strings. * * @param storageStrings the strings representing each parameter. * @param index the starting index in the array of strings. * @return the new index in the array. */ @Override protected int loadFrom(String[] storageStrings, int index) { index = super.loadFrom(storageStrings, index); valueName = storageStrings[index++]; valueIndex = Integer.parseInt(storageStrings[index++]); return index; } /** * Returns the storage string for the receiver. */ @Override String getStorageString() { String superStorage = super.getStorageString(); StringBuilder sb = new StringBuilder(); sb.append(superStorage); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(valueName); sb.append(DESCRIPTOR_DATA_STORAGE_SEPARATOR); sb.append(valueIndex); return sb.toString(); } } /* ================== * Event Display parameters. * ================== */ protected String mName; private boolean mPidFiltering = false; private ArrayList<Integer> mPidFilterList = null; protected final ArrayList<ValueDisplayDescriptor> mValueDescriptors = new ArrayList<ValueDisplayDescriptor>(); private final ArrayList<OccurrenceDisplayDescriptor> mOccurrenceDescriptors = new ArrayList<OccurrenceDisplayDescriptor>(); /* ================== * Event Display members for display purpose. * ================== */ // chart objects /** * This is a map of (descriptor, map2) where map2 is a map of (pid, chart-series) */ protected final HashMap<ValueDisplayDescriptor, HashMap<Integer, TimeSeries>> mValueDescriptorSeriesMap = new HashMap<ValueDisplayDescriptor, HashMap<Integer, TimeSeries>>(); /** * This is a map of (descriptor, map2) where map2 is a map of (pid, chart-series) */ protected final HashMap<OccurrenceDisplayDescriptor, HashMap<Integer, TimeSeries>> mOcurrenceDescriptorSeriesMap = new HashMap<OccurrenceDisplayDescriptor, HashMap<Integer, TimeSeries>>(); /** * This is a map of (ValueType, dataset) */ protected final HashMap<ValueType, TimeSeriesCollection> mValueTypeDataSetMap = new HashMap<ValueType, TimeSeriesCollection>(); protected JFreeChart mChart; protected TimeSeriesCollection mOccurrenceDataSet; protected int mDataSetCount; private ChartComposite mChartComposite; protected long mMaximumChartItemAge = -1; protected long mHistWidth = 1; // log objects. protected Table mLogTable; /* ================== * Misc data. * ================== */ protected int mValueDescriptorCheck = EVENT_CHECK_FAILED; EventDisplay(String name) { mName = name; } static EventDisplay clone(EventDisplay from) { EventDisplay ed = eventDisplayFactory(from.getDisplayType(), from.getName()); ed.mName = from.mName; ed.mPidFiltering = from.mPidFiltering; ed.mMaximumChartItemAge = from.mMaximumChartItemAge; ed.mHistWidth = from.mHistWidth; if (from.mPidFilterList != null) { ed.mPidFilterList = new ArrayList<Integer>(); ed.mPidFilterList.addAll(from.mPidFilterList); } for (ValueDisplayDescriptor desc : from.mValueDescriptors) { ed.mValueDescriptors.add(new ValueDisplayDescriptor(desc)); } ed.mValueDescriptorCheck = from.mValueDescriptorCheck; for (OccurrenceDisplayDescriptor desc : from.mOccurrenceDescriptors) { ed.mOccurrenceDescriptors.add(new OccurrenceDisplayDescriptor(desc)); } return ed; } /** * Returns the parameters of the receiver as a single String for storage. */ String getStorageString() { StringBuilder sb = new StringBuilder(); sb.append(mName); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(getDisplayType()); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(Boolean.toString(mPidFiltering)); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(getPidStorageString()); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(getDescriptorStorageString(mValueDescriptors)); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(getDescriptorStorageString(mOccurrenceDescriptors)); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(mMaximumChartItemAge); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); sb.append(mHistWidth); sb.append(DISPLAY_DATA_STORAGE_SEPARATOR); return sb.toString(); } void setName(String name) { mName = name; } String getName() { return mName; } void setPidFiltering(boolean filterByPid) { mPidFiltering = filterByPid; } boolean getPidFiltering() { return mPidFiltering; } void setPidFilterList(ArrayList<Integer> pids) { if (mPidFiltering == false) { new InvalidParameterException(); } mPidFilterList = pids; } ArrayList<Integer> getPidFilterList() { return mPidFilterList; } void addPidFiler(int pid) { if (mPidFiltering == false) { new InvalidParameterException(); } if (mPidFilterList == null) { mPidFilterList = new ArrayList<Integer>(); } mPidFilterList.add(pid); } /** * Returns an iterator to the list of {@link ValueDisplayDescriptor}. */ Iterator<ValueDisplayDescriptor> getValueDescriptors() { return mValueDescriptors.iterator(); } /** * Update checks on the descriptors. Must be called whenever a descriptor is modified outside * of this class. */ void updateValueDescriptorCheck() { mValueDescriptorCheck = checkDescriptors(); } /** * Returns an iterator to the list of {@link OccurrenceDisplayDescriptor}. */ Iterator<OccurrenceDisplayDescriptor> getOccurrenceDescriptors() { return mOccurrenceDescriptors.iterator(); } /** * Adds a descriptor. This can be a {@link OccurrenceDisplayDescriptor} or a * {@link ValueDisplayDescriptor}. * * @param descriptor the descriptor to be added. */ void addDescriptor(OccurrenceDisplayDescriptor descriptor) { if (descriptor instanceof ValueDisplayDescriptor) { mValueDescriptors.add((ValueDisplayDescriptor) descriptor); mValueDescriptorCheck = checkDescriptors(); } else { mOccurrenceDescriptors.add(descriptor); } } /** * Returns a descriptor by index and class (extending {@link OccurrenceDisplayDescriptor}). * * @param descriptorClass the class of the descriptor to return. * @param index the index of the descriptor to return. * @return either a {@link OccurrenceDisplayDescriptor} or a {@link ValueDisplayDescriptor} * or <code>null</code> if <code>descriptorClass</code> is another class. */ OccurrenceDisplayDescriptor getDescriptor( Class<? extends OccurrenceDisplayDescriptor> descriptorClass, int index) { if (descriptorClass == OccurrenceDisplayDescriptor.class) { return mOccurrenceDescriptors.get(index); } else if (descriptorClass == ValueDisplayDescriptor.class) { return mValueDescriptors.get(index); } return null; } /** * Removes a descriptor based on its class and index. * * @param descriptorClass the class of the descriptor. * @param index the index of the descriptor to be removed. */ void removeDescriptor(Class<? extends OccurrenceDisplayDescriptor> descriptorClass, int index) { if (descriptorClass == OccurrenceDisplayDescriptor.class) { mOccurrenceDescriptors.remove(index); } else if (descriptorClass == ValueDisplayDescriptor.class) { mValueDescriptors.remove(index); mValueDescriptorCheck = checkDescriptors(); } } Control createCompositeChart(final Composite parent, EventLogParser logParser, String title) { mChart = ChartFactory.createTimeSeriesChart( null, null /* timeAxisLabel */, null /* valueAxisLabel */, null, /* dataset. set below */ true /* legend */, false /* tooltips */, false /* urls */); // get the font to make a proper title. We need to convert the swt font, // into an awt font. Font f = parent.getFont(); FontData[] fData = f.getFontData(); // event though on Mac OS there could be more than one fontData, we'll only use // the first one. FontData firstFontData = fData[0]; java.awt.Font awtFont = SWTUtils.toAwtFont(parent.getDisplay(), firstFontData, true /* ensureSameSize */); mChart.setTitle(new TextTitle(title, awtFont)); final XYPlot xyPlot = mChart.getXYPlot(); xyPlot.setRangeCrosshairVisible(true); xyPlot.setRangeCrosshairLockedOnData(true); xyPlot.setDomainCrosshairVisible(true); xyPlot.setDomainCrosshairLockedOnData(true); mChart.addChangeListener(new ChartChangeListener() { public void chartChanged(ChartChangeEvent event) { ChartChangeEventType type = event.getType(); if (type == ChartChangeEventType.GENERAL) { // because the value we need (rangeCrosshair and domainCrosshair) are // updated on the draw, but the notification happens before the draw, // we process the click in a future runnable! parent.getDisplay().asyncExec(new Runnable() { public void run() { processClick(xyPlot); } }); } } }); mChartComposite = new ChartComposite(parent, SWT.BORDER, mChart, ChartComposite.DEFAULT_WIDTH, ChartComposite.DEFAULT_HEIGHT, ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH, ChartComposite.DEFAULT_MINIMUM_DRAW_HEIGHT, 3000, // max draw width. We don't want it to zoom, so we put a big number 3000, // max draw height. We don't want it to zoom, so we put a big number true, // off-screen buffer true, // properties true, // save true, // print true, // zoom true); // tooltips mChartComposite.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { mValueTypeDataSetMap.clear(); mDataSetCount = 0; mOccurrenceDataSet = null; mChart = null; mChartComposite = null; mValueDescriptorSeriesMap.clear(); mOcurrenceDescriptorSeriesMap.clear(); } }); return mChartComposite; } private void processClick(XYPlot xyPlot) { double rangeValue = xyPlot.getRangeCrosshairValue(); if (rangeValue != 0) { double domainValue = xyPlot.getDomainCrosshairValue(); Millisecond msec = new Millisecond(new Date((long) domainValue)); // look for values in the dataset that contains data at this TimePeriod Set<ValueDisplayDescriptor> descKeys = mValueDescriptorSeriesMap.keySet(); for (ValueDisplayDescriptor descKey : descKeys) { HashMap<Integer, TimeSeries> map = mValueDescriptorSeriesMap.get(descKey); Set<Integer> pidKeys = map.keySet(); for (Integer pidKey : pidKeys) { TimeSeries series = map.get(pidKey); Number value = series.getValue(msec); if (value != null) { // found a match. lets check against the actual value. if (value.doubleValue() == rangeValue) { return; } } } } } } /** * Resizes the <code>index</code>-th column of the log {@link Table} (if applicable). * Subclasses can override if necessary. * <p/> * This does nothing if the <code>Table</code> object is <code>null</code> (because the display * type does not use a column) or if the <code>index</code>-th column is in fact the originating * column passed as argument. * * @param index the index of the column to resize * @param sourceColumn the original column that was resize, and on which we need to sync the * index-th column width. */ void resizeColumn(int index, TableColumn sourceColumn) { } /** * Sets the current {@link EventLogParser} object. * Subclasses can override if necessary. */ protected void setNewLogParser(EventLogParser logParser) { } /** * Prepares the {@link EventDisplay} for a multi event display. */ void startMultiEventDisplay() { if (mLogTable != null) { mLogTable.setRedraw(false); } } /** * Finalizes the {@link EventDisplay} after a multi event display. */ void endMultiEventDisplay() { if (mLogTable != null) { mLogTable.setRedraw(true); } } /** * Returns the {@link Table} object used to display events, if any. * * @return a Table object or <code>null</code>. */ Table getTable() { return mLogTable; } /** * Loads a new {@link EventDisplay} from a storage string. The string must have been created * with {@link #getStorageString()}. * * @param storageString the storage string * @return a new {@link EventDisplay} or null if the load failed. */ static EventDisplay load(String storageString) { if (storageString.length() > 0) { // the storage string is separated by ':' String[] values = storageString.split(Pattern.quote(DISPLAY_DATA_STORAGE_SEPARATOR)); try { int index = 0; String name = values[index++]; int displayType = Integer.parseInt(values[index++]); boolean pidFiltering = Boolean.parseBoolean(values[index++]); EventDisplay ed = eventDisplayFactory(displayType, name); ed.setPidFiltering(pidFiltering); // because empty sections are removed by String.split(), we have to check // the index for those. if (index < values.length) { ed.loadPidFilters(values[index++]); } if (index < values.length) { ed.loadValueDescriptors(values[index++]); } if (index < values.length) { ed.loadOccurrenceDescriptors(values[index++]); } ed.updateValueDescriptorCheck(); if (index < values.length) { ed.mMaximumChartItemAge = Long.parseLong(values[index++]); } if (index < values.length) { ed.mHistWidth = Long.parseLong(values[index++]); } return ed; } catch (RuntimeException re) { // we'll return null below. Log.e("ddms", re); } } return null; } private String getPidStorageString() { if (mPidFilterList != null) { StringBuilder sb = new StringBuilder(); boolean first = true; for (Integer i : mPidFilterList) { if (first == false) { sb.append(PID_STORAGE_SEPARATOR); } else { first = false; } sb.append(i); } return sb.toString(); } return ""; //$NON-NLS-1$ } private void loadPidFilters(String storageString) { if (storageString.length() > 0) { String[] values = storageString.split(Pattern.quote(PID_STORAGE_SEPARATOR)); for (String value : values) { if (mPidFilterList == null) { mPidFilterList = new ArrayList<Integer>(); } mPidFilterList.add(Integer.parseInt(value)); } } } private String getDescriptorStorageString( ArrayList<? extends OccurrenceDisplayDescriptor> descriptorList) { StringBuilder sb = new StringBuilder(); boolean first = true; for (OccurrenceDisplayDescriptor descriptor : descriptorList) { if (first == false) { sb.append(DESCRIPTOR_STORAGE_SEPARATOR); } else { first = false; } sb.append(descriptor.getStorageString()); } return sb.toString(); } private void loadOccurrenceDescriptors(String storageString) { if (storageString.length() == 0) { return; } String[] values = storageString.split(Pattern.quote(DESCRIPTOR_STORAGE_SEPARATOR)); for (String value : values) { OccurrenceDisplayDescriptor desc = new OccurrenceDisplayDescriptor(); desc.loadFrom(value); mOccurrenceDescriptors.add(desc); } } private void loadValueDescriptors(String storageString) { if (storageString.length() == 0) { return; } String[] values = storageString.split(Pattern.quote(DESCRIPTOR_STORAGE_SEPARATOR)); for (String value : values) { ValueDisplayDescriptor desc = new ValueDisplayDescriptor(); desc.loadFrom(value); mValueDescriptors.add(desc); } } /** * Fills a list with {@link OccurrenceDisplayDescriptor} (or a subclass of it) from another * list if they are configured to display the {@link EventContainer} * * @param event the event container * @param fullList the list with all the descriptors. * @param outList the list to fill. */ @SuppressWarnings("unchecked") private void getDescriptors(EventContainer event, ArrayList<? extends OccurrenceDisplayDescriptor> fullList, ArrayList outList) { for (OccurrenceDisplayDescriptor descriptor : fullList) { try { // first check the event tag. if (descriptor.eventTag == event.mTag) { // now check if we have a filter on a value if (descriptor.filterValueIndex == -1 || event.testValue(descriptor.filterValueIndex, descriptor.filterValue, descriptor.filterCompareMethod)) { outList.add(descriptor); } } } catch (InvalidTypeException ite) { // if the filter for the descriptor was incorrect, we ignore the descriptor. } catch (ArrayIndexOutOfBoundsException aioobe) { // if the index was wrong (the event content may have changed since we setup the // display), we do nothing but log the error Log.e("Event Log", String.format( "ArrayIndexOutOfBoundsException occured when checking %1$d-th value of event %2$d", //$NON-NLS-1$ descriptor.filterValueIndex, descriptor.eventTag)); } } } /** * Filters the {@link com.android.ddmlib.log.EventContainer}, and fills two list of {@link com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor} * and {@link com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor} configured to display the event. * * @param event * @param valueDescriptors * @param occurrenceDescriptors * @return true if the event should be displayed. */ protected boolean filterEvent(EventContainer event, ArrayList<ValueDisplayDescriptor> valueDescriptors, ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors) { // test the pid first (if needed) if (mPidFiltering && mPidFilterList != null) { boolean found = false; for (int pid : mPidFilterList) { if (pid == event.pid) { found = true; break; } } if (found == false) { return false; } } // now get the list of matching descriptors getDescriptors(event, mValueDescriptors, valueDescriptors); getDescriptors(event, mOccurrenceDescriptors, occurrenceDescriptors); // and return whether there is at least one match in either list. return (valueDescriptors.size() > 0 || occurrenceDescriptors.size() > 0); } /** * Checks all the {@link ValueDisplayDescriptor} for similarity. * If all the event values are from the same tag, the method will return EVENT_CHECK_SAME_TAG. * If all the event/value are the same, the method will return EVENT_CHECK_SAME_VALUE * * @return flag as described above */ private int checkDescriptors() { if (mValueDescriptors.size() < 2) { return EVENT_CHECK_SAME_VALUE; } int tag = -1; int index = -1; for (ValueDisplayDescriptor display : mValueDescriptors) { if (tag == -1) { tag = display.eventTag; index = display.valueIndex; } else { if (tag != display.eventTag) { return EVENT_CHECK_FAILED; } else { if (index != -1) { if (index != display.valueIndex) { index = -1; } } } } } if (index == -1) { return EVENT_CHECK_SAME_TAG; } return EVENT_CHECK_SAME_VALUE; } /** * Resets the time limit on the chart to be infinite. */ void resetChartTimeLimit() { mMaximumChartItemAge = -1; } /** * Sets the time limit on the charts. * * @param timeLimit the time limit in seconds. */ void setChartTimeLimit(long timeLimit) { mMaximumChartItemAge = timeLimit; } long getChartTimeLimit() { return mMaximumChartItemAge; } /** * m * Resets the histogram width */ void resetHistWidth() { mHistWidth = 1; } /** * Sets the histogram width * * @param histWidth the width in hours */ void setHistWidth(long histWidth) { mHistWidth = histWidth; } long getHistWidth() { return mHistWidth; } }