diff options
Diffstat (limited to 'ddms/libs/ddmuilib/src')
135 files changed, 0 insertions, 27743 deletions
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AbstractBufferFindTarget.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/AbstractBufferFindTarget.java deleted file mode 100644 index 13a787a..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AbstractBufferFindTarget.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import java.util.regex.Pattern; - -/** - * {@link AbstractBufferFindTarget} implements methods to find items inside a buffer. It takes - * care of the logic to search backwards/forwards in the buffer, wrapping around when necessary. - * The actual contents of the buffer should be provided by the classes that extend this. - */ -public abstract class AbstractBufferFindTarget implements IFindTarget { - private int mCurrentSearchIndex; - - // Single element cache of the last search regex - private Pattern mLastSearchPattern; - private String mLastSearchText; - - @Override - public boolean findAndSelect(String text, boolean isNewSearch, boolean searchForward) { - boolean found = false; - int maxIndex = getItemCount(); - - synchronized (this) { - // Find starting index for this search - if (isNewSearch) { - // for new searches, start from an appropriate place as provided by the delegate - mCurrentSearchIndex = getStartingIndex(); - } else { - // for ongoing searches (finding next match for the same term), continue from - // the current result index - mCurrentSearchIndex = getNext(mCurrentSearchIndex, searchForward, maxIndex); - } - - // Create a regex pattern based on the search term. - Pattern pattern; - if (text.equals(mLastSearchText)) { - pattern = mLastSearchPattern; - } else { - pattern = Pattern.compile(text, Pattern.CASE_INSENSITIVE); - mLastSearchPattern = pattern; - mLastSearchText = text; - } - - // Iterate through the list of items. The search ends if we have gone through - // all items once. - int index = mCurrentSearchIndex; - do { - String msgText = getItem(mCurrentSearchIndex); - if (msgText != null && pattern.matcher(msgText).find()) { - found = true; - break; - } - - mCurrentSearchIndex = getNext(mCurrentSearchIndex, searchForward, maxIndex); - } while (index != mCurrentSearchIndex); // loop through entire contents once - } - - if (found) { - selectAndReveal(mCurrentSearchIndex); - } - - return found; - } - - /** Indicate that the log buffer has scrolled by certain number of elements */ - public void scrollBy(int delta) { - synchronized (this) { - if (mCurrentSearchIndex > 0) { - mCurrentSearchIndex = Math.max(0, mCurrentSearchIndex - delta); - } - } - } - - private int getNext(int index, boolean searchForward, int max) { - // increment or decrement index - index = searchForward ? index + 1 : index - 1; - - // take care of underflow - if (index == -1) { - index = max - 1; - } - - // ..and overflow - if (index == max) { - index = 0; - } - - return index; - } - - /** Obtain the number of items in the buffer */ - public abstract int getItemCount(); - - /** Obtain the item at given index */ - public abstract String getItem(int index); - - /** Select and reveal the item at given index */ - public abstract void selectAndReveal(int index); - - /** Obtain the index from which search should begin */ - public abstract int getStartingIndex(); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java deleted file mode 100644 index 10799ec..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.Log; -import com.android.ddmlib.NativeLibraryMapInfo; -import com.android.ddmlib.NativeStackCallInfo; - -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * Represents an addr2line process to get filename/method information from a - * memory address.<br> - * Each process can only handle one library, which should be provided when - * creating a new process.<br> - * <br> - * The processes take some time to load as they need to parse the library files. - * For this reason, processes cannot be manually started. Instead the class - * keeps an internal list of processes and one asks for a process for a specific - * library, using <code>getProcess(String library)<code>.<br></br> - * Internally, the processes are started in pipe mode to be able to query them - * with multiple addresses. - */ -public class Addr2Line { - private static final String ANDROID_SYMBOLS_ENVVAR = "ANDROID_SYMBOLS"; - - private static final String LIBRARY_NOT_FOUND_MESSAGE_FORMAT = - "Unable to locate library %s on disk. Addresses mapping to this library " - + "will not be resolved. In order to fix this, set the the library search path " - + "in the UI, or set the environment variable " + ANDROID_SYMBOLS_ENVVAR + "."; - - /** - * Loaded processes list. This is also used as a locking object for any - * methods dealing with starting/stopping/creating processes/querying for - * method. - */ - private static final HashMap<String, Addr2Line> sProcessCache = - new HashMap<String, Addr2Line>(); - - /** - * byte array representing a carriage return. Used to push addresses in the - * process pipes. - */ - private static final byte[] sCrLf = { - '\n' - }; - - /** Path to the library */ - private NativeLibraryMapInfo mLibrary; - - /** the command line process */ - private Process mProcess; - - /** buffer to read the result of the command line process from */ - private BufferedReader mResultReader; - - /** - * output stream to provide new addresses to decode to the command line - * process - */ - private BufferedOutputStream mAddressWriter; - - private static final String DEFAULT_LIBRARY_SYMBOLS_FOLDER; - static { - String symbols = System.getenv(ANDROID_SYMBOLS_ENVVAR); - if (symbols == null) { - DEFAULT_LIBRARY_SYMBOLS_FOLDER = DdmUiPreferences.getSymbolDirectory(); - } else { - DEFAULT_LIBRARY_SYMBOLS_FOLDER = symbols; - } - } - - private static List<String> mLibrarySearchPaths = new ArrayList<String>(); - - /** - * Set the search path where libraries should be found. - * @param path search path to use, can be a colon separated list of paths if multiple folders - * should be searched - */ - public static void setSearchPath(String path) { - mLibrarySearchPaths.clear(); - mLibrarySearchPaths.addAll(Arrays.asList(path.split(":"))); - } - - /** - * Returns the instance of a Addr2Line process for the specified library. - * <br>The library should be in a format that makes<br> - * <code>$ANDROID_PRODUCT_OUT + "/symbols" + library</code> a valid file. - * - * @param library the library in which to look for addresses. - * @return a new Addr2Line object representing a started process, ready to - * be queried for addresses. If any error happened when launching a - * new process, <code>null</code> will be returned. - */ - public static Addr2Line getProcess(final NativeLibraryMapInfo library) { - String libName = library.getLibraryName(); - - // synchronize around the hashmap object - if (libName != null) { - synchronized (sProcessCache) { - // look for an existing process - Addr2Line process = sProcessCache.get(libName); - - // if we don't find one, we create it - if (process == null) { - process = new Addr2Line(library); - - // then we start it - boolean status = process.start(); - - if (status) { - // if starting the process worked, then we add it to the - // list. - sProcessCache.put(libName, process); - } else { - // otherwise we just drop the object, to return null - process = null; - } - } - // return the process - return process; - } - } - return null; - } - - /** - * Construct the object with a library name. The library should be present - * in the search path as provided by ANDROID_SYMBOLS, ANDROID_OUT/symbols, or in the user - * provided search path. - * - * @param library the library in which to look for address. - */ - private Addr2Line(final NativeLibraryMapInfo library) { - mLibrary = library; - } - - /** - * Search for the library in the library search path and obtain the full path to where it - * is found. - * @return fully resolved path to the library if found in search path, null otherwise - */ - private String getLibraryPath(String library) { - // first check the symbols folder - String path = DEFAULT_LIBRARY_SYMBOLS_FOLDER + library; - if (new File(path).exists()) { - return path; - } - - for (String p : mLibrarySearchPaths) { - // try appending the full path on device - String fullPath = p + "/" + library; - if (new File(fullPath).exists()) { - return fullPath; - } - - // try appending basename(library) - fullPath = p + "/" + new File(library).getName(); - if (new File(fullPath).exists()) { - return fullPath; - } - } - - return null; - } - - /** - * Starts the command line process. - * - * @return true if the process was started, false if it failed to start, or - * if there was any other errors. - */ - private boolean start() { - // because this is only called from getProcess() we know we don't need - // to synchronize this code. - - String addr2Line = System.getenv("ANDROID_ADDR2LINE"); - if (addr2Line == null) { - addr2Line = DdmUiPreferences.getAddr2Line(); - } - - // build the command line - String[] command = new String[5]; - command[0] = addr2Line; - command[1] = "-C"; - command[2] = "-f"; - command[3] = "-e"; - - String fullPath = getLibraryPath(mLibrary.getLibraryName()); - if (fullPath == null) { - String msg = String.format(LIBRARY_NOT_FOUND_MESSAGE_FORMAT, mLibrary.getLibraryName()); - Log.e("ddm-Addr2Line", msg); - return false; - } - - command[4] = fullPath; - - try { - // attempt to start the process - mProcess = Runtime.getRuntime().exec(command); - - if (mProcess != null) { - // get the result reader - InputStreamReader is = new InputStreamReader(mProcess - .getInputStream()); - mResultReader = new BufferedReader(is); - - // get the outstream to write the addresses - mAddressWriter = new BufferedOutputStream(mProcess - .getOutputStream()); - - // check our streams are here - if (mResultReader == null || mAddressWriter == null) { - // not here? stop the process and return false; - mProcess.destroy(); - mProcess = null; - return false; - } - - // return a success - return true; - } - - } catch (IOException e) { - // log the error - String msg = String.format( - "Error while trying to start %1$s process for library %2$s", - DdmUiPreferences.getAddr2Line(), mLibrary); - Log.e("ddm-Addr2Line", msg); - - // drop the process just in case - if (mProcess != null) { - mProcess.destroy(); - mProcess = null; - } - } - - // we can be here either cause the allocation of mProcess failed, or we - // caught an exception - return false; - } - - /** - * Stops the command line process. - */ - public void stop() { - synchronized (sProcessCache) { - if (mProcess != null) { - // remove the process from the list - sProcessCache.remove(mLibrary); - - // then stops the process - mProcess.destroy(); - - // set the reference to null. - // this allows to make sure another thread calling getAddress() - // will not query a stopped thread - mProcess = null; - } - } - } - - /** - * Stops all current running processes. - */ - public static void stopAll() { - // because of concurrent access (and our use of HashMap.values()), we - // can't rely on the synchronized inside stop(). We need to put one - // around the whole loop. - synchronized (sProcessCache) { - // just a basic loop on all the values in the hashmap and call to - // stop(); - Collection<Addr2Line> col = sProcessCache.values(); - for (Addr2Line a2l : col) { - a2l.stop(); - } - } - } - - /** - * Looks up an address and returns method name, source file name, and line - * number. - * - * @param addr the address to look up - * @return a BacktraceInfo object containing the method/filename/linenumber - * or null if the process we stopped before the query could be - * processed, or if an IO exception happened. - */ - public NativeStackCallInfo getAddress(long addr) { - long offset = addr - mLibrary.getStartAddress(); - - // even though we don't access the hashmap object, we need to - // synchronized on it to prevent - // another thread from stopping the process we're going to query. - synchronized (sProcessCache) { - // check the process is still alive/allocated - if (mProcess != null) { - // prepare to the write the address to the output buffer. - - // first, conversion to a string containing the hex value. - String tmp = Long.toString(offset, 16); - - try { - // write the address to the buffer - mAddressWriter.write(tmp.getBytes()); - - // add CR-LF - mAddressWriter.write(sCrLf); - - // flush it all. - mAddressWriter.flush(); - - // read the result. We need to read 2 lines - String method = mResultReader.readLine(); - String source = mResultReader.readLine(); - - // make the backtrace object and return it - if (method != null && source != null) { - return new NativeStackCallInfo(addr, mLibrary.getLibraryName(), method, source); - } - } catch (IOException e) { - // log the error - Log.e("ddms", - "Error while trying to get information for addr: " - + tmp + " in library: " + mLibrary); - // we'll return null later - } - } - } - return null; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java deleted file mode 100644 index a48f73d..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java +++ /dev/null @@ -1,651 +0,0 @@ -/* - * 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; - -import com.android.ddmlib.AllocationInfo; -import com.android.ddmlib.AllocationInfo.AllocationSorter; -import com.android.ddmlib.AllocationInfo.SortMode; -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData.AllocationTrackingStatus; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Sash; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -/** - * Base class for our information panels. - */ -public class AllocationPanel extends TablePanel { - - private final static String PREFS_ALLOC_COL_NUMBER = "allocPanel.Col00"; //$NON-NLS-1$ - private final static String PREFS_ALLOC_COL_SIZE = "allocPanel.Col0"; //$NON-NLS-1$ - private final static String PREFS_ALLOC_COL_CLASS = "allocPanel.Col1"; //$NON-NLS-1$ - private final static String PREFS_ALLOC_COL_THREAD = "allocPanel.Col2"; //$NON-NLS-1$ - private final static String PREFS_ALLOC_COL_TRACE_CLASS = "allocPanel.Col3"; //$NON-NLS-1$ - private final static String PREFS_ALLOC_COL_TRACE_METHOD = "allocPanel.Col4"; //$NON-NLS-1$ - - private final static String PREFS_ALLOC_SASH = "allocPanel.sash"; //$NON-NLS-1$ - - private static final String PREFS_STACK_COLUMN = "allocPanel.stack.col0"; //$NON-NLS-1$ - - private Composite mAllocationBase; - private Table mAllocationTable; - private TableViewer mAllocationViewer; - - private StackTracePanel mStackTracePanel; - private Table mStackTraceTable; - private Button mEnableButton; - private Button mRequestButton; - private Button mTraceFilterCheck; - - private final AllocationSorter mSorter = new AllocationSorter(); - private TableColumn mSortColumn; - private Image mSortUpImg; - private Image mSortDownImg; - private String mFilterText = null; - - /** - * Content Provider to display the allocations of a client. - * Expected input is a {@link Client} object, elements used in the table are of type - * {@link AllocationInfo}. - */ - private class AllocationContentProvider implements IStructuredContentProvider { - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof Client) { - AllocationInfo[] allocs = ((Client)inputElement).getClientData().getAllocations(); - if (allocs != null) { - if (mFilterText != null && mFilterText.length() > 0) { - allocs = getFilteredAllocations(allocs, mFilterText); - } - Arrays.sort(allocs, mSorter); - return allocs; - } - } - - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - } - - /** - * A Label Provider to use with {@link AllocationContentProvider}. It expects the elements to be - * of type {@link AllocationInfo}. - */ - private static class AllocationLabelProvider implements ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof AllocationInfo) { - AllocationInfo alloc = (AllocationInfo)element; - switch (columnIndex) { - case 0: - return Integer.toString(alloc.getAllocNumber()); - case 1: - return Integer.toString(alloc.getSize()); - case 2: - return alloc.getAllocatedClass(); - case 3: - return Short.toString(alloc.getThreadId()); - case 4: - return alloc.getFirstTraceClassName(); - case 5: - return alloc.getFirstTraceMethodName(); - } - } - - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Create our control(s). - */ - @Override - protected Control createControl(Composite parent) { - final IPreferenceStore store = DdmUiPreferences.getStore(); - - Display display = parent.getDisplay(); - - // get some images - mSortUpImg = ImageLoader.getDdmUiLibLoader().loadImage("sort_up.png", display); - mSortDownImg = ImageLoader.getDdmUiLibLoader().loadImage("sort_down.png", display); - - // base composite for selected client with enabled thread update. - mAllocationBase = new Composite(parent, SWT.NONE); - mAllocationBase.setLayout(new FormLayout()); - - // table above the sash - Composite topParent = new Composite(mAllocationBase, SWT.NONE); - topParent.setLayout(new GridLayout(6, false)); - - mEnableButton = new Button(topParent, SWT.PUSH); - mEnableButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - Client current = getCurrentClient(); - AllocationTrackingStatus status = current.getClientData().getAllocationStatus(); - if (status == AllocationTrackingStatus.ON) { - current.enableAllocationTracker(false); - } else { - current.enableAllocationTracker(true); - } - current.requestAllocationStatus(); - } - }); - - mRequestButton = new Button(topParent, SWT.PUSH); - mRequestButton.setText("Get Allocations"); - mRequestButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - getCurrentClient().requestAllocationDetails(); - } - }); - - setUpButtons(false /* enabled */, AllocationTrackingStatus.OFF); - - GridData gridData; - - Composite spacer = new Composite(topParent, SWT.NONE); - spacer.setLayoutData(gridData = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(topParent, SWT.NONE).setText("Filter:"); - - final Text filterText = new Text(topParent, SWT.BORDER); - filterText.setLayoutData(gridData = new GridData(GridData.FILL_HORIZONTAL)); - gridData.widthHint = 200; - - filterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - mFilterText = filterText.getText().trim(); - mAllocationViewer.refresh(); - } - }); - - mTraceFilterCheck = new Button(topParent, SWT.CHECK); - mTraceFilterCheck.setText("Inc. trace"); - mTraceFilterCheck.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - mAllocationViewer.refresh(); - } - }); - - mAllocationTable = new Table(topParent, SWT.MULTI | SWT.FULL_SELECTION); - mAllocationTable.setLayoutData(gridData = new GridData(GridData.FILL_BOTH)); - gridData.horizontalSpan = 6; - mAllocationTable.setHeaderVisible(true); - mAllocationTable.setLinesVisible(true); - - final TableColumn numberCol = TableHelper.createTableColumn( - mAllocationTable, - "Alloc Order", - SWT.RIGHT, - "Alloc Order", //$NON-NLS-1$ - PREFS_ALLOC_COL_NUMBER, store); - numberCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(numberCol, SortMode.NUMBER); - } - }); - - final TableColumn sizeCol = TableHelper.createTableColumn( - mAllocationTable, - "Allocation Size", - SWT.RIGHT, - "888", //$NON-NLS-1$ - PREFS_ALLOC_COL_SIZE, store); - sizeCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(sizeCol, SortMode.SIZE); - } - }); - - final TableColumn classCol = TableHelper.createTableColumn( - mAllocationTable, - "Allocated Class", - SWT.LEFT, - "Allocated Class", //$NON-NLS-1$ - PREFS_ALLOC_COL_CLASS, store); - classCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(classCol, SortMode.CLASS); - } - }); - - final TableColumn threadCol = TableHelper.createTableColumn( - mAllocationTable, - "Thread Id", - SWT.LEFT, - "999", //$NON-NLS-1$ - PREFS_ALLOC_COL_THREAD, store); - threadCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(threadCol, SortMode.THREAD); - } - }); - - final TableColumn inClassCol = TableHelper.createTableColumn( - mAllocationTable, - "Allocated in", - SWT.LEFT, - "utime", //$NON-NLS-1$ - PREFS_ALLOC_COL_TRACE_CLASS, store); - inClassCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(inClassCol, SortMode.IN_CLASS); - } - }); - - final TableColumn inMethodCol = TableHelper.createTableColumn( - mAllocationTable, - "Allocated in", - SWT.LEFT, - "utime", //$NON-NLS-1$ - PREFS_ALLOC_COL_TRACE_METHOD, store); - inMethodCol.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - setSortColumn(inMethodCol, SortMode.IN_METHOD); - } - }); - - // init the default sort colum - switch (mSorter.getSortMode()) { - case SIZE: - mSortColumn = sizeCol; - break; - case CLASS: - mSortColumn = classCol; - break; - case THREAD: - mSortColumn = threadCol; - break; - case IN_CLASS: - mSortColumn = inClassCol; - break; - case IN_METHOD: - mSortColumn = inMethodCol; - break; - } - - mSortColumn.setImage(mSorter.isDescending() ? mSortDownImg : mSortUpImg); - - mAllocationViewer = new TableViewer(mAllocationTable); - mAllocationViewer.setContentProvider(new AllocationContentProvider()); - mAllocationViewer.setLabelProvider(new AllocationLabelProvider()); - - mAllocationViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - AllocationInfo selectedAlloc = getAllocationSelection(event.getSelection()); - updateAllocationStackTrace(selectedAlloc); - } - }); - - // the separating sash - final Sash sash = new Sash(mAllocationBase, SWT.HORIZONTAL); - Color darkGray = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); - sash.setBackground(darkGray); - - // the UI below the sash - mStackTracePanel = new StackTracePanel(); - mStackTraceTable = mStackTracePanel.createPanel(mAllocationBase, PREFS_STACK_COLUMN, store); - - // now setup the sash. - // form layout data - FormData data = new FormData(); - data.top = new FormAttachment(0, 0); - data.bottom = new FormAttachment(sash, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - topParent.setLayoutData(data); - - final FormData sashData = new FormData(); - if (store != null && store.contains(PREFS_ALLOC_SASH)) { - sashData.top = new FormAttachment(0, store.getInt(PREFS_ALLOC_SASH)); - } else { - sashData.top = new FormAttachment(50,0); // 50% across - } - sashData.left = new FormAttachment(0, 0); - sashData.right = new FormAttachment(100, 0); - sash.setLayoutData(sashData); - - data = new FormData(); - data.top = new FormAttachment(sash, 0); - data.bottom = new FormAttachment(100, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mStackTraceTable.setLayoutData(data); - - // allow resizes, but cap at minPanelWidth - sash.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event e) { - Rectangle sashRect = sash.getBounds(); - Rectangle panelRect = mAllocationBase.getClientArea(); - int bottom = panelRect.height - sashRect.height - 100; - e.y = Math.max(Math.min(e.y, bottom), 100); - if (e.y != sashRect.y) { - sashData.top = new FormAttachment(0, e.y); - store.setValue(PREFS_ALLOC_SASH, e.y); - mAllocationBase.layout(); - } - } - }); - - return mAllocationBase; - } - - @Override - public void dispose() { - mSortUpImg.dispose(); - mSortDownImg.dispose(); - super.dispose(); - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mAllocationTable.setFocus(); - } - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client == getCurrentClient()) { - if ((changeMask & Client.CHANGE_HEAP_ALLOCATIONS) != 0) { - try { - mAllocationTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - mAllocationViewer.refresh(); - updateAllocationStackCall(); - } - }); - } catch (SWTException e) { - // widget is disposed, we do nothing - } - } else if ((changeMask & Client.CHANGE_HEAP_ALLOCATION_STATUS) != 0) { - try { - mAllocationTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - setUpButtons(true, client.getClientData().getAllocationStatus()); - } - }); - } catch (SWTException e) { - // widget is disposed, we do nothing - } - } - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()}. - */ - @Override - public void deviceSelected() { - // pass - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - if (mAllocationTable.isDisposed()) { - return; - } - - Client client = getCurrentClient(); - - mStackTracePanel.setCurrentClient(client); - mStackTracePanel.setViewerInput(null); // always empty on client selection change. - - if (client != null) { - setUpButtons(true /* enabled */, client.getClientData().getAllocationStatus()); - } else { - setUpButtons(false /* enabled */, AllocationTrackingStatus.OFF); - } - - mAllocationViewer.setInput(client); - } - - /** - * Updates the stack call of the currently selected thread. - * <p/> - * This <b>must</b> be called from the UI thread. - */ - private void updateAllocationStackCall() { - Client client = getCurrentClient(); - if (client != null) { - // get the current selection in the ThreadTable - AllocationInfo selectedAlloc = getAllocationSelection(null); - - if (selectedAlloc != null) { - updateAllocationStackTrace(selectedAlloc); - } else { - updateAllocationStackTrace(null); - } - } - } - - /** - * updates the stackcall of the specified allocation. If <code>null</code> the UI is emptied - * of current data. - * @param thread - */ - private void updateAllocationStackTrace(AllocationInfo alloc) { - mStackTracePanel.setViewerInput(alloc); - } - - @Override - protected void setTableFocusListener() { - addTableToFocusListener(mAllocationTable); - addTableToFocusListener(mStackTraceTable); - } - - /** - * Returns the current allocation selection or <code>null</code> if none is found. - * If a {@link ISelection} object is specified, the first {@link AllocationInfo} from this - * selection is returned, otherwise, the <code>ISelection</code> returned by - * {@link TableViewer#getSelection()} is used. - * @param selection the {@link ISelection} to use, or <code>null</code> - */ - private AllocationInfo getAllocationSelection(ISelection selection) { - if (selection == null) { - selection = mAllocationViewer.getSelection(); - } - - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object object = structuredSelection.getFirstElement(); - if (object instanceof AllocationInfo) { - return (AllocationInfo)object; - } - } - - return null; - } - - /** - * - * @param enabled - * @param trackingStatus - */ - private void setUpButtons(boolean enabled, AllocationTrackingStatus trackingStatus) { - if (enabled) { - switch (trackingStatus) { - case UNKNOWN: - mEnableButton.setText("?"); - mEnableButton.setEnabled(false); - mRequestButton.setEnabled(false); - break; - case OFF: - mEnableButton.setText("Start Tracking"); - mEnableButton.setEnabled(true); - mRequestButton.setEnabled(false); - break; - case ON: - mEnableButton.setText("Stop Tracking"); - mEnableButton.setEnabled(true); - mRequestButton.setEnabled(true); - break; - } - } else { - mEnableButton.setEnabled(false); - mRequestButton.setEnabled(false); - mEnableButton.setText("Start Tracking"); - } - } - - private void setSortColumn(final TableColumn column, SortMode sortMode) { - // set the new sort mode - mSorter.setSortMode(sortMode); - - mAllocationTable.setRedraw(false); - - // remove image from previous sort colum - if (mSortColumn != column) { - mSortColumn.setImage(null); - } - - mSortColumn = column; - if (mSorter.isDescending()) { - mSortColumn.setImage(mSortDownImg); - } else { - mSortColumn.setImage(mSortUpImg); - } - - mAllocationTable.setRedraw(true); - mAllocationViewer.refresh(); - } - - private AllocationInfo[] getFilteredAllocations(AllocationInfo[] allocations, - String filterText) { - ArrayList<AllocationInfo> results = new ArrayList<AllocationInfo>(); - // Using default locale here such that the locale-specific c - Locale locale = Locale.getDefault(); - filterText = filterText.toLowerCase(locale); - boolean fullTrace = mTraceFilterCheck.getSelection(); - - for (AllocationInfo info : allocations) { - if (info.filter(filterText, fullTrace, locale)) { - results.add(info); - } - } - - return results.toArray(new AllocationInfo[results.size()]); - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/BackgroundThread.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/BackgroundThread.java deleted file mode 100644 index 0ed4c95..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/BackgroundThread.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.Log; - -/** - * base background thread class. The class provides a synchronous quit method - * which sets a quitting flag to true. Inheriting classes should regularly test - * this flag with <code>isQuitting()</code> and should finish if the flag is - * true. - */ -public abstract class BackgroundThread extends Thread { - private boolean mQuit = false; - - /** - * Tell the thread to exit. This is usually called from the UI thread. The - * call is synchronous and will only return once the thread has terminated - * itself. - */ - public final void quit() { - mQuit = true; - Log.d("ddms", "Waiting for BackgroundThread to quit"); - try { - this.join(); - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - - /** returns if the thread was asked to quit. */ - protected final boolean isQuitting() { - return mQuit; - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/BaseHeapPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/BaseHeapPanel.java deleted file mode 100644 index 3e66ea5..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/BaseHeapPanel.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.HeapSegment; -import com.android.ddmlib.ClientData.HeapData; -import com.android.ddmlib.HeapSegment.HeapSegmentElement; - -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; - -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; - - -/** - * Base Panel for heap panels. - */ -public abstract class BaseHeapPanel extends TablePanel { - - /** store the processed heap segment, so that we don't recompute Image for nothing */ - protected byte[] mProcessedHeapData; - private Map<Integer, ArrayList<HeapSegmentElement>> mHeapMap; - - /** - * Serialize the heap data into an array. The resulting array is available through - * <code>getSerializedData()</code>. - * @param heapData The heap data to serialize - * @return true if the data changed. - */ - protected boolean serializeHeapData(HeapData heapData) { - Collection<HeapSegment> heapSegments; - - // Atomically get and clear the heap data. - synchronized (heapData) { - // get the segments - heapSegments = heapData.getHeapSegments(); - - - if (heapSegments != null) { - // if they are not null, we never processed them. - // Before we process then, we drop them from the HeapData - heapData.clearHeapData(); - - // process them into a linear byte[] - doSerializeHeapData(heapSegments); - heapData.setProcessedHeapData(mProcessedHeapData); - heapData.setProcessedHeapMap(mHeapMap); - - } else { - // the heap segments are null. Let see if the heapData contains a - // list that is already processed. - - byte[] pixData = heapData.getProcessedHeapData(); - - // and compare it to the one we currently have in the panel. - if (pixData == mProcessedHeapData) { - // looks like its the same - return false; - } else { - mProcessedHeapData = pixData; - } - - Map<Integer, ArrayList<HeapSegmentElement>> heapMap = - heapData.getProcessedHeapMap(); - mHeapMap = heapMap; - } - } - - return true; - } - - /** - * Returns the serialized heap data - */ - protected byte[] getSerializedData() { - return mProcessedHeapData; - } - - /** - * Processes and serialize the heapData. - * <p/> - * The resulting serialized array is {@link #mProcessedHeapData}. - * <p/> - * the resulting map is {@link #mHeapMap}. - * @param heapData the collection of {@link HeapSegment} that forms the heap data. - */ - private void doSerializeHeapData(Collection<HeapSegment> heapData) { - mHeapMap = new TreeMap<Integer, ArrayList<HeapSegmentElement>>(); - - Iterator<HeapSegment> iterator; - ByteArrayOutputStream out; - - out = new ByteArrayOutputStream(4 * 1024); - - iterator = heapData.iterator(); - while (iterator.hasNext()) { - HeapSegment hs = iterator.next(); - - HeapSegmentElement e = null; - while (true) { - int v; - - e = hs.getNextElement(null); - if (e == null) { - break; - } - - if (e.getSolidity() == HeapSegmentElement.SOLIDITY_FREE) { - v = 1; - } else { - v = e.getKind() + 2; - } - - // put the element in the map - ArrayList<HeapSegmentElement> elementList = mHeapMap.get(v); - if (elementList == null) { - elementList = new ArrayList<HeapSegmentElement>(); - mHeapMap.put(v, elementList); - } - elementList.add(e); - - - int len = e.getLength() / 8; - while (len > 0) { - out.write(v); - --len; - } - } - } - mProcessedHeapData = out.toByteArray(); - - // sort the segment element in the heap info. - Collection<ArrayList<HeapSegmentElement>> elementLists = mHeapMap.values(); - for (ArrayList<HeapSegmentElement> elementList : elementLists) { - Collections.sort(elementList); - } - } - - /** - * Creates a linear image of the heap data. - * @param pixData - * @param h - * @param palette - * @return - */ - protected ImageData createLinearHeapImage(byte[] pixData, int h, PaletteData palette) { - int w = pixData.length / h; - if (pixData.length % h != 0) { - w++; - } - - // Create the heap image. - ImageData id = new ImageData(w, h, 8, palette); - - int x = 0; - int y = 0; - for (byte b : pixData) { - if (b >= 0) { - id.setPixel(x, y, b); - } - - y++; - if (y >= h) { - y = 0; - x++; - } - } - - return id; - } - - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ClientDisplayPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ClientDisplayPanel.java deleted file mode 100644 index a711933..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ClientDisplayPanel.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; - -public abstract class ClientDisplayPanel extends SelectionDependentPanel - implements IClientChangeListener { - - @Override - protected void postCreation() { - AndroidDebugBridge.addClientChangeListener(this); - } - - public void dispose() { - AndroidDebugBridge.removeClientChangeListener(this); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DdmUiPreferences.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/DdmUiPreferences.java deleted file mode 100644 index db3642b..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DdmUiPreferences.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import org.eclipse.jface.preference.IPreferenceStore; - -/** - * Preference entry point for ddmuilib. Allows the lib to access a preference - * store (org.eclipse.jface.preference.IPreferenceStore) defined by the - * application that includes the lib. - */ -public final class DdmUiPreferences { - - public static final int DEFAULT_THREAD_REFRESH_INTERVAL = 4; // seconds - - private static int sThreadRefreshInterval = DEFAULT_THREAD_REFRESH_INTERVAL; - - private static IPreferenceStore mStore; - - private static String sSymbolLocation =""; //$NON-NLS-1$ - private static String sAddr2LineLocation =""; //$NON-NLS-1$ - private static String sTraceviewLocation =""; //$NON-NLS-1$ - - public static void setStore(IPreferenceStore store) { - mStore = store; - } - - public static IPreferenceStore getStore() { - return mStore; - } - - public static int getThreadRefreshInterval() { - return sThreadRefreshInterval; - } - - public static void setThreadRefreshInterval(int port) { - sThreadRefreshInterval = port; - } - - public static String getSymbolDirectory() { - return sSymbolLocation; - } - - public static void setSymbolsLocation(String location) { - sSymbolLocation = location; - } - - public static String getAddr2Line() { - return sAddr2LineLocation; - } - - public static void setAddr2LineLocation(String location) { - sAddr2LineLocation = location; - } - - public static String getTraceview() { - return sTraceviewLocation; - } - - public static void setTraceviewLocation(String location) { - sTraceviewLocation = location; - } - - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java deleted file mode 100644 index a24b8a0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; -import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; -import com.android.ddmlib.ClientData.DebuggerStatus; -import com.android.ddmlib.DdmPreferences; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.IDevice.DeviceState; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * A display of both the devices and their clients. - */ -public final class DevicePanel extends Panel implements IDebugBridgeChangeListener, - IDeviceChangeListener, IClientChangeListener { - - private final static String PREFS_COL_NAME_SERIAL = "devicePanel.Col0"; //$NON-NLS-1$ - private final static String PREFS_COL_PID_STATE = "devicePanel.Col1"; //$NON-NLS-1$ - private final static String PREFS_COL_PORT_BUILD = "devicePanel.Col4"; //$NON-NLS-1$ - - private final static int DEVICE_COL_SERIAL = 0; - private final static int DEVICE_COL_STATE = 1; - // col 2, 3 not used. - private final static int DEVICE_COL_BUILD = 4; - - private final static int CLIENT_COL_NAME = 0; - private final static int CLIENT_COL_PID = 1; - private final static int CLIENT_COL_THREAD = 2; - private final static int CLIENT_COL_HEAP = 3; - private final static int CLIENT_COL_PORT = 4; - - public final static int ICON_WIDTH = 16; - public final static String ICON_THREAD = "thread.png"; //$NON-NLS-1$ - public final static String ICON_HEAP = "heap.png"; //$NON-NLS-1$ - public final static String ICON_HALT = "halt.png"; //$NON-NLS-1$ - public final static String ICON_GC = "gc.png"; //$NON-NLS-1$ - public final static String ICON_HPROF = "hprof.png"; //$NON-NLS-1$ - public final static String ICON_TRACING_START = "tracing_start.png"; //$NON-NLS-1$ - public final static String ICON_TRACING_STOP = "tracing_stop.png"; //$NON-NLS-1$ - - private IDevice mCurrentDevice; - private Client mCurrentClient; - - private Tree mTree; - private TreeViewer mTreeViewer; - - private Image mDeviceImage; - private Image mEmulatorImage; - - private Image mThreadImage; - private Image mHeapImage; - private Image mWaitingImage; - private Image mDebuggerImage; - private Image mDebugErrorImage; - - private final ArrayList<IUiSelectionListener> mListeners = new ArrayList<IUiSelectionListener>(); - - private final ArrayList<IDevice> mDevicesToExpand = new ArrayList<IDevice>(); - - private boolean mAdvancedPortSupport; - - /** - * A Content provider for the {@link TreeViewer}. - * <p/> - * The input is a {@link AndroidDebugBridge}. First level elements are {@link IDevice} objects, - * and second level elements are {@link Client} object. - */ - private class ContentProvider implements ITreeContentProvider { - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof IDevice) { - return ((IDevice)parentElement).getClients(); - } - return new Object[0]; - } - - @Override - public Object getParent(Object element) { - if (element instanceof Client) { - return ((Client)element).getDevice(); - } - return null; - } - - @Override - public boolean hasChildren(Object element) { - if (element instanceof IDevice) { - return ((IDevice)element).hasClients(); - } - - // Clients never have children. - return false; - } - - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof AndroidDebugBridge) { - return ((AndroidDebugBridge)inputElement).getDevices(); - } - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - } - - /** - * A Label Provider for the {@link TreeViewer} in {@link DevicePanel}. It provides - * labels and images for {@link IDevice} and {@link Client} objects. - */ - private class LabelProvider implements ITableLabelProvider { - @Override - public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex == DEVICE_COL_SERIAL && element instanceof IDevice) { - IDevice device = (IDevice)element; - if (device.isEmulator()) { - return mEmulatorImage; - } - - return mDeviceImage; - } else if (element instanceof Client) { - Client client = (Client)element; - ClientData cd = client.getClientData(); - - switch (columnIndex) { - case CLIENT_COL_NAME: - switch (cd.getDebuggerConnectionStatus()) { - case DEFAULT: - return null; - case WAITING: - return mWaitingImage; - case ATTACHED: - return mDebuggerImage; - case ERROR: - return mDebugErrorImage; - } - return null; - case CLIENT_COL_THREAD: - if (client.isThreadUpdateEnabled()) { - return mThreadImage; - } - return null; - case CLIENT_COL_HEAP: - if (client.isHeapUpdateEnabled()) { - return mHeapImage; - } - return null; - } - } - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof IDevice) { - IDevice device = (IDevice)element; - switch (columnIndex) { - case DEVICE_COL_SERIAL: - return device.getName(); - case DEVICE_COL_STATE: - return getStateString(device); - case DEVICE_COL_BUILD: { - String version = device.getProperty(IDevice.PROP_BUILD_VERSION); - if (version != null) { - String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE); - if (device.isEmulator()) { - String avdName = device.getAvdName(); - if (avdName == null) { - avdName = "?"; // the device is probably not online yet, so - // we don't know its AVD name just yet. - } - if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$ - return String.format("%1$s [%2$s, debug]", avdName, - version); - } else { - return String.format("%1$s [%2$s]", avdName, version); //$NON-NLS-1$ - } - } else { - if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$ - return String.format("%1$s, debug", version); - } else { - return String.format("%1$s", version); //$NON-NLS-1$ - } - } - } else { - return "unknown"; - } - } - } - } else if (element instanceof Client) { - Client client = (Client)element; - ClientData cd = client.getClientData(); - - switch (columnIndex) { - case CLIENT_COL_NAME: - String name = cd.getClientDescription(); - if (name != null) { - if (cd.isValidUserId() && cd.getUserId() != 0) { - return String.format(Locale.US, "%s (%d)", name, cd.getUserId()); - } else { - return name; - } - } - return "?"; - case CLIENT_COL_PID: - return Integer.toString(cd.getPid()); - case CLIENT_COL_PORT: - if (mAdvancedPortSupport) { - int port = client.getDebuggerListenPort(); - String portString = "?"; - if (port != 0) { - portString = Integer.toString(port); - } - if (client.isSelectedClient()) { - return String.format("%1$s / %2$d", portString, //$NON-NLS-1$ - DdmPreferences.getSelectedDebugPort()); - } - - return portString; - } - } - } - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Classes which implement this interface provide methods that deals - * with {@link IDevice} and {@link Client} selection changes coming from the ui. - */ - public interface IUiSelectionListener { - /** - * Sent when a new {@link IDevice} and {@link Client} are selected. - * @param selectedDevice the selected device. If null, no devices are selected. - * @param selectedClient The selected client. If null, no clients are selected. - */ - public void selectionChanged(IDevice selectedDevice, Client selectedClient); - } - - /** - * Creates the {@link DevicePanel} object. - * @param loader - * @param advancedPortSupport if true the device panel will add support for selected client port - * and display the ports in the ui. - */ - public DevicePanel(boolean advancedPortSupport) { - mAdvancedPortSupport = advancedPortSupport; - } - - public void addSelectionListener(IUiSelectionListener listener) { - mListeners.add(listener); - } - - public void removeSelectionListener(IUiSelectionListener listener) { - mListeners.remove(listener); - } - - @Override - protected Control createControl(Composite parent) { - loadImages(parent.getDisplay()); - - parent.setLayout(new FillLayout()); - - // create the tree and its column - mTree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION); - mTree.setHeaderVisible(true); - mTree.setLinesVisible(true); - - IPreferenceStore store = DdmUiPreferences.getStore(); - - TableHelper.createTreeColumn(mTree, "Name", SWT.LEFT, - "com.android.home", //$NON-NLS-1$ - PREFS_COL_NAME_SERIAL, store); - TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$ - "Offline", //$NON-NLS-1$ - PREFS_COL_PID_STATE, store); - - TreeColumn col = new TreeColumn(mTree, SWT.NONE); - col.setWidth(ICON_WIDTH + 8); - col.setResizable(false); - col = new TreeColumn(mTree, SWT.NONE); - col.setWidth(ICON_WIDTH + 8); - col.setResizable(false); - - TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$ - "9999-9999", //$NON-NLS-1$ - PREFS_COL_PORT_BUILD, store); - - // create the tree viewer - mTreeViewer = new TreeViewer(mTree); - - // make the device auto expanded. - mTreeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS); - - // set up the content and label providers. - mTreeViewer.setContentProvider(new ContentProvider()); - mTreeViewer.setLabelProvider(new LabelProvider()); - - mTree.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - notifyListeners(); - } - }); - - return mTree; - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mTree.setFocus(); - } - - @Override - protected void postCreation() { - // ask for notification of changes in AndroidDebugBridge (a new one is created when - // adb is restarted from a different location), IDevice and Client objects. - AndroidDebugBridge.addDebugBridgeChangeListener(this); - AndroidDebugBridge.addDeviceChangeListener(this); - AndroidDebugBridge.addClientChangeListener(this); - } - - public void dispose() { - AndroidDebugBridge.removeDebugBridgeChangeListener(this); - AndroidDebugBridge.removeDeviceChangeListener(this); - AndroidDebugBridge.removeClientChangeListener(this); - } - - /** - * Returns the selected {@link Client}. May be null. - */ - public Client getSelectedClient() { - return mCurrentClient; - } - - /** - * Returns the selected {@link IDevice}. If a {@link Client} is selected, it returns the - * IDevice object containing the client. - */ - public IDevice getSelectedDevice() { - return mCurrentDevice; - } - - /** - * Kills the selected {@link Client} by sending its VM a halt command. - */ - public void killSelectedClient() { - if (mCurrentClient != null) { - Client client = mCurrentClient; - - // reset the selection to the device. - TreePath treePath = new TreePath(new Object[] { mCurrentDevice }); - TreeSelection treeSelection = new TreeSelection(treePath); - mTreeViewer.setSelection(treeSelection); - - client.kill(); - } - } - - /** - * Forces a GC on the selected {@link Client}. - */ - public void forceGcOnSelectedClient() { - if (mCurrentClient != null) { - mCurrentClient.executeGarbageCollector(); - } - } - - public void dumpHprof() { - if (mCurrentClient != null) { - mCurrentClient.dumpHprof(); - } - } - - public void toggleMethodProfiling() { - if (mCurrentClient != null) { - mCurrentClient.toggleMethodProfiling(); - } - } - - public void setEnabledHeapOnSelectedClient(boolean enable) { - if (mCurrentClient != null) { - mCurrentClient.setHeapUpdateEnabled(enable); - } - } - - public void setEnabledThreadOnSelectedClient(boolean enable) { - if (mCurrentClient != null) { - mCurrentClient.setThreadUpdateEnabled(enable); - } - } - - /** - * Sent when a new {@link AndroidDebugBridge} is started. - * <p/> - * This is sent from a non UI thread. - * @param bridge the new {@link AndroidDebugBridge} object. - * - * @see IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge) - */ - @Override - public void bridgeChanged(final AndroidDebugBridge bridge) { - if (mTree.isDisposed() == false) { - exec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - // set up the data source. - mTreeViewer.setInput(bridge); - - // notify the listener of a possible selection change. - notifyListeners(); - } else { - // tree is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this); - AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this); - AndroidDebugBridge.removeClientChangeListener(DevicePanel.this); - } - } - }); - } - - // all current devices are obsolete - synchronized (mDevicesToExpand) { - mDevicesToExpand.clear(); - } - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceConnected(IDevice) - */ - @Override - public void deviceConnected(IDevice device) { - exec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - // refresh all - mTreeViewer.refresh(); - - // notify the listener of a possible selection change. - notifyListeners(); - } else { - // tree is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this); - AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this); - AndroidDebugBridge.removeClientChangeListener(DevicePanel.this); - } - } - }); - - // if it doesn't have clients yet, it'll need to be manually expanded when it gets them. - if (device.hasClients() == false) { - synchronized (mDevicesToExpand) { - mDevicesToExpand.add(device); - } - } - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceDisconnected(IDevice) - */ - @Override - public void deviceDisconnected(IDevice device) { - deviceConnected(device); - - // just in case, we remove it from the list of devices to expand. - synchronized (mDevicesToExpand) { - mDevicesToExpand.remove(device); - } - } - - /** - * Sent when a device data changed, or when clients are started/terminated on the device. - * <p/> - * This is sent from a non UI thread. - * @param device the device that was updated. - * @param changeMask the mask indicating what changed. - * - * @see IDeviceChangeListener#deviceChanged(IDevice) - */ - @Override - public void deviceChanged(final IDevice device, int changeMask) { - boolean expand = false; - synchronized (mDevicesToExpand) { - int index = mDevicesToExpand.indexOf(device); - if (device.hasClients() && index != -1) { - mDevicesToExpand.remove(index); - expand = true; - } - } - - final boolean finalExpand = expand; - - exec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - // look if the current device is selected. This is done in case the current - // client of this particular device was killed. In this case, we'll need to - // manually reselect the device. - - IDevice selectedDevice = getSelectedDevice(); - - // refresh the device - mTreeViewer.refresh(device); - - // if the selected device was the changed device and the new selection is - // empty, we reselect the device. - if (selectedDevice == device && mTreeViewer.getSelection().isEmpty()) { - mTreeViewer.setSelection(new TreeSelection(new TreePath( - new Object[] { device }))); - } - - // notify the listener of a possible selection change. - notifyListeners(); - - if (finalExpand) { - mTreeViewer.setExpandedState(device, true); - } - } else { - // tree is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this); - AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this); - AndroidDebugBridge.removeClientChangeListener(DevicePanel.this); - } - } - }); - } - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, final int changeMask) { - exec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - // refresh the client - mTreeViewer.refresh(client); - - if ((changeMask & Client.CHANGE_DEBUGGER_STATUS) == - Client.CHANGE_DEBUGGER_STATUS && - client.getClientData().getDebuggerConnectionStatus() == - DebuggerStatus.WAITING) { - // make sure the device is expanded. Normally the setSelection below - // will auto expand, but the children of device may not already exist - // at this time. Forcing an expand will make the TreeViewer create them. - IDevice device = client.getDevice(); - if (mTreeViewer.getExpandedState(device) == false) { - mTreeViewer.setExpandedState(device, true); - } - - // create and set the selection - TreePath treePath = new TreePath(new Object[] { device, client}); - TreeSelection treeSelection = new TreeSelection(treePath); - mTreeViewer.setSelection(treeSelection); - - if (mAdvancedPortSupport) { - client.setAsSelectedClient(); - } - - // notify the listener of a possible selection change. - notifyListeners(device, client); - } - } else { - // tree is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this); - AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this); - AndroidDebugBridge.removeClientChangeListener(DevicePanel.this); - } - } - }); - } - - private void loadImages(Display display) { - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - - if (mDeviceImage == null) { - mDeviceImage = loader.loadImage(display, "device.png", //$NON-NLS-1$ - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_RED)); - } - if (mEmulatorImage == null) { - mEmulatorImage = loader.loadImage(display, - "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$ - display.getSystemColor(SWT.COLOR_BLUE)); - } - if (mThreadImage == null) { - mThreadImage = loader.loadImage(display, ICON_THREAD, - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_YELLOW)); - } - if (mHeapImage == null) { - mHeapImage = loader.loadImage(display, ICON_HEAP, - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_BLUE)); - } - if (mWaitingImage == null) { - mWaitingImage = loader.loadImage(display, - "debug-wait.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$ - display.getSystemColor(SWT.COLOR_RED)); - } - if (mDebuggerImage == null) { - mDebuggerImage = loader.loadImage(display, - "debug-attach.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$ - display.getSystemColor(SWT.COLOR_GREEN)); - } - if (mDebugErrorImage == null) { - mDebugErrorImage = loader.loadImage(display, - "debug-error.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$ - display.getSystemColor(SWT.COLOR_RED)); - } - } - - /** - * Returns a display string representing the state of the device. - * @param d the device - */ - private static String getStateString(IDevice d) { - DeviceState deviceState = d.getState(); - if (deviceState == DeviceState.ONLINE) { - return "Online"; - } else if (deviceState == DeviceState.OFFLINE) { - return "Offline"; - } else if (deviceState == DeviceState.BOOTLOADER) { - return "Bootloader"; - } - - return "??"; - } - - /** - * Executes the {@link Runnable} in the UI thread. - * @param runnable the runnable to execute. - */ - private void exec(Runnable runnable) { - try { - Display display = mTree.getDisplay(); - display.asyncExec(runnable); - } catch (SWTException e) { - // tree is disposed, we need to do something. lets remove ourselves from the listener. - AndroidDebugBridge.removeDebugBridgeChangeListener(this); - AndroidDebugBridge.removeDeviceChangeListener(this); - AndroidDebugBridge.removeClientChangeListener(this); - } - } - - private void notifyListeners() { - // get the selection - TreeItem[] items = mTree.getSelection(); - - Client client = null; - IDevice device = null; - - if (items.length == 1) { - Object object = items[0].getData(); - if (object instanceof Client) { - client = (Client)object; - device = client.getDevice(); - } else if (object instanceof IDevice) { - device = (IDevice)object; - } - } - - notifyListeners(device, client); - } - - private void notifyListeners(IDevice selectedDevice, Client selectedClient) { - if (selectedDevice != mCurrentDevice || selectedClient != mCurrentClient) { - mCurrentDevice = selectedDevice; - mCurrentClient = selectedClient; - - for (IUiSelectionListener listener : mListeners) { - // notify the listener with a try/catch-all to make sure this thread won't die - // because of an uncaught exception before all the listeners were notified. - try { - listener.selectionChanged(selectedDevice, selectedClient); - } catch (Exception e) { - } - } - } - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/EmulatorControlPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/EmulatorControlPanel.java deleted file mode 100644 index 82aed98..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/EmulatorControlPanel.java +++ /dev/null @@ -1,1463 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.EmulatorConsole; -import com.android.ddmlib.EmulatorConsole.GsmMode; -import com.android.ddmlib.EmulatorConsole.GsmStatus; -import com.android.ddmlib.EmulatorConsole.NetworkStatus; -import com.android.ddmlib.IDevice; -import com.android.ddmuilib.location.CoordinateControls; -import com.android.ddmuilib.location.GpxParser; -import com.android.ddmuilib.location.GpxParser.Track; -import com.android.ddmuilib.location.KmlParser; -import com.android.ddmuilib.location.TrackContentProvider; -import com.android.ddmuilib.location.TrackLabelProvider; -import com.android.ddmuilib.location.TrackPoint; -import com.android.ddmuilib.location.WayPoint; -import com.android.ddmuilib.location.WayPointContentProvider; -import com.android.ddmuilib.location.WayPointLabelProvider; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.custom.ScrolledComposite; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.TabFolder; -import org.eclipse.swt.widgets.TabItem; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; - -/** - * Panel to control the emulator using EmulatorConsole objects. - */ -public class EmulatorControlPanel extends SelectionDependentPanel { - - // default location: Patio outside Charlie's - private final static double DEFAULT_LONGITUDE = -122.084095; - private final static double DEFAULT_LATITUDE = 37.422006; - - private final static String SPEED_FORMAT = "Speed: %1$dX"; - - - /** - * Map between the display gsm mode and the internal tag used by the display. - */ - private final static String[][] GSM_MODES = new String[][] { - { "unregistered", GsmMode.UNREGISTERED.getTag() }, - { "home", GsmMode.HOME.getTag() }, - { "roaming", GsmMode.ROAMING.getTag() }, - { "searching", GsmMode.SEARCHING.getTag() }, - { "denied", GsmMode.DENIED.getTag() }, - }; - - private final static String[] NETWORK_SPEEDS = new String[] { - "Full", - "GSM", - "HSCSD", - "GPRS", - "EDGE", - "UMTS", - "HSDPA", - }; - - private final static String[] NETWORK_LATENCIES = new String[] { - "None", - "GPRS", - "EDGE", - "UMTS", - }; - - private final static int[] PLAY_SPEEDS = new int[] { 1, 2, 5, 10, 20, 50 }; - - private final static String RE_PHONE_NUMBER = "^[+#0-9]+$"; //$NON-NLS-1$ - private final static String PREFS_WAYPOINT_COL_NAME = "emulatorControl.waypoint.name"; //$NON-NLS-1$ - private final static String PREFS_WAYPOINT_COL_LONGITUDE = "emulatorControl.waypoint.longitude"; //$NON-NLS-1$ - private final static String PREFS_WAYPOINT_COL_LATITUDE = "emulatorControl.waypoint.latitude"; //$NON-NLS-1$ - private final static String PREFS_WAYPOINT_COL_ELEVATION = "emulatorControl.waypoint.elevation"; //$NON-NLS-1$ - private final static String PREFS_WAYPOINT_COL_DESCRIPTION = "emulatorControl.waypoint.desc"; //$NON-NLS-1$ - private final static String PREFS_TRACK_COL_NAME = "emulatorControl.track.name"; //$NON-NLS-1$ - private final static String PREFS_TRACK_COL_COUNT = "emulatorControl.track.count"; //$NON-NLS-1$ - private final static String PREFS_TRACK_COL_FIRST = "emulatorControl.track.first"; //$NON-NLS-1$ - private final static String PREFS_TRACK_COL_LAST = "emulatorControl.track.last"; //$NON-NLS-1$ - private final static String PREFS_TRACK_COL_COMMENT = "emulatorControl.track.comment"; //$NON-NLS-1$ - - private EmulatorConsole mEmulatorConsole; - - private Composite mParent; - - private Label mVoiceLabel; - private Combo mVoiceMode; - private Label mDataLabel; - private Combo mDataMode; - private Label mSpeedLabel; - private Combo mNetworkSpeed; - private Label mLatencyLabel; - private Combo mNetworkLatency; - - private Label mNumberLabel; - private Text mPhoneNumber; - - private Button mVoiceButton; - private Button mSmsButton; - - private Label mMessageLabel; - private Text mSmsMessage; - - private Button mCallButton; - private Button mCancelButton; - - private TabFolder mLocationFolders; - - private Button mDecimalButton; - private Button mSexagesimalButton; - private CoordinateControls mLongitudeControls; - private CoordinateControls mLatitudeControls; - private Button mGpxUploadButton; - private Table mGpxWayPointTable; - private Table mGpxTrackTable; - private Button mKmlUploadButton; - private Table mKmlWayPointTable; - - private Button mPlayGpxButton; - private Button mGpxBackwardButton; - private Button mGpxForwardButton; - private Button mGpxSpeedButton; - private Button mPlayKmlButton; - private Button mKmlBackwardButton; - private Button mKmlForwardButton; - private Button mKmlSpeedButton; - - private Image mPlayImage; - private Image mPauseImage; - - private Thread mPlayingThread; - private boolean mPlayingTrack; - private int mPlayDirection = 1; - private int mSpeed; - private int mSpeedIndex; - - private final SelectionAdapter mDirectionButtonAdapter = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - Button b = (Button)e.getSource(); - if (b.getSelection() == false) { - // basically the button was unselected, which we don't allow. - // so we reselect it. - b.setSelection(true); - return; - } - - // now handle selection change. - if (b == mGpxForwardButton || b == mKmlForwardButton) { - mGpxBackwardButton.setSelection(false); - mGpxForwardButton.setSelection(true); - mKmlBackwardButton.setSelection(false); - mKmlForwardButton.setSelection(true); - mPlayDirection = 1; - - } else { - mGpxBackwardButton.setSelection(true); - mGpxForwardButton.setSelection(false); - mKmlBackwardButton.setSelection(true); - mKmlForwardButton.setSelection(false); - mPlayDirection = -1; - } - } - }; - - private final SelectionAdapter mSpeedButtonAdapter = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mSpeedIndex = (mSpeedIndex+1) % PLAY_SPEEDS.length; - mSpeed = PLAY_SPEEDS[mSpeedIndex]; - - mGpxSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); - mGpxPlayControls.pack(); - mKmlSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); - mKmlPlayControls.pack(); - - if (mPlayingThread != null) { - mPlayingThread.interrupt(); - } - } - }; - private Composite mKmlPlayControls; - private Composite mGpxPlayControls; - - - public EmulatorControlPanel() { - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()} - */ - @Override - public void deviceSelected() { - handleNewDevice(getCurrentDevice()); - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()} - */ - @Override - public void clientSelected() { - // pass - } - - /** - * Creates a control capable of displaying some information. This is - * called once, when the application is initializing, from the UI thread. - */ - @Override - protected Control createControl(Composite parent) { - mParent = parent; - - final ScrolledComposite scollingParent = new ScrolledComposite(parent, SWT.V_SCROLL); - scollingParent.setExpandVertical(true); - scollingParent.setExpandHorizontal(true); - scollingParent.setLayoutData(new GridData(GridData.FILL_BOTH)); - - final Composite top = new Composite(scollingParent, SWT.NONE); - scollingParent.setContent(top); - top.setLayout(new GridLayout(1, false)); - - // set the resize for the scrolling to work (why isn't that done automatically?!?) - scollingParent.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Rectangle r = scollingParent.getClientArea(); - scollingParent.setMinSize(top.computeSize(r.width, SWT.DEFAULT)); - } - }); - - createRadioControls(top); - - createCallControls(top); - - createLocationControls(top); - - doEnable(false); - - top.layout(); - Rectangle r = scollingParent.getClientArea(); - scollingParent.setMinSize(top.computeSize(r.width, SWT.DEFAULT)); - - return scollingParent; - } - - /** - * Create Radio (on/off/roaming, for voice/data) controls. - * @param top - */ - private void createRadioControls(final Composite top) { - Group g1 = new Group(top, SWT.NONE); - g1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - g1.setLayout(new GridLayout(2, false)); - g1.setText("Telephony Status"); - - // the inside of the group is 2 composite so that all the column of the controls (mainly - // combos) have the same width, while not taking the whole screen width - Composite insideGroup = new Composite(g1, SWT.NONE); - GridLayout gl = new GridLayout(4, false); - gl.marginBottom = gl.marginHeight = gl.marginLeft = gl.marginRight = 0; - insideGroup.setLayout(gl); - - mVoiceLabel = new Label(insideGroup, SWT.NONE); - mVoiceLabel.setText("Voice:"); - mVoiceLabel.setAlignment(SWT.RIGHT); - - mVoiceMode = new Combo(insideGroup, SWT.READ_ONLY); - mVoiceMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - for (String[] mode : GSM_MODES) { - mVoiceMode.add(mode[0]); - } - mVoiceMode.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - setVoiceMode(mVoiceMode.getSelectionIndex()); - } - }); - - mSpeedLabel = new Label(insideGroup, SWT.NONE); - mSpeedLabel.setText("Speed:"); - mSpeedLabel.setAlignment(SWT.RIGHT); - - mNetworkSpeed = new Combo(insideGroup, SWT.READ_ONLY); - mNetworkSpeed.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - for (String mode : NETWORK_SPEEDS) { - mNetworkSpeed.add(mode); - } - mNetworkSpeed.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - setNetworkSpeed(mNetworkSpeed.getSelectionIndex()); - } - }); - - mDataLabel = new Label(insideGroup, SWT.NONE); - mDataLabel.setText("Data:"); - mDataLabel.setAlignment(SWT.RIGHT); - - mDataMode = new Combo(insideGroup, SWT.READ_ONLY); - mDataMode.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - for (String[] mode : GSM_MODES) { - mDataMode.add(mode[0]); - } - mDataMode.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - setDataMode(mDataMode.getSelectionIndex()); - } - }); - - mLatencyLabel = new Label(insideGroup, SWT.NONE); - mLatencyLabel.setText("Latency:"); - mLatencyLabel.setAlignment(SWT.RIGHT); - - mNetworkLatency = new Combo(insideGroup, SWT.READ_ONLY); - mNetworkLatency.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - for (String mode : NETWORK_LATENCIES) { - mNetworkLatency.add(mode); - } - mNetworkLatency.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - setNetworkLatency(mNetworkLatency.getSelectionIndex()); - } - }); - - // now an empty label to take the rest of the width of the group - Label l = new Label(g1, SWT.NONE); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - } - - /** - * Create Voice/SMS call/hang up controls - * @param top - */ - private void createCallControls(final Composite top) { - GridLayout gl; - Group g2 = new Group(top, SWT.NONE); - g2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - g2.setLayout(new GridLayout(1, false)); - g2.setText("Telephony Actions"); - - // horizontal composite for label + text field - Composite phoneComp = new Composite(g2, SWT.NONE); - phoneComp.setLayoutData(new GridData(GridData.FILL_BOTH)); - gl = new GridLayout(2, false); - gl.marginBottom = gl.marginHeight = gl.marginLeft = gl.marginRight = 0; - phoneComp.setLayout(gl); - - mNumberLabel = new Label(phoneComp, SWT.NONE); - mNumberLabel.setText("Incoming number:"); - - mPhoneNumber = new Text(phoneComp, SWT.BORDER | SWT.LEFT | SWT.SINGLE); - mPhoneNumber.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mPhoneNumber.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - // Reenable the widgets based on the content of the text. - // doEnable checks the validity of the phone number to enable/disable some - // widgets. - // Looks like we're getting a callback at creation time, so we can't - // suppose that we are enabled when the text is modified... - doEnable(mEmulatorConsole != null); - } - }); - - mVoiceButton = new Button(phoneComp, SWT.RADIO); - GridData gd = new GridData(); - gd.horizontalSpan = 2; - mVoiceButton.setText("Voice"); - mVoiceButton.setLayoutData(gd); - mVoiceButton.setEnabled(false); - mVoiceButton.setSelection(true); - mVoiceButton.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - doEnable(true); - - if (mVoiceButton.getSelection()) { - mCallButton.setText("Call"); - } else { - mCallButton.setText("Send"); - } - } - }); - - mSmsButton = new Button(phoneComp, SWT.RADIO); - mSmsButton.setText("SMS"); - gd = new GridData(); - gd.horizontalSpan = 2; - mSmsButton.setLayoutData(gd); - mSmsButton.setEnabled(false); - // Since there are only 2 radio buttons, we can put a listener on only one (they - // are both called on select and unselect event. - - mMessageLabel = new Label(phoneComp, SWT.NONE); - gd = new GridData(); - gd.verticalAlignment = SWT.TOP; - mMessageLabel.setLayoutData(gd); - mMessageLabel.setText("Message:"); - mMessageLabel.setEnabled(false); - - mSmsMessage = new Text(phoneComp, SWT.BORDER | SWT.LEFT | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); - mSmsMessage.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.heightHint = 70; - mSmsMessage.setEnabled(false); - - // composite to put the 2 buttons horizontally - Composite g2ButtonComp = new Composite(g2, SWT.NONE); - g2ButtonComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - gl = new GridLayout(2, false); - gl.marginWidth = gl.marginHeight = 0; - g2ButtonComp.setLayout(gl); - - // now a button below the phone number - mCallButton = new Button(g2ButtonComp, SWT.PUSH); - mCallButton.setText("Call"); - mCallButton.setEnabled(false); - mCallButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mEmulatorConsole != null) { - if (mVoiceButton.getSelection()) { - processCommandResult(mEmulatorConsole.call(mPhoneNumber.getText().trim())); - } else { - // we need to encode the message. We need to replace the carriage return - // character by the 2 character string \n. - // Because of this the \ character needs to be escaped as well. - // ReplaceAll() expects regexp so \ char are escaped twice. - String message = mSmsMessage.getText(); - message = message.replaceAll("\\\\", //$NON-NLS-1$ - "\\\\\\\\"); //$NON-NLS-1$ - - // While the normal line delimiter is returned by Text.getLineDelimiter() - // it seems copy pasting text coming from somewhere else could have another - // delimited. For this reason, we'll replace is several steps - - // replace the dual CR-LF - message = message.replaceAll("\r\n", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - // replace remaining stand alone \n - message = message.replaceAll("\n", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - // replace remaining stand alone \r - message = message.replaceAll("\r", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - processCommandResult(mEmulatorConsole.sendSms(mPhoneNumber.getText().trim(), - message)); - } - } - } - }); - - mCancelButton = new Button(g2ButtonComp, SWT.PUSH); - mCancelButton.setText("Hang Up"); - mCancelButton.setEnabled(false); - mCancelButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mEmulatorConsole != null) { - if (mVoiceButton.getSelection()) { - processCommandResult(mEmulatorConsole.cancelCall( - mPhoneNumber.getText().trim())); - } - } - } - }); - } - - /** - * Create Location controls. - * @param top - */ - private void createLocationControls(final Composite top) { - Label l = new Label(top, SWT.NONE); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - l.setText("Location Controls"); - - mLocationFolders = new TabFolder(top, SWT.NONE); - mLocationFolders.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - Composite manualLocationComp = new Composite(mLocationFolders, SWT.NONE); - TabItem item = new TabItem(mLocationFolders, SWT.NONE); - item.setText("Manual"); - item.setControl(manualLocationComp); - - createManualLocationControl(manualLocationComp); - - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - mPlayImage = loader.loadImage("play.png", mParent.getDisplay()); //$NON-NLS-1$ - mPauseImage = loader.loadImage("pause.png", mParent.getDisplay()); //$NON-NLS-1$ - - Composite gpxLocationComp = new Composite(mLocationFolders, SWT.NONE); - item = new TabItem(mLocationFolders, SWT.NONE); - item.setText("GPX"); - item.setControl(gpxLocationComp); - - createGpxLocationControl(gpxLocationComp); - - Composite kmlLocationComp = new Composite(mLocationFolders, SWT.NONE); - kmlLocationComp.setLayout(new FillLayout()); - item = new TabItem(mLocationFolders, SWT.NONE); - item.setText("KML"); - item.setControl(kmlLocationComp); - - createKmlLocationControl(kmlLocationComp); - } - - private void createManualLocationControl(Composite manualLocationComp) { - final StackLayout sl; - GridLayout gl; - Label label; - - manualLocationComp.setLayout(new GridLayout(1, false)); - mDecimalButton = new Button(manualLocationComp, SWT.RADIO); - mDecimalButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mDecimalButton.setText("Decimal"); - mSexagesimalButton = new Button(manualLocationComp, SWT.RADIO); - mSexagesimalButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mSexagesimalButton.setText("Sexagesimal"); - - // composite to hold and switching between the 2 modes. - final Composite content = new Composite(manualLocationComp, SWT.NONE); - content.setLayout(sl = new StackLayout()); - - // decimal display - final Composite decimalContent = new Composite(content, SWT.NONE); - decimalContent.setLayout(gl = new GridLayout(2, false)); - gl.marginHeight = gl.marginWidth = 0; - - mLongitudeControls = new CoordinateControls(); - mLatitudeControls = new CoordinateControls(); - - label = new Label(decimalContent, SWT.NONE); - label.setText("Longitude"); - - mLongitudeControls.createDecimalText(decimalContent); - - label = new Label(decimalContent, SWT.NONE); - label.setText("Latitude"); - - mLatitudeControls.createDecimalText(decimalContent); - - // sexagesimal content - final Composite sexagesimalContent = new Composite(content, SWT.NONE); - sexagesimalContent.setLayout(gl = new GridLayout(7, false)); - gl.marginHeight = gl.marginWidth = 0; - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("Longitude"); - - mLongitudeControls.createSexagesimalDegreeText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("\u00B0"); // degree character - - mLongitudeControls.createSexagesimalMinuteText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("'"); - - mLongitudeControls.createSexagesimalSecondText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("\""); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("Latitude"); - - mLatitudeControls.createSexagesimalDegreeText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("\u00B0"); - - mLatitudeControls.createSexagesimalMinuteText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("'"); - - mLatitudeControls.createSexagesimalSecondText(sexagesimalContent); - - label = new Label(sexagesimalContent, SWT.NONE); - label.setText("\""); - - // set the default display to decimal - sl.topControl = decimalContent; - mDecimalButton.setSelection(true); - - mDecimalButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mDecimalButton.getSelection()) { - sl.topControl = decimalContent; - } else { - sl.topControl = sexagesimalContent; - } - content.layout(); - } - }); - - Button sendButton = new Button(manualLocationComp, SWT.PUSH); - sendButton.setText("Send"); - sendButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mEmulatorConsole != null) { - processCommandResult(mEmulatorConsole.sendLocation( - mLongitudeControls.getValue(), mLatitudeControls.getValue(), 0)); - } - } - }); - - mLongitudeControls.setValue(DEFAULT_LONGITUDE); - mLatitudeControls.setValue(DEFAULT_LATITUDE); - } - - private void createGpxLocationControl(Composite gpxLocationComp) { - GridData gd; - - IPreferenceStore store = DdmUiPreferences.getStore(); - - gpxLocationComp.setLayout(new GridLayout(1, false)); - - mGpxUploadButton = new Button(gpxLocationComp, SWT.PUSH); - mGpxUploadButton.setText("Load GPX..."); - - // Table for way point - mGpxWayPointTable = new Table(gpxLocationComp, - SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); - mGpxWayPointTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.heightHint = 100; - mGpxWayPointTable.setHeaderVisible(true); - mGpxWayPointTable.setLinesVisible(true); - - TableHelper.createTableColumn(mGpxWayPointTable, "Name", SWT.LEFT, - "Some Name", - PREFS_WAYPOINT_COL_NAME, store); - TableHelper.createTableColumn(mGpxWayPointTable, "Longitude", SWT.LEFT, - "-199.999999", - PREFS_WAYPOINT_COL_LONGITUDE, store); - TableHelper.createTableColumn(mGpxWayPointTable, "Latitude", SWT.LEFT, - "-199.999999", - PREFS_WAYPOINT_COL_LATITUDE, store); - TableHelper.createTableColumn(mGpxWayPointTable, "Elevation", SWT.LEFT, - "99999.9", - PREFS_WAYPOINT_COL_ELEVATION, store); - TableHelper.createTableColumn(mGpxWayPointTable, "Description", SWT.LEFT, - "Some Description", - PREFS_WAYPOINT_COL_DESCRIPTION, store); - - final TableViewer gpxWayPointViewer = new TableViewer(mGpxWayPointTable); - gpxWayPointViewer.setContentProvider(new WayPointContentProvider()); - gpxWayPointViewer.setLabelProvider(new WayPointLabelProvider()); - - gpxWayPointViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object selectedObject = structuredSelection.getFirstElement(); - if (selectedObject instanceof WayPoint) { - WayPoint wayPoint = (WayPoint)selectedObject; - - if (mEmulatorConsole != null && mPlayingTrack == false) { - processCommandResult(mEmulatorConsole.sendLocation( - wayPoint.getLongitude(), wayPoint.getLatitude(), - wayPoint.getElevation())); - } - } - } - } - }); - - // table for tracks. - mGpxTrackTable = new Table(gpxLocationComp, - SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); - mGpxTrackTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.heightHint = 100; - mGpxTrackTable.setHeaderVisible(true); - mGpxTrackTable.setLinesVisible(true); - - TableHelper.createTableColumn(mGpxTrackTable, "Name", SWT.LEFT, - "Some very long name", - PREFS_TRACK_COL_NAME, store); - TableHelper.createTableColumn(mGpxTrackTable, "Point Count", SWT.RIGHT, - "9999", - PREFS_TRACK_COL_COUNT, store); - TableHelper.createTableColumn(mGpxTrackTable, "First Point Time", SWT.LEFT, - "999-99-99T99:99:99Z", - PREFS_TRACK_COL_FIRST, store); - TableHelper.createTableColumn(mGpxTrackTable, "Last Point Time", SWT.LEFT, - "999-99-99T99:99:99Z", - PREFS_TRACK_COL_LAST, store); - TableHelper.createTableColumn(mGpxTrackTable, "Comment", SWT.LEFT, - "-199.999999", - PREFS_TRACK_COL_COMMENT, store); - - final TableViewer gpxTrackViewer = new TableViewer(mGpxTrackTable); - gpxTrackViewer.setContentProvider(new TrackContentProvider()); - gpxTrackViewer.setLabelProvider(new TrackLabelProvider()); - - gpxTrackViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object selectedObject = structuredSelection.getFirstElement(); - if (selectedObject instanceof Track) { - Track track = (Track)selectedObject; - - if (mEmulatorConsole != null && mPlayingTrack == false) { - TrackPoint[] points = track.getPoints(); - processCommandResult(mEmulatorConsole.sendLocation( - points[0].getLongitude(), points[0].getLatitude(), - points[0].getElevation())); - } - - mPlayGpxButton.setEnabled(true); - mGpxBackwardButton.setEnabled(true); - mGpxForwardButton.setEnabled(true); - mGpxSpeedButton.setEnabled(true); - - return; - } - } - - mPlayGpxButton.setEnabled(false); - mGpxBackwardButton.setEnabled(false); - mGpxForwardButton.setEnabled(false); - mGpxSpeedButton.setEnabled(false); - } - }); - - mGpxUploadButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); - - fileDialog.setText("Load GPX File"); - fileDialog.setFilterExtensions(new String[] { "*.gpx" } ); - - String fileName = fileDialog.open(); - if (fileName != null) { - GpxParser parser = new GpxParser(fileName); - if (parser.parse()) { - gpxWayPointViewer.setInput(parser.getWayPoints()); - gpxTrackViewer.setInput(parser.getTracks()); - } - } - } - }); - - mGpxPlayControls = new Composite(gpxLocationComp, SWT.NONE); - GridLayout gl; - mGpxPlayControls.setLayout(gl = new GridLayout(5, false)); - gl.marginHeight = gl.marginWidth = 0; - mGpxPlayControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mPlayGpxButton = new Button(mGpxPlayControls, SWT.PUSH | SWT.FLAT); - mPlayGpxButton.setImage(mPlayImage); - mPlayGpxButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mPlayingTrack == false) { - ISelection selection = gpxTrackViewer.getSelection(); - if (selection.isEmpty() == false && selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object selectedObject = structuredSelection.getFirstElement(); - if (selectedObject instanceof Track) { - Track track = (Track)selectedObject; - playTrack(track); - } - } - } else { - // if we're playing, then we pause - mPlayingTrack = false; - if (mPlayingThread != null) { - mPlayingThread.interrupt(); - } - } - } - }); - - Label separator = new Label(mGpxPlayControls, SWT.SEPARATOR | SWT.VERTICAL); - separator.setLayoutData(gd = new GridData( - GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); - gd.heightHint = 0; - - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - mGpxBackwardButton = new Button(mGpxPlayControls, SWT.TOGGLE | SWT.FLAT); - mGpxBackwardButton.setImage(loader.loadImage("backward.png", mParent.getDisplay())); //$NON-NLS-1$ - mGpxBackwardButton.setSelection(false); - mGpxBackwardButton.addSelectionListener(mDirectionButtonAdapter); - mGpxForwardButton = new Button(mGpxPlayControls, SWT.TOGGLE | SWT.FLAT); - mGpxForwardButton.setImage(loader.loadImage("forward.png", mParent.getDisplay())); //$NON-NLS-1$ - mGpxForwardButton.setSelection(true); - mGpxForwardButton.addSelectionListener(mDirectionButtonAdapter); - - mGpxSpeedButton = new Button(mGpxPlayControls, SWT.PUSH | SWT.FLAT); - - mSpeedIndex = 0; - mSpeed = PLAY_SPEEDS[mSpeedIndex]; - - mGpxSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); - mGpxSpeedButton.addSelectionListener(mSpeedButtonAdapter); - - mPlayGpxButton.setEnabled(false); - mGpxBackwardButton.setEnabled(false); - mGpxForwardButton.setEnabled(false); - mGpxSpeedButton.setEnabled(false); - - } - - private void createKmlLocationControl(Composite kmlLocationComp) { - GridData gd; - - IPreferenceStore store = DdmUiPreferences.getStore(); - - kmlLocationComp.setLayout(new GridLayout(1, false)); - - mKmlUploadButton = new Button(kmlLocationComp, SWT.PUSH); - mKmlUploadButton.setText("Load KML..."); - - // Table for way point - mKmlWayPointTable = new Table(kmlLocationComp, - SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION); - mKmlWayPointTable.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.heightHint = 200; - mKmlWayPointTable.setHeaderVisible(true); - mKmlWayPointTable.setLinesVisible(true); - - TableHelper.createTableColumn(mKmlWayPointTable, "Name", SWT.LEFT, - "Some Name", - PREFS_WAYPOINT_COL_NAME, store); - TableHelper.createTableColumn(mKmlWayPointTable, "Longitude", SWT.LEFT, - "-199.999999", - PREFS_WAYPOINT_COL_LONGITUDE, store); - TableHelper.createTableColumn(mKmlWayPointTable, "Latitude", SWT.LEFT, - "-199.999999", - PREFS_WAYPOINT_COL_LATITUDE, store); - TableHelper.createTableColumn(mKmlWayPointTable, "Elevation", SWT.LEFT, - "99999.9", - PREFS_WAYPOINT_COL_ELEVATION, store); - TableHelper.createTableColumn(mKmlWayPointTable, "Description", SWT.LEFT, - "Some Description", - PREFS_WAYPOINT_COL_DESCRIPTION, store); - - final TableViewer kmlWayPointViewer = new TableViewer(mKmlWayPointTable); - kmlWayPointViewer.setContentProvider(new WayPointContentProvider()); - kmlWayPointViewer.setLabelProvider(new WayPointLabelProvider()); - - mKmlUploadButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); - - fileDialog.setText("Load KML File"); - fileDialog.setFilterExtensions(new String[] { "*.kml" } ); - - String fileName = fileDialog.open(); - if (fileName != null) { - KmlParser parser = new KmlParser(fileName); - if (parser.parse()) { - kmlWayPointViewer.setInput(parser.getWayPoints()); - - mPlayKmlButton.setEnabled(true); - mKmlBackwardButton.setEnabled(true); - mKmlForwardButton.setEnabled(true); - mKmlSpeedButton.setEnabled(true); - } - } - } - }); - - kmlWayPointViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object selectedObject = structuredSelection.getFirstElement(); - if (selectedObject instanceof WayPoint) { - WayPoint wayPoint = (WayPoint)selectedObject; - - if (mEmulatorConsole != null && mPlayingTrack == false) { - processCommandResult(mEmulatorConsole.sendLocation( - wayPoint.getLongitude(), wayPoint.getLatitude(), - wayPoint.getElevation())); - } - } - } - } - }); - - - - mKmlPlayControls = new Composite(kmlLocationComp, SWT.NONE); - GridLayout gl; - mKmlPlayControls.setLayout(gl = new GridLayout(5, false)); - gl.marginHeight = gl.marginWidth = 0; - mKmlPlayControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mPlayKmlButton = new Button(mKmlPlayControls, SWT.PUSH | SWT.FLAT); - mPlayKmlButton.setImage(mPlayImage); - mPlayKmlButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mPlayingTrack == false) { - Object input = kmlWayPointViewer.getInput(); - if (input instanceof WayPoint[]) { - playKml((WayPoint[])input); - } - } else { - // if we're playing, then we pause - mPlayingTrack = false; - if (mPlayingThread != null) { - mPlayingThread.interrupt(); - } - } - } - }); - - Label separator = new Label(mKmlPlayControls, SWT.SEPARATOR | SWT.VERTICAL); - separator.setLayoutData(gd = new GridData( - GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); - gd.heightHint = 0; - - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - mKmlBackwardButton = new Button(mKmlPlayControls, SWT.TOGGLE | SWT.FLAT); - mKmlBackwardButton.setImage(loader.loadImage("backward.png", mParent.getDisplay())); //$NON-NLS-1$ - mKmlBackwardButton.setSelection(false); - mKmlBackwardButton.addSelectionListener(mDirectionButtonAdapter); - mKmlForwardButton = new Button(mKmlPlayControls, SWT.TOGGLE | SWT.FLAT); - mKmlForwardButton.setImage(loader.loadImage("forward.png", mParent.getDisplay())); //$NON-NLS-1$ - mKmlForwardButton.setSelection(true); - mKmlForwardButton.addSelectionListener(mDirectionButtonAdapter); - - mKmlSpeedButton = new Button(mKmlPlayControls, SWT.PUSH | SWT.FLAT); - - mSpeedIndex = 0; - mSpeed = PLAY_SPEEDS[mSpeedIndex]; - - mKmlSpeedButton.setText(String.format(SPEED_FORMAT, mSpeed)); - mKmlSpeedButton.addSelectionListener(mSpeedButtonAdapter); - - mPlayKmlButton.setEnabled(false); - mKmlBackwardButton.setEnabled(false); - mKmlForwardButton.setEnabled(false); - mKmlSpeedButton.setEnabled(false); - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - } - - @Override - protected void postCreation() { - // pass - } - - private synchronized void setDataMode(int selectionIndex) { - if (mEmulatorConsole != null) { - processCommandResult(mEmulatorConsole.setGsmDataMode( - GsmMode.getEnum(GSM_MODES[selectionIndex][1]))); - } - } - - private synchronized void setVoiceMode(int selectionIndex) { - if (mEmulatorConsole != null) { - processCommandResult(mEmulatorConsole.setGsmVoiceMode( - GsmMode.getEnum(GSM_MODES[selectionIndex][1]))); - } - } - - private synchronized void setNetworkLatency(int selectionIndex) { - if (mEmulatorConsole != null) { - processCommandResult(mEmulatorConsole.setNetworkLatency(selectionIndex)); - } - } - - private synchronized void setNetworkSpeed(int selectionIndex) { - if (mEmulatorConsole != null) { - processCommandResult(mEmulatorConsole.setNetworkSpeed(selectionIndex)); - } - } - - - /** - * Callback on device selection change. - * @param device the new selected device - */ - public void handleNewDevice(IDevice device) { - if (mParent.isDisposed()) { - return; - } - // unlink to previous console. - synchronized (this) { - mEmulatorConsole = null; - } - - try { - // get the emulator console for this device - // First we need the device itself - if (device != null) { - GsmStatus gsm = null; - NetworkStatus netstatus = null; - - synchronized (this) { - mEmulatorConsole = EmulatorConsole.getConsole(device); - if (mEmulatorConsole != null) { - // get the gsm status - gsm = mEmulatorConsole.getGsmStatus(); - netstatus = mEmulatorConsole.getNetworkStatus(); - - if (gsm == null || netstatus == null) { - mEmulatorConsole = null; - } - } - } - - if (gsm != null && netstatus != null) { - Display d = mParent.getDisplay(); - if (d.isDisposed() == false) { - final GsmStatus f_gsm = gsm; - final NetworkStatus f_netstatus = netstatus; - - d.asyncExec(new Runnable() { - @Override - public void run() { - if (f_gsm.voice != GsmMode.UNKNOWN) { - mVoiceMode.select(getGsmComboIndex(f_gsm.voice)); - } else { - mVoiceMode.clearSelection(); - } - if (f_gsm.data != GsmMode.UNKNOWN) { - mDataMode.select(getGsmComboIndex(f_gsm.data)); - } else { - mDataMode.clearSelection(); - } - - if (f_netstatus.speed != -1) { - mNetworkSpeed.select(f_netstatus.speed); - } else { - mNetworkSpeed.clearSelection(); - } - - if (f_netstatus.latency != -1) { - mNetworkLatency.select(f_netstatus.latency); - } else { - mNetworkLatency.clearSelection(); - } - } - }); - } - } - } - } finally { - // enable/disable the ui - boolean enable = false; - synchronized (this) { - enable = mEmulatorConsole != null; - } - - enable(enable); - } - } - - /** - * Enable or disable the ui. Can be called from non ui threads. - * @param enabled - */ - private void enable(final boolean enabled) { - try { - Display d = mParent.getDisplay(); - d.asyncExec(new Runnable() { - @Override - public void run() { - if (mParent.isDisposed() == false) { - doEnable(enabled); - } - } - }); - } catch (SWTException e) { - // disposed. do nothing - } - } - - private boolean isValidPhoneNumber() { - String number = mPhoneNumber.getText().trim(); - - return number.matches(RE_PHONE_NUMBER); - } - - /** - * Enable or disable the ui. Cannot be called from non ui threads. - * @param enabled - */ - protected void doEnable(boolean enabled) { - mVoiceLabel.setEnabled(enabled); - mVoiceMode.setEnabled(enabled); - - mDataLabel.setEnabled(enabled); - mDataMode.setEnabled(enabled); - - mSpeedLabel.setEnabled(enabled); - mNetworkSpeed.setEnabled(enabled); - - mLatencyLabel.setEnabled(enabled); - mNetworkLatency.setEnabled(enabled); - - // Calling setEnabled on a text field will trigger a modifyText event, so we don't do it - // if we don't need to. - if (mPhoneNumber.isEnabled() != enabled) { - mNumberLabel.setEnabled(enabled); - mPhoneNumber.setEnabled(enabled); - } - - boolean valid = isValidPhoneNumber(); - - mVoiceButton.setEnabled(enabled && valid); - mSmsButton.setEnabled(enabled && valid); - - boolean smsValid = enabled && valid && mSmsButton.getSelection(); - - // Calling setEnabled on a text field will trigger a modifyText event, so we don't do it - // if we don't need to. - if (mSmsMessage.isEnabled() != smsValid) { - mMessageLabel.setEnabled(smsValid); - mSmsMessage.setEnabled(smsValid); - } - if (enabled == false) { - mSmsMessage.setText(""); //$NON-NLs-1$ - } - - mCallButton.setEnabled(enabled && valid); - mCancelButton.setEnabled(enabled && valid && mVoiceButton.getSelection()); - - if (enabled == false) { - mVoiceMode.clearSelection(); - mDataMode.clearSelection(); - mNetworkSpeed.clearSelection(); - mNetworkLatency.clearSelection(); - if (mPhoneNumber.getText().length() > 0) { - mPhoneNumber.setText(""); //$NON-NLS-1$ - } - } - - // location controls - mLocationFolders.setEnabled(enabled); - - mDecimalButton.setEnabled(enabled); - mSexagesimalButton.setEnabled(enabled); - mLongitudeControls.setEnabled(enabled); - mLatitudeControls.setEnabled(enabled); - - mGpxUploadButton.setEnabled(enabled); - mGpxWayPointTable.setEnabled(enabled); - mGpxTrackTable.setEnabled(enabled); - mKmlUploadButton.setEnabled(enabled); - mKmlWayPointTable.setEnabled(enabled); - } - - /** - * Returns the index of the combo item matching a specific GsmMode. - * @param mode - */ - private int getGsmComboIndex(GsmMode mode) { - for (int i = 0 ; i < GSM_MODES.length; i++) { - String[] modes = GSM_MODES[i]; - if (mode.getTag().equals(modes[1])) { - return i; - } - } - return -1; - } - - /** - * Processes the result of a command sent to the console. - * @param result the result of the command. - */ - private boolean processCommandResult(final String result) { - if (result != EmulatorConsole.RESULT_OK) { - try { - mParent.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - if (mParent.isDisposed() == false) { - MessageDialog.openError(mParent.getShell(), "Emulator Console", - result); - } - } - }); - } catch (SWTException e) { - // we're quitting, just ignore - } - - return false; - } - - return true; - } - - /** - * @param track - */ - private void playTrack(final Track track) { - // no need to synchronize this check, the worst that can happen, is we start the thread - // for nothing. - if (mEmulatorConsole != null) { - mPlayGpxButton.setImage(mPauseImage); - mPlayKmlButton.setImage(mPauseImage); - mPlayingTrack = true; - - mPlayingThread = new Thread() { - @Override - public void run() { - try { - TrackPoint[] trackPoints = track.getPoints(); - int count = trackPoints.length; - - // get the start index. - int start = 0; - if (mPlayDirection == -1) { - start = count - 1; - } - - for (int p = start; p >= 0 && p < count; p += mPlayDirection) { - if (mPlayingTrack == false) { - return; - } - - // get the current point and send its location to - // the emulator. - final TrackPoint trackPoint = trackPoints[p]; - - synchronized (EmulatorControlPanel.this) { - if (mEmulatorConsole == null || - processCommandResult(mEmulatorConsole.sendLocation( - trackPoint.getLongitude(), trackPoint.getLatitude(), - trackPoint.getElevation())) == false) { - return; - } - } - - // if this is not the final point, then get the next one and - // compute the delta time - int nextIndex = p + mPlayDirection; - if (nextIndex >=0 && nextIndex < count) { - TrackPoint nextPoint = trackPoints[nextIndex]; - - long delta = nextPoint.getTime() - trackPoint.getTime(); - if (delta < 0) { - delta = -delta; - } - - long startTime = System.currentTimeMillis(); - - try { - sleep(delta / mSpeed); - } catch (InterruptedException e) { - if (mPlayingTrack == false) { - return; - } - - // we got interrupted, lets make sure we can play - do { - long waited = System.currentTimeMillis() - startTime; - long needToWait = delta / mSpeed; - if (waited < needToWait) { - try { - sleep(needToWait - waited); - } catch (InterruptedException e1) { - // we'll just loop and wait again if needed. - // unless we're supposed to stop - if (mPlayingTrack == false) { - return; - } - } - } else { - break; - } - } while (true); - } - } - } - } finally { - mPlayingTrack = false; - try { - mParent.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - if (mPlayGpxButton.isDisposed() == false) { - mPlayGpxButton.setImage(mPlayImage); - mPlayKmlButton.setImage(mPlayImage); - } - } - }); - } catch (SWTException e) { - // we're quitting, just ignore - } - } - } - }; - - mPlayingThread.start(); - } - } - - private void playKml(final WayPoint[] trackPoints) { - // no need to synchronize this check, the worst that can happen, is we start the thread - // for nothing. - if (mEmulatorConsole != null) { - mPlayGpxButton.setImage(mPauseImage); - mPlayKmlButton.setImage(mPauseImage); - mPlayingTrack = true; - - mPlayingThread = new Thread() { - @Override - public void run() { - try { - int count = trackPoints.length; - - // get the start index. - int start = 0; - if (mPlayDirection == -1) { - start = count - 1; - } - - for (int p = start; p >= 0 && p < count; p += mPlayDirection) { - if (mPlayingTrack == false) { - return; - } - - // get the current point and send its location to - // the emulator. - WayPoint trackPoint = trackPoints[p]; - - synchronized (EmulatorControlPanel.this) { - if (mEmulatorConsole == null || - processCommandResult(mEmulatorConsole.sendLocation( - trackPoint.getLongitude(), trackPoint.getLatitude(), - trackPoint.getElevation())) == false) { - return; - } - } - - // if this is not the final point, then get the next one and - // compute the delta time - int nextIndex = p + mPlayDirection; - if (nextIndex >=0 && nextIndex < count) { - - long delta = 1000; // 1 second - if (delta < 0) { - delta = -delta; - } - - long startTime = System.currentTimeMillis(); - - try { - sleep(delta / mSpeed); - } catch (InterruptedException e) { - if (mPlayingTrack == false) { - return; - } - - // we got interrupted, lets make sure we can play - do { - long waited = System.currentTimeMillis() - startTime; - long needToWait = delta / mSpeed; - if (waited < needToWait) { - try { - sleep(needToWait - waited); - } catch (InterruptedException e1) { - // we'll just loop and wait again if needed. - // unless we're supposed to stop - if (mPlayingTrack == false) { - return; - } - } - } else { - break; - } - } while (true); - } - } - } - } finally { - mPlayingTrack = false; - try { - mParent.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - if (mPlayGpxButton.isDisposed() == false) { - mPlayGpxButton.setImage(mPlayImage); - mPlayKmlButton.setImage(mPlayImage); - } - } - }); - } catch (SWTException e) { - // we're quitting, just ignore - } - } - } - }; - - mPlayingThread.start(); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/FindDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/FindDialog.java deleted file mode 100644 index fe3f438..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/FindDialog.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2012 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; - - -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** - * {@link FindDialog} provides a text box where users can enter text that should be - * searched for in the target editor/view. The buttons "Find Previous" and "Find Next" - * allow users to search forwards/backwards. This dialog simply provides a front end for the user - * and the actual task of searching is delegated to the {@link IFindTarget}. - */ -public class FindDialog extends Dialog { - private Label mStatusLabel; - private Button mFindNext; - private Button mFindPrevious; - private final IFindTarget mTarget; - private Text mSearchText; - private String mPreviousSearchText; - private final int mDefaultButtonId; - - /** Id of the "Find Next" button */ - public static final int FIND_NEXT_ID = IDialogConstants.CLIENT_ID; - - /** Id of the "Find Previous button */ - public static final int FIND_PREVIOUS_ID = IDialogConstants.CLIENT_ID + 1; - - public FindDialog(Shell shell, IFindTarget target) { - this(shell, target, FIND_PREVIOUS_ID); - } - - /** - * Construct a find dialog. - * @param shell shell to use - * @param target delegate to be invoked on user action - * @param defaultButtonId one of {@code #FIND_NEXT_ID} or {@code #FIND_PREVIOUS_ID}. - */ - public FindDialog(Shell shell, IFindTarget target, int defaultButtonId) { - super(shell); - - mTarget = target; - mDefaultButtonId = defaultButtonId; - - setShellStyle((getShellStyle() & ~SWT.APPLICATION_MODAL) | SWT.MODELESS); - setBlockOnOpen(true); - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite panel = new Composite(parent, SWT.NONE); - panel.setLayout(new GridLayout(2, false)); - panel.setLayoutData(new GridData(GridData.FILL_BOTH)); - - Label lblMessage = new Label(panel, SWT.NONE); - lblMessage.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - lblMessage.setText("Find:"); - - mSearchText = new Text(panel, SWT.BORDER); - mSearchText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mSearchText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - boolean hasText = !mSearchText.getText().trim().isEmpty(); - mFindNext.setEnabled(hasText); - mFindPrevious.setEnabled(hasText); - } - }); - - mStatusLabel = new Label(panel, SWT.NONE); - mStatusLabel.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_DARK_RED)); - GridData gd = new GridData(); - gd.horizontalSpan = 2; - gd.grabExcessHorizontalSpace = true; - mStatusLabel.setLayoutData(gd); - - return panel; - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, false); - - mFindNext = createButton(parent, FIND_NEXT_ID, "Find Next", - mDefaultButtonId == FIND_NEXT_ID); - mFindPrevious = createButton(parent, FIND_PREVIOUS_ID, "Find Previous", - mDefaultButtonId != FIND_NEXT_ID); - mFindNext.setEnabled(false); - mFindPrevious.setEnabled(false); - } - - @Override - protected void buttonPressed(int buttonId) { - if (buttonId == IDialogConstants.CLOSE_ID) { - close(); - return; - } - - if (buttonId == FIND_PREVIOUS_ID || buttonId == FIND_NEXT_ID) { - if (mTarget != null) { - String searchText = mSearchText.getText(); - boolean newSearch = !searchText.equals(mPreviousSearchText); - mPreviousSearchText = searchText; - boolean searchForward = buttonId == FIND_NEXT_ID; - - boolean hasMatches = mTarget.findAndSelect(searchText, newSearch, searchForward); - if (!hasMatches) { - mStatusLabel.setText("String not found"); - mStatusLabel.pack(); - } else { - mStatusLabel.setText(""); - } - } - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/HeapPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/HeapPanel.java deleted file mode 100644 index d0af8b0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/HeapPanel.java +++ /dev/null @@ -1,1310 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; -import com.android.ddmlib.HeapSegment.HeapSegmentElement; -import com.android.ddmlib.Log; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.CategoryAxis; -import org.jfree.chart.axis.CategoryLabelPositions; -import org.jfree.chart.labels.CategoryToolTipGenerator; -import org.jfree.chart.plot.CategoryPlot; -import org.jfree.chart.plot.Plot; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.renderer.category.CategoryItemRenderer; -import org.jfree.chart.title.TextTitle; -import org.jfree.data.category.CategoryDataset; -import org.jfree.data.category.DefaultCategoryDataset; -import org.jfree.experimental.chart.swt.ChartComposite; -import org.jfree.experimental.swt.SWTUtils; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - - -/** - * Base class for our information panels. - */ -public final class HeapPanel extends BaseHeapPanel { - private static final String PREFS_STATS_COL_TYPE = "heapPanel.col0"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_COUNT = "heapPanel.col1"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_SIZE = "heapPanel.col2"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_SMALLEST = "heapPanel.col3"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_LARGEST = "heapPanel.col4"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_MEDIAN = "heapPanel.col5"; //$NON-NLS-1$ - private static final String PREFS_STATS_COL_AVERAGE = "heapPanel.col6"; //$NON-NLS-1$ - - /* args to setUpdateStatus() */ - private static final int NOT_SELECTED = 0; - private static final int NOT_ENABLED = 1; - private static final int ENABLED = 2; - - /** color palette and map legend. NATIVE is the last enum is a 0 based enum list, so we need - * Native+1 at least. We also need 2 more entries for free area and expansion area. */ - private static final int NUM_PALETTE_ENTRIES = HeapSegmentElement.KIND_NATIVE+2 +1; - private static final String[] mMapLegend = new String[NUM_PALETTE_ENTRIES]; - private static final PaletteData mMapPalette = createPalette(); - - private static final boolean DISPLAY_HEAP_BITMAP = false; - private static final boolean DISPLAY_HILBERT_BITMAP = false; - - private static final int PLACEHOLDER_HILBERT_SIZE = 200; - private static final int PLACEHOLDER_LINEAR_V_SIZE = 100; - private static final int PLACEHOLDER_LINEAR_H_SIZE = 300; - - private static final int[] ZOOMS = {100, 50, 25}; - - private static final NumberFormat sByteFormatter = NumberFormat.getInstance(); - private static final NumberFormat sLargeByteFormatter = NumberFormat.getInstance(); - private static final NumberFormat sCountFormatter = NumberFormat.getInstance(); - - static { - sByteFormatter.setMinimumFractionDigits(0); - sByteFormatter.setMaximumFractionDigits(1); - sLargeByteFormatter.setMinimumFractionDigits(3); - sLargeByteFormatter.setMaximumFractionDigits(3); - - sCountFormatter.setGroupingUsed(true); - } - - private Display mDisplay; - - private Composite mTop; // real top - private Label mUpdateStatus; - private Table mHeapSummary; - private Combo mDisplayMode; - - //private ScrolledComposite mScrolledComposite; - - private Composite mDisplayBase; // base of the displays. - private StackLayout mDisplayStack; - - private Composite mStatisticsBase; - private Table mStatisticsTable; - private JFreeChart mChart; - private ChartComposite mChartComposite; - private Button mGcButton; - private DefaultCategoryDataset mAllocCountDataSet; - - private Composite mLinearBase; - private Label mLinearHeapImage; - - private Composite mHilbertBase; - private Label mHilbertHeapImage; - private Group mLegend; - private Combo mZoom; - - /** Image used for the hilbert display. Since we recreate a new image every time, we - * keep this one around to dispose it. */ - private Image mHilbertImage; - private Image mLinearImage; - private Composite[] mLayout; - - /* - * Create color palette for map. Set up titles for legend. - */ - private static PaletteData createPalette() { - RGB colors[] = new RGB[NUM_PALETTE_ENTRIES]; - colors[0] - = new RGB(192, 192, 192); // non-heap pixels are gray - mMapLegend[0] - = "(heap expansion area)"; - - colors[1] - = new RGB(0, 0, 0); // free chunks are black - mMapLegend[1] - = "free"; - - colors[HeapSegmentElement.KIND_OBJECT + 2] - = new RGB(0, 0, 255); // objects are blue - mMapLegend[HeapSegmentElement.KIND_OBJECT + 2] - = "data object"; - - colors[HeapSegmentElement.KIND_CLASS_OBJECT + 2] - = new RGB(0, 255, 0); // class objects are green - mMapLegend[HeapSegmentElement.KIND_CLASS_OBJECT + 2] - = "class object"; - - colors[HeapSegmentElement.KIND_ARRAY_1 + 2] - = new RGB(255, 0, 0); // byte/bool arrays are red - mMapLegend[HeapSegmentElement.KIND_ARRAY_1 + 2] - = "1-byte array (byte[], boolean[])"; - - colors[HeapSegmentElement.KIND_ARRAY_2 + 2] - = new RGB(255, 128, 0); // short/char arrays are orange - mMapLegend[HeapSegmentElement.KIND_ARRAY_2 + 2] - = "2-byte array (short[], char[])"; - - colors[HeapSegmentElement.KIND_ARRAY_4 + 2] - = new RGB(255, 255, 0); // obj/int/float arrays are yellow - mMapLegend[HeapSegmentElement.KIND_ARRAY_4 + 2] - = "4-byte array (object[], int[], float[])"; - - colors[HeapSegmentElement.KIND_ARRAY_8 + 2] - = new RGB(255, 128, 128); // long/double arrays are pink - mMapLegend[HeapSegmentElement.KIND_ARRAY_8 + 2] - = "8-byte array (long[], double[])"; - - colors[HeapSegmentElement.KIND_UNKNOWN + 2] - = new RGB(255, 0, 255); // unknown objects are cyan - mMapLegend[HeapSegmentElement.KIND_UNKNOWN + 2] - = "unknown object"; - - colors[HeapSegmentElement.KIND_NATIVE + 2] - = new RGB(64, 64, 64); // native objects are dark gray - mMapLegend[HeapSegmentElement.KIND_NATIVE + 2] - = "non-Java object"; - - return new PaletteData(colors); - } - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client == getCurrentClient()) { - if ((changeMask & Client.CHANGE_HEAP_MODE) == Client.CHANGE_HEAP_MODE || - (changeMask & Client.CHANGE_HEAP_DATA) == Client.CHANGE_HEAP_DATA) { - try { - mTop.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - clientSelected(); - } - }); - } catch (SWTException e) { - // display is disposed (app is quitting most likely), we do nothing. - } - } - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()} - */ - @Override - public void deviceSelected() { - // pass - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - if (mTop.isDisposed()) - return; - - Client client = getCurrentClient(); - - Log.d("ddms", "HeapPanel: changed " + client); - - if (client != null) { - ClientData cd = client.getClientData(); - - if (client.isHeapUpdateEnabled()) { - mGcButton.setEnabled(true); - mDisplayMode.setEnabled(true); - setUpdateStatus(ENABLED); - } else { - setUpdateStatus(NOT_ENABLED); - mGcButton.setEnabled(false); - mDisplayMode.setEnabled(false); - } - - fillSummaryTable(cd); - - int mode = mDisplayMode.getSelectionIndex(); - if (mode == 0) { - fillDetailedTable(client, false /* forceRedraw */); - } else { - if (DISPLAY_HEAP_BITMAP) { - renderHeapData(cd, mode - 1, false /* forceRedraw */); - } - } - } else { - mGcButton.setEnabled(false); - mDisplayMode.setEnabled(false); - fillSummaryTable(null); - fillDetailedTable(null, true); - setUpdateStatus(NOT_SELECTED); - } - - // sizes of things change frequently, so redo layout - //mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT, - // SWT.DEFAULT)); - mDisplayBase.layout(); - //mScrolledComposite.redraw(); - } - - /** - * Create our control(s). - */ - @Override - protected Control createControl(Composite parent) { - mDisplay = parent.getDisplay(); - - GridLayout gl; - - mTop = new Composite(parent, SWT.NONE); - mTop.setLayout(new GridLayout(1, false)); - mTop.setLayoutData(new GridData(GridData.FILL_BOTH)); - - mUpdateStatus = new Label(mTop, SWT.NONE); - setUpdateStatus(NOT_SELECTED); - - Composite summarySection = new Composite(mTop, SWT.NONE); - summarySection.setLayout(gl = new GridLayout(2, false)); - gl.marginHeight = gl.marginWidth = 0; - - mHeapSummary = createSummaryTable(summarySection); - mGcButton = new Button(summarySection, SWT.PUSH); - mGcButton.setText("Cause GC"); - mGcButton.setEnabled(false); - mGcButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - Client client = getCurrentClient(); - if (client != null) { - client.executeGarbageCollector(); - } - } - }); - - Composite comboSection = new Composite(mTop, SWT.NONE); - gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - comboSection.setLayout(gl); - - Label displayLabel = new Label(comboSection, SWT.NONE); - displayLabel.setText("Display: "); - - mDisplayMode = new Combo(comboSection, SWT.READ_ONLY); - mDisplayMode.setEnabled(false); - mDisplayMode.add("Stats"); - if (DISPLAY_HEAP_BITMAP) { - mDisplayMode.add("Linear"); - if (DISPLAY_HILBERT_BITMAP) { - mDisplayMode.add("Hilbert"); - } - } - - // the base of the displays. - mDisplayBase = new Composite(mTop, SWT.NONE); - mDisplayBase.setLayoutData(new GridData(GridData.FILL_BOTH)); - mDisplayStack = new StackLayout(); - mDisplayBase.setLayout(mDisplayStack); - - // create the statistics display - mStatisticsBase = new Composite(mDisplayBase, SWT.NONE); - //mStatisticsBase.setLayoutData(new GridData(GridData.FILL_BOTH)); - mStatisticsBase.setLayout(gl = new GridLayout(1, false)); - gl.marginHeight = gl.marginWidth = 0; - mDisplayStack.topControl = mStatisticsBase; - - mStatisticsTable = createDetailedTable(mStatisticsBase); - mStatisticsTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createChart(); - - //create the linear composite - mLinearBase = new Composite(mDisplayBase, SWT.NONE); - //mLinearBase.setLayoutData(new GridData()); - gl = new GridLayout(1, false); - gl.marginHeight = gl.marginWidth = 0; - mLinearBase.setLayout(gl); - - { - mLinearHeapImage = new Label(mLinearBase, SWT.NONE); - mLinearHeapImage.setLayoutData(new GridData()); - mLinearHeapImage.setImage(ImageLoader.createPlaceHolderArt(mDisplay, - PLACEHOLDER_LINEAR_H_SIZE, PLACEHOLDER_LINEAR_V_SIZE, - mDisplay.getSystemColor(SWT.COLOR_BLUE))); - - // create a composite to contain the bottom part (legend) - Composite bottomSection = new Composite(mLinearBase, SWT.NONE); - gl = new GridLayout(1, false); - gl.marginHeight = gl.marginWidth = 0; - bottomSection.setLayout(gl); - - createLegend(bottomSection); - } - -/* - mScrolledComposite = new ScrolledComposite(mTop, SWT.H_SCROLL | SWT.V_SCROLL); - mScrolledComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - mScrolledComposite.setExpandHorizontal(true); - mScrolledComposite.setExpandVertical(true); - mScrolledComposite.setContent(mDisplayBase); -*/ - - - // create the hilbert display. - mHilbertBase = new Composite(mDisplayBase, SWT.NONE); - //mHilbertBase.setLayoutData(new GridData()); - gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - mHilbertBase.setLayout(gl); - - if (DISPLAY_HILBERT_BITMAP) { - mHilbertHeapImage = new Label(mHilbertBase, SWT.NONE); - mHilbertHeapImage.setLayoutData(new GridData()); - mHilbertHeapImage.setImage(ImageLoader.createPlaceHolderArt(mDisplay, - PLACEHOLDER_HILBERT_SIZE, PLACEHOLDER_HILBERT_SIZE, - mDisplay.getSystemColor(SWT.COLOR_BLUE))); - - // create a composite to contain the right part (legend + zoom) - Composite rightSection = new Composite(mHilbertBase, SWT.NONE); - gl = new GridLayout(1, false); - gl.marginHeight = gl.marginWidth = 0; - rightSection.setLayout(gl); - - Composite zoomComposite = new Composite(rightSection, SWT.NONE); - gl = new GridLayout(2, false); - zoomComposite.setLayout(gl); - - Label l = new Label(zoomComposite, SWT.NONE); - l.setText("Zoom:"); - mZoom = new Combo(zoomComposite, SWT.READ_ONLY); - for (int z : ZOOMS) { - mZoom.add(String.format("%1$d%%", z)); //$NON-NLS-1$ - } - - mZoom.select(0); - mZoom.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - setLegendText(mZoom.getSelectionIndex()); - Client client = getCurrentClient(); - if (client != null) { - renderHeapData(client.getClientData(), 1, true); - mTop.pack(); - } - } - }); - - createLegend(rightSection); - } - mHilbertBase.pack(); - - mLayout = new Composite[] { mStatisticsBase, mLinearBase, mHilbertBase }; - mDisplayMode.select(0); - mDisplayMode.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int index = mDisplayMode.getSelectionIndex(); - Client client = getCurrentClient(); - - if (client != null) { - if (index == 0) { - fillDetailedTable(client, true /* forceRedraw */); - } else { - renderHeapData(client.getClientData(), index-1, true /* forceRedraw */); - } - } - - mDisplayStack.topControl = mLayout[index]; - //mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT, - // SWT.DEFAULT)); - mDisplayBase.layout(); - //mScrolledComposite.redraw(); - } - }); - - //mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT, - // SWT.DEFAULT)); - mDisplayBase.layout(); - //mScrolledComposite.redraw(); - - return mTop; - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mHeapSummary.setFocus(); - } - - - private Table createSummaryTable(Composite base) { - Table tab = new Table(base, SWT.SINGLE | SWT.FULL_SELECTION); - tab.setHeaderVisible(true); - tab.setLinesVisible(true); - - TableColumn col; - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("ID"); - col.pack(); - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("000.000WW"); //$NON-NLS-1$ - col.pack(); - col.setText("Heap Size"); - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("000.000WW"); //$NON-NLS-1$ - col.pack(); - col.setText("Allocated"); - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("000.000WW"); //$NON-NLS-1$ - col.pack(); - col.setText("Free"); - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("000.00%"); //$NON-NLS-1$ - col.pack(); - col.setText("% Used"); - - col = new TableColumn(tab, SWT.RIGHT); - col.setText("000,000,000"); //$NON-NLS-1$ - col.pack(); - col.setText("# Objects"); - - // make sure there is always one empty item so that one table row is always displayed. - TableItem item = new TableItem(tab, SWT.NONE); - item.setText(""); - - return tab; - } - - private Table createDetailedTable(Composite base) { - IPreferenceStore store = DdmUiPreferences.getStore(); - - Table tab = new Table(base, SWT.SINGLE | SWT.FULL_SELECTION); - tab.setHeaderVisible(true); - tab.setLinesVisible(true); - - TableHelper.createTableColumn(tab, "Type", SWT.LEFT, - "4-byte array (object[], int[], float[])", //$NON-NLS-1$ - PREFS_STATS_COL_TYPE, store); - - TableHelper.createTableColumn(tab, "Count", SWT.RIGHT, - "00,000", //$NON-NLS-1$ - PREFS_STATS_COL_COUNT, store); - - TableHelper.createTableColumn(tab, "Total Size", SWT.RIGHT, - "000.000 WW", //$NON-NLS-1$ - PREFS_STATS_COL_SIZE, store); - - TableHelper.createTableColumn(tab, "Smallest", SWT.RIGHT, - "000.000 WW", //$NON-NLS-1$ - PREFS_STATS_COL_SMALLEST, store); - - TableHelper.createTableColumn(tab, "Largest", SWT.RIGHT, - "000.000 WW", //$NON-NLS-1$ - PREFS_STATS_COL_LARGEST, store); - - TableHelper.createTableColumn(tab, "Median", SWT.RIGHT, - "000.000 WW", //$NON-NLS-1$ - PREFS_STATS_COL_MEDIAN, store); - - TableHelper.createTableColumn(tab, "Average", SWT.RIGHT, - "000.000 WW", //$NON-NLS-1$ - PREFS_STATS_COL_AVERAGE, store); - - tab.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - - Client client = getCurrentClient(); - if (client != null) { - int index = mStatisticsTable.getSelectionIndex(); - TableItem item = mStatisticsTable.getItem(index); - - if (item != null) { - Map<Integer, ArrayList<HeapSegmentElement>> heapMap = - client.getClientData().getVmHeapData().getProcessedHeapMap(); - - ArrayList<HeapSegmentElement> list = heapMap.get(item.getData()); - if (list != null) { - showChart(list); - } - } - } - - } - }); - - return tab; - } - - /** - * Creates the chart below the statistics table - */ - private void createChart() { - mAllocCountDataSet = new DefaultCategoryDataset(); - mChart = ChartFactory.createBarChart(null, "Size", "Count", mAllocCountDataSet, - PlotOrientation.VERTICAL, false, true, false); - - // get the font to make a proper title. We need to convert the swt font, - // into an awt font. - Font f = mStatisticsBase.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(mStatisticsBase.getDisplay(), - firstFontData, true /* ensureSameSize */); - - mChart.setTitle(new TextTitle("Allocation count per size", awtFont)); - - Plot plot = mChart.getPlot(); - if (plot instanceof CategoryPlot) { - // get the plot - CategoryPlot categoryPlot = (CategoryPlot)plot; - - // set the domain axis to draw labels that are displayed even with many values. - CategoryAxis domainAxis = categoryPlot.getDomainAxis(); - domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_90); - - CategoryItemRenderer renderer = categoryPlot.getRenderer(); - renderer.setBaseToolTipGenerator(new CategoryToolTipGenerator() { - @Override - public String generateToolTip(CategoryDataset dataset, int row, int column) { - // get the key for the size of the allocation - ByteLong columnKey = (ByteLong)dataset.getColumnKey(column); - String rowKey = (String)dataset.getRowKey(row); - Number value = dataset.getValue(rowKey, columnKey); - - return String.format("%1$d %2$s of %3$d bytes", value.intValue(), rowKey, - columnKey.getValue()); - } - }); - } - mChartComposite = new ChartComposite(mStatisticsBase, 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 - false, // zoom - true); // tooltips - - mChartComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - } - - private static String prettyByteCount(long bytes) { - double fracBytes = bytes; - String units = " B"; - if (fracBytes < 1024) { - return sByteFormatter.format(fracBytes) + units; - } else { - fracBytes /= 1024; - units = " KB"; - } - if (fracBytes >= 1024) { - fracBytes /= 1024; - units = " MB"; - } - if (fracBytes >= 1024) { - fracBytes /= 1024; - units = " GB"; - } - - return sLargeByteFormatter.format(fracBytes) + units; - } - - private static String approximateByteCount(long bytes) { - double fracBytes = bytes; - String units = ""; - if (fracBytes >= 1024) { - fracBytes /= 1024; - units = "K"; - } - if (fracBytes >= 1024) { - fracBytes /= 1024; - units = "M"; - } - if (fracBytes >= 1024) { - fracBytes /= 1024; - units = "G"; - } - - return sByteFormatter.format(fracBytes) + units; - } - - private static String addCommasToNumber(long num) { - return sCountFormatter.format(num); - } - - private static String fractionalPercent(long num, long denom) { - double val = (double)num / (double)denom; - val *= 100; - - NumberFormat nf = NumberFormat.getInstance(); - nf.setMinimumFractionDigits(2); - nf.setMaximumFractionDigits(2); - return nf.format(val) + "%"; - } - - private void fillSummaryTable(ClientData cd) { - if (mHeapSummary.isDisposed()) { - return; - } - - mHeapSummary.setRedraw(false); - mHeapSummary.removeAll(); - - int numRows = 0; - if (cd != null) { - synchronized (cd) { - Iterator<Integer> iter = cd.getVmHeapIds(); - - while (iter.hasNext()) { - numRows++; - Integer id = iter.next(); - Map<String, Long> heapInfo = cd.getVmHeapInfo(id); - if (heapInfo == null) { - continue; - } - long sizeInBytes = heapInfo.get(ClientData.HEAP_SIZE_BYTES); - long bytesAllocated = heapInfo.get(ClientData.HEAP_BYTES_ALLOCATED); - long objectsAllocated = heapInfo.get(ClientData.HEAP_OBJECTS_ALLOCATED); - - TableItem item = new TableItem(mHeapSummary, SWT.NONE); - item.setText(0, id.toString()); - - item.setText(1, prettyByteCount(sizeInBytes)); - item.setText(2, prettyByteCount(bytesAllocated)); - item.setText(3, prettyByteCount(sizeInBytes - bytesAllocated)); - item.setText(4, fractionalPercent(bytesAllocated, sizeInBytes)); - item.setText(5, addCommasToNumber(objectsAllocated)); - } - } - } - - if (numRows == 0) { - // make sure there is always one empty item so that one table row is always displayed. - TableItem item = new TableItem(mHeapSummary, SWT.NONE); - item.setText(""); - } - - mHeapSummary.pack(); - mHeapSummary.setRedraw(true); - } - - private void fillDetailedTable(Client client, boolean forceRedraw) { - // first check if the client is invalid or heap updates are not enabled. - if (client == null || client.isHeapUpdateEnabled() == false) { - mStatisticsTable.removeAll(); - showChart(null); - return; - } - - ClientData cd = client.getClientData(); - - Map<Integer, ArrayList<HeapSegmentElement>> heapMap; - - // Atomically get and clear the heap data. - synchronized (cd) { - if (serializeHeapData(cd.getVmHeapData()) == false && forceRedraw == false) { - // no change, we return. - return; - } - - heapMap = cd.getVmHeapData().getProcessedHeapMap(); - } - - // we have new data, lets display it. - - // First, get the current selection, and its key. - int index = mStatisticsTable.getSelectionIndex(); - Integer selectedKey = null; - if (index != -1) { - selectedKey = (Integer)mStatisticsTable.getItem(index).getData(); - } - - // disable redraws and remove all from the table. - mStatisticsTable.setRedraw(false); - mStatisticsTable.removeAll(); - - if (heapMap != null) { - int selectedIndex = -1; - ArrayList<HeapSegmentElement> selectedList = null; - - // get the keys - Set<Integer> keys = heapMap.keySet(); - int iter = 0; // use a manual iter int because Set<?> doesn't have an index - // based accessor. - for (Integer key : keys) { - ArrayList<HeapSegmentElement> list = heapMap.get(key); - - // check if this is the key that is supposed to be selected - if (key.equals(selectedKey)) { - selectedIndex = iter; - selectedList = list; - } - iter++; - - TableItem item = new TableItem(mStatisticsTable, SWT.NONE); - item.setData(key); - - // get the type - item.setText(0, mMapLegend[key]); - - // set the count, smallest, largest - int count = list.size(); - item.setText(1, addCommasToNumber(count)); - - if (count > 0) { - item.setText(3, prettyByteCount(list.get(0).getLength())); - item.setText(4, prettyByteCount(list.get(count-1).getLength())); - - int median = count / 2; - HeapSegmentElement element = list.get(median); - long size = element.getLength(); - item.setText(5, prettyByteCount(size)); - - long totalSize = 0; - for (int i = 0 ; i < count; i++) { - element = list.get(i); - - size = element.getLength(); - totalSize += size; - } - - // set the average and total - item.setText(2, prettyByteCount(totalSize)); - item.setText(6, prettyByteCount(totalSize / count)); - } - } - - mStatisticsTable.setRedraw(true); - - if (selectedIndex != -1) { - mStatisticsTable.setSelection(selectedIndex); - showChart(selectedList); - } else { - showChart(null); - } - } else { - mStatisticsTable.setRedraw(true); - } - } - - private static class ByteLong implements Comparable<ByteLong> { - private long mValue; - - private ByteLong(long value) { - mValue = value; - } - - public long getValue() { - return mValue; - } - - @Override - public String toString() { - return approximateByteCount(mValue); - } - - @Override - public int compareTo(ByteLong other) { - if (mValue != other.mValue) { - return mValue < other.mValue ? -1 : 1; - } - return 0; - } - - } - - /** - * Fills the chart with the content of the list of {@link HeapSegmentElement}. - */ - private void showChart(ArrayList<HeapSegmentElement> list) { - mAllocCountDataSet.clear(); - - if (list != null) { - String rowKey = "Alloc Count"; - - long currentSize = -1; - int currentCount = 0; - for (HeapSegmentElement element : list) { - if (element.getLength() != currentSize) { - if (currentSize != -1) { - ByteLong columnKey = new ByteLong(currentSize); - mAllocCountDataSet.addValue(currentCount, rowKey, columnKey); - } - - currentSize = element.getLength(); - currentCount = 1; - } else { - currentCount++; - } - } - - // add the last item - if (currentSize != -1) { - ByteLong columnKey = new ByteLong(currentSize); - mAllocCountDataSet.addValue(currentCount, rowKey, columnKey); - } - } - } - - /* - * Add a color legend to the specified table. - */ - private void createLegend(Composite parent) { - mLegend = new Group(parent, SWT.NONE); - mLegend.setText(getLegendText(0)); - - mLegend.setLayout(new GridLayout(2, false)); - - RGB[] colors = mMapPalette.colors; - - for (int i = 0; i < NUM_PALETTE_ENTRIES; i++) { - Image tmpImage = createColorRect(parent.getDisplay(), colors[i]); - - Label l = new Label(mLegend, SWT.NONE); - l.setImage(tmpImage); - - l = new Label(mLegend, SWT.NONE); - l.setText(mMapLegend[i]); - } - } - - private String getLegendText(int level) { - int bytes = 8 * (100 / ZOOMS[level]); - - return String.format("Key (1 pixel = %1$d bytes)", bytes); - } - - private void setLegendText(int level) { - mLegend.setText(getLegendText(level)); - - } - - /* - * Create a nice rectangle in the specified color. - */ - private Image createColorRect(Display display, RGB color) { - int width = 32; - int height = 16; - - Image img = new Image(display, width, height); - GC gc = new GC(img); - gc.setBackground(new Color(display, color)); - gc.fillRectangle(0, 0, width, height); - gc.dispose(); - return img; - } - - - /* - * Are updates enabled? - */ - private void setUpdateStatus(int status) { - switch (status) { - case NOT_SELECTED: - mUpdateStatus.setText("Select a client to see heap updates"); - break; - case NOT_ENABLED: - mUpdateStatus.setText("Heap updates are " + - "NOT ENABLED for this client"); - break; - case ENABLED: - mUpdateStatus.setText("Heap updates will happen after " + - "every GC for this client"); - break; - default: - throw new RuntimeException(); - } - - mUpdateStatus.pack(); - } - - - /** - * Return the closest power of two greater than or equal to value. - * - * @param value the return value will be >= value - * @return a power of two >= value. If value > 2^31, 2^31 is returned. - */ -//xxx use Integer.highestOneBit() or numberOfLeadingZeros(). - private int nextPow2(int value) { - for (int i = 31; i >= 0; --i) { - if ((value & (1<<i)) != 0) { - if (i < 31) { - return 1<<(i + 1); - } else { - return 1<<31; - } - } - } - return 0; - } - - private int zOrderData(ImageData id, byte pixData[]) { - int maxX = 0; - for (int i = 0; i < pixData.length; i++) { - /* Tread the pixData index as a z-order curve index and - * decompose into Cartesian coordinates. - */ - int x = (i & 1) | - ((i >>> 2) & 1) << 1 | - ((i >>> 4) & 1) << 2 | - ((i >>> 6) & 1) << 3 | - ((i >>> 8) & 1) << 4 | - ((i >>> 10) & 1) << 5 | - ((i >>> 12) & 1) << 6 | - ((i >>> 14) & 1) << 7 | - ((i >>> 16) & 1) << 8 | - ((i >>> 18) & 1) << 9 | - ((i >>> 20) & 1) << 10 | - ((i >>> 22) & 1) << 11 | - ((i >>> 24) & 1) << 12 | - ((i >>> 26) & 1) << 13 | - ((i >>> 28) & 1) << 14 | - ((i >>> 30) & 1) << 15; - int y = ((i >>> 1) & 1) << 0 | - ((i >>> 3) & 1) << 1 | - ((i >>> 5) & 1) << 2 | - ((i >>> 7) & 1) << 3 | - ((i >>> 9) & 1) << 4 | - ((i >>> 11) & 1) << 5 | - ((i >>> 13) & 1) << 6 | - ((i >>> 15) & 1) << 7 | - ((i >>> 17) & 1) << 8 | - ((i >>> 19) & 1) << 9 | - ((i >>> 21) & 1) << 10 | - ((i >>> 23) & 1) << 11 | - ((i >>> 25) & 1) << 12 | - ((i >>> 27) & 1) << 13 | - ((i >>> 29) & 1) << 14 | - ((i >>> 31) & 1) << 15; - try { - id.setPixel(x, y, pixData[i]); - if (x > maxX) { - maxX = x; - } - } catch (IllegalArgumentException ex) { - System.out.println("bad pixels: i " + i + - ", w " + id.width + - ", h " + id.height + - ", x " + x + - ", y " + y); - throw ex; - } - } - return maxX; - } - - private final static int HILBERT_DIR_N = 0; - private final static int HILBERT_DIR_S = 1; - private final static int HILBERT_DIR_E = 2; - private final static int HILBERT_DIR_W = 3; - - private void hilbertWalk(ImageData id, InputStream pixData, - int order, int x, int y, int dir) - throws IOException { - if (x >= id.width || y >= id.height) { - return; - } else if (order == 0) { - try { - int p = pixData.read(); - if (p >= 0) { - // flip along x=y axis; assume width == height - id.setPixel(y, x, p); - - /* Skanky; use an otherwise-unused ImageData field - * to keep track of the max x,y used. Note that x and y are inverted. - */ - if (y > id.x) { - id.x = y; - } - if (x > id.y) { - id.y = x; - } - } -//xxx just give up; don't bother walking the rest of the image - } catch (IllegalArgumentException ex) { - System.out.println("bad pixels: order " + order + - ", dir " + dir + - ", w " + id.width + - ", h " + id.height + - ", x " + x + - ", y " + y); - throw ex; - } - } else { - order--; - int delta = 1 << order; - int nextX = x + delta; - int nextY = y + delta; - - switch (dir) { - case HILBERT_DIR_E: - hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_N); - hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_E); - hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_E); - hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_S); - break; - case HILBERT_DIR_N: - hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_E); - hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_N); - hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_N); - hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_W); - break; - case HILBERT_DIR_S: - hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_W); - hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_S); - hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_S); - hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_E); - break; - case HILBERT_DIR_W: - hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_S); - hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_W); - hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_W); - hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_N); - break; - default: - throw new RuntimeException("Unexpected Hilbert direction " + - dir); - } - } - } - - private Point hilbertOrderData(ImageData id, byte pixData[]) { - - int order = 0; - for (int n = 1; n < id.width; n *= 2) { - order++; - } - /* Skanky; use an otherwise-unused ImageData field - * to keep track of maxX. - */ - Point p = new Point(0,0); - int oldIdX = id.x; - int oldIdY = id.y; - id.x = id.y = 0; - try { - hilbertWalk(id, new ByteArrayInputStream(pixData), - order, 0, 0, HILBERT_DIR_E); - p.x = id.x; - p.y = id.y; - } catch (IOException ex) { - System.err.println("Exception during hilbertWalk()"); - p.x = id.height; - p.y = id.width; - } - id.x = oldIdX; - id.y = oldIdY; - return p; - } - - private ImageData createHilbertHeapImage(byte pixData[]) { - int w, h; - - // Pick an image size that the largest of heaps will fit into. - w = (int)Math.sqrt(((16 * 1024 * 1024)/8)); - - // Space-filling curves require a power-of-2 width. - w = nextPow2(w); - h = w; - - // Create the heap image. - ImageData id = new ImageData(w, h, 8, mMapPalette); - - // Copy the data into the image - //int maxX = zOrderData(id, pixData); - Point maxP = hilbertOrderData(id, pixData); - - // update the max size to make it a round number once the zoom is applied - int factor = 100 / ZOOMS[mZoom.getSelectionIndex()]; - if (factor != 1) { - int tmp = maxP.x % factor; - if (tmp != 0) { - maxP.x += factor - tmp; - } - - tmp = maxP.y % factor; - if (tmp != 0) { - maxP.y += factor - tmp; - } - } - - if (maxP.y < id.height) { - // Crop the image down to the interesting part. - id = new ImageData(id.width, maxP.y, id.depth, id.palette, - id.scanlinePad, id.data); - } - - if (maxP.x < id.width) { - // crop the image again. A bit trickier this time. - ImageData croppedId = new ImageData(maxP.x, id.height, id.depth, id.palette); - - int[] buffer = new int[maxP.x]; - for (int l = 0 ; l < id.height; l++) { - id.getPixels(0, l, maxP.x, buffer, 0); - croppedId.setPixels(0, l, maxP.x, buffer, 0); - } - - id = croppedId; - } - - // apply the zoom - if (factor != 1) { - id = id.scaledTo(id.width / factor, id.height / factor); - } - - return id; - } - - /** - * Convert the raw heap data to an image. We know we're running in - * the UI thread, so we can issue graphics commands directly. - * - * http://help.eclipse.org/help31/nftopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html - * - * @param cd The client data - * @param mode The display mode. 0 = linear, 1 = hilbert. - * @param forceRedraw - */ - private void renderHeapData(ClientData cd, int mode, boolean forceRedraw) { - Image image; - - byte[] pixData; - - // Atomically get and clear the heap data. - synchronized (cd) { - if (serializeHeapData(cd.getVmHeapData()) == false && forceRedraw == false) { - // no change, we return. - return; - } - - pixData = getSerializedData(); - } - - if (pixData != null) { - ImageData id; - if (mode == 1) { - id = createHilbertHeapImage(pixData); - } else { - id = createLinearHeapImage(pixData, 200, mMapPalette); - } - - image = new Image(mDisplay, id); - } else { - // Render a placeholder image. - int width, height; - if (mode == 1) { - width = height = PLACEHOLDER_HILBERT_SIZE; - } else { - width = PLACEHOLDER_LINEAR_H_SIZE; - height = PLACEHOLDER_LINEAR_V_SIZE; - } - image = new Image(mDisplay, width, height); - GC gc = new GC(image); - gc.setForeground(mDisplay.getSystemColor(SWT.COLOR_RED)); - gc.drawLine(0, 0, width-1, height-1); - gc.dispose(); - gc = null; - } - - // set the new image - - if (mode == 1) { - if (mHilbertImage != null) { - mHilbertImage.dispose(); - } - - mHilbertImage = image; - mHilbertHeapImage.setImage(mHilbertImage); - mHilbertHeapImage.pack(true); - mHilbertBase.layout(); - mHilbertBase.pack(true); - } else { - if (mLinearImage != null) { - mLinearImage.dispose(); - } - - mLinearImage = image; - mLinearHeapImage.setImage(mLinearImage); - mLinearHeapImage.pack(true); - mLinearBase.layout(); - mLinearBase.pack(true); - } - } - - @Override - protected void setTableFocusListener() { - addTableToFocusListener(mHeapSummary); - } -} - diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/IFindTarget.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/IFindTarget.java deleted file mode 100644 index 9aa6943..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/IFindTarget.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2012 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; - -public interface IFindTarget { - boolean findAndSelect(String text, boolean isNewSearch, boolean searchForward); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ITableFocusListener.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ITableFocusListener.java deleted file mode 100644 index 37dd9a0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ITableFocusListener.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import org.eclipse.swt.dnd.Clipboard; - -/** - * An object listening to focus change in Table objects.<br> - * For application not relying on a RCP to provide menu changes based on focus, - * this class allows to get monitor the focus change of several Table widget - * and update the menu action accordingly. - */ -public interface ITableFocusListener { - - public interface IFocusedTableActivator { - public void copy(Clipboard clipboard); - - public void selectAll(); - } - - public void focusGained(IFocusedTableActivator activator); - - public void focusLost(IFocusedTableActivator activator); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ImageLoader.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ImageLoader.java deleted file mode 100644 index fd480f6..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ImageLoader.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.Log; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; - -import java.io.InputStream; -import java.net.URL; -import java.util.HashMap; - -/** - * Class to load images stored in a jar file. - * All images are loaded from /images/<var>filename</var> - * - * Because Java requires to know the jar file in which to load the image from, a class is required - * when getting the instance. Instances are cached and associated to the class passed to - * {@link #getLoader(Class)}. - * - * {@link #getDdmUiLibLoader()} use {@link ImageLoader#getClass()} as the class. This is to be used - * to load images from ddmuilib. - * - * Loaded images are stored so that 2 calls with the same filename will return the same object. - * This also means that {@link Image} object returned by the loader should never be disposed. - * - */ -public class ImageLoader { - - private static final String PATH = "/images/"; //$NON-NLS-1$ - - private final HashMap<String, Image> mLoadedImages = new HashMap<String, Image>(); - private static final HashMap<Class<?>, ImageLoader> mInstances = - new HashMap<Class<?>, ImageLoader>(); - private final Class<?> mClass; - - /** - * Private constructor, creating an instance associated with a class. - * The class is used to identify which jar file the images are loaded from. - */ - private ImageLoader(Class<?> theClass) { - if (theClass == null) { - theClass = ImageLoader.class; - } - mClass = theClass; - } - - /** - * Returns the {@link ImageLoader} instance to load images from ddmuilib.jar - */ - public static ImageLoader getDdmUiLibLoader() { - return getLoader(null); - } - - /** - * Returns an {@link ImageLoader} to load images based on a given class. - * - * The loader will load images from the jar from which the class was loaded. using - * {@link Class#getResource(String)} and {@link Class#getResourceAsStream(String)}. - * - * Since all images are loaded using the path /images/<var>filename</var>, any class from the - * jar will work. However since the loader is cached and reused when the query provides the same - * class instance, and since the loader will also cache the loaded images, it is recommended - * to always use the same class for a given Jar file. - * - */ - public static ImageLoader getLoader(Class<?> theClass) { - ImageLoader instance = mInstances.get(theClass); - if (instance == null) { - instance = new ImageLoader(theClass); - mInstances.put(theClass, instance); - } - - return instance; - } - - /** - * Disposes all images for all instances. - * This should only be called when the program exits. - */ - public static void dispose() { - for (ImageLoader loader : mInstances.values()) { - loader.doDispose(); - } - } - - private synchronized void doDispose() { - for (Image image : mLoadedImages.values()) { - image.dispose(); - } - - mLoadedImages.clear(); - } - - /** - * Returns an {@link ImageDescriptor} for a given filename. - * - * This searches for an image located at /images/<var>filename</var>. - * - * @param filename the filename of the image to load. - */ - public ImageDescriptor loadDescriptor(String filename) { - URL url = mClass.getResource(PATH + filename); - // TODO cache in a map - return ImageDescriptor.createFromURL(url); - } - - /** - * Returns an {@link Image} for a given filename. - * - * This searches for an image located at /images/<var>filename</var>. - * - * @param filename the filename of the image to load. - * @param display the Display object - */ - public synchronized Image loadImage(String filename, Display display) { - Image img = mLoadedImages.get(filename); - if (img == null) { - String tmp = PATH + filename; - InputStream imageStream = mClass.getResourceAsStream(tmp); - - if (imageStream != null) { - img = new Image(display, imageStream); - mLoadedImages.put(filename, img); - } - - if (img == null) { - throw new RuntimeException("Failed to load " + tmp); - } - } - - return img; - } - - /** - * Loads an image from a resource. This method used a class to locate the - * resources, and then load the filename from /images inside the resources.<br> - * Extra parameters allows for creation of a replacement image of the - * loading failed. - * - * @param display the Display object - * @param fileName the file name - * @param width optional width to create replacement Image. If -1, null be - * be returned if the loading fails. - * @param height optional height to create replacement Image. If -1, null be - * be returned if the loading fails. - * @param phColor optional color to create replacement Image. If null, Blue - * color will be used. - * @return a new Image or null if the loading failed and the optional - * replacement size was -1 - */ - public Image loadImage(Display display, String fileName, int width, int height, - Color phColor) { - - Image img = loadImage(fileName, display); - - if (img == null) { - Log.w("ddms", "Couldn't load " + fileName); - // if we had the extra parameter to create replacement image then we - // create and return it. - if (width != -1 && height != -1) { - return createPlaceHolderArt(display, width, height, - phColor != null ? phColor : display - .getSystemColor(SWT.COLOR_BLUE)); - } - - // otherwise, just return null - return null; - } - - return img; - } - - /** - * Create place-holder art with the specified color. - */ - public static Image createPlaceHolderArt(Display display, int width, - int height, Color color) { - Image img = new Image(display, width, height); - GC gc = new GC(img); - gc.setForeground(color); - gc.drawLine(0, 0, width, height); - gc.drawLine(0, height - 1, width, -1); - gc.dispose(); - return img; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java deleted file mode 100644 index 60dc2c0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; - -import org.eclipse.swt.SWT; -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.eclipse.swt.widgets.TableItem; - -/** - * Display client info in a two-column format. - */ -public class InfoPanel extends TablePanel { - private Table mTable; - private TableColumn mCol2; - - private static final String mLabels[] = { - "DDM-aware?", - "App description:", - "VM version:", - "Process ID:", - "Supports Profiling Control:", - "Supports HPROF Control:", - }; - private static final int ENT_DDM_AWARE = 0; - private static final int ENT_APP_DESCR = 1; - private static final int ENT_VM_VERSION = 2; - private static final int ENT_PROCESS_ID = 3; - private static final int ENT_SUPPORTS_PROFILING = 4; - private static final int ENT_SUPPORTS_HPROF = 5; - - /** - * Create our control(s). - */ - @Override - protected Control createControl(Composite parent) { - mTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION); - mTable.setHeaderVisible(false); - mTable.setLinesVisible(false); - - TableColumn col1 = new TableColumn(mTable, SWT.RIGHT); - col1.setText("name"); - mCol2 = new TableColumn(mTable, SWT.LEFT); - mCol2.setText("PlaceHolderContentForWidth"); - - TableItem item; - for (int i = 0; i < mLabels.length; i++) { - item = new TableItem(mTable, SWT.NONE); - item.setText(0, mLabels[i]); - item.setText(1, "-"); - } - - col1.pack(); - mCol2.pack(); - - return mTable; - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mTable.setFocus(); - } - - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_PORT}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client == getCurrentClient()) { - if ((changeMask & Client.CHANGE_INFO) == Client.CHANGE_INFO) { - if (mTable.isDisposed()) - return; - - mTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - clientSelected(); - } - }); - } - } - } - - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()} - */ - @Override - public void deviceSelected() { - // pass - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()} - */ - @Override - public void clientSelected() { - if (mTable.isDisposed()) - return; - - Client client = getCurrentClient(); - - if (client == null) { - for (int i = 0; i < mLabels.length; i++) { - TableItem item = mTable.getItem(i); - item.setText(1, "-"); - } - } else { - TableItem item; - String clientDescription, vmIdentifier, isDdmAware, - pid; - - ClientData cd = client.getClientData(); - synchronized (cd) { - clientDescription = (cd.getClientDescription() != null) ? - cd.getClientDescription() : "?"; - vmIdentifier = (cd.getVmIdentifier() != null) ? - cd.getVmIdentifier() : "?"; - isDdmAware = cd.isDdmAware() ? - "yes" : "no"; - pid = (cd.getPid() != 0) ? - String.valueOf(cd.getPid()) : "?"; - } - - item = mTable.getItem(ENT_APP_DESCR); - item.setText(1, clientDescription); - item = mTable.getItem(ENT_VM_VERSION); - item.setText(1, vmIdentifier); - item = mTable.getItem(ENT_DDM_AWARE); - item.setText(1, isDdmAware); - item = mTable.getItem(ENT_PROCESS_ID); - item.setText(1, pid); - - item = mTable.getItem(ENT_SUPPORTS_PROFILING); - if (cd.hasFeature(ClientData.FEATURE_PROFILING_STREAMING)) { - item.setText(1, "Yes"); - } else if (cd.hasFeature(ClientData.FEATURE_PROFILING)) { - item.setText(1, "Yes (Application must be able to write on the SD Card)"); - } else { - item.setText(1, "No"); - } - - item = mTable.getItem(ENT_SUPPORTS_HPROF); - if (cd.hasFeature(ClientData.FEATURE_HPROF_STREAMING)) { - item.setText(1, "Yes"); - } else if (cd.hasFeature(ClientData.FEATURE_HPROF)) { - item.setText(1, "Yes (Application must be able to write on the SD Card)"); - } else { - item.setText(1, "No"); - } - } - - mCol2.pack(); - - //Log.i("ddms", "InfoPanel: changed " + client); - } - - @Override - protected void setTableFocusListener() { - addTableToFocusListener(mTable); - } -} - diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/NativeHeapPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/NativeHeapPanel.java deleted file mode 100644 index 337bff2..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/NativeHeapPanel.java +++ /dev/null @@ -1,1648 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; -import com.android.ddmlib.HeapSegment.HeapSegmentElement; -import com.android.ddmlib.Log; -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeLibraryMapInfo; -import com.android.ddmlib.NativeStackCallInfo; -import com.android.ddmuilib.annotation.WorkerThread; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Sash; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -/** - * Panel with native heap information. - */ -public final class NativeHeapPanel extends BaseHeapPanel { - - /** color palette and map legend. NATIVE is the last enum is a 0 based enum list, so we need - * Native+1 at least. We also need 2 more entries for free area and expansion area. */ - private static final int NUM_PALETTE_ENTRIES = HeapSegmentElement.KIND_NATIVE+2 +1; - private static final String[] mMapLegend = new String[NUM_PALETTE_ENTRIES]; - private static final PaletteData mMapPalette = createPalette(); - - private static final int ALLOC_DISPLAY_ALL = 0; - private static final int ALLOC_DISPLAY_PRE_ZYGOTE = 1; - private static final int ALLOC_DISPLAY_POST_ZYGOTE = 2; - - private Display mDisplay; - - private Composite mBase; - - private Label mUpdateStatus; - - /** combo giving choice of what to display: all, pre-zygote, post-zygote */ - private Combo mAllocDisplayCombo; - - private Button mFullUpdateButton; - - // see CreateControl() - //private Button mDiffUpdateButton; - - private Combo mDisplayModeCombo; - - /** stack composite for mode (1-2) & 3 */ - private Composite mTopStackComposite; - - private StackLayout mTopStackLayout; - - /** stack composite for mode 1 & 2 */ - private Composite mAllocationStackComposite; - - private StackLayout mAllocationStackLayout; - - /** top level container for mode 1 & 2 */ - private Composite mTableModeControl; - - /** top level object for the allocation mode */ - private Control mAllocationModeTop; - - /** top level for the library mode */ - private Control mLibraryModeTopControl; - - /** composite for page UI and total memory display */ - private Composite mPageUIComposite; - - private Label mTotalMemoryLabel; - - private Label mPageLabel; - - private Button mPageNextButton; - - private Button mPagePreviousButton; - - private Table mAllocationTable; - - private Table mLibraryTable; - - private Table mLibraryAllocationTable; - - private Table mDetailTable; - - private Label mImage; - - private int mAllocDisplayMode = ALLOC_DISPLAY_ALL; - - /** - * pointer to current stackcall thread computation in order to quit it if - * required (new update requested) - */ - private StackCallThread mStackCallThread; - - /** Current Library Allocation table fill thread. killed if selection changes */ - private FillTableThread mFillTableThread; - - /** - * current client data. Used to access the malloc info when switching pages - * or selecting allocation to show stack call - */ - private ClientData mClientData; - - /** - * client data from a previous display. used when asking for an "update & diff" - */ - private ClientData mBackUpClientData; - - /** list of NativeAllocationInfo objects filled with the list from ClientData */ - private final ArrayList<NativeAllocationInfo> mAllocations = - new ArrayList<NativeAllocationInfo>(); - - /** list of the {@link NativeAllocationInfo} being displayed based on the selection - * of {@link #mAllocDisplayCombo}. - */ - private final ArrayList<NativeAllocationInfo> mDisplayedAllocations = - new ArrayList<NativeAllocationInfo>(); - - /** list of NativeAllocationInfo object kept as backup when doing an "update & diff" */ - private final ArrayList<NativeAllocationInfo> mBackUpAllocations = - new ArrayList<NativeAllocationInfo>(); - - /** back up of the total memory, used when doing an "update & diff" */ - private int mBackUpTotalMemory; - - private int mCurrentPage = 0; - - private int mPageCount = 0; - - /** - * list of allocation per Library. This is created from the list of - * NativeAllocationInfo objects that is stored in the ClientData object. Since we - * don't keep this list around, it is recomputed everytime the client - * changes. - */ - private final ArrayList<LibraryAllocations> mLibraryAllocations = - new ArrayList<LibraryAllocations>(); - - /* args to setUpdateStatus() */ - private static final int NOT_SELECTED = 0; - - private static final int NOT_ENABLED = 1; - - private static final int ENABLED = 2; - - private static final int DISPLAY_PER_PAGE = 20; - - private static final String PREFS_ALLOCATION_SASH = "NHallocSash"; //$NON-NLS-1$ - private static final String PREFS_LIBRARY_SASH = "NHlibrarySash"; //$NON-NLS-1$ - private static final String PREFS_DETAIL_ADDRESS = "NHdetailAddress"; //$NON-NLS-1$ - private static final String PREFS_DETAIL_LIBRARY = "NHdetailLibrary"; //$NON-NLS-1$ - private static final String PREFS_DETAIL_METHOD = "NHdetailMethod"; //$NON-NLS-1$ - private static final String PREFS_DETAIL_FILE = "NHdetailFile"; //$NON-NLS-1$ - private static final String PREFS_DETAIL_LINE = "NHdetailLine"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_TOTAL = "NHallocTotal"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_COUNT = "NHallocCount"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_SIZE = "NHallocSize"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_LIBRARY = "NHallocLib"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_METHOD = "NHallocMethod"; //$NON-NLS-1$ - private static final String PREFS_ALLOC_FILE = "NHallocFile"; //$NON-NLS-1$ - private static final String PREFS_LIB_LIBRARY = "NHlibLibrary"; //$NON-NLS-1$ - private static final String PREFS_LIB_SIZE = "NHlibSize"; //$NON-NLS-1$ - private static final String PREFS_LIB_COUNT = "NHlibCount"; //$NON-NLS-1$ - private static final String PREFS_LIBALLOC_TOTAL = "NHlibAllocTotal"; //$NON-NLS-1$ - private static final String PREFS_LIBALLOC_COUNT = "NHlibAllocCount"; //$NON-NLS-1$ - private static final String PREFS_LIBALLOC_SIZE = "NHlibAllocSize"; //$NON-NLS-1$ - private static final String PREFS_LIBALLOC_METHOD = "NHlibAllocMethod"; //$NON-NLS-1$ - - /** static formatter object to format all numbers as #,### */ - private static DecimalFormat sFormatter; - static { - sFormatter = (DecimalFormat)NumberFormat.getInstance(); - if (sFormatter == null) { - sFormatter = new DecimalFormat("#,###"); - } else { - sFormatter.applyPattern("#,###"); - } - } - - - /** - * caching mechanism to avoid recomputing the backtrace for a particular - * address several times. - */ - private HashMap<Long, NativeStackCallInfo> mSourceCache = - new HashMap<Long, NativeStackCallInfo>(); - private long mTotalSize; - private Button mSaveButton; - private Button mSymbolsButton; - - /** - * thread class to convert the address call into method, file and line - * number in the background. - */ - private class StackCallThread extends BackgroundThread { - private ClientData mClientData; - - public StackCallThread(ClientData cd) { - mClientData = cd; - } - - public ClientData getClientData() { - return mClientData; - } - - @Override - public void run() { - // loop through all the NativeAllocationInfo and init them - Iterator<NativeAllocationInfo> iter = mAllocations.iterator(); - int total = mAllocations.size(); - int count = 0; - while (iter.hasNext()) { - - if (isQuitting()) - return; - - NativeAllocationInfo info = iter.next(); - if (info.isStackCallResolved() == false) { - final List<Long> list = info.getStackCallAddresses(); - final int size = list.size(); - - ArrayList<NativeStackCallInfo> resolvedStackCall = - new ArrayList<NativeStackCallInfo>(); - - for (int i = 0; i < size; i++) { - long addr = list.get(i); - - // first check if the addr has already been converted. - NativeStackCallInfo source = mSourceCache.get(addr); - - // if not we convert it - if (source == null) { - source = sourceForAddr(addr); - mSourceCache.put(addr, source); - } - - resolvedStackCall.add(source); - } - - info.setResolvedStackCall(resolvedStackCall); - } - // after every DISPLAY_PER_PAGE we ask for a ui refresh, unless - // we reach total, since we also do it after the loop - // (only an issue in case we have a perfect number of page) - count++; - if ((count % DISPLAY_PER_PAGE) == 0 && count != total) { - if (updateNHAllocationStackCalls(mClientData, count) == false) { - // looks like the app is quitting, so we just - // stopped the thread - return; - } - } - } - - updateNHAllocationStackCalls(mClientData, count); - } - - private NativeStackCallInfo sourceForAddr(long addr) { - NativeLibraryMapInfo library = getLibraryFor(addr); - - if (library != null) { - - Addr2Line process = Addr2Line.getProcess(library); - if (process != null) { - // remove the base of the library address - NativeStackCallInfo info = process.getAddress(addr); - if (info != null) { - return info; - } - } - } - - return new NativeStackCallInfo(addr, - library != null ? library.getLibraryName() : null, - Long.toHexString(addr), - ""); - } - - private NativeLibraryMapInfo getLibraryFor(long addr) { - for (NativeLibraryMapInfo info : mClientData.getMappedNativeLibraries()) { - if (info.isWithinLibrary(addr)) { - return info; - } - } - - Log.d("ddm-nativeheap", "Failed finding Library for " + Long.toHexString(addr)); - return null; - } - - /** - * update the Native Heap panel with the amount of allocation for which the - * stack call has been computed. This is called from a non UI thread, but - * will be executed in the UI thread. - * - * @param count the amount of allocation - * @return false if the display was disposed and the update couldn't happen - */ - private boolean updateNHAllocationStackCalls(final ClientData clientData, final int count) { - if (mDisplay.isDisposed() == false) { - mDisplay.asyncExec(new Runnable() { - @Override - public void run() { - updateAllocationStackCalls(clientData, count); - } - }); - return true; - } - return false; - } - } - - private class FillTableThread extends BackgroundThread { - private LibraryAllocations mLibAlloc; - - private int mMax; - - public FillTableThread(LibraryAllocations liballoc, int m) { - mLibAlloc = liballoc; - mMax = m; - } - - @Override - public void run() { - for (int i = mMax; i > 0 && isQuitting() == false; i -= 10) { - updateNHLibraryAllocationTable(mLibAlloc, mMax - i, mMax - i + 10); - } - } - - /** - * updates the library allocation table in the Native Heap panel. This is - * called from a non UI thread, but will be executed in the UI thread. - * - * @param liballoc the current library allocation object being displayed - * @param start start index of items that need to be displayed - * @param end end index of the items that need to be displayed - */ - private void updateNHLibraryAllocationTable(final LibraryAllocations libAlloc, - final int start, final int end) { - if (mDisplay.isDisposed() == false) { - mDisplay.asyncExec(new Runnable() { - @Override - public void run() { - updateLibraryAllocationTable(libAlloc, start, end); - } - }); - } - - } - } - - /** class to aggregate allocations per library */ - public static class LibraryAllocations { - private String mLibrary; - - private final ArrayList<NativeAllocationInfo> mLibAllocations = - new ArrayList<NativeAllocationInfo>(); - - private int mSize; - - private int mCount; - - /** construct the aggregate object for a library */ - public LibraryAllocations(final String lib) { - mLibrary = lib; - } - - /** get the library name */ - public String getLibrary() { - return mLibrary; - } - - /** add a NativeAllocationInfo object to this aggregate object */ - public void addAllocation(NativeAllocationInfo info) { - mLibAllocations.add(info); - } - - /** get an iterator on the NativeAllocationInfo objects */ - public Iterator<NativeAllocationInfo> getAllocations() { - return mLibAllocations.iterator(); - } - - /** get a NativeAllocationInfo object by index */ - public NativeAllocationInfo getAllocation(int index) { - return mLibAllocations.get(index); - } - - /** returns the NativeAllocationInfo object count */ - public int getAllocationSize() { - return mLibAllocations.size(); - } - - /** returns the total allocation size */ - public int getSize() { - return mSize; - } - - /** returns the number of allocations */ - public int getCount() { - return mCount; - } - - /** - * compute the allocation count and size for allocation objects added - * through <code>addAllocation()</code>, and sort the objects by - * total allocation size. - */ - public void computeAllocationSizeAndCount() { - mSize = 0; - mCount = 0; - for (NativeAllocationInfo info : mLibAllocations) { - mCount += info.getAllocationCount(); - mSize += info.getAllocationCount() * info.getSize(); - } - Collections.sort(mLibAllocations, new Comparator<NativeAllocationInfo>() { - @Override - public int compare(NativeAllocationInfo o1, NativeAllocationInfo o2) { - return o2.getAllocationCount() * o2.getSize() - - o1.getAllocationCount() * o1.getSize(); - } - }); - } - } - - /** - * Create our control(s). - */ - @Override - protected Control createControl(Composite parent) { - - mDisplay = parent.getDisplay(); - - mBase = new Composite(parent, SWT.NONE); - GridLayout gl = new GridLayout(1, false); - gl.horizontalSpacing = 0; - gl.verticalSpacing = 0; - mBase.setLayout(gl); - mBase.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // composite for <update btn> <status> - Composite tmp = new Composite(mBase, SWT.NONE); - tmp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - tmp.setLayout(gl = new GridLayout(2, false)); - gl.marginWidth = gl.marginHeight = 0; - - mFullUpdateButton = new Button(tmp, SWT.NONE); - mFullUpdateButton.setText("Full Update"); - mFullUpdateButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mBackUpClientData = null; - mDisplayModeCombo.setEnabled(false); - mSaveButton.setEnabled(false); - emptyTables(); - // if we already have a stack call computation for this - // client - // we stop it - if (mStackCallThread != null && - mStackCallThread.getClientData() == mClientData) { - mStackCallThread.quit(); - mStackCallThread = null; - } - mLibraryAllocations.clear(); - Client client = getCurrentClient(); - if (client != null) { - client.requestNativeHeapInformation(); - } - } - }); - - mUpdateStatus = new Label(tmp, SWT.NONE); - mUpdateStatus.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - // top layout for the combos and oter controls on the right. - Composite top_layout = new Composite(mBase, SWT.NONE); - top_layout.setLayout(gl = new GridLayout(4, false)); - gl.marginWidth = gl.marginHeight = 0; - - new Label(top_layout, SWT.NONE).setText("Show:"); - - mAllocDisplayCombo = new Combo(top_layout, SWT.DROP_DOWN | SWT.READ_ONLY); - mAllocDisplayCombo.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mAllocDisplayCombo.add("All Allocations"); - mAllocDisplayCombo.add("Pre-Zygote Allocations"); - mAllocDisplayCombo.add("Zygote Child Allocations (Z)"); - mAllocDisplayCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onAllocDisplayChange(); - } - }); - mAllocDisplayCombo.select(0); - - // separator - Label separator = new Label(top_layout, SWT.SEPARATOR | SWT.VERTICAL); - GridData gd; - separator.setLayoutData(gd = new GridData( - GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); - gd.heightHint = 0; - gd.verticalSpan = 2; - - mSaveButton = new Button(top_layout, SWT.PUSH); - mSaveButton.setText("Save..."); - mSaveButton.setEnabled(false); - mSaveButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(mBase.getShell(), SWT.SAVE); - - fileDialog.setText("Save Allocations"); - fileDialog.setFileName("allocations.txt"); - - String fileName = fileDialog.open(); - if (fileName != null) { - saveAllocations(fileName); - } - } - }); - - /* - * TODO: either fix the diff mechanism or remove it altogether. - mDiffUpdateButton = new Button(top_layout, SWT.NONE); - mDiffUpdateButton.setText("Update && Diff"); - mDiffUpdateButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // since this is an update and diff, we need to store the - // current list - // of mallocs - mBackUpAllocations.clear(); - mBackUpAllocations.addAll(mAllocations); - mBackUpClientData = mClientData; - mBackUpTotalMemory = mClientData.getTotalNativeMemory(); - - mDisplayModeCombo.setEnabled(false); - emptyTables(); - // if we already have a stack call computation for this - // client - // we stop it - if (mStackCallThread != null && - mStackCallThread.getClientData() == mClientData) { - mStackCallThread.quit(); - mStackCallThread = null; - } - mLibraryAllocations.clear(); - Client client = getCurrentClient(); - if (client != null) { - client.requestNativeHeapInformation(); - } - } - }); - */ - - Label l = new Label(top_layout, SWT.NONE); - l.setText("Display:"); - - mDisplayModeCombo = new Combo(top_layout, SWT.DROP_DOWN | SWT.READ_ONLY); - mDisplayModeCombo.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mDisplayModeCombo.setItems(new String[] { "Allocation List", "By Libraries" }); - mDisplayModeCombo.select(0); - mDisplayModeCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - switchDisplayMode(); - } - }); - mDisplayModeCombo.setEnabled(false); - - mSymbolsButton = new Button(top_layout, SWT.PUSH); - mSymbolsButton.setText("Load Symbols"); - mSymbolsButton.setEnabled(false); - - - // create a composite that will contains the actual content composites, - // in stack mode layout. - // This top level composite contains 2 other composites. - // * one for both Allocations and Libraries mode - // * one for flat mode (which is gone for now) - - mTopStackComposite = new Composite(mBase, SWT.NONE); - mTopStackComposite.setLayout(mTopStackLayout = new StackLayout()); - mTopStackComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // create 1st and 2nd modes - createTableDisplay(mTopStackComposite); - - mTopStackLayout.topControl = mTableModeControl; - mTopStackComposite.layout(); - - setUpdateStatus(NOT_SELECTED); - - // Work in progress - // TODO add image display of native heap. - //mImage = new Label(mBase, SWT.NONE); - - mBase.pack(); - - return mBase; - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - // TODO - } - - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client == getCurrentClient()) { - if ((changeMask & Client.CHANGE_NATIVE_HEAP_DATA) == Client.CHANGE_NATIVE_HEAP_DATA) { - if (mBase.isDisposed()) - return; - - mBase.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - clientSelected(); - } - }); - } - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()}. - */ - @Override - public void deviceSelected() { - // pass - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - if (mBase.isDisposed()) - return; - - Client client = getCurrentClient(); - - mDisplayModeCombo.setEnabled(false); - emptyTables(); - - Log.d("ddms", "NativeHeapPanel: changed " + client); - - if (client != null) { - ClientData cd = client.getClientData(); - mClientData = cd; - - // if (cd.getShowHeapUpdates()) - setUpdateStatus(ENABLED); - // else - // setUpdateStatus(NOT_ENABLED); - - initAllocationDisplay(); - - //renderBitmap(cd); - } else { - mClientData = null; - setUpdateStatus(NOT_SELECTED); - } - - mBase.pack(); - } - - /** - * Update the UI with the newly compute stack calls, unless the UI switched - * to a different client. - * - * @param cd the ClientData for which the stack call are being computed. - * @param count the current count of allocations for which the stack calls - * have been computed. - */ - @WorkerThread - public void updateAllocationStackCalls(ClientData cd, int count) { - // we have to check that the panel still shows the same clientdata than - // the thread is computing for. - if (cd == mClientData) { - - int total = mAllocations.size(); - - if (count == total) { - // we're done: do something - mDisplayModeCombo.setEnabled(true); - mSaveButton.setEnabled(true); - - mStackCallThread = null; - } else { - // work in progress, update the progress bar. -// mUiThread.setStatusLine("Computing stack call: " + count -// + "/" + total); - } - - // FIXME: attempt to only update when needed. - // Because the number of pages is not related to mAllocations.size() anymore - // due to pre-zygote/post-zygote display, update all the time. - // At some point we should remove the pages anyway, since it's getting computed - // really fast now. -// if ((mCurrentPage + 1) * DISPLAY_PER_PAGE == count -// || (count == total && mCurrentPage == mPageCount - 1)) { - try { - // get the current selection of the allocation - int index = mAllocationTable.getSelectionIndex(); - NativeAllocationInfo info = null; - - if (index != -1) { - info = (NativeAllocationInfo)mAllocationTable.getItem(index).getData(); - } - - // empty the table - emptyTables(); - - // fill it again - fillAllocationTable(); - - // reselect - mAllocationTable.setSelection(index); - - // display detail table if needed - if (info != null) { - fillDetailTable(info); - } - } catch (SWTException e) { - if (mAllocationTable.isDisposed()) { - // looks like the table is disposed. Let's ignore it. - } else { - throw e; - } - } - - } else { - // old client still running. doesn't really matter. - } - } - - @Override - protected void setTableFocusListener() { - addTableToFocusListener(mAllocationTable); - addTableToFocusListener(mLibraryTable); - addTableToFocusListener(mLibraryAllocationTable); - addTableToFocusListener(mDetailTable); - } - - protected void onAllocDisplayChange() { - mAllocDisplayMode = mAllocDisplayCombo.getSelectionIndex(); - - // create the new list - updateAllocDisplayList(); - - updateTotalMemoryDisplay(); - - // reset the ui. - mCurrentPage = 0; - updatePageUI(); - switchDisplayMode(); - } - - private void updateAllocDisplayList() { - mTotalSize = 0; - mDisplayedAllocations.clear(); - for (NativeAllocationInfo info : mAllocations) { - if (mAllocDisplayMode == ALLOC_DISPLAY_ALL || - (mAllocDisplayMode == ALLOC_DISPLAY_PRE_ZYGOTE ^ info.isZygoteChild())) { - mDisplayedAllocations.add(info); - mTotalSize += info.getSize() * info.getAllocationCount(); - } else { - // skip this item - continue; - } - } - - int count = mDisplayedAllocations.size(); - - mPageCount = count / DISPLAY_PER_PAGE; - - // need to add a page for the rest of the div - if ((count % DISPLAY_PER_PAGE) > 0) { - mPageCount++; - } - } - - private void updateTotalMemoryDisplay() { - switch (mAllocDisplayMode) { - case ALLOC_DISPLAY_ALL: - mTotalMemoryLabel.setText(String.format("Total Memory: %1$s Bytes", - sFormatter.format(mTotalSize))); - break; - case ALLOC_DISPLAY_PRE_ZYGOTE: - mTotalMemoryLabel.setText(String.format("Zygote Memory: %1$s Bytes", - sFormatter.format(mTotalSize))); - break; - case ALLOC_DISPLAY_POST_ZYGOTE: - mTotalMemoryLabel.setText(String.format("Post-zygote Memory: %1$s Bytes", - sFormatter.format(mTotalSize))); - break; - } - } - - - private void switchDisplayMode() { - switch (mDisplayModeCombo.getSelectionIndex()) { - case 0: {// allocations - mTopStackLayout.topControl = mTableModeControl; - mAllocationStackLayout.topControl = mAllocationModeTop; - mAllocationStackComposite.layout(); - mTopStackComposite.layout(); - emptyTables(); - fillAllocationTable(); - } - break; - case 1: {// libraries - mTopStackLayout.topControl = mTableModeControl; - mAllocationStackLayout.topControl = mLibraryModeTopControl; - mAllocationStackComposite.layout(); - mTopStackComposite.layout(); - emptyTables(); - fillLibraryTable(); - } - break; - } - } - - private void initAllocationDisplay() { - if (mStackCallThread != null) { - mStackCallThread.quit(); - } - - mAllocations.clear(); - mAllocations.addAll(mClientData.getNativeAllocationList()); - - updateAllocDisplayList(); - - // if we have a previous clientdata and it matches the current one. we - // do a diff between the new list and the old one. - if (mBackUpClientData != null && mBackUpClientData == mClientData) { - - ArrayList<NativeAllocationInfo> add = new ArrayList<NativeAllocationInfo>(); - - // we go through the list of NativeAllocationInfo in the new list and check if - // there's one with the same exact data (size, allocation, count and - // stackcall addresses) in the old list. - // if we don't find any, we add it to the "add" list - for (NativeAllocationInfo mi : mAllocations) { - boolean found = false; - for (NativeAllocationInfo old_mi : mBackUpAllocations) { - if (mi.equals(old_mi)) { - found = true; - break; - } - } - if (found == false) { - add.add(mi); - } - } - - // put the result in mAllocations - mAllocations.clear(); - mAllocations.addAll(add); - - // display the difference in memory usage. This is computed - // calculating the memory usage of the objects in mAllocations. - int count = 0; - for (NativeAllocationInfo allocInfo : mAllocations) { - count += allocInfo.getSize() * allocInfo.getAllocationCount(); - } - - mTotalMemoryLabel.setText(String.format("Memory Difference: %1$s Bytes", - sFormatter.format(count))); - } - else { - // display the full memory usage - updateTotalMemoryDisplay(); - //mDiffUpdateButton.setEnabled(mClientData.getTotalNativeMemory() > 0); - } - mTotalMemoryLabel.pack(); - - // update the page ui - mDisplayModeCombo.select(0); - - mLibraryAllocations.clear(); - - // reset to first page - mCurrentPage = 0; - - // update the label - updatePageUI(); - - // now fill the allocation Table with the current page - switchDisplayMode(); - - // start the thread to compute the stack calls - if (mAllocations.size() > 0) { - mStackCallThread = new StackCallThread(mClientData); - mStackCallThread.start(); - } - } - - private void updatePageUI() { - - // set the label and pack to update the layout, otherwise - // the label will be cut off if the new size is bigger - if (mPageCount == 0) { - mPageLabel.setText("0 of 0 allocations."); - } else { - StringBuffer buffer = new StringBuffer(); - // get our starting index - int start = (mCurrentPage * DISPLAY_PER_PAGE) + 1; - // end index, taking into account the last page can be half full - int count = mDisplayedAllocations.size(); - int end = Math.min(start + DISPLAY_PER_PAGE - 1, count); - buffer.append(sFormatter.format(start)); - buffer.append(" - "); - buffer.append(sFormatter.format(end)); - buffer.append(" of "); - buffer.append(sFormatter.format(count)); - buffer.append(" allocations."); - mPageLabel.setText(buffer.toString()); - } - - // handle the button enabled state. - mPagePreviousButton.setEnabled(mCurrentPage > 0); - // reminder: mCurrentPage starts at 0. - mPageNextButton.setEnabled(mCurrentPage < mPageCount - 1); - - mPageLabel.pack(); - mPageUIComposite.pack(); - - } - - private void fillAllocationTable() { - // get the count - int count = mDisplayedAllocations.size(); - - // get our starting index - int start = mCurrentPage * DISPLAY_PER_PAGE; - - // loop for DISPLAY_PER_PAGE or till we reach count - int end = start + DISPLAY_PER_PAGE; - - for (int i = start; i < end && i < count; i++) { - NativeAllocationInfo info = mDisplayedAllocations.get(i); - - TableItem item = null; - - if (mAllocDisplayMode == ALLOC_DISPLAY_ALL) { - item = new TableItem(mAllocationTable, SWT.NONE); - item.setText(0, (info.isZygoteChild() ? "Z " : "") + - sFormatter.format(info.getSize() * info.getAllocationCount())); - item.setText(1, sFormatter.format(info.getAllocationCount())); - item.setText(2, sFormatter.format(info.getSize())); - } else if (mAllocDisplayMode == ALLOC_DISPLAY_PRE_ZYGOTE ^ info.isZygoteChild()) { - item = new TableItem(mAllocationTable, SWT.NONE); - item.setText(0, sFormatter.format(info.getSize() * info.getAllocationCount())); - item.setText(1, sFormatter.format(info.getAllocationCount())); - item.setText(2, sFormatter.format(info.getSize())); - } else { - // skip this item - continue; - } - - item.setData(info); - - NativeStackCallInfo bti = info.getRelevantStackCallInfo(); - if (bti != null) { - String lib = bti.getLibraryName(); - String method = bti.getMethodName(); - String source = bti.getSourceFile(); - if (lib != null) - item.setText(3, lib); - if (method != null) - item.setText(4, method); - if (source != null) - item.setText(5, source); - } - } - } - - private void fillLibraryTable() { - // fill the library table - sortAllocationsPerLibrary(); - - for (LibraryAllocations liballoc : mLibraryAllocations) { - if (liballoc != null) { - TableItem item = new TableItem(mLibraryTable, SWT.NONE); - String lib = liballoc.getLibrary(); - item.setText(0, lib != null ? lib : ""); - item.setText(1, sFormatter.format(liballoc.getSize())); - item.setText(2, sFormatter.format(liballoc.getCount())); - } - } - } - - private void fillLibraryAllocationTable() { - mLibraryAllocationTable.removeAll(); - mDetailTable.removeAll(); - int index = mLibraryTable.getSelectionIndex(); - if (index != -1) { - LibraryAllocations liballoc = mLibraryAllocations.get(index); - // start a thread that will fill table 10 at a time to keep the ui - // responsive, but first we kill the previous one if there was one - if (mFillTableThread != null) { - mFillTableThread.quit(); - } - mFillTableThread = new FillTableThread(liballoc, - liballoc.getAllocationSize()); - mFillTableThread.start(); - } - } - - public void updateLibraryAllocationTable(LibraryAllocations liballoc, - int start, int end) { - try { - if (mLibraryTable.isDisposed() == false) { - int index = mLibraryTable.getSelectionIndex(); - if (index != -1) { - LibraryAllocations newliballoc = mLibraryAllocations.get( - index); - if (newliballoc == liballoc) { - int count = liballoc.getAllocationSize(); - for (int i = start; i < end && i < count; i++) { - NativeAllocationInfo info = liballoc.getAllocation(i); - - TableItem item = new TableItem( - mLibraryAllocationTable, SWT.NONE); - item.setText(0, sFormatter.format( - info.getSize() * info.getAllocationCount())); - item.setText(1, sFormatter.format(info.getAllocationCount())); - item.setText(2, sFormatter.format(info.getSize())); - - NativeStackCallInfo stackCallInfo = info.getRelevantStackCallInfo(); - if (stackCallInfo != null) { - item.setText(3, stackCallInfo.getMethodName()); - } - } - } else { - // we should quit the thread - if (mFillTableThread != null) { - mFillTableThread.quit(); - mFillTableThread = null; - } - } - } - } - } catch (SWTException e) { - Log.e("ddms", "error when updating the library allocation table"); - } - } - - private void fillDetailTable(final NativeAllocationInfo mi) { - mDetailTable.removeAll(); - mDetailTable.setRedraw(false); - - try { - // populate the detail Table with the back trace - List<Long> addresses = mi.getStackCallAddresses(); - List<NativeStackCallInfo> resolvedStackCall = mi.getResolvedStackCall(); - - if (resolvedStackCall == null) { - return; - } - - for (int i = 0 ; i < resolvedStackCall.size(); i++) { - if (addresses.get(i) == null || addresses.get(i).longValue() == 0) { - continue; - } - - long addr = addresses.get(i).longValue(); - NativeStackCallInfo source = resolvedStackCall.get(i); - - TableItem item = new TableItem(mDetailTable, SWT.NONE); - item.setText(0, String.format("%08x", addr)); //$NON-NLS-1$ - - String libraryName = source.getLibraryName(); - String methodName = source.getMethodName(); - String sourceFile = source.getSourceFile(); - int lineNumber = source.getLineNumber(); - - if (libraryName != null) - item.setText(1, libraryName); - if (methodName != null) - item.setText(2, methodName); - if (sourceFile != null) - item.setText(3, sourceFile); - if (lineNumber != -1) - item.setText(4, Integer.toString(lineNumber)); - } - } finally { - mDetailTable.setRedraw(true); - } - } - - /* - * Are updates enabled? - */ - private void setUpdateStatus(int status) { - switch (status) { - case NOT_SELECTED: - mUpdateStatus.setText("Select a client to see heap info"); - mAllocDisplayCombo.setEnabled(false); - mFullUpdateButton.setEnabled(false); - //mDiffUpdateButton.setEnabled(false); - break; - case NOT_ENABLED: - mUpdateStatus.setText("Heap updates are " + "NOT ENABLED for this client"); - mAllocDisplayCombo.setEnabled(false); - mFullUpdateButton.setEnabled(false); - //mDiffUpdateButton.setEnabled(false); - break; - case ENABLED: - mUpdateStatus.setText("Press 'Full Update' to retrieve " + "latest data"); - mAllocDisplayCombo.setEnabled(true); - mFullUpdateButton.setEnabled(true); - //mDiffUpdateButton.setEnabled(true); - break; - default: - throw new RuntimeException(); - } - - mUpdateStatus.pack(); - } - - /** - * Create the Table display. This includes a "detail" Table in the bottom - * half and 2 modes in the top half: allocation Table and - * library+allocations Tables. - * - * @param base the top parent to create the display into - */ - private void createTableDisplay(Composite base) { - final int minPanelWidth = 60; - - final IPreferenceStore prefs = DdmUiPreferences.getStore(); - - // top level composite for mode 1 & 2 - mTableModeControl = new Composite(base, SWT.NONE); - GridLayout gl = new GridLayout(1, false); - gl.marginLeft = gl.marginRight = gl.marginTop = gl.marginBottom = 0; - mTableModeControl.setLayout(gl); - mTableModeControl.setLayoutData(new GridData(GridData.FILL_BOTH)); - - mTotalMemoryLabel = new Label(mTableModeControl, SWT.NONE); - mTotalMemoryLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTotalMemoryLabel.setText("Total Memory: 0 Bytes"); - - // the top half of these modes is dynamic - - final Composite sash_composite = new Composite(mTableModeControl, - SWT.NONE); - sash_composite.setLayout(new FormLayout()); - sash_composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // create the stacked composite - mAllocationStackComposite = new Composite(sash_composite, SWT.NONE); - mAllocationStackLayout = new StackLayout(); - mAllocationStackComposite.setLayout(mAllocationStackLayout); - mAllocationStackComposite.setLayoutData(new GridData( - GridData.FILL_BOTH)); - - // create the top half for mode 1 - createAllocationTopHalf(mAllocationStackComposite); - - // create the top half for mode 2 - createLibraryTopHalf(mAllocationStackComposite); - - final Sash sash = new Sash(sash_composite, SWT.HORIZONTAL); - - // bottom half of these modes is the same: detail table - createDetailTable(sash_composite); - - // init value for stack - mAllocationStackLayout.topControl = mAllocationModeTop; - - // form layout data - FormData data = new FormData(); - data.top = new FormAttachment(mTotalMemoryLabel, 0); - data.bottom = new FormAttachment(sash, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mAllocationStackComposite.setLayoutData(data); - - final FormData sashData = new FormData(); - if (prefs != null && prefs.contains(PREFS_ALLOCATION_SASH)) { - sashData.top = new FormAttachment(0, - prefs.getInt(PREFS_ALLOCATION_SASH)); - } else { - sashData.top = new FormAttachment(50, 0); // 50% across - } - sashData.left = new FormAttachment(0, 0); - sashData.right = new FormAttachment(100, 0); - sash.setLayoutData(sashData); - - data = new FormData(); - data.top = new FormAttachment(sash, 0); - data.bottom = new FormAttachment(100, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mDetailTable.setLayoutData(data); - - // allow resizes, but cap at minPanelWidth - sash.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event e) { - Rectangle sashRect = sash.getBounds(); - Rectangle panelRect = sash_composite.getClientArea(); - int bottom = panelRect.height - sashRect.height - minPanelWidth; - e.y = Math.max(Math.min(e.y, bottom), minPanelWidth); - if (e.y != sashRect.y) { - sashData.top = new FormAttachment(0, e.y); - prefs.setValue(PREFS_ALLOCATION_SASH, e.y); - sash_composite.layout(); - } - } - }); - } - - private void createDetailTable(Composite base) { - - final IPreferenceStore prefs = DdmUiPreferences.getStore(); - - mDetailTable = new Table(base, SWT.MULTI | SWT.FULL_SELECTION); - mDetailTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - mDetailTable.setHeaderVisible(true); - mDetailTable.setLinesVisible(true); - - TableHelper.createTableColumn(mDetailTable, "Address", SWT.RIGHT, - "00000000", PREFS_DETAIL_ADDRESS, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mDetailTable, "Library", SWT.LEFT, - "abcdefghijklmnopqrst", PREFS_DETAIL_LIBRARY, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mDetailTable, "Method", SWT.LEFT, - "abcdefghijklmnopqrst", PREFS_DETAIL_METHOD, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mDetailTable, "File", SWT.LEFT, - "abcdefghijklmnopqrstuvwxyz", PREFS_DETAIL_FILE, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mDetailTable, "Line", SWT.RIGHT, - "9,999", PREFS_DETAIL_LINE, prefs); //$NON-NLS-1$ - } - - private void createAllocationTopHalf(Composite b) { - final IPreferenceStore prefs = DdmUiPreferences.getStore(); - - Composite base = new Composite(b, SWT.NONE); - mAllocationModeTop = base; - GridLayout gl = new GridLayout(1, false); - gl.marginLeft = gl.marginRight = gl.marginTop = gl.marginBottom = 0; - gl.verticalSpacing = 0; - base.setLayout(gl); - base.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // horizontal layout for memory total and pages UI - mPageUIComposite = new Composite(base, SWT.NONE); - mPageUIComposite.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_BEGINNING)); - gl = new GridLayout(3, false); - gl.marginLeft = gl.marginRight = gl.marginTop = gl.marginBottom = 0; - gl.horizontalSpacing = 0; - mPageUIComposite.setLayout(gl); - - // Page UI - mPagePreviousButton = new Button(mPageUIComposite, SWT.NONE); - mPagePreviousButton.setText("<"); - mPagePreviousButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mCurrentPage--; - updatePageUI(); - emptyTables(); - fillAllocationTable(); - } - }); - - mPageNextButton = new Button(mPageUIComposite, SWT.NONE); - mPageNextButton.setText(">"); - mPageNextButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mCurrentPage++; - updatePageUI(); - emptyTables(); - fillAllocationTable(); - } - }); - - mPageLabel = new Label(mPageUIComposite, SWT.NONE); - mPageLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - updatePageUI(); - - mAllocationTable = new Table(base, SWT.MULTI | SWT.FULL_SELECTION); - mAllocationTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - mAllocationTable.setHeaderVisible(true); - mAllocationTable.setLinesVisible(true); - - TableHelper.createTableColumn(mAllocationTable, "Total", SWT.RIGHT, - "9,999,999", PREFS_ALLOC_TOTAL, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mAllocationTable, "Count", SWT.RIGHT, - "9,999", PREFS_ALLOC_COUNT, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mAllocationTable, "Size", SWT.RIGHT, - "999,999", PREFS_ALLOC_SIZE, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mAllocationTable, "Library", SWT.LEFT, - "abcdefghijklmnopqrst", PREFS_ALLOC_LIBRARY, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mAllocationTable, "Method", SWT.LEFT, - "abcdefghijklmnopqrst", PREFS_ALLOC_METHOD, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mAllocationTable, "File", SWT.LEFT, - "abcdefghijklmnopqrstuvwxyz", PREFS_ALLOC_FILE, prefs); //$NON-NLS-1$ - - mAllocationTable.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // get the selection index - int index = mAllocationTable.getSelectionIndex(); - if (index >= 0 && index < mAllocationTable.getItemCount()) { - TableItem item = mAllocationTable.getItem(index); - if (item != null && item.getData() instanceof NativeAllocationInfo) { - fillDetailTable((NativeAllocationInfo)item.getData()); - } - } - } - }); - } - - private void createLibraryTopHalf(Composite base) { - final int minPanelWidth = 60; - - final IPreferenceStore prefs = DdmUiPreferences.getStore(); - - // create a composite that'll contain 2 tables horizontally - final Composite top = new Composite(base, SWT.NONE); - mLibraryModeTopControl = top; - top.setLayout(new FormLayout()); - top.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // first table: library - mLibraryTable = new Table(top, SWT.MULTI | SWT.FULL_SELECTION); - mLibraryTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - mLibraryTable.setHeaderVisible(true); - mLibraryTable.setLinesVisible(true); - - TableHelper.createTableColumn(mLibraryTable, "Library", SWT.LEFT, - "abcdefghijklmnopqrstuvwxyz", PREFS_LIB_LIBRARY, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mLibraryTable, "Size", SWT.RIGHT, - "9,999,999", PREFS_LIB_SIZE, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mLibraryTable, "Count", SWT.RIGHT, - "9,999", PREFS_LIB_COUNT, prefs); //$NON-NLS-1$ - - mLibraryTable.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - fillLibraryAllocationTable(); - } - }); - - final Sash sash = new Sash(top, SWT.VERTICAL); - - // 2nd table: allocation per library - mLibraryAllocationTable = new Table(top, SWT.MULTI | SWT.FULL_SELECTION); - mLibraryAllocationTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - mLibraryAllocationTable.setHeaderVisible(true); - mLibraryAllocationTable.setLinesVisible(true); - - TableHelper.createTableColumn(mLibraryAllocationTable, "Total", - SWT.RIGHT, "9,999,999", PREFS_LIBALLOC_TOTAL, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mLibraryAllocationTable, "Count", - SWT.RIGHT, "9,999", PREFS_LIBALLOC_COUNT, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mLibraryAllocationTable, "Size", - SWT.RIGHT, "999,999", PREFS_LIBALLOC_SIZE, prefs); //$NON-NLS-1$ - TableHelper.createTableColumn(mLibraryAllocationTable, "Method", - SWT.LEFT, "abcdefghijklmnopqrst", PREFS_LIBALLOC_METHOD, prefs); //$NON-NLS-1$ - - mLibraryAllocationTable.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // get the index of the selection in the library table - int index1 = mLibraryTable.getSelectionIndex(); - // get the index in the library allocation table - int index2 = mLibraryAllocationTable.getSelectionIndex(); - // get the MallocInfo object - if (index1 != -1 && index2 != -1) { - LibraryAllocations liballoc = mLibraryAllocations.get(index1); - NativeAllocationInfo info = liballoc.getAllocation(index2); - fillDetailTable(info); - } - } - }); - - // form layout data - FormData data = new FormData(); - data.top = new FormAttachment(0, 0); - data.bottom = new FormAttachment(100, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(sash, 0); - mLibraryTable.setLayoutData(data); - - final FormData sashData = new FormData(); - if (prefs != null && prefs.contains(PREFS_LIBRARY_SASH)) { - sashData.left = new FormAttachment(0, - prefs.getInt(PREFS_LIBRARY_SASH)); - } else { - sashData.left = new FormAttachment(50, 0); - } - sashData.bottom = new FormAttachment(100, 0); - sashData.top = new FormAttachment(0, 0); // 50% across - sash.setLayoutData(sashData); - - data = new FormData(); - data.top = new FormAttachment(0, 0); - data.bottom = new FormAttachment(100, 0); - data.left = new FormAttachment(sash, 0); - data.right = new FormAttachment(100, 0); - mLibraryAllocationTable.setLayoutData(data); - - // allow resizes, but cap at minPanelWidth - sash.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event e) { - Rectangle sashRect = sash.getBounds(); - Rectangle panelRect = top.getClientArea(); - int right = panelRect.width - sashRect.width - minPanelWidth; - e.x = Math.max(Math.min(e.x, right), minPanelWidth); - if (e.x != sashRect.x) { - sashData.left = new FormAttachment(0, e.x); - prefs.setValue(PREFS_LIBRARY_SASH, e.y); - top.layout(); - } - } - }); - } - - private void emptyTables() { - mAllocationTable.removeAll(); - mLibraryTable.removeAll(); - mLibraryAllocationTable.removeAll(); - mDetailTable.removeAll(); - } - - private void sortAllocationsPerLibrary() { - if (mClientData != null) { - mLibraryAllocations.clear(); - - // create a hash map of LibraryAllocations to access aggregate - // objects already created - HashMap<String, LibraryAllocations> libcache = - new HashMap<String, LibraryAllocations>(); - - // get the allocation count - int count = mDisplayedAllocations.size(); - for (int i = 0; i < count; i++) { - NativeAllocationInfo allocInfo = mDisplayedAllocations.get(i); - - NativeStackCallInfo stackCallInfo = allocInfo.getRelevantStackCallInfo(); - if (stackCallInfo != null) { - String libraryName = stackCallInfo.getLibraryName(); - LibraryAllocations liballoc = libcache.get(libraryName); - if (liballoc == null) { - // didn't find a library allocation object already - // created so we create one - liballoc = new LibraryAllocations(libraryName); - // add it to the cache - libcache.put(libraryName, liballoc); - // add it to the list - mLibraryAllocations.add(liballoc); - } - // add the MallocInfo object to it. - liballoc.addAllocation(allocInfo); - } - } - // now that the list is created, we need to compute the size and - // sort it by size. This will also sort the MallocInfo objects - // inside each LibraryAllocation objects. - for (LibraryAllocations liballoc : mLibraryAllocations) { - liballoc.computeAllocationSizeAndCount(); - } - - // now we sort it - Collections.sort(mLibraryAllocations, - new Comparator<LibraryAllocations>() { - @Override - public int compare(LibraryAllocations o1, - LibraryAllocations o2) { - return o2.getSize() - o1.getSize(); - } - }); - } - } - - private void renderBitmap(ClientData cd) { - byte[] pixData; - - // Atomically get and clear the heap data. - synchronized (cd) { - if (serializeHeapData(cd.getVmHeapData()) == false) { - // no change, we return. - return; - } - - pixData = getSerializedData(); - - ImageData id = createLinearHeapImage(pixData, 200, mMapPalette); - Image image = new Image(mBase.getDisplay(), id); - mImage.setImage(image); - mImage.pack(true); - } - } - - /* - * Create color palette for map. Set up titles for legend. - */ - private static PaletteData createPalette() { - RGB colors[] = new RGB[NUM_PALETTE_ENTRIES]; - colors[0] - = new RGB(192, 192, 192); // non-heap pixels are gray - mMapLegend[0] - = "(heap expansion area)"; - - colors[1] - = new RGB(0, 0, 0); // free chunks are black - mMapLegend[1] - = "free"; - - colors[HeapSegmentElement.KIND_OBJECT + 2] - = new RGB(0, 0, 255); // objects are blue - mMapLegend[HeapSegmentElement.KIND_OBJECT + 2] - = "data object"; - - colors[HeapSegmentElement.KIND_CLASS_OBJECT + 2] - = new RGB(0, 255, 0); // class objects are green - mMapLegend[HeapSegmentElement.KIND_CLASS_OBJECT + 2] - = "class object"; - - colors[HeapSegmentElement.KIND_ARRAY_1 + 2] - = new RGB(255, 0, 0); // byte/bool arrays are red - mMapLegend[HeapSegmentElement.KIND_ARRAY_1 + 2] - = "1-byte array (byte[], boolean[])"; - - colors[HeapSegmentElement.KIND_ARRAY_2 + 2] - = new RGB(255, 128, 0); // short/char arrays are orange - mMapLegend[HeapSegmentElement.KIND_ARRAY_2 + 2] - = "2-byte array (short[], char[])"; - - colors[HeapSegmentElement.KIND_ARRAY_4 + 2] - = new RGB(255, 255, 0); // obj/int/float arrays are yellow - mMapLegend[HeapSegmentElement.KIND_ARRAY_4 + 2] - = "4-byte array (object[], int[], float[])"; - - colors[HeapSegmentElement.KIND_ARRAY_8 + 2] - = new RGB(255, 128, 128); // long/double arrays are pink - mMapLegend[HeapSegmentElement.KIND_ARRAY_8 + 2] - = "8-byte array (long[], double[])"; - - colors[HeapSegmentElement.KIND_UNKNOWN + 2] - = new RGB(255, 0, 255); // unknown objects are cyan - mMapLegend[HeapSegmentElement.KIND_UNKNOWN + 2] - = "unknown object"; - - colors[HeapSegmentElement.KIND_NATIVE + 2] - = new RGB(64, 64, 64); // native objects are dark gray - mMapLegend[HeapSegmentElement.KIND_NATIVE + 2] - = "non-Java object"; - - return new PaletteData(colors); - } - - private void saveAllocations(String fileName) { - try { - PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(fileName))); - - for (NativeAllocationInfo alloc : mAllocations) { - out.println(alloc.toString()); - } - out.close(); - } catch (IOException e) { - Log.e("Native", e); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Panel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/Panel.java deleted file mode 100644 index d910cc7..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Panel.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - - -/** - * Base class for our information panels. - */ -public abstract class Panel { - - public final Control createPanel(Composite parent) { - Control panelControl = createControl(parent); - - postCreation(); - - return panelControl; - } - - protected abstract void postCreation(); - - /** - * Creates a control capable of displaying some information. This is - * called once, when the application is initializing, from the UI thread. - */ - protected abstract Control createControl(Composite parent); - - /** - * Sets the focus to the proper control inside the panel. - */ - public abstract void setFocus(); -} - diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/PortFieldEditor.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/PortFieldEditor.java deleted file mode 100644 index 533372e..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/PortFieldEditor.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import org.eclipse.jface.preference.IntegerFieldEditor; -import org.eclipse.swt.widgets.Composite; - -/** - * Edit an integer field, validating it as a port number. - */ -public class PortFieldEditor extends IntegerFieldEditor { - - public boolean mRecursiveCheck = false; - - public PortFieldEditor(String name, String label, Composite parent) { - super(name, label, parent); - setValidateStrategy(VALIDATE_ON_KEY_STROKE); - } - - /* - * Get the current value of the field, as an integer. - */ - public int getCurrentValue() { - int val; - try { - val = Integer.parseInt(getStringValue()); - } - catch (NumberFormatException nfe) { - val = -1; - } - return val; - } - - /* - * Check the validity of the field. - */ - @Override - protected boolean checkState() { - if (super.checkState() == false) { - return false; - } - //Log.i("ddms", "check state " + getStringValue()); - boolean err = false; - int val = getCurrentValue(); - if (val < 1024 || val > 32767) { - setErrorMessage("Port must be between 1024 and 32767"); - err = true; - } else { - setErrorMessage(null); - err = false; - } - showErrorMessage(); - return !err; - } - - protected void updateCheckState(PortFieldEditor pfe) { - pfe.refreshValidState(); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java deleted file mode 100644 index b0f885a..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log; -import com.android.ddmlib.RawImage; -import com.android.ddmlib.TimeoutException; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.ImageTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Dialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; - -import java.io.File; -import java.io.IOException; -import java.util.Calendar; - - -/** - * Gather a screen shot from the device and save it to a file. - */ -public class ScreenShotDialog extends Dialog { - - private Label mBusyLabel; - private Label mImageLabel; - private Button mSave; - private IDevice mDevice; - private RawImage mRawImage; - private Clipboard mClipboard; - - /** Number of 90 degree rotations applied to the current image */ - private int mRotateCount = 0; - - /** - * Create with default style. - */ - public ScreenShotDialog(Shell parent) { - this(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); - mClipboard = new Clipboard(parent.getDisplay()); - } - - /** - * Create with app-defined style. - */ - public ScreenShotDialog(Shell parent, int style) { - super(parent, style); - } - - /** - * Prepare and display the dialog. - * @param device The {@link IDevice} from which to get the screenshot. - */ - public void open(IDevice device) { - mDevice = device; - - Shell parent = getParent(); - Shell shell = new Shell(parent, getStyle()); - shell.setText("Device Screen Capture"); - - createContents(shell); - shell.pack(); - shell.open(); - - updateDeviceImage(shell); - - Display display = parent.getDisplay(); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - - } - - /* - * Create the screen capture dialog contents. - */ - private void createContents(final Shell shell) { - GridData data; - - final int colCount = 5; - - shell.setLayout(new GridLayout(colCount, true)); - - // "refresh" button - Button refresh = new Button(shell, SWT.PUSH); - refresh.setText("Refresh"); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.widthHint = 80; - refresh.setLayoutData(data); - refresh.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateDeviceImage(shell); - // RawImage only allows us to rotate the image 90 degrees at the time, - // so to preserve the current rotation we must call getRotated() - // the same number of times the user has done it manually. - // TODO: improve the RawImage class. - for (int i=0; i < mRotateCount; i++) { - mRawImage = mRawImage.getRotated(); - } - updateImageDisplay(shell); - } - }); - - // "rotate" button - Button rotate = new Button(shell, SWT.PUSH); - rotate.setText("Rotate"); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.widthHint = 80; - rotate.setLayoutData(data); - rotate.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mRawImage != null) { - mRotateCount = (mRotateCount + 1) % 4; - mRawImage = mRawImage.getRotated(); - updateImageDisplay(shell); - } - } - }); - - // "save" button - mSave = new Button(shell, SWT.PUSH); - mSave.setText("Save"); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.widthHint = 80; - mSave.setLayoutData(data); - mSave.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - saveImage(shell); - } - }); - - Button copy = new Button(shell, SWT.PUSH); - copy.setText("Copy"); - copy.setToolTipText("Copy the screenshot to the clipboard"); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.widthHint = 80; - copy.setLayoutData(data); - copy.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - copy(); - } - }); - - - // "done" button - Button done = new Button(shell, SWT.PUSH); - done.setText("Done"); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.widthHint = 80; - done.setLayoutData(data); - done.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - shell.close(); - } - }); - - // title/"capturing" label - mBusyLabel = new Label(shell, SWT.NONE); - mBusyLabel.setText("Preparing..."); - data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); - data.horizontalSpan = colCount; - mBusyLabel.setLayoutData(data); - - // space for the image - mImageLabel = new Label(shell, SWT.BORDER); - data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); - data.horizontalSpan = colCount; - mImageLabel.setLayoutData(data); - Display display = shell.getDisplay(); - mImageLabel.setImage(ImageLoader.createPlaceHolderArt( - display, 50, 50, display.getSystemColor(SWT.COLOR_BLUE))); - - - shell.setDefaultButton(done); - } - - /** - * Copies the content of {@link #mImageLabel} to the clipboard. - */ - private void copy() { - mClipboard.setContents( - new Object[] { - mImageLabel.getImage().getImageData() - }, new Transfer[] { - ImageTransfer.getInstance() - }); - } - - /** - * Captures a new image from the device, and display it. - */ - private void updateDeviceImage(Shell shell) { - mBusyLabel.setText("Capturing..."); // no effect - - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); - - mRawImage = getDeviceImage(); - - updateImageDisplay(shell); - } - - /** - * Updates the display with {@link #mRawImage}. - * @param shell - */ - private void updateImageDisplay(Shell shell) { - Image image; - if (mRawImage == null) { - Display display = shell.getDisplay(); - image = ImageLoader.createPlaceHolderArt( - display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE)); - - mSave.setEnabled(false); - mBusyLabel.setText("Screen not available"); - } else { - // convert raw data to an Image. - PaletteData palette = new PaletteData( - mRawImage.getRedMask(), - mRawImage.getGreenMask(), - mRawImage.getBlueMask()); - - ImageData imageData = new ImageData(mRawImage.width, mRawImage.height, - mRawImage.bpp, palette, 1, mRawImage.data); - image = new Image(getParent().getDisplay(), imageData); - - mSave.setEnabled(true); - mBusyLabel.setText("Captured image:"); - } - - mImageLabel.setImage(image); - mImageLabel.pack(); - shell.pack(); - - // there's no way to restore old cursor; assume it's ARROW - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); - } - - /** - * Grabs an image from an ADB-connected device and returns it as a {@link RawImage}. - */ - private RawImage getDeviceImage() { - try { - return mDevice.getScreenshot(); - } - catch (IOException ioe) { - Log.w("ddms", "Unable to get frame buffer: " + ioe.getMessage()); - return null; - } catch (TimeoutException e) { - Log.w("ddms", "Unable to get frame buffer: timeout "); - return null; - } catch (AdbCommandRejectedException e) { - Log.w("ddms", "Unable to get frame buffer: " + e.getMessage()); - return null; - } - } - - /* - * Prompt the user to save the image to disk. - */ - private void saveImage(Shell shell) { - FileDialog dlg = new FileDialog(shell, SWT.SAVE); - - Calendar now = Calendar.getInstance(); - String fileName = String.format("device-%tF-%tH%tM%tS.png", - now, now, now, now); - - dlg.setText("Save image..."); - dlg.setFileName(fileName); - - String lastDir = DdmUiPreferences.getStore().getString("lastImageSaveDir"); - if (lastDir.length() == 0) { - lastDir = DdmUiPreferences.getStore().getString("imageSaveDir"); - } - dlg.setFilterPath(lastDir); - dlg.setFilterNames(new String[] { - "PNG Files (*.png)" - }); - dlg.setFilterExtensions(new String[] { - "*.png" //$NON-NLS-1$ - }); - - fileName = dlg.open(); - if (fileName != null) { - // FileDialog.getFilterPath() does NOT always return the current - // directory of the FileDialog; on the Mac it sometimes just returns - // the value the dialog was initialized with. It does however return - // the full path as its return value, so just pick the path from - // there. - if (!fileName.endsWith(".png")) { - fileName = fileName + ".png"; - } - - String saveDir = new File(fileName).getParent(); - if (saveDir != null) { - DdmUiPreferences.getStore().setValue("lastImageSaveDir", saveDir); - } - - Log.d("ddms", "Saving image to " + fileName); - ImageData imageData = mImageLabel.getImage().getImageData(); - - try { - org.eclipse.swt.graphics.ImageLoader loader = - new org.eclipse.swt.graphics.ImageLoader(); - - loader.data = new ImageData[] { imageData }; - loader.save(fileName, SWT.IMAGE_PNG); - } - catch (SWTException e) { - Log.w("ddms", "Unable to save " + fileName + ": " + e.getMessage()); - } - } - } - -} - diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SelectionDependentPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SelectionDependentPanel.java deleted file mode 100644 index e6d2211..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SelectionDependentPanel.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.Client; -import com.android.ddmlib.IDevice; - -/** - * A Panel that requires {@link Device}/{@link Client} selection notifications. - */ -public abstract class SelectionDependentPanel extends Panel { - private IDevice mCurrentDevice = null; - private Client mCurrentClient = null; - - /** - * Returns the current {@link Device}. - * @return the current device or null if none are selected. - */ - protected final IDevice getCurrentDevice() { - return mCurrentDevice; - } - - /** - * Returns the current {@link Client}. - * @return the current client or null if none are selected. - */ - protected final Client getCurrentClient() { - return mCurrentClient; - } - - /** - * Sent when a new device is selected. - * @param selectedDevice the selected device. - */ - public final void deviceSelected(IDevice selectedDevice) { - if (selectedDevice != mCurrentDevice) { - mCurrentDevice = selectedDevice; - deviceSelected(); - } - } - - /** - * Sent when a new client is selected. - * @param selectedClient the selected client. - */ - public final void clientSelected(Client selectedClient) { - if (selectedClient != mCurrentClient) { - mCurrentClient = selectedClient; - clientSelected(); - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()}. - */ - public abstract void deviceSelected(); - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - public abstract void clientSelected(); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/StackTracePanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/StackTracePanel.java deleted file mode 100644 index b00120b..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/StackTracePanel.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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; - -import com.android.ddmlib.Client; -import com.android.ddmlib.IStackTraceInfo; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; - -/** - * Stack Trace Panel. - * <p/>This is not a panel in the regular sense. Instead this is just an object around the creation - * and management of a Stack Trace display. - * <p/>UI creation is done through - * {@link #createPanel(Composite, String, IPreferenceStore)}. - * - */ -public final class StackTracePanel { - - private static ISourceRevealer sSourceRevealer; - - private Table mStackTraceTable; - private TableViewer mStackTraceViewer; - - private Client mCurrentClient; - - - /** - * Content Provider to display the stack trace of a thread. - * Expected input is a {@link IStackTraceInfo} object. - */ - private static class StackTraceContentProvider implements IStructuredContentProvider { - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof IStackTraceInfo) { - // getElement cannot return null, so we return an empty array - // if there's no stack trace - StackTraceElement trace[] = ((IStackTraceInfo)inputElement).getStackTrace(); - if (trace != null) { - return trace; - } - } - - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - } - - - /** - * A Label Provider to use with {@link StackTraceContentProvider}. It expects the elements to be - * of type {@link StackTraceElement}. - */ - private static class StackTraceLabelProvider implements ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof StackTraceElement && columnIndex == 0) { - StackTraceElement traceElement = (StackTraceElement) element; - return " at " + traceElement.toString(); - } - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Classes which implement this interface provide a method that is able to reveal a method - * in a source editor - */ - public interface ISourceRevealer { - /** - * Sent to reveal a particular line in a source editor - * @param applicationName the name of the application running the source. - * @param className the fully qualified class name - * @param line the line to reveal - */ - public void reveal(String applicationName, String className, int line); - } - - - /** - * Sets the {@link ISourceRevealer} object able to reveal source code in a source editor. - * @param revealer - */ - public static void setSourceRevealer(ISourceRevealer revealer) { - sSourceRevealer = revealer; - } - - /** - * Creates the controls for the StrackTrace display. - * <p/>This method will set the parent {@link Composite} to use a {@link GridLayout} with - * 2 columns. - * @param parent the parent composite. - * @param prefs_stack_column - * @param store - */ - public Table createPanel(Composite parent, String prefs_stack_column, - IPreferenceStore store) { - - mStackTraceTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION); - mStackTraceTable.setHeaderVisible(false); - mStackTraceTable.setLinesVisible(false); - - TableHelper.createTableColumn( - mStackTraceTable, - "Info", - SWT.LEFT, - "SomeLongClassName.method(android/somepackage/someotherpackage/somefile.java:99999)", //$NON-NLS-1$ - prefs_stack_column, store); - - mStackTraceViewer = new TableViewer(mStackTraceTable); - mStackTraceViewer.setContentProvider(new StackTraceContentProvider()); - mStackTraceViewer.setLabelProvider(new StackTraceLabelProvider()); - - mStackTraceViewer.addDoubleClickListener(new IDoubleClickListener() { - @Override - public void doubleClick(DoubleClickEvent event) { - if (sSourceRevealer != null && mCurrentClient != null) { - // get the selected stack trace element - ISelection selection = mStackTraceViewer.getSelection(); - - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object object = structuredSelection.getFirstElement(); - if (object instanceof StackTraceElement) { - StackTraceElement traceElement = (StackTraceElement)object; - - if (traceElement.isNativeMethod() == false) { - sSourceRevealer.reveal( - mCurrentClient.getClientData().getClientDescription(), - traceElement.getClassName(), - traceElement.getLineNumber()); - } - } - } - } - } - }); - - return mStackTraceTable; - } - - /** - * Sets the input for the {@link TableViewer}. - * @param input the {@link IStackTraceInfo} that will provide the viewer with the list of - * {@link StackTraceElement} - */ - public void setViewerInput(IStackTraceInfo input) { - mStackTraceViewer.setInput(input); - mStackTraceViewer.refresh(); - } - - /** - * Sets the current client running the stack trace. - * @param currentClient the {@link Client}. - */ - public void setCurrentClient(Client currentClient) { - mCurrentClient = currentClient; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java deleted file mode 100644 index 732de59..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2010 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; - -import com.android.ddmlib.SyncException; -import com.android.ddmlib.SyncService; -import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import com.android.ddmlib.TimeoutException; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.swt.widgets.Shell; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; - -/** - * Helper class to run a Sync in a {@link ProgressMonitorDialog}. - */ -public class SyncProgressHelper { - - /** - * a runnable class run with an {@link ISyncProgressMonitor}. - */ - public interface SyncRunnable { - /** Runs the sync action */ - void run(ISyncProgressMonitor monitor) throws SyncException, IOException, TimeoutException; - /** close the {@link SyncService} */ - void close(); - } - - /** - * Runs a {@link SyncRunnable} in a {@link ProgressMonitorDialog}. - * @param runnable The {@link SyncRunnable} to run. - * @param progressMessage the message to display in the progress dialog - * @param parentShell the parent shell for the progress dialog. - * - * @throws InvocationTargetException - * @throws InterruptedException - * @throws SyncException if an error happens during the push of the package on the device. - * @throws IOException - * @throws TimeoutException - */ - public static void run(final SyncRunnable runnable, final String progressMessage, - final Shell parentShell) - throws InvocationTargetException, InterruptedException, SyncException, IOException, - TimeoutException { - - final Exception[] result = new Exception[1]; - new ProgressMonitorDialog(parentShell).run(true, true, new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) { - try { - runnable.run(new SyncProgressMonitor(monitor, progressMessage)); - } catch (Exception e) { - result[0] = e; - } finally { - runnable.close(); - } - } - }); - - if (result[0] instanceof SyncException) { - SyncException se = (SyncException)result[0]; - if (se.wasCanceled()) { - // no need to throw this - return; - } - throw se; - } - - // just do some casting so that the method declaration matches what's thrown. - if (result[0] instanceof TimeoutException) { - throw (TimeoutException)result[0]; - } - - if (result[0] instanceof IOException) { - throw (IOException)result[0]; - } - - if (result[0] instanceof RuntimeException) { - throw (RuntimeException)result[0]; - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressMonitor.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressMonitor.java deleted file mode 100644 index 4254f67..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressMonitor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2009 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; - -import com.android.ddmlib.SyncService.ISyncProgressMonitor; - -import org.eclipse.core.runtime.IProgressMonitor; - -/** - * Implementation of the {@link ISyncProgressMonitor} wrapping an Eclipse {@link IProgressMonitor}. - */ -public class SyncProgressMonitor implements ISyncProgressMonitor { - - private IProgressMonitor mMonitor; - private String mName; - - public SyncProgressMonitor(IProgressMonitor monitor, String name) { - mMonitor = monitor; - mName = name; - } - - @Override - public void start(int totalWork) { - mMonitor.beginTask(mName, totalWork); - } - - @Override - public void stop() { - mMonitor.done(); - } - - @Override - public void advance(int work) { - mMonitor.worked(work); - } - - @Override - public boolean isCanceled() { - return mMonitor.isCanceled(); - } - - @Override - public void startSubTask(String name) { - mMonitor.subTask(name); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java deleted file mode 100644 index 8ba2171..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java +++ /dev/null @@ -1,907 +0,0 @@ -/* - * 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; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.IShellOutputReceiver; -import com.android.ddmlib.Log; -import com.android.ddmlib.NullOutputReceiver; -import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.SysinfoPanel.BugReportParser.GfxProfileData; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.data.category.DefaultCategoryDataset; -import org.jfree.data.general.DefaultPieDataset; -import org.jfree.experimental.chart.swt.ChartComposite; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Displays system information graphs obtained from a bugreport file or device. - */ -public class SysinfoPanel extends TablePanel implements IShellOutputReceiver { - - // UI components - private Label mLabel; - private Button mFetchButton; - private Combo mDisplayMode; - - private DefaultPieDataset mDataset; - private DefaultCategoryDataset mBarDataSet; - - private StackLayout mStackLayout; - private Composite mChartComposite; - private Composite mPieChartComposite; - private Composite mStackedBarComposite; - - // The bugreport file to process - private File mDataFile; - - // To get output from adb commands - private FileOutputStream mTempStream; - - // Selects the current display: MODE_CPU, etc. - private int mMode = 0; - private String mGfxPackageName; - - private static final int MODE_CPU = 0; - private static final int MODE_MEMINFO = 1; - private static final int MODE_GFXINFO = 2; - - // argument to dumpsys; section in the bugreport holding the data - private static final String DUMP_COMMAND[] = { - "dumpsys cpuinfo", - "cat /proc/meminfo ; procrank", - "dumpsys gfxinfo", - }; - - private static final String CAPTIONS[] = { - "CPU load", - "Memory usage", - "Frame Render Time", - }; - - /** Shell property that controls whether graphics profiling is enabled or not. */ - private static final String PROP_GFX_PROFILING = "debug.hwui.profile"; //$NON-NLS-1$ - - /** - * Generates the dataset to display. - * - * @param file The bugreport file to process. - */ - private void generateDataset(File file) { - if (file == null) { - return; - } - try { - BufferedReader br = getBugreportReader(file); - if (mMode == MODE_CPU) { - readCpuDataset(br); - } else if (mMode == MODE_MEMINFO) { - readMeminfoDataset(br); - } else if (mMode == MODE_GFXINFO) { - readGfxInfoDataset(br); - } - br.close(); - } catch (IOException e) { - Log.e("DDMS", e); - } - } - - /** - * Sent when a new device is selected. The new device can be accessed with - * {@link #getCurrentDevice()} - */ - @Override - public void deviceSelected() { - if (getCurrentDevice() != null) { - mFetchButton.setEnabled(true); - loadFromDevice(); - } else { - mFetchButton.setEnabled(false); - } - } - - /** - * Sent when a new client is selected. The new client can be accessed with - * {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mDisplayMode.setFocus(); - } - - /** - * Fetches a new bugreport from the device and updates the display. - * Fetching is asynchronous. See also addOutput, flush, and isCancelled. - */ - private void loadFromDevice() { - clearDataSet(); - - if (mMode == MODE_GFXINFO) { - boolean en = isGfxProfilingEnabled(); - if (!en) { - if (enableGfxProfiling()) { - MessageDialog.openInformation(Display.getCurrent().getActiveShell(), - "DDMS", - "Graphics profiling was enabled on the device.\n" + - "It may be necessary to relaunch your application to see profile information."); - } else { - MessageDialog.openError(Display.getCurrent().getActiveShell(), - "DDMS", - "Unexpected error enabling graphics profiling on device.\n"); - return; - } - } - } - - final String command = getDumpsysCommand(mMode); - if (command == null) { - return; - } - - Thread t = new Thread(new Runnable() { - @Override - public void run() { - try { - initShellOutputBuffer(); - if (mMode == MODE_MEMINFO) { - // Hack to add bugreport-style section header for meminfo - mTempStream.write("------ MEMORY INFO ------\n".getBytes()); - } - getCurrentDevice().executeShellCommand(command, SysinfoPanel.this); - } catch (IOException e) { - Log.e("DDMS", e); - } catch (TimeoutException e) { - Log.e("DDMS", e); - } catch (AdbCommandRejectedException e) { - Log.e("DDMS", e); - } catch (ShellCommandUnresponsiveException e) { - Log.e("DDMS", e); - } - } - }, "Sysinfo Output Collector"); - t.start(); - } - - private boolean isGfxProfilingEnabled() { - IDevice device = getCurrentDevice(); - if (device == null) { - return false; - } - - String prop; - try { - prop = device.getPropertySync(PROP_GFX_PROFILING); - return Boolean.valueOf(prop); - } catch (Exception e) { - return false; - } - } - - private boolean enableGfxProfiling() { - IDevice device = getCurrentDevice(); - if (device == null) { - return false; - } - - try { - device.executeShellCommand("setprop " + PROP_GFX_PROFILING + " true", - new NullOutputReceiver()); - } catch (Exception e) { - return false; - } - - return true; - } - - private String getDumpsysCommand(int mode) { - if (mode == MODE_GFXINFO) { - Client c = getCurrentClient(); - if (c == null) { - return null; - } - - ClientData cd = c.getClientData(); - if (cd == null) { - return null; - } - - mGfxPackageName = cd.getClientDescription(); - if (mGfxPackageName == null) { - return null; - } - - return "dumpsys gfxinfo " + mGfxPackageName; - } else if (mode < DUMP_COMMAND.length) { - return DUMP_COMMAND[mode]; - } - - return null; - } - - /** - * Initializes temporary output file for executeShellCommand(). - * - * @throws IOException on file error - */ - void initShellOutputBuffer() throws IOException { - mDataFile = File.createTempFile("ddmsfile", ".txt"); - mDataFile.deleteOnExit(); - mTempStream = new FileOutputStream(mDataFile); - } - - /** - * Adds output to the temp file. IShellOutputReceiver method. Called by - * executeShellCommand(). - */ - @Override - public void addOutput(byte[] data, int offset, int length) { - try { - mTempStream.write(data, offset, length); - } catch (IOException e) { - Log.e("DDMS", e); - } - } - - /** - * Processes output from shell command. IShellOutputReceiver method. The - * output is passed to generateDataset(). Called by executeShellCommand() on - * completion. - */ - @Override - public void flush() { - if (mTempStream != null) { - try { - mTempStream.close(); - generateDataset(mDataFile); - mTempStream = null; - mDataFile = null; - } catch (IOException e) { - Log.e("DDMS", e); - } - } - } - - /** - * IShellOutputReceiver method. - * - * @return false - don't cancel - */ - @Override - public boolean isCancelled() { - return false; - } - - /** - * Create our controls for the UI panel. - */ - @Override - protected Control createControl(Composite parent) { - Composite top = new Composite(parent, SWT.NONE); - top.setLayout(new GridLayout(1, false)); - top.setLayoutData(new GridData(GridData.FILL_BOTH)); - - Composite buttons = new Composite(top, SWT.NONE); - buttons.setLayout(new RowLayout()); - - mDisplayMode = new Combo(buttons, SWT.PUSH); - for (String mode : CAPTIONS) { - mDisplayMode.add(mode); - } - mDisplayMode.select(mMode); - mDisplayMode.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mMode = mDisplayMode.getSelectionIndex(); - if (mDataFile != null) { - generateDataset(mDataFile); - } else if (getCurrentDevice() != null) { - loadFromDevice(); - } - } - }); - - mFetchButton = new Button(buttons, SWT.PUSH); - mFetchButton.setText("Update from Device"); - mFetchButton.setEnabled(false); - mFetchButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - loadFromDevice(); - } - }); - - mLabel = new Label(top, SWT.NONE); - mLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mChartComposite = new Composite(top, SWT.NONE); - mChartComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - mStackLayout = new StackLayout(); - mChartComposite.setLayout(mStackLayout); - - mPieChartComposite = createPieChartComposite(mChartComposite); - mStackedBarComposite = createStackedBarComposite(mChartComposite); - - mStackLayout.topControl = mPieChartComposite; - - return top; - } - - private Composite createStackedBarComposite(Composite chartComposite) { - mBarDataSet = new DefaultCategoryDataset(); - JFreeChart chart = ChartFactory.createStackedBarChart("Per Frame Rendering Time", - "Frame #", "Time (ms)", mBarDataSet, PlotOrientation.VERTICAL, - true /* legend */, true /* tooltips */, false /* urls */); - - ChartComposite c = newChartComposite(chart, chartComposite); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - return c; - } - - private Composite createPieChartComposite(Composite chartComposite) { - mDataset = new DefaultPieDataset(); - JFreeChart chart = ChartFactory.createPieChart("", mDataset, false - /* legend */, true/* tooltips */, false /* urls */); - - ChartComposite c = newChartComposite(chart, chartComposite); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - return c; - } - - private ChartComposite newChartComposite(JFreeChart chart, Composite parent) { - return new ChartComposite(parent, - SWT.BORDER, chart, - ChartComposite.DEFAULT_HEIGHT, - 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 - false, // zoom - true); - } - - @Override - public void clientChanged(final Client client, int changeMask) { - // Don't care - } - - /** - * Helper to open a bugreport and skip to the specified section. - * - * @param file File to open - * @return Reader to bugreport file - * @throws java.io.IOException on file error - */ - private BufferedReader getBugreportReader(File file) throws - IOException { - return new BufferedReader(new FileReader(file)); - } - - /** - * Parse the time string generated by BatteryStats. - * A typical new-format string is "11d 13h 45m 39s 999ms". - * A typical old-format string is "12.3 sec". - * @return time in ms - */ - private static long parseTimeMs(String s) { - long total = 0; - // Matches a single component e.g. "12.3 sec" or "45ms" - Pattern p = Pattern.compile("([\\d\\.]+)\\s*([a-z]+)"); - Matcher m = p.matcher(s); - while (m.find()) { - String label = m.group(2); - if ("sec".equals(label)) { - // Backwards compatibility with old time format - total += (long) (Double.parseDouble(m.group(1)) * 1000); - continue; - } - long value = Integer.parseInt(m.group(1)); - if ("d".equals(label)) { - total += value * 24 * 60 * 60 * 1000; - } else if ("h".equals(label)) { - total += value * 60 * 60 * 1000; - } else if ("m".equals(label)) { - total += value * 60 * 1000; - } else if ("s".equals(label)) { - total += value * 1000; - } else if ("ms".equals(label)) { - total += value; - } - } - return total; - } - - public static final class BugReportParser { - public static final class DataValue { - final String name; - final double value; - - public DataValue(String n, double v) { - name = n; - value = v; - } - }; - - /** Components of the time it takes to draw a single frame. */ - public static final class GfxProfileData { - /** draw time (time spent building display lists) in ms */ - final double draw; - - /** process time (time spent by Android's 2D renderer to execute display lists) (ms) */ - final double process; - - /** execute time (time spent to send frame to the compositor) in ms */ - final double execute; - - public GfxProfileData(double draw, double process, double execute) { - this.draw = draw; - this.process = process; - this.execute = execute; - } - } - - public static List<GfxProfileData> parseGfxInfo(BufferedReader br) throws IOException { - Pattern headerPattern = Pattern.compile("\\s+Draw\\s+Process\\s+Execute"); - - String line = null; - while ((line = br.readLine()) != null) { - Matcher m = headerPattern.matcher(line); - if (m.find()) { - break; - } - } - - if (line == null) { - return Collections.emptyList(); - } - - // parse something like: " 0.85 1.10 0.61\n", 3 doubles basically - Pattern dataPattern = - Pattern.compile("(\\d*\\.\\d+)\\s+(\\d*\\.\\d+)\\s+(\\d*\\.\\d+)"); - - List<GfxProfileData> data = new ArrayList<BugReportParser.GfxProfileData>(128); - while ((line = br.readLine()) != null) { - Matcher m = dataPattern.matcher(line); - if (!m.find()) { - break; - } - - double draw = safeParseDouble(m.group(1)); - double process = safeParseDouble(m.group(2)); - double execute = safeParseDouble(m.group(3)); - - data.add(new GfxProfileData(draw, process, execute)); - } - - return data; - } - - /** - * Processes wakelock information from bugreport. Updates mDataset with the - * new data. - * - * @param br Reader providing the content - * @throws IOException if error reading file - */ - public static List<DataValue> readWakelockDataset(BufferedReader br) throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - - Pattern lockPattern = Pattern.compile("Wake lock (\\S+): (.+) partial"); - Pattern totalPattern = Pattern.compile("Total: (.+) uptime"); - double total = 0; - boolean inCurrent = false; - - while (true) { - String line = br.readLine(); - if (line == null || line.startsWith("DUMP OF SERVICE")) { - // Done, or moved on to the next service - break; - } - if (line.startsWith("Current Battery Usage Statistics")) { - inCurrent = true; - } else if (inCurrent) { - Matcher m = lockPattern.matcher(line); - if (m.find()) { - double value = parseTimeMs(m.group(2)) / 1000.; - results.add(new DataValue(m.group(1), value)); - total -= value; - } else { - m = totalPattern.matcher(line); - if (m.find()) { - total += parseTimeMs(m.group(1)) / 1000.; - } - } - } - } - if (total > 0) { - results.add(new DataValue("Unlocked", total)); - } - - return results; - } - - /** - * Processes alarm information from bugreport. Updates mDataset with the new - * data. - * - * @param br Reader providing the content - * @throws IOException if error reading file - */ - public static List<DataValue> readAlarmDataset(BufferedReader br) throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - Pattern pattern = Pattern.compile("(\\d+) alarms: Intent .*\\.([^. ]+) flags"); - - while (true) { - String line = br.readLine(); - if (line == null || line.startsWith("DUMP OF SERVICE")) { - // Done, or moved on to the next service - break; - } - Matcher m = pattern.matcher(line); - if (m.find()) { - long count = Long.parseLong(m.group(1)); - String name = m.group(2); - results.add(new DataValue(name, count)); - } - } - - return results; - } - - /** - * Processes cpu load information from bugreport. Updates mDataset with the - * new data. - * - * @param br Reader providing the content - * @throws IOException if error reading file - */ - public static List<DataValue> readCpuDataset(BufferedReader br) throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - Pattern pattern1 = Pattern.compile("(\\S+): (\\S+)% = (.+)% user . (.+)% kernel"); - Pattern pattern2 = Pattern.compile("(\\S+)% (\\S+): (.+)% user . (.+)% kernel"); - - while (true) { - String line = br.readLine(); - if (line == null) { - break; - } - line = line.trim(); - - if (line.startsWith("Load:")) { - continue; - } - - String name = ""; - double user = 0, kernel = 0, both = 0; - boolean found = false; - - // try pattern1 - Matcher m = pattern1.matcher(line); - if (m.find()) { - found = true; - name = m.group(1); - both = safeParseLong(m.group(2)); - user = safeParseLong(m.group(3)); - kernel = safeParseLong(m.group(4)); - } - - // try pattern2 - m = pattern2.matcher(line); - if (m.find()) { - found = true; - name = m.group(2); - both = safeParseDouble(m.group(1)); - user = safeParseDouble(m.group(3)); - kernel = safeParseDouble(m.group(4)); - } - - if (!found) { - continue; - } - - if ("TOTAL".equals(name)) { - if (both < 100) { - results.add(new DataValue("Idle", (100 - both))); - } - } else { - // Try to make graphs more useful even with rounding; - // log often has 0% user + 0% kernel = 1% total - // We arbitrarily give extra to kernel - if (user > 0) { - results.add(new DataValue(name + " (user)", user)); - } - if (kernel > 0) { - results.add(new DataValue(name + " (kernel)" , both - user)); - } - if (user == 0 && kernel == 0 && both > 0) { - results.add(new DataValue(name, both)); - } - } - - } - - return results; - } - - private static long safeParseLong(String s) { - try { - return Long.parseLong(s); - } catch (NumberFormatException e) { - return 0; - } - } - - private static double safeParseDouble(String s) { - try { - return Double.parseDouble(s); - } catch (NumberFormatException e) { - return 0; - } - } - - /** - * Processes meminfo information from bugreport. Updates mDataset with the - * new data. - * - * @param br Reader providing the content - * @throws IOException if error reading file - */ - public static List<DataValue> readMeminfoDataset(BufferedReader br) throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - Pattern valuePattern = Pattern.compile("(\\d+) kB"); - long total = 0; - long other = 0; - - // Scan meminfo - String line = null; - while ((line = br.readLine()) != null) { - if (line.contains("----")) { - continue; - } - - Matcher m = valuePattern.matcher(line); - if (m.find()) { - long kb = Long.parseLong(m.group(1)); - if (line.startsWith("MemTotal")) { - total = kb; - } else if (line.startsWith("MemFree")) { - results.add(new DataValue("Free", kb)); - total -= kb; - } else if (line.startsWith("Slab")) { - results.add(new DataValue("Slab", kb)); - total -= kb; - } else if (line.startsWith("PageTables")) { - results.add(new DataValue("PageTables", kb)); - total -= kb; - } else if (line.startsWith("Buffers") && kb > 0) { - results.add(new DataValue("Buffers", kb)); - total -= kb; - } else if (line.startsWith("Inactive")) { - results.add(new DataValue("Inactive", kb)); - total -= kb; - } else if (line.startsWith("MemFree")) { - results.add(new DataValue("Free", kb)); - total -= kb; - } - } else { - break; - } - } - - List<DataValue> procRankResults = readProcRankDataset(br, line); - for (DataValue procRank : procRankResults) { - if (procRank.value > 2000) { // only show processes using > 2000K in memory - results.add(procRank); - } else { - other += procRank.value; - } - - total -= procRank.value; - } - - if (other > 0) { - results.add(new DataValue("Other", other)); - } - - // The Pss calculation is not necessarily accurate as accounting memory to - // a process is not accurate. So only if there really is unaccounted for memory do we - // add it to the pie. - if (total > 0) { - results.add(new DataValue("Unknown", total)); - } - - return results; - } - - static List<DataValue> readProcRankDataset(BufferedReader br, String header) - throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - - if (header == null || !header.contains("PID")) { - return results; - } - - Splitter PROCRANK_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults(); - List<String> fields = Lists.newArrayList(PROCRANK_SPLITTER.split(header)); - int pssIndex = fields.indexOf("Pss"); - int cmdIndex = fields.indexOf("cmdline"); - - if (pssIndex == -1 || cmdIndex == -1) { - return results; - } - - String line; - while ((line = br.readLine()) != null) { - // Extract pss field from procrank output - fields = Lists.newArrayList(PROCRANK_SPLITTER.split(line)); - - if (fields.size() < cmdIndex) { - break; - } - - String cmdline = fields.get(cmdIndex).replace("/system/bin/", ""); - String pssInK = fields.get(pssIndex); - if (pssInK.endsWith("K")) { - pssInK = pssInK.substring(0, pssInK.length() - 1); - } - long pss = safeParseLong(pssInK); - results.add(new DataValue(cmdline, pss)); - } - - return results; - } - - /** - * Processes sync information from bugreport. Updates mDataset with the new - * data. - * - * @param br Reader providing the content - * @throws IOException if error reading file - */ - public static List<DataValue> readSyncDataset(BufferedReader br) throws IOException { - List<DataValue> results = new ArrayList<DataValue>(); - - while (true) { - String line = br.readLine(); - if (line == null || line.startsWith("DUMP OF SERVICE")) { - // Done, or moved on to the next service - break; - } - if (line.startsWith(" |") && line.length() > 70) { - String authority = line.substring(3, 18).trim(); - String duration = line.substring(61, 70).trim(); - // Duration is MM:SS or HH:MM:SS (DateUtils.formatElapsedTime) - String durParts[] = duration.split(":"); - if (durParts.length == 2) { - long dur = Long.parseLong(durParts[0]) * 60 + Long - .parseLong(durParts[1]); - results.add(new DataValue(authority, dur)); - } else if (duration.length() == 3) { - long dur = Long.parseLong(durParts[0]) * 3600 - + Long.parseLong(durParts[1]) * 60 + Long - .parseLong(durParts[2]); - results.add(new DataValue(authority, dur)); - } - } - } - - return results; - } - } - - private void readCpuDataset(BufferedReader br) throws IOException { - updatePieDataSet(BugReportParser.readCpuDataset(br), ""); - } - - private void readMeminfoDataset(BufferedReader br) throws IOException { - updatePieDataSet(BugReportParser.readMeminfoDataset(br), "PSS in kB"); - } - - private void readGfxInfoDataset(BufferedReader br) throws IOException { - updateBarChartDataSet(BugReportParser.parseGfxInfo(br), - mGfxPackageName == null ? "" : mGfxPackageName); - } - - private void clearDataSet() { - mLabel.setText(""); - mDataset.clear(); - mBarDataSet.clear(); - } - - private void updatePieDataSet(final List<BugReportParser.DataValue> data, final String label) { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - mLabel.setText(label); - mStackLayout.topControl = mPieChartComposite; - mChartComposite.layout(); - - for (BugReportParser.DataValue d : data) { - mDataset.setValue(d.name, d.value); - } - } - }); - } - - private void updateBarChartDataSet(final List<GfxProfileData> gfxProfileData, - final String label) { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - mLabel.setText(label); - mStackLayout.topControl = mStackedBarComposite; - mChartComposite.layout(); - - for (int i = 0; i < gfxProfileData.size(); i++) { - GfxProfileData d = gfxProfileData.get(i); - String frameNumber = Integer.toString(i); - - mBarDataSet.addValue(d.draw, "Draw", frameNumber); - mBarDataSet.addValue(d.process, "Process", frameNumber); - mBarDataSet.addValue(d.execute, "Execute", frameNumber); - } - } - }); - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/TableHelper.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/TableHelper.java deleted file mode 100644 index 66dcc0a..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/TableHelper.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; - -/** - * Utility class to help using Table objects. - * - */ -public final class TableHelper { - /** - * Create a TableColumn with the specified parameters. If a - * <code>PreferenceStore</code> object and a preference entry name String - * object are provided then the column will listen to change in its width - * and update the preference store accordingly. - * - * @param parent The Table parent object - * @param header The header string - * @param style The column style - * @param sample_text A sample text to figure out column width if preference - * value is missing - * @param pref_name The preference entry name for column width - * @param prefs The preference store - * @return The TableColumn object that was created - */ - public static TableColumn createTableColumn(Table parent, String header, - int style, String sample_text, final String pref_name, - final IPreferenceStore prefs) { - - // create the column - TableColumn col = new TableColumn(parent, style); - - // if there is no pref store or the entry is missing, we use the sample - // text and pack the column. - // Otherwise we just read the width from the prefs and apply it. - if (prefs == null || prefs.contains(pref_name) == false) { - col.setText(sample_text); - col.pack(); - - // init the prefs store with the current value - if (prefs != null) { - prefs.setValue(pref_name, col.getWidth()); - } - } else { - col.setWidth(prefs.getInt(pref_name)); - } - - // set the header - col.setText(header); - - // if there is a pref store and a pref entry name, then we setup a - // listener to catch column resize to put store the new width value. - if (prefs != null && pref_name != null) { - col.addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - // get the new width - int w = ((TableColumn)e.widget).getWidth(); - - // store in pref store - prefs.setValue(pref_name, w); - } - }); - } - - return col; - } - - /** - * Create a TreeColumn with the specified parameters. If a - * <code>PreferenceStore</code> object and a preference entry name String - * object are provided then the column will listen to change in its width - * and update the preference store accordingly. - * - * @param parent The Table parent object - * @param header The header string - * @param style The column style - * @param sample_text A sample text to figure out column width if preference - * value is missing - * @param pref_name The preference entry name for column width - * @param prefs The preference store - */ - public static void createTreeColumn(Tree parent, String header, int style, - String sample_text, final String pref_name, - final IPreferenceStore prefs) { - - // create the column - TreeColumn col = new TreeColumn(parent, style); - - // if there is no pref store or the entry is missing, we use the sample - // text and pack the column. - // Otherwise we just read the width from the prefs and apply it. - if (prefs == null || prefs.contains(pref_name) == false) { - col.setText(sample_text); - col.pack(); - - // init the prefs store with the current value - if (prefs != null) { - prefs.setValue(pref_name, col.getWidth()); - } - } else { - col.setWidth(prefs.getInt(pref_name)); - } - - // set the header - col.setText(header); - - // if there is a pref store and a pref entry name, then we setup a - // listener to catch column resize to put store the new width value. - if (prefs != null && pref_name != null) { - col.addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - // get the new width - int w = ((TreeColumn)e.widget).getWidth(); - - // store in pref store - prefs.setValue(pref_name, w); - } - }); - } - } - - /** - * Create a TreeColumn with the specified parameters. If a - * <code>PreferenceStore</code> object and a preference entry name String - * object are provided then the column will listen to change in its width - * and update the preference store accordingly. - * - * @param parent The Table parent object - * @param header The header string - * @param style The column style - * @param width the width of the column if the preference value is missing - * @param pref_name The preference entry name for column width - * @param prefs The preference store - */ - public static void createTreeColumn(Tree parent, String header, int style, - int width, final String pref_name, - final IPreferenceStore prefs) { - - // create the column - TreeColumn col = new TreeColumn(parent, style); - - // if there is no pref store or the entry is missing, we use the sample - // text and pack the column. - // Otherwise we just read the width from the prefs and apply it. - if (prefs == null || prefs.contains(pref_name) == false) { - col.setWidth(width); - - // init the prefs store with the current value - if (prefs != null) { - prefs.setValue(pref_name, width); - } - } else { - col.setWidth(prefs.getInt(pref_name)); - } - - // set the header - col.setText(header); - - // if there is a pref store and a pref entry name, then we setup a - // listener to catch column resize to put store the new width value. - if (prefs != null && pref_name != null) { - col.addControlListener(new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - // get the new width - int w = ((TreeColumn)e.widget).getWidth(); - - // store in pref store - prefs.setValue(pref_name, w); - } - }); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/TablePanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/TablePanel.java deleted file mode 100644 index c1eb7f6..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/TablePanel.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmuilib.ITableFocusListener.IFocusedTableActivator; - -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; - -import java.util.Arrays; - -/** - * Base class for panel containing Table that need to support copy-paste-selectAll - */ -public abstract class TablePanel extends ClientDisplayPanel { - private ITableFocusListener mGlobalListener; - - /** - * Sets a TableFocusListener which will be notified when one of the tables - * gets or loses focus. - * - * @param listener - */ - public void setTableFocusListener(ITableFocusListener listener) { - // record the global listener, to make sure table created after - // this call will still be setup. - mGlobalListener = listener; - - setTableFocusListener(); - } - - /** - * Sets up the Table of object of the panel to work with the global listener.<br> - * Default implementation does nothing. - */ - protected void setTableFocusListener() { - - } - - /** - * Sets up a Table object to notify the global Table Focus listener when it - * gets or loses the focus. - * - * @param table the Table object. - * @param colStart - * @param colEnd - */ - protected final void addTableToFocusListener(final Table table, - final int colStart, final int colEnd) { - // create the activator for this table - final IFocusedTableActivator activator = new IFocusedTableActivator() { - @Override - public void copy(Clipboard clipboard) { - int[] selection = table.getSelectionIndices(); - - // we need to sort the items to be sure. - Arrays.sort(selection); - - // all lines must be concatenated. - StringBuilder sb = new StringBuilder(); - - // loop on the selection and output the file. - for (int i : selection) { - TableItem item = table.getItem(i); - for (int c = colStart ; c <= colEnd ; c++) { - sb.append(item.getText(c)); - sb.append('\t'); - } - sb.append('\n'); - } - - // now add that to the clipboard if the string has content - String data = sb.toString(); - if (data != null && data.length() > 0) { - clipboard.setContents( - new Object[] { data }, - new Transfer[] { TextTransfer.getInstance() }); - } - } - - @Override - public void selectAll() { - table.selectAll(); - } - }; - - // add the focus listener on the table to notify the global listener - table.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - mGlobalListener.focusGained(activator); - } - - @Override - public void focusLost(FocusEvent e) { - mGlobalListener.focusLost(activator); - } - }); - } - - /** - * Sets up a Table object to notify the global Table Focus listener when it - * gets or loses the focus.<br> - * When the copy method is invoked, all columns are put in the clipboard, separated - * by tabs - * - * @param table the Table object. - */ - protected final void addTableToFocusListener(final Table table) { - addTableToFocusListener(table, 0, table.getColumnCount()-1); - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ThreadPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ThreadPanel.java deleted file mode 100644 index 81e245d..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ThreadPanel.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.Client; -import com.android.ddmlib.ThreadInfo; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Sash; -import org.eclipse.swt.widgets.Table; - -import java.util.Date; - -/** - * Base class for our information panels. - */ -public class ThreadPanel extends TablePanel { - - private final static String PREFS_THREAD_COL_ID = "threadPanel.Col0"; //$NON-NLS-1$ - private final static String PREFS_THREAD_COL_TID = "threadPanel.Col1"; //$NON-NLS-1$ - private final static String PREFS_THREAD_COL_STATUS = "threadPanel.Col2"; //$NON-NLS-1$ - private final static String PREFS_THREAD_COL_UTIME = "threadPanel.Col3"; //$NON-NLS-1$ - private final static String PREFS_THREAD_COL_STIME = "threadPanel.Col4"; //$NON-NLS-1$ - private final static String PREFS_THREAD_COL_NAME = "threadPanel.Col5"; //$NON-NLS-1$ - - private final static String PREFS_THREAD_SASH = "threadPanel.sash"; //$NON-NLS-1$ - - private static final String PREFS_STACK_COLUMN = "threadPanel.stack.col0"; //$NON-NLS-1$ - - private Display mDisplay; - private Composite mBase; - private Label mNotEnabled; - private Label mNotSelected; - - private Composite mThreadBase; - private Table mThreadTable; - private TableViewer mThreadViewer; - - private Composite mStackTraceBase; - private Button mRefreshStackTraceButton; - private Label mStackTraceTimeLabel; - private StackTracePanel mStackTracePanel; - private Table mStackTraceTable; - - /** Indicates if a timer-based Runnable is current requesting thread updates regularly. */ - private boolean mMustStopRecurringThreadUpdate = false; - /** Flag to tell the recurring thread update to stop running */ - private boolean mRecurringThreadUpdateRunning = false; - - private Object mLock = new Object(); - - private static final String[] THREAD_STATUS = { - "Zombie", "Runnable", "TimedWait", "Monitor", - "Wait", "Initializing", "Starting", "Native", "VmWait", - "Suspended" - }; - - /** - * Content Provider to display the threads of a client. - * Expected input is a {@link Client} object. - */ - private static class ThreadContentProvider implements IStructuredContentProvider { - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof Client) { - return ((Client)inputElement).getClientData().getThreads(); - } - - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - } - - - /** - * A Label Provider to use with {@link ThreadContentProvider}. It expects the elements to be - * of type {@link ThreadInfo}. - */ - private static class ThreadLabelProvider implements ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof ThreadInfo) { - ThreadInfo thread = (ThreadInfo)element; - switch (columnIndex) { - case 0: - return (thread.isDaemon() ? "*" : "") + //$NON-NLS-1$ //$NON-NLS-2$ - String.valueOf(thread.getThreadId()); - case 1: - return String.valueOf(thread.getTid()); - case 2: - if (thread.getStatus() >= 0 && thread.getStatus() < THREAD_STATUS.length) - return THREAD_STATUS[thread.getStatus()]; - return "unknown"; - case 3: - return String.valueOf(thread.getUtime()); - case 4: - return String.valueOf(thread.getStime()); - case 5: - return thread.getThreadName(); - } - } - - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Create our control(s). - */ - @Override - protected Control createControl(Composite parent) { - mDisplay = parent.getDisplay(); - - final IPreferenceStore store = DdmUiPreferences.getStore(); - - mBase = new Composite(parent, SWT.NONE); - mBase.setLayout(new StackLayout()); - - // UI for thread not enabled - mNotEnabled = new Label(mBase, SWT.CENTER | SWT.WRAP); - mNotEnabled.setText("Thread updates not enabled for selected client\n" - + "(use toolbar button to enable)"); - - // UI for not client selected - mNotSelected = new Label(mBase, SWT.CENTER | SWT.WRAP); - mNotSelected.setText("no client is selected"); - - // base composite for selected client with enabled thread update. - mThreadBase = new Composite(mBase, SWT.NONE); - mThreadBase.setLayout(new FormLayout()); - - // table above the sash - mThreadTable = new Table(mThreadBase, SWT.MULTI | SWT.FULL_SELECTION); - mThreadTable.setHeaderVisible(true); - mThreadTable.setLinesVisible(true); - - TableHelper.createTableColumn( - mThreadTable, - "ID", - SWT.RIGHT, - "888", //$NON-NLS-1$ - PREFS_THREAD_COL_ID, store); - - TableHelper.createTableColumn( - mThreadTable, - "Tid", - SWT.RIGHT, - "88888", //$NON-NLS-1$ - PREFS_THREAD_COL_TID, store); - - TableHelper.createTableColumn( - mThreadTable, - "Status", - SWT.LEFT, - "timed-wait", //$NON-NLS-1$ - PREFS_THREAD_COL_STATUS, store); - - TableHelper.createTableColumn( - mThreadTable, - "utime", - SWT.RIGHT, - "utime", //$NON-NLS-1$ - PREFS_THREAD_COL_UTIME, store); - - TableHelper.createTableColumn( - mThreadTable, - "stime", - SWT.RIGHT, - "utime", //$NON-NLS-1$ - PREFS_THREAD_COL_STIME, store); - - TableHelper.createTableColumn( - mThreadTable, - "Name", - SWT.LEFT, - "android.class.ReallyLongClassName.MethodName", //$NON-NLS-1$ - PREFS_THREAD_COL_NAME, store); - - mThreadViewer = new TableViewer(mThreadTable); - mThreadViewer.setContentProvider(new ThreadContentProvider()); - mThreadViewer.setLabelProvider(new ThreadLabelProvider()); - - mThreadViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - requestThreadStackTrace(getThreadSelection(event.getSelection())); - } - }); - mThreadViewer.addDoubleClickListener(new IDoubleClickListener() { - @Override - public void doubleClick(DoubleClickEvent event) { - requestThreadStackTrace(getThreadSelection(event.getSelection())); - } - }); - - // the separating sash - final Sash sash = new Sash(mThreadBase, SWT.HORIZONTAL); - Color darkGray = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); - sash.setBackground(darkGray); - - // the UI below the sash - mStackTraceBase = new Composite(mThreadBase, SWT.NONE); - mStackTraceBase.setLayout(new GridLayout(2, false)); - - mRefreshStackTraceButton = new Button(mStackTraceBase, SWT.PUSH); - mRefreshStackTraceButton.setText("Refresh"); - mRefreshStackTraceButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - requestThreadStackTrace(getThreadSelection(null)); - } - }); - - mStackTraceTimeLabel = new Label(mStackTraceBase, SWT.NONE); - mStackTraceTimeLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mStackTracePanel = new StackTracePanel(); - mStackTraceTable = mStackTracePanel.createPanel(mStackTraceBase, PREFS_STACK_COLUMN, store); - - GridData gd; - mStackTraceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); - gd.horizontalSpan = 2; - - // now setup the sash. - // form layout data - FormData data = new FormData(); - data.top = new FormAttachment(0, 0); - data.bottom = new FormAttachment(sash, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mThreadTable.setLayoutData(data); - - final FormData sashData = new FormData(); - if (store != null && store.contains(PREFS_THREAD_SASH)) { - sashData.top = new FormAttachment(0, store.getInt(PREFS_THREAD_SASH)); - } else { - sashData.top = new FormAttachment(50,0); // 50% across - } - sashData.left = new FormAttachment(0, 0); - sashData.right = new FormAttachment(100, 0); - sash.setLayoutData(sashData); - - data = new FormData(); - data.top = new FormAttachment(sash, 0); - data.bottom = new FormAttachment(100, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mStackTraceBase.setLayoutData(data); - - // allow resizes, but cap at minPanelWidth - sash.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event e) { - Rectangle sashRect = sash.getBounds(); - Rectangle panelRect = mThreadBase.getClientArea(); - int bottom = panelRect.height - sashRect.height - 100; - e.y = Math.max(Math.min(e.y, bottom), 100); - if (e.y != sashRect.y) { - sashData.top = new FormAttachment(0, e.y); - store.setValue(PREFS_THREAD_SASH, e.y); - mThreadBase.layout(); - } - } - }); - - ((StackLayout)mBase.getLayout()).topControl = mNotSelected; - - return mBase; - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mThreadTable.setFocus(); - } - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client == getCurrentClient()) { - if ((changeMask & Client.CHANGE_THREAD_MODE) != 0 || - (changeMask & Client.CHANGE_THREAD_DATA) != 0) { - try { - mThreadTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - clientSelected(); - } - }); - } catch (SWTException e) { - // widget is disposed, we do nothing - } - } else if ((changeMask & Client.CHANGE_THREAD_STACKTRACE) != 0) { - try { - mThreadTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - updateThreadStackCall(); - } - }); - } catch (SWTException e) { - // widget is disposed, we do nothing - } - } - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()}. - */ - @Override - public void deviceSelected() { - // pass - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - if (mThreadTable.isDisposed()) { - return; - } - - Client client = getCurrentClient(); - - mStackTracePanel.setCurrentClient(client); - - if (client != null) { - if (!client.isThreadUpdateEnabled()) { - ((StackLayout)mBase.getLayout()).topControl = mNotEnabled; - mThreadViewer.setInput(null); - - // if we are currently updating the thread, stop doing it. - mMustStopRecurringThreadUpdate = true; - } else { - ((StackLayout)mBase.getLayout()).topControl = mThreadBase; - mThreadViewer.setInput(client); - - synchronized (mLock) { - // if we're not updating we start the process - if (mRecurringThreadUpdateRunning == false) { - startRecurringThreadUpdate(); - } else if (mMustStopRecurringThreadUpdate) { - // else if there's a runnable that's still going to get called, lets - // simply cancel the stop, and keep going - mMustStopRecurringThreadUpdate = false; - } - } - } - } else { - ((StackLayout)mBase.getLayout()).topControl = mNotSelected; - mThreadViewer.setInput(null); - } - - mBase.layout(); - } - - private void requestThreadStackTrace(ThreadInfo selectedThread) { - if (selectedThread != null) { - Client client = (Client) mThreadViewer.getInput(); - if (client != null) { - client.requestThreadStackTrace(selectedThread.getThreadId()); - } - } - } - - /** - * Updates the stack call of the currently selected thread. - * <p/> - * This <b>must</b> be called from the UI thread. - */ - private void updateThreadStackCall() { - Client client = getCurrentClient(); - if (client != null) { - // get the current selection in the ThreadTable - ThreadInfo selectedThread = getThreadSelection(null); - - if (selectedThread != null) { - updateThreadStackTrace(selectedThread); - } else { - updateThreadStackTrace(null); - } - } - } - - /** - * updates the stackcall of the specified thread. If <code>null</code> the UI is emptied - * of current data. - * @param thread - */ - private void updateThreadStackTrace(ThreadInfo thread) { - mStackTracePanel.setViewerInput(thread); - - if (thread != null) { - mRefreshStackTraceButton.setEnabled(true); - long stackcallTime = thread.getStackCallTime(); - if (stackcallTime != 0) { - String label = new Date(stackcallTime).toString(); - mStackTraceTimeLabel.setText(label); - } else { - mStackTraceTimeLabel.setText(""); //$NON-NLS-1$ - } - } else { - mRefreshStackTraceButton.setEnabled(true); - mStackTraceTimeLabel.setText(""); //$NON-NLS-1$ - } - } - - @Override - protected void setTableFocusListener() { - addTableToFocusListener(mThreadTable); - addTableToFocusListener(mStackTraceTable); - } - - /** - * Initiate recurring events. We use a shorter "initialWait" so we do the - * first execution sooner. We don't do it immediately because we want to - * give the clients a chance to get set up. - */ - private void startRecurringThreadUpdate() { - mRecurringThreadUpdateRunning = true; - int initialWait = 1000; - - mDisplay.timerExec(initialWait, new Runnable() { - @Override - public void run() { - synchronized (mLock) { - // lets check we still want updates. - if (mMustStopRecurringThreadUpdate == false) { - Client client = getCurrentClient(); - if (client != null) { - client.requestThreadUpdate(); - - mDisplay.timerExec( - DdmUiPreferences.getThreadRefreshInterval() * 1000, this); - } else { - // we don't have a Client, which means the runnable is not - // going to be called through the timer. We reset the running flag. - mRecurringThreadUpdateRunning = false; - } - } else { - // else actually stops (don't call the timerExec) and reset the flags. - mRecurringThreadUpdateRunning = false; - mMustStopRecurringThreadUpdate = false; - } - } - } - }); - } - - /** - * Returns the current thread selection or <code>null</code> if none is found. - * If a {@link ISelection} object is specified, the first {@link ThreadInfo} from this selection - * is returned, otherwise, the <code>ISelection</code> returned by - * {@link TableViewer#getSelection()} is used. - * @param selection the {@link ISelection} to use, or <code>null</code> - */ - private ThreadInfo getThreadSelection(ISelection selection) { - if (selection == null) { - selection = mThreadViewer.getSelection(); - } - - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object object = structuredSelection.getFirstElement(); - if (object instanceof ThreadInfo) { - return (ThreadInfo)object; - } - } - - return null; - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ICommonAction.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ICommonAction.java deleted file mode 100644 index 856b874..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ICommonAction.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2007 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.actions; - -/** - * Common interface for basic action handling. This allows the common ui - * components to access ToolItem or Action the same way. - */ -public interface ICommonAction { - /** - * Sets the enabled state of this action. - * @param enabled <code>true</code> to enable, and - * <code>false</code> to disable - */ - public void setEnabled(boolean enabled); - - /** - * Sets the checked status of this action. - * @param checked the new checked status - */ - public void setChecked(boolean checked); - - /** - * Sets the {@link Runnable} that will be executed when the action is triggered. - */ - public void setRunnable(Runnable runnable); -} - diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ToolItemAction.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ToolItemAction.java deleted file mode 100644 index c7fef32..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ToolItemAction.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2007 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.actions; - -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; - -/** - * Wrapper around {@link ToolItem} to implement {@link ICommonAction} - */ -public class ToolItemAction implements ICommonAction { - public ToolItem item; - - public ToolItemAction(ToolBar parent, int style) { - item = new ToolItem(parent, style); - } - - /** - * Sets the enabled state of this action. - * @param enabled <code>true</code> to enable, and - * <code>false</code> to disable - * @see ICommonAction#setChecked(boolean) - */ - @Override - public void setChecked(boolean checked) { - item.setSelection(checked); - } - - /** - * Sets the enabled state of this action. - * @param enabled <code>true</code> to enable, and - * <code>false</code> to disable - * @see ICommonAction#setEnabled(boolean) - */ - @Override - public void setEnabled(boolean enabled) { - item.setEnabled(enabled); - } - - /** - * Sets the {@link Runnable} that will be executed when the action is triggered (through - * {@link SelectionListener#widgetSelected(SelectionEvent)} on the wrapped {@link ToolItem}). - * @see ICommonAction#setRunnable(Runnable) - */ - @Override - public void setRunnable(final Runnable runnable) { - item.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - runnable.run(); - } - }); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/UiThread.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/UiThread.java deleted file mode 100644 index 8e9e11b..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/UiThread.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Simple utility annotation used only to mark methods that are executed on the UI thread. - * This annotation's sole purpose is to help reading the source code. It has no additional effect. - */ -@Target({ ElementType.METHOD }) -@Retention(RetentionPolicy.SOURCE) -public @interface UiThread { -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/WorkerThread.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/WorkerThread.java deleted file mode 100644 index e767eda..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/WorkerThread.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Simple utility annotation used only to mark methods that are not executed on the UI thread. - * This annotation's sole purpose is to help reading the source code. It has no additional effect. - */ -@Target({ ElementType.METHOD }) -@Retention(RetentionPolicy.SOURCE) -public @interface WorkerThread { -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/DdmConsole.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/DdmConsole.java deleted file mode 100644 index 4df4376..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/DdmConsole.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2007 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.console; - - -/** - * Static Console used to ouput messages. By default outputs the message to System.out and - * System.err, but can receive a IDdmConsole object which will actually do something. - */ -public class DdmConsole { - - private static IDdmConsole mConsole; - - /** - * Prints a message to the android console. - * @param message the message to print - * @param forceDisplay if true, this force the console to be displayed. - */ - public static void printErrorToConsole(String message) { - if (mConsole != null) { - mConsole.printErrorToConsole(message); - } else { - System.err.println(message); - } - } - - /** - * Prints several messages to the android console. - * @param messages the messages to print - * @param forceDisplay if true, this force the console to be displayed. - */ - public static void printErrorToConsole(String[] messages) { - if (mConsole != null) { - mConsole.printErrorToConsole(messages); - } else { - for (String message : messages) { - System.err.println(message); - } - } - } - - /** - * Prints a message to the android console. - * @param message the message to print - * @param forceDisplay if true, this force the console to be displayed. - */ - public static void printToConsole(String message) { - if (mConsole != null) { - mConsole.printToConsole(message); - } else { - System.out.println(message); - } - } - - /** - * Prints several messages to the android console. - * @param messages the messages to print - * @param forceDisplay if true, this force the console to be displayed. - */ - public static void printToConsole(String[] messages) { - if (mConsole != null) { - mConsole.printToConsole(messages); - } else { - for (String message : messages) { - System.out.println(message); - } - } - } - - /** - * Sets a IDdmConsole to override the default behavior of the console - * @param console The new IDdmConsole - * **/ - public static void setConsole(IDdmConsole console) { - mConsole = console; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/IDdmConsole.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/IDdmConsole.java deleted file mode 100644 index 3679d41..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/console/IDdmConsole.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 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.console; - - -/** - * DDMS console interface. - */ -public interface IDdmConsole { - /** - * Prints a message to the android console. - * @param message the message to print - */ - public void printErrorToConsole(String message); - - /** - * Prints several messages to the android console. - * @param messages the messages to print - */ - public void printErrorToConsole(String[] messages); - - /** - * Prints a message to the android console. - * @param message the message to print - */ - public void printToConsole(String message); - - /** - * Prints several messages to the android console. - * @param messages the messages to print - */ - public void printToConsole(String[] messages); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceContentProvider.java deleted file mode 100644 index 062d4f0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceContentProvider.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2007 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.explorer; - -import com.android.ddmlib.FileListingService; -import com.android.ddmlib.FileListingService.FileEntry; -import com.android.ddmlib.FileListingService.IListingReceiver; - -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Tree; - -/** - * Content provider class for device Explorer. - */ -class DeviceContentProvider implements ITreeContentProvider { - - private TreeViewer mViewer; - private FileListingService mFileListingService; - private FileEntry mRootEntry; - - private IListingReceiver sListingReceiver = new IListingReceiver() { - @Override - public void setChildren(final FileEntry entry, FileEntry[] children) { - final Tree t = mViewer.getTree(); - if (t != null && t.isDisposed() == false) { - Display display = t.getDisplay(); - if (display.isDisposed() == false) { - display.asyncExec(new Runnable() { - @Override - public void run() { - if (t.isDisposed() == false) { - // refresh the entry. - mViewer.refresh(entry); - - // force it open, since on linux and windows - // when getChildren() returns null, the node is - // not considered expanded. - mViewer.setExpandedState(entry, true); - } - } - }); - } - } - } - - @Override - public void refreshEntry(final FileEntry entry) { - final Tree t = mViewer.getTree(); - if (t != null && t.isDisposed() == false) { - Display display = t.getDisplay(); - if (display.isDisposed() == false) { - display.asyncExec(new Runnable() { - @Override - public void run() { - if (t.isDisposed() == false) { - // refresh the entry. - mViewer.refresh(entry); - } - } - }); - } - } - } - }; - - /** - * - */ - public DeviceContentProvider() { - } - - public void setListingService(FileListingService fls) { - mFileListingService = fls; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) - */ - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof FileEntry) { - FileEntry parentEntry = (FileEntry)parentElement; - - Object[] oldEntries = parentEntry.getCachedChildren(); - Object[] newEntries = mFileListingService.getChildren(parentEntry, - true, sListingReceiver); - - if (newEntries != null) { - return newEntries; - } else { - // if null was returned, this means the cache was not valid, - // and a thread was launched for ls. sListingReceiver will be - // notified with the new entries. - return oldEntries; - } - } - return new Object[0]; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) - */ - @Override - public Object getParent(Object element) { - if (element instanceof FileEntry) { - FileEntry entry = (FileEntry)element; - - return entry.getParent(); - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) - */ - @Override - public boolean hasChildren(Object element) { - if (element instanceof FileEntry) { - FileEntry entry = (FileEntry)element; - - return entry.getType() == FileListingService.TYPE_DIRECTORY; - } - return false; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) - */ - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof FileEntry) { - FileEntry entry = (FileEntry)inputElement; - if (entry.isRoot()) { - return getChildren(mRootEntry); - } - } - - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IContentProvider#dispose() - */ - @Override - public void dispose() { - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) - */ - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - if (viewer instanceof TreeViewer) { - mViewer = (TreeViewer)viewer; - } - if (newInput instanceof FileEntry) { - mRootEntry = (FileEntry)newInput; - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java deleted file mode 100644 index b69d3b5..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java +++ /dev/null @@ -1,922 +0,0 @@ -/* - * Copyright (C) 2007 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.explorer; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.DdmConstants; -import com.android.ddmlib.FileListingService; -import com.android.ddmlib.FileListingService.FileEntry; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.IShellOutputReceiver; -import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.SyncException; -import com.android.ddmlib.SyncService; -import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.ImageLoader; -import com.android.ddmuilib.Panel; -import com.android.ddmuilib.SyncProgressHelper; -import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; -import com.android.ddmuilib.TableHelper; -import com.android.ddmuilib.actions.ICommonAction; -import com.android.ddmuilib.console.DdmConsole; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.IInputValidator; -import org.eclipse.jface.dialogs.InputDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.ViewerDropAdapter; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.DND; -import org.eclipse.swt.dnd.FileTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.dnd.TransferData; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Device filesystem explorer class. - */ -public class DeviceExplorer extends Panel { - - private final static String TRACE_KEY_EXT = ".key"; // $NON-NLS-1S - private final static String TRACE_DATA_EXT = ".data"; // $NON-NLS-1S - - private static Pattern mKeyFilePattern = Pattern.compile( - "(.+)\\" + TRACE_KEY_EXT); // $NON-NLS-1S - private static Pattern mDataFilePattern = Pattern.compile( - "(.+)\\" + TRACE_DATA_EXT); // $NON-NLS-1S - - public static String COLUMN_NAME = "android.explorer.name"; //$NON-NLS-1S - public static String COLUMN_SIZE = "android.explorer.size"; //$NON-NLS-1S - public static String COLUMN_DATE = "android.explorer.data"; //$NON-NLS-1S - public static String COLUMN_TIME = "android.explorer.time"; //$NON-NLS-1S - public static String COLUMN_PERMISSIONS = "android.explorer.permissions"; // $NON-NLS-1S - public static String COLUMN_INFO = "android.explorer.info"; // $NON-NLS-1S - - private Composite mParent; - private TreeViewer mTreeViewer; - private Tree mTree; - private DeviceContentProvider mContentProvider; - - private ICommonAction mPushAction; - private ICommonAction mPullAction; - private ICommonAction mDeleteAction; - private ICommonAction mCreateNewFolderAction; - - private Image mFileImage; - private Image mFolderImage; - private Image mPackageImage; - private Image mOtherImage; - - private IDevice mCurrentDevice; - - private String mDefaultSave; - - public DeviceExplorer() { - } - - /** - * Sets custom images for the device explorer. If none are set then defaults are used. - * This can be useful to set platform-specific explorer icons. - * - * This should be called before {@link #createControl(Composite)}. - * - * @param fileImage the icon to represent a file. - * @param folderImage the icon to represent a folder. - * @param packageImage the icon to represent an apk. - * @param otherImage the icon to represent other types of files. - */ - public void setCustomImages(Image fileImage, Image folderImage, Image packageImage, - Image otherImage) { - mFileImage = fileImage; - mFolderImage = folderImage; - mPackageImage = packageImage; - mOtherImage = otherImage; - } - - /** - * Sets the actions so that the device explorer can enable/disable them based on the current - * selection - * @param pushAction - * @param pullAction - * @param deleteAction - * @param createNewFolderAction - */ - public void setActions(ICommonAction pushAction, ICommonAction pullAction, - ICommonAction deleteAction, ICommonAction createNewFolderAction) { - mPushAction = pushAction; - mPullAction = pullAction; - mDeleteAction = deleteAction; - mCreateNewFolderAction = createNewFolderAction; - } - - /** - * Creates a control capable of displaying some information. This is - * called once, when the application is initializing, from the UI thread. - */ - @Override - protected Control createControl(Composite parent) { - mParent = parent; - parent.setLayout(new FillLayout()); - - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - if (mFileImage == null) { - mFileImage = loader.loadImage("file.png", mParent.getDisplay()); - } - if (mFolderImage == null) { - mFolderImage = loader.loadImage("folder.png", mParent.getDisplay()); - } - if (mPackageImage == null) { - mPackageImage = loader.loadImage("android.png", mParent.getDisplay()); - } - if (mOtherImage == null) { - // TODO: find a default image for other. - } - - mTree = new Tree(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL); - mTree.setHeaderVisible(true); - - IPreferenceStore store = DdmUiPreferences.getStore(); - - // create columns - TableHelper.createTreeColumn(mTree, "Name", SWT.LEFT, - "0000drwxrwxrwx", COLUMN_NAME, store); //$NON-NLS-1$ - TableHelper.createTreeColumn(mTree, "Size", SWT.RIGHT, - "000000", COLUMN_SIZE, store); //$NON-NLS-1$ - TableHelper.createTreeColumn(mTree, "Date", SWT.LEFT, - "2007-08-14", COLUMN_DATE, store); //$NON-NLS-1$ - TableHelper.createTreeColumn(mTree, "Time", SWT.LEFT, - "20:54", COLUMN_TIME, store); //$NON-NLS-1$ - TableHelper.createTreeColumn(mTree, "Permissions", SWT.LEFT, - "drwxrwxrwx", COLUMN_PERMISSIONS, store); //$NON-NLS-1$ - TableHelper.createTreeColumn(mTree, "Info", SWT.LEFT, - "drwxrwxrwx", COLUMN_INFO, store); //$NON-NLS-1$ - - // create the jface wrapper - mTreeViewer = new TreeViewer(mTree); - - // setup data provider - mContentProvider = new DeviceContentProvider(); - mTreeViewer.setContentProvider(mContentProvider); - mTreeViewer.setLabelProvider(new FileLabelProvider(mFileImage, - mFolderImage, mPackageImage, mOtherImage)); - - // setup a listener for selection - mTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - ISelection sel = event.getSelection(); - if (sel.isEmpty()) { - mPullAction.setEnabled(false); - mPushAction.setEnabled(false); - mDeleteAction.setEnabled(false); - mCreateNewFolderAction.setEnabled(false); - return; - } - if (sel instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection) sel; - Object element = selection.getFirstElement(); - if (element == null) - return; - if (element instanceof FileEntry) { - mPullAction.setEnabled(true); - mPushAction.setEnabled(selection.size() == 1); - if (selection.size() == 1) { - FileEntry entry = (FileEntry) element; - setDeleteEnabledState(entry); - mCreateNewFolderAction.setEnabled(entry.isDirectory()); - } else { - mDeleteAction.setEnabled(false); - } - } - } - } - }); - - // add support for double click - mTreeViewer.addDoubleClickListener(new IDoubleClickListener() { - @Override - public void doubleClick(DoubleClickEvent event) { - ISelection sel = event.getSelection(); - - if (sel instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection) sel; - - if (selection.size() == 1) { - FileEntry entry = (FileEntry)selection.getFirstElement(); - String name = entry.getName(); - - FileEntry parentEntry = entry.getParent(); - - // can't really do anything with no parent - if (parentEntry == null) { - return; - } - - // check this is a file like we want. - Matcher m = mKeyFilePattern.matcher(name); - if (m.matches()) { - // get the name w/o the extension - String baseName = m.group(1); - - // add the data extension - String dataName = baseName + TRACE_DATA_EXT; - - FileEntry dataEntry = parentEntry.findChild(dataName); - - handleTraceDoubleClick(baseName, entry, dataEntry); - - } else { - m = mDataFilePattern.matcher(name); - if (m.matches()) { - // get the name w/o the extension - String baseName = m.group(1); - - // add the key extension - String keyName = baseName + TRACE_KEY_EXT; - - FileEntry keyEntry = parentEntry.findChild(keyName); - - handleTraceDoubleClick(baseName, keyEntry, entry); - } - } - } - } - } - }); - - // setup drop listener - mTreeViewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, - new Transfer[] { FileTransfer.getInstance() }, - new ViewerDropAdapter(mTreeViewer) { - @Override - public boolean performDrop(Object data) { - // get the item on which we dropped the item(s) - FileEntry target = (FileEntry)getCurrentTarget(); - - // in case we drop at the same level as root - if (target == null) { - return false; - } - - // if the target is not a directory, we get the parent directory - if (target.isDirectory() == false) { - target = target.getParent(); - } - - if (target == null) { - return false; - } - - // get the list of files to drop - String[] files = (String[])data; - - // do the drop - pushFiles(files, target); - - // we need to finish with a refresh - refresh(target); - - return true; - } - - @Override - public boolean validateDrop(Object target, int operation, TransferData transferType) { - if (target == null) { - return false; - } - - // convert to the real item - FileEntry targetEntry = (FileEntry)target; - - // if the target is not a directory, we get the parent directory - if (targetEntry.isDirectory() == false) { - target = targetEntry.getParent(); - } - - if (target == null) { - return false; - } - - return true; - } - }); - - // create and start the refresh thread - new Thread("Device Ls refresher") { - @Override - public void run() { - while (true) { - try { - sleep(FileListingService.REFRESH_RATE); - } catch (InterruptedException e) { - return; - } - - if (mTree != null && mTree.isDisposed() == false) { - Display display = mTree.getDisplay(); - if (display.isDisposed() == false) { - display.asyncExec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - mTreeViewer.refresh(true); - } - } - }); - } else { - return; - } - } else { - return; - } - } - - } - }.start(); - - return mTree; - } - - @Override - protected void postCreation() { - - } - - /** - * Sets the focus to the proper control inside the panel. - */ - @Override - public void setFocus() { - mTree.setFocus(); - } - - /** - * Processes a double click on a trace file - * @param baseName the base name of the 2 files. - * @param keyEntry The FileEntry for the .key file. - * @param dataEntry The FileEntry for the .data file. - */ - private void handleTraceDoubleClick(String baseName, FileEntry keyEntry, - FileEntry dataEntry) { - // first we need to download the files. - File keyFile; - File dataFile; - String path; - try { - // create a temp file for keyFile - File f = File.createTempFile(baseName, DdmConstants.DOT_TRACE); - f.delete(); - f.mkdir(); - - path = f.getAbsolutePath(); - - keyFile = new File(path + File.separator + keyEntry.getName()); - dataFile = new File(path + File.separator + dataEntry.getName()); - } catch (IOException e) { - return; - } - - // download the files - try { - SyncService sync = mCurrentDevice.getSyncService(); - if (sync != null) { - ISyncProgressMonitor monitor = SyncService.getNullProgressMonitor(); - sync.pullFile(keyEntry, keyFile.getAbsolutePath(), monitor); - sync.pullFile(dataEntry, dataFile.getAbsolutePath(), monitor); - - // now that we have the file, we need to launch traceview - String[] command = new String[2]; - command[0] = DdmUiPreferences.getTraceview(); - command[1] = path + File.separator + baseName; - - try { - final Process p = Runtime.getRuntime().exec(command); - - // create a thread for the output - new Thread("Traceview output") { - @Override - public void run() { - // create a buffer to read the stderr output - InputStreamReader is = new InputStreamReader(p.getErrorStream()); - BufferedReader resultReader = new BufferedReader(is); - - // read the lines as they come. if null is returned, it's - // because the process finished - try { - while (true) { - String line = resultReader.readLine(); - if (line != null) { - DdmConsole.printErrorToConsole("Traceview: " + line); - } else { - break; - } - } - // get the return code from the process - p.waitFor(); - } catch (IOException e) { - } catch (InterruptedException e) { - - } - } - }.start(); - - } catch (IOException e) { - } - } - } catch (IOException e) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); - return; - } catch (SyncException e) { - if (e.wasCanceled() == false) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); - return; - } - } catch (TimeoutException e) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: timeout", keyEntry.getName())); - } catch (AdbCommandRejectedException e) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); - } - } - - /** - * Pull the current selection on the local drive. This method displays - * a dialog box to let the user select where to store the file(s) and - * folder(s). - */ - public void pullSelection() { - // get the selection - TreeItem[] items = mTree.getSelection(); - - // name of the single file pull, or null if we're pulling a directory - // or more than one object. - String filePullName = null; - FileEntry singleEntry = null; - - // are we pulling a single file? - if (items.length == 1) { - singleEntry = (FileEntry)items[0].getData(); - if (singleEntry.getType() == FileListingService.TYPE_FILE) { - filePullName = singleEntry.getName(); - } - } - - // where do we save by default? - String defaultPath = mDefaultSave; - if (defaultPath == null) { - defaultPath = System.getProperty("user.home"); //$NON-NLS-1$ - } - - if (filePullName != null) { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.SAVE); - - fileDialog.setText("Get Device File"); - fileDialog.setFileName(filePullName); - fileDialog.setFilterPath(defaultPath); - - String fileName = fileDialog.open(); - if (fileName != null) { - mDefaultSave = fileDialog.getFilterPath(); - - pullFile(singleEntry, fileName); - } - } else { - DirectoryDialog directoryDialog = new DirectoryDialog(mParent.getShell(), SWT.SAVE); - - directoryDialog.setText("Get Device Files/Folders"); - directoryDialog.setFilterPath(defaultPath); - - String directoryName = directoryDialog.open(); - if (directoryName != null) { - pullSelection(items, directoryName); - } - } - } - - /** - * Push new file(s) and folder(s) into the current selection. Current - * selection must be single item. If the current selection is not a - * directory, the parent directory is used. - * This method displays a dialog to let the user choose file to push to - * the device. - */ - public void pushIntoSelection() { - // get the name of the object we're going to pull - TreeItem[] items = mTree.getSelection(); - - if (items.length == 0) { - return; - } - - FileDialog dlg = new FileDialog(mParent.getShell(), SWT.OPEN); - String fileName; - - dlg.setText("Put File on Device"); - - // There should be only one. - FileEntry entry = (FileEntry)items[0].getData(); - dlg.setFileName(entry.getName()); - - String defaultPath = mDefaultSave; - if (defaultPath == null) { - defaultPath = System.getProperty("user.home"); //$NON-NLS-1$ - } - dlg.setFilterPath(defaultPath); - - fileName = dlg.open(); - if (fileName != null) { - mDefaultSave = dlg.getFilterPath(); - - // we need to figure out the remote path based on the current selection type. - String remotePath; - FileEntry toRefresh = entry; - if (entry.isDirectory()) { - remotePath = entry.getFullPath(); - } else { - toRefresh = entry.getParent(); - remotePath = toRefresh.getFullPath(); - } - - pushFile(fileName, remotePath); - mTreeViewer.refresh(toRefresh); - } - } - - public void deleteSelection() { - // get the name of the object we're going to pull - TreeItem[] items = mTree.getSelection(); - - if (items.length != 1) { - return; - } - - FileEntry entry = (FileEntry)items[0].getData(); - final FileEntry parentEntry = entry.getParent(); - - // create the delete command - String command = "rm " + entry.getFullEscapedPath(); //$NON-NLS-1$ - - try { - mCurrentDevice.executeShellCommand(command, new IShellOutputReceiver() { - @Override - public void addOutput(byte[] data, int offset, int length) { - // pass - // TODO get output to display errors if any. - } - - @Override - public void flush() { - mTreeViewer.refresh(parentEntry); - } - - @Override - public boolean isCancelled() { - return false; - } - }); - } catch (IOException e) { - // adb failed somehow, we do nothing. We should be displaying the error from the output - // of the shell command. - } catch (TimeoutException e) { - // adb failed somehow, we do nothing. We should be displaying the error from the output - // of the shell command. - } catch (AdbCommandRejectedException e) { - // adb failed somehow, we do nothing. We should be displaying the error from the output - // of the shell command. - } catch (ShellCommandUnresponsiveException e) { - // adb failed somehow, we do nothing. We should be displaying the error from the output - // of the shell command. - } - - } - - public void createNewFolderInSelection() { - TreeItem[] items = mTree.getSelection(); - - if (items.length != 1) { - return; - } - - final FileEntry entry = (FileEntry) items[0].getData(); - - if (entry.isDirectory()) { - InputDialog inputDialog = new InputDialog(mTree.getShell(), "New Folder", - "Please enter the new folder name", "New Folder", new IInputValidator() { - @Override - public String isValid(String newText) { - if ((newText != null) && (newText.length() > 0) - && (newText.trim().length() > 0) - && (newText.indexOf('/') == -1) - && (newText.indexOf('\\') == -1)) { - return null; - } else { - return "Invalid name"; - } - } - }); - inputDialog.open(); - String value = inputDialog.getValue(); - - if (value != null) { - // create the mkdir command - String command = "mkdir " + entry.getFullEscapedPath() //$NON-NLS-1$ - + FileListingService.FILE_SEPARATOR + FileEntry.escape(value); - - try { - mCurrentDevice.executeShellCommand(command, new IShellOutputReceiver() { - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public void flush() { - mTreeViewer.refresh(entry); - } - - @Override - public void addOutput(byte[] data, int offset, int length) { - String errorMessage; - if (data != null) { - errorMessage = new String(data); - } else { - errorMessage = ""; - } - Status status = new Status(IStatus.ERROR, - "DeviceExplorer", 0, errorMessage, null); //$NON-NLS-1$ - ErrorDialog.openError(mTree.getShell(), "New Folder Error", - "New Folder Error", status); - } - }); - } catch (TimeoutException e) { - // adb failed somehow, we do nothing. We should be - // displaying the error from the output of the shell - // command. - } catch (AdbCommandRejectedException e) { - // adb failed somehow, we do nothing. We should be - // displaying the error from the output of the shell - // command. - } catch (ShellCommandUnresponsiveException e) { - // adb failed somehow, we do nothing. We should be - // displaying the error from the output of the shell - // command. - } catch (IOException e) { - // adb failed somehow, we do nothing. We should be - // displaying the error from the output of the shell - // command. - } - } - } - } - - /** - * Force a full refresh of the explorer. - */ - public void refresh() { - mTreeViewer.refresh(true); - } - - /** - * Sets the new device to explorer - */ - public void switchDevice(final IDevice device) { - if (device != mCurrentDevice) { - mCurrentDevice = device; - // now we change the input. but we need to do that in the - // ui thread. - if (mTree.isDisposed() == false) { - Display d = mTree.getDisplay(); - d.asyncExec(new Runnable() { - @Override - public void run() { - if (mTree.isDisposed() == false) { - // new service - if (mCurrentDevice != null) { - FileListingService fls = mCurrentDevice.getFileListingService(); - mContentProvider.setListingService(fls); - mTreeViewer.setInput(fls.getRoot()); - } - } - } - }); - } - } - } - - /** - * Refresh an entry from a non ui thread. - * @param entry the entry to refresh. - */ - private void refresh(final FileEntry entry) { - Display d = mTreeViewer.getTree().getDisplay(); - d.asyncExec(new Runnable() { - @Override - public void run() { - mTreeViewer.refresh(entry); - } - }); - } - - /** - * Pulls the selection from a device. - * @param items the tree selection the remote file on the device - * @param localDirector the local directory in which to save the files. - */ - private void pullSelection(TreeItem[] items, final String localDirectory) { - try { - final SyncService sync = mCurrentDevice.getSyncService(); - if (sync != null) { - // make a list of the FileEntry. - ArrayList<FileEntry> entries = new ArrayList<FileEntry>(); - for (TreeItem item : items) { - Object data = item.getData(); - if (data instanceof FileEntry) { - entries.add((FileEntry)data); - } - } - final FileEntry[] entryArray = entries.toArray( - new FileEntry[entries.size()]); - - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) - throws SyncException, IOException, TimeoutException { - sync.pull(entryArray, localDirectory, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, "Pulling file(s) from the device", mParent.getShell()); - } - } catch (SyncException e) { - if (e.wasCanceled() == false) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull selection: %1$s", e.getMessage())); - } - } catch (Exception e) { - DdmConsole.printErrorToConsole( "Failed to pull selection"); - DdmConsole.printErrorToConsole(e.getMessage()); - } - } - - /** - * Pulls a file from a device. - * @param remote the remote file on the device - * @param local the destination filepath - */ - private void pullFile(final FileEntry remote, final String local) { - try { - final SyncService sync = mCurrentDevice.getSyncService(); - if (sync != null) { - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) - throws SyncException, IOException, TimeoutException { - sync.pullFile(remote, local, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, String.format("Pulling %1$s from the device", remote.getName()), - mParent.getShell()); - } - } catch (SyncException e) { - if (e.wasCanceled() == false) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull selection: %1$s", e.getMessage())); - } - } catch (Exception e) { - DdmConsole.printErrorToConsole( "Failed to pull selection"); - DdmConsole.printErrorToConsole(e.getMessage()); - } - } - - /** - * Pushes several files and directory into a remote directory. - * @param localFiles - * @param remoteDirectory - */ - private void pushFiles(final String[] localFiles, final FileEntry remoteDirectory) { - try { - final SyncService sync = mCurrentDevice.getSyncService(); - if (sync != null) { - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) - throws SyncException, IOException, TimeoutException { - sync.push(localFiles, remoteDirectory, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, "Pushing file(s) to the device", mParent.getShell()); - } - } catch (SyncException e) { - if (e.wasCanceled() == false) { - DdmConsole.printErrorToConsole(String.format( - "Failed to push selection: %1$s", e.getMessage())); - } - } catch (Exception e) { - DdmConsole.printErrorToConsole("Failed to push the items"); - DdmConsole.printErrorToConsole(e.getMessage()); - } - } - - /** - * Pushes a file on a device. - * @param local the local filepath of the file to push - * @param remoteDirectory the remote destination directory on the device - */ - private void pushFile(final String local, final String remoteDirectory) { - try { - final SyncService sync = mCurrentDevice.getSyncService(); - if (sync != null) { - // get the file name - String[] segs = local.split(Pattern.quote(File.separator)); - String name = segs[segs.length-1]; - final String remoteFile = remoteDirectory + FileListingService.FILE_SEPARATOR - + name; - - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) - throws SyncException, IOException, TimeoutException { - sync.pushFile(local, remoteFile, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, String.format("Pushing %1$s to the device.", name), mParent.getShell()); - } - } catch (SyncException e) { - if (e.wasCanceled() == false) { - DdmConsole.printErrorToConsole(String.format( - "Failed to push selection: %1$s", e.getMessage())); - } - } catch (Exception e) { - DdmConsole.printErrorToConsole("Failed to push the item(s)."); - DdmConsole.printErrorToConsole(e.getMessage()); - } - } - - /** - * Sets the enabled state based on a FileEntry properties - * @param element The selected FileEntry - */ - protected void setDeleteEnabledState(FileEntry element) { - mDeleteAction.setEnabled(element.getType() == FileListingService.TYPE_FILE); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/FileLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/FileLabelProvider.java deleted file mode 100644 index 1240e59..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/FileLabelProvider.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2007 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.explorer; - -import com.android.ddmlib.FileListingService; -import com.android.ddmlib.FileListingService.FileEntry; - -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.graphics.Image; - -/** - * Label provider for the FileEntry. - */ -class FileLabelProvider implements ILabelProvider, ITableLabelProvider { - - private Image mFileImage; - private Image mFolderImage; - private Image mPackageImage; - private Image mOtherImage; - - /** - * Creates Label provider with custom images. - * @param fileImage the Image to represent a file - * @param folderImage the Image to represent a folder - * @param packageImage the Image to represent a .apk file. If null, - * fileImage is used instead. - * @param otherImage the Image to represent all other entry type. - */ - public FileLabelProvider(Image fileImage, Image folderImage, - Image packageImage, Image otherImage) { - mFileImage = fileImage; - mFolderImage = folderImage; - mOtherImage = otherImage; - if (packageImage != null) { - mPackageImage = packageImage; - } else { - mPackageImage = fileImage; - } - } - - /** - * Creates a label provider with default images. - * - */ - public FileLabelProvider() { - - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) - */ - @Override - public Image getImage(Object element) { - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) - */ - @Override - public String getText(Object element) { - return null; - } - - @Override - public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex == 0) { - if (element instanceof FileEntry) { - FileEntry entry = (FileEntry)element; - switch (entry.getType()) { - case FileListingService.TYPE_FILE: - case FileListingService.TYPE_LINK: - // get the name and extension - if (entry.isApplicationPackage()) { - return mPackageImage; - } - return mFileImage; - case FileListingService.TYPE_DIRECTORY: - case FileListingService.TYPE_DIRECTORY_LINK: - return mFolderImage; - } - } - - // default case return a different image. - return mOtherImage; - } - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof FileEntry) { - FileEntry entry = (FileEntry)element; - - switch (columnIndex) { - case 0: - return entry.getName(); - case 1: - return entry.getSize(); - case 2: - return entry.getDate(); - case 3: - return entry.getTime(); - case 4: - return entry.getPermissions(); - case 5: - return entry.getInfo(); - } - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) - */ - @Override - public void addListener(ILabelProviderListener listener) { - // we don't need listeners. - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() - */ - @Override - public void dispose() { - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String) - */ - @Override - public boolean isLabelProperty(Object element, String property) { - return false; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) - */ - @Override - public void removeListener(ILabelProviderListener listener) { - // we don't need listeners - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java deleted file mode 100644 index f50a94c..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2009 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.handler; - -import com.android.ddmlib.ClientData.IHprofDumpHandler; -import com.android.ddmlib.ClientData.IMethodProfilingHandler; -import com.android.ddmlib.SyncException; -import com.android.ddmlib.SyncService; -import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.SyncProgressHelper; -import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; - -/** - * Base handler class for handler dealing with files located on a device. - * - * @see IHprofDumpHandler - * @see IMethodProfilingHandler - */ -public abstract class BaseFileHandler { - - protected final Shell mParentShell; - - public BaseFileHandler(Shell parentShell) { - mParentShell = parentShell; - } - - protected abstract String getDialogTitle(); - - /** - * Prompts the user for a save location and pulls the remote files into this location. - * <p/>This <strong>must</strong> be called from the UI Thread. - * @param sync the {@link SyncService} to use to pull the file from the device - * @param localFileName The default local name - * @param remoteFilePath The name of the file to pull off of the device - * @param title The title of the File Save dialog. - * @return The result of the pull as a {@link SyncResult} object, or null if the sync - * didn't happen (canceled by the user). - * @throws InvocationTargetException - * @throws InterruptedException - * @throws SyncException if an error happens during the push of the package on the device. - * @throws IOException - */ - protected void promptAndPull(final SyncService sync, - String localFileName, final String remoteFilePath, String title) - throws InvocationTargetException, InterruptedException, SyncException, TimeoutException, - IOException { - FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); - - fileDialog.setText(title); - fileDialog.setFileName(localFileName); - - final String localFilePath = fileDialog.open(); - if (localFilePath != null) { - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) throws SyncException, IOException, - TimeoutException { - sync.pullFile(remoteFilePath, localFilePath, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, - String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); - } - } - - /** - * Prompts the user for a save location and copies a temp file into it. - * <p/>This <strong>must</strong> be called from the UI Thread. - * @param localFileName The default local name - * @param tempFilePath The name of the temp file to copy. - * @param title The title of the File Save dialog. - * @return true if success, false on error or cancel. - */ - protected boolean promptAndSave(String localFileName, byte[] data, String title) { - FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); - - fileDialog.setText(title); - fileDialog.setFileName(localFileName); - - String localFilePath = fileDialog.open(); - if (localFilePath != null) { - try { - saveFile(data, new File(localFilePath)); - return true; - } catch (IOException e) { - String errorMsg = e.getMessage(); - displayErrorInUiThread( - "Failed to save file '%1$s'%2$s", - localFilePath, - errorMsg != null ? ":\n" + errorMsg : "."); - } - } - - return false; - } - - /** - * Display an error message. - * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the - * UI Thread. This is safe to be called from a non-UI Thread. - * @param format the string to display - * @param args the string arguments - */ - protected void displayErrorInUiThread(final String format, final Object... args) { - mParentShell.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - MessageDialog.openError(mParentShell, getDialogTitle(), - String.format(format, args)); - } - }); - } - - /** - * Display an error message. - * This must be called from the UI Thread. - * @param format the string to display - * @param args the string arguments - */ - protected void displayErrorFromUiThread(final String format, final Object... args) { - MessageDialog.openError(mParentShell, getDialogTitle(), - String.format(format, args)); - } - - /** - * Saves a given data into a temp file and returns its corresponding {@link File} object. - * @param data the data to save - * @return the File into which the data was written or null if it failed. - * @throws IOException - */ - protected File saveTempFile(byte[] data, String extension) throws IOException { - File f = File.createTempFile("ddms", extension); - saveFile(data, f); - return f; - } - - /** - * Saves some data into a given File. - * @param data the data to save - * @param output the file into the data is saved. - * @throws IOException - */ - protected void saveFile(byte[] data, File output) throws IOException { - FileOutputStream fos = null; - try { - fos = new FileOutputStream(output); - fos.write(data); - } finally { - if (fos != null) { - fos.close(); - } - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java deleted file mode 100644 index ab1b5f7..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2009 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.handler; - -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData.IMethodProfilingHandler; -import com.android.ddmlib.DdmConstants; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log; -import com.android.ddmlib.SyncException; -import com.android.ddmlib.SyncService; -import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.SyncProgressHelper; -import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; -import com.android.ddmuilib.console.DdmConsole; - -import org.eclipse.swt.widgets.Shell; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; - -/** - * Handler for Method tracing. - * This will pull the trace file into a temp file and launch traceview. - */ -public class MethodProfilingHandler extends BaseFileHandler - implements IMethodProfilingHandler { - - public MethodProfilingHandler(Shell parentShell) { - super(parentShell); - } - - @Override - protected String getDialogTitle() { - return "Method Profiling Error"; - } - - @Override - public void onStartFailure(final Client client, final String message) { - displayErrorInUiThread( - "Unable to create Method Profiling file for application '%1$s'\n\n%2$s" + - "Check logcat for more information.", - client.getClientData().getClientDescription(), - message != null ? message + "\n\n" : ""); - } - - @Override - public void onEndFailure(final Client client, final String message) { - displayErrorInUiThread( - "Unable to finish Method Profiling for application '%1$s'\n\n%2$s" + - "Check logcat for more information.", - client.getClientData().getClientDescription(), - message != null ? message + "\n\n" : ""); - } - - @Override - public void onSuccess(final String remoteFilePath, final Client client) { - mParentShell.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - if (remoteFilePath == null) { - displayErrorFromUiThread( - "Unable to download trace file: unknown file name.\n" + - "This can happen if you disconnected the device while recording the trace."); - return; - } - - final IDevice device = client.getDevice(); - try { - // get the sync service to pull the HPROF file - final SyncService sync = client.getDevice().getSyncService(); - if (sync != null) { - pullAndOpen(sync, remoteFilePath); - } else { - displayErrorFromUiThread( - "Unable to download trace file from device '%1$s'.", - device.getSerialNumber()); - } - } catch (Exception e) { - displayErrorFromUiThread("Unable to download trace file from device '%1$s'.", - device.getSerialNumber()); - } - } - - }); - } - - @Override - public void onSuccess(byte[] data, final Client client) { - try { - File tempFile = saveTempFile(data, DdmConstants.DOT_TRACE); - open(tempFile.getAbsolutePath()); - } catch (IOException e) { - String errorMsg = e.getMessage(); - displayErrorInUiThread( - "Failed to save trace data into temp file%1$s", - errorMsg != null ? ":\n" + errorMsg : "."); - } - } - - /** - * pulls and open a file. This is run from the UI thread. - */ - private void pullAndOpen(final SyncService sync, final String remoteFilePath) - throws InvocationTargetException, InterruptedException, IOException { - // get a temp file - File temp = File.createTempFile("android", DdmConstants.DOT_TRACE); //$NON-NLS-1$ - final String tempPath = temp.getAbsolutePath(); - - // pull the file - try { - SyncProgressHelper.run(new SyncRunnable() { - @Override - public void run(ISyncProgressMonitor monitor) - throws SyncException, IOException, TimeoutException { - sync.pullFile(remoteFilePath, tempPath, monitor); - } - - @Override - public void close() { - sync.close(); - } - }, - String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); - - // open the temp file in traceview - open(tempPath); - } catch (SyncException e) { - if (e.wasCanceled() == false) { - displayErrorFromUiThread("Unable to download trace file:\n\n%1$s", e.getMessage()); - } - } catch (TimeoutException e) { - displayErrorFromUiThread("Unable to download trace file:\n\ntimeout"); - } - } - - protected void open(String tempPath) { - // now that we have the file, we need to launch traceview - String[] command = new String[2]; - command[0] = DdmUiPreferences.getTraceview(); - command[1] = tempPath; - - try { - final Process p = Runtime.getRuntime().exec(command); - - // create a thread for the output - new Thread("Traceview output") { - @Override - public void run() { - // create a buffer to read the stderr output - InputStreamReader is = new InputStreamReader(p.getErrorStream()); - BufferedReader resultReader = new BufferedReader(is); - - // read the lines as they come. if null is returned, it's - // because the process finished - try { - while (true) { - String line = resultReader.readLine(); - if (line != null) { - DdmConsole.printErrorToConsole("Traceview: " + line); - } else { - break; - } - } - // get the return code from the process - p.waitFor(); - } catch (Exception e) { - Log.e("traceview", e); - } - } - }.start(); - } catch (IOException e) { - Log.e("traceview", e); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDataImporter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDataImporter.java deleted file mode 100644 index 88db5cc..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDataImporter.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeStackCallInfo; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.operation.IRunnableWithProgress; - -import java.io.IOException; -import java.io.LineNumberReader; -import java.io.Reader; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.InputMismatchException; -import java.util.List; -import java.util.Scanner; -import java.util.regex.Pattern; - -public class NativeHeapDataImporter implements IRunnableWithProgress { - private LineNumberReader mReader; - private int mStartLineNumber; - private int mEndLineNumber; - - private NativeHeapSnapshot mSnapshot; - - public NativeHeapDataImporter(Reader stream) { - mReader = new LineNumberReader(stream); - mReader.setLineNumber(1); // start numbering at 1 - } - - @Override - public void run(IProgressMonitor monitor) - throws InvocationTargetException, InterruptedException { - monitor.beginTask("Importing Heap Data", IProgressMonitor.UNKNOWN); - - List<NativeAllocationInfo> allocations = new ArrayList<NativeAllocationInfo>(); - try { - while (true) { - String line; - StringBuilder sb = new StringBuilder(); - - // read in a sequence of lines corresponding to a single NativeAllocationInfo - mStartLineNumber = mReader.getLineNumber(); - while ((line = mReader.readLine()) != null) { - if (line.trim().length() == 0) { - // each block of allocations end with an empty line - break; - } - - sb.append(line); - sb.append('\n'); - } - mEndLineNumber = mReader.getLineNumber(); - - // parse those lines into a NativeAllocationInfo object - String allocationBlock = sb.toString(); - if (allocationBlock.trim().length() > 0) { - allocations.add(getNativeAllocation(allocationBlock)); - } - - if (line == null) { // EOF - break; - } - } - } catch (Exception e) { - if (e.getMessage() == null) { - e = new RuntimeException(genericErrorMessage("Unexpected Parse error")); - } - throw new InvocationTargetException(e); - } finally { - try { - mReader.close(); - } catch (IOException e) { - // we can ignore this exception - } - monitor.done(); - } - - mSnapshot = new NativeHeapSnapshot(allocations); - } - - /** Parse a single native allocation dump. This is the complement of - * {@link NativeAllocationInfo#toString()}. - * - * An allocation is of the following form: - * Allocations: 1 - * Size: 344748 - * Total Size: 344748 - * BeginStackTrace: - * 40069bd8 /lib/libc_malloc_leak.so --- get_backtrace --- /libc/bionic/malloc_leak.c:258 - * 40069dd8 /lib/libc_malloc_leak.so --- leak_calloc --- /libc/bionic/malloc_leak.c:576 - * 40069bd8 /lib/libc_malloc_leak.so --- 40069bd8 --- - * 40069dd8 /lib/libc_malloc_leak.so --- 40069dd8 --- - * EndStackTrace - * Note that in the above stack trace, the last two lines are examples where the address - * was not resolved. - * - * @param block a string of lines corresponding to a single {@code NativeAllocationInfo} - * @return parse the input and return the corresponding {@link NativeAllocationInfo} - * @throws InputMismatchException if there are any parse errors - */ - private NativeAllocationInfo getNativeAllocation(String block) { - Scanner sc = new Scanner(block); - - String kw = sc.next(); - if (!NativeAllocationInfo.ALLOCATIONS_KW.equals(kw)) { - throw new InputMismatchException( - expectedKeywordErrorMessage(NativeAllocationInfo.ALLOCATIONS_KW, kw)); - } - - int allocations = sc.nextInt(); - - kw = sc.next(); - if (!NativeAllocationInfo.SIZE_KW.equals(kw)) { - throw new InputMismatchException( - expectedKeywordErrorMessage(NativeAllocationInfo.SIZE_KW, kw)); - } - - int size = sc.nextInt(); - - kw = sc.next(); - if (!NativeAllocationInfo.TOTAL_SIZE_KW.equals(kw)) { - throw new InputMismatchException( - expectedKeywordErrorMessage(NativeAllocationInfo.TOTAL_SIZE_KW, kw)); - } - - int totalSize = sc.nextInt(); - if (totalSize != size * allocations) { - throw new InputMismatchException( - genericErrorMessage("Total Size does not match size * # of allocations")); - } - - NativeAllocationInfo info = new NativeAllocationInfo(size, allocations); - - kw = sc.next(); - if (!NativeAllocationInfo.BEGIN_STACKTRACE_KW.equals(kw)) { - throw new InputMismatchException( - expectedKeywordErrorMessage(NativeAllocationInfo.BEGIN_STACKTRACE_KW, kw)); - } - - List<NativeStackCallInfo> stackInfo = new ArrayList<NativeStackCallInfo>(); - Pattern endTracePattern = Pattern.compile(NativeAllocationInfo.END_STACKTRACE_KW); - - while (true) { - long address = sc.nextLong(16); - info.addStackCallAddress(address); - - String library = sc.next(); - sc.next(); // ignore "---" - String method = scanTillSeparator(sc, "---"); - - String filename = ""; - if (!isUnresolved(method, address)) { - filename = sc.next(); - } - - stackInfo.add(new NativeStackCallInfo(address, library, method, filename)); - - if (sc.hasNext(endTracePattern)) { - break; - } - } - - info.setResolvedStackCall(stackInfo); - return info; - } - - private String scanTillSeparator(Scanner sc, String separator) { - StringBuilder sb = new StringBuilder(); - - while (true) { - String token = sc.next(); - if (token.equals(separator)) { - break; - } - - sb.append(token); - - // We do not know the exact delimiter that was skipped over, but we know - // that there was atleast 1 whitespace. Add a single whitespace character - // to account for this. - sb.append(' '); - } - - return sb.toString().trim(); - } - - private boolean isUnresolved(String method, long address) { - // a method is unresolved if it is just the hex representation of the address - return Long.toString(address, 16).equals(method); - } - - private String genericErrorMessage(String message) { - return String.format("%1$s between lines %2$d and %3$d", - message, mStartLineNumber, mEndLineNumber); - } - - private String expectedKeywordErrorMessage(String expected, String actual) { - return String.format("Expected keyword '%1$s', saw '%2$s' between lines %3$d to %4$d.", - expected, actual, mStartLineNumber, mEndLineNumber); - } - - public NativeHeapSnapshot getImportedSnapshot() { - return mSnapshot; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDiffSnapshot.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDiffSnapshot.java deleted file mode 100644 index 9eb6ddf..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDiffSnapshot.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Models a heap snapshot that is the difference between two snapshots. - */ -public class NativeHeapDiffSnapshot extends NativeHeapSnapshot { - private long mCommonAllocationsTotalMemory; - - public NativeHeapDiffSnapshot(NativeHeapSnapshot newSnapshot, NativeHeapSnapshot oldSnapshot) { - // The diff snapshots behaves like a snapshot that only contains the new allocations - // not present in the old snapshot - super(getNewAllocations(newSnapshot, oldSnapshot)); - - Set<NativeAllocationInfo> commonAllocations = - new HashSet<NativeAllocationInfo>(oldSnapshot.getAllocations()); - commonAllocations.retainAll(newSnapshot.getAllocations()); - - // Memory common between the old and new snapshots - mCommonAllocationsTotalMemory = getTotalMemory(commonAllocations); - } - - private static List<NativeAllocationInfo> getNewAllocations(NativeHeapSnapshot newSnapshot, - NativeHeapSnapshot oldSnapshot) { - Set<NativeAllocationInfo> allocations = - new HashSet<NativeAllocationInfo>(newSnapshot.getAllocations()); - allocations.removeAll(oldSnapshot.getAllocations()); - return new ArrayList<NativeAllocationInfo>(allocations); - } - - @Override - public String getFormattedMemorySize() { - // for a diff snapshot, we report the following string for display: - // xxx bytes new allocation + yyy bytes retained from previous allocation - // = zzz bytes total - - long newAllocations = getTotalSize(); - return String.format("%s bytes new + %s bytes retained = %s bytes total", - formatMemorySize(newAllocations), - formatMemorySize(mCommonAllocationsTotalMemory), - formatMemorySize(newAllocations + mCommonAllocationsTotalMemory)); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapLabelProvider.java deleted file mode 100644 index b96fa02..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapLabelProvider.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeStackCallInfo; - -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.swt.graphics.Image; - -/** - * A Label Provider for the Native Heap TreeViewer in {@link NativeHeapPanel}. - */ -public class NativeHeapLabelProvider extends LabelProvider implements ITableLabelProvider { - private long mTotalSize; - - @Override - public Image getColumnImage(Object arg0, int arg1) { - return null; - } - - @Override - public String getColumnText(Object element, int index) { - if (element instanceof NativeAllocationInfo) { - return getColumnTextForNativeAllocation((NativeAllocationInfo) element, index); - } - - if (element instanceof NativeLibraryAllocationInfo) { - return getColumnTextForNativeLibrary((NativeLibraryAllocationInfo) element, index); - } - - return null; - } - - private String getColumnTextForNativeAllocation(NativeAllocationInfo info, int index) { - NativeStackCallInfo stackInfo = info.getRelevantStackCallInfo(); - - switch (index) { - case 0: - return stackInfo == null ? stackResolutionStatus(info) : stackInfo.getLibraryName(); - case 1: - return Integer.toString(info.getSize() * info.getAllocationCount()); - case 2: - return getPercentageString(info.getSize() * info.getAllocationCount(), mTotalSize); - case 3: - String prefix = ""; - if (!info.isZygoteChild()) { - prefix = "Z "; - } - return prefix + Integer.toString(info.getAllocationCount()); - case 4: - return Integer.toString(info.getSize()); - case 5: - return stackInfo == null ? stackResolutionStatus(info) : stackInfo.getMethodName(); - default: - return null; - } - } - - private String getColumnTextForNativeLibrary(NativeLibraryAllocationInfo info, int index) { - switch (index) { - case 0: - return info.getLibraryName(); - case 1: - return Long.toString(info.getTotalSize()); - case 2: - return getPercentageString(info.getTotalSize(), mTotalSize); - default: - return null; - } - } - - private String getPercentageString(long size, long total) { - if (total == 0) { - return ""; - } - - return String.format("%.1f%%", (float)(size * 100)/(float)total); - } - - private String stackResolutionStatus(NativeAllocationInfo info) { - if (info.isStackCallResolved()) { - return "?"; // resolved and unknown - } else { - return "Resolving..."; // still resolving... - } - } - - /** - * Set the total size of the heap dump for use in percentage calculations. - * This value should be set whenever the input to the tree changes so that the percentages - * are computed correctly. - */ - public void setTotalSize(long totalSize) { - mTotalSize = totalSize; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapPanel.java deleted file mode 100644 index f6631b7..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapPanel.java +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.Client; -import com.android.ddmlib.Log; -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeLibraryMapInfo; -import com.android.ddmlib.NativeStackCallInfo; -import com.android.ddmuilib.Addr2Line; -import com.android.ddmuilib.BaseHeapPanel; -import com.android.ddmuilib.ITableFocusListener; -import com.android.ddmuilib.ITableFocusListener.IFocusedTableActivator; -import com.android.ddmuilib.ImageLoader; -import com.android.ddmuilib.TableHelper; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Sash; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Reader; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** Panel to display native heap information. */ -public class NativeHeapPanel extends BaseHeapPanel { - private static final boolean USE_OLD_RESOLVER; - static { - String useOldResolver = System.getenv("ANDROID_DDMS_OLD_SYMRESOLVER"); - if (useOldResolver != null && useOldResolver.equalsIgnoreCase("true")) { - USE_OLD_RESOLVER = true; - } else { - USE_OLD_RESOLVER = false; - } - } - private final int MAX_DISPLAYED_ERROR_ITEMS = 5; - - private static final String TOOLTIP_EXPORT_DATA = "Export Heap Data"; - private static final String TOOLTIP_ZYGOTE_ALLOCATIONS = "Show Zygote Allocations"; - private static final String TOOLTIP_DIFFS_ONLY = "Only show new allocations not present in previous snapshot"; - private static final String TOOLTIP_GROUPBY = "Group allocations by library."; - - private static final String EXPORT_DATA_IMAGE = "save.png"; - private static final String ZYGOTE_IMAGE = "zygote.png"; - private static final String DIFFS_ONLY_IMAGE = "diff.png"; - private static final String GROUPBY_IMAGE = "groupby.png"; - - private static final String SNAPSHOT_HEAP_BUTTON_TEXT = "Snapshot Current Native Heap Usage"; - private static final String LOAD_HEAP_DATA_BUTTON_TEXT = "Import Heap Data"; - private static final String SYMBOL_SEARCH_PATH_LABEL_TEXT = "Symbol Search Path:"; - private static final String SYMBOL_SEARCH_PATH_TEXT_MESSAGE = - "List of colon separated paths to search for symbol debug information. See tooltip for examples."; - private static final String SYMBOL_SEARCH_PATH_TOOLTIP_TEXT = - "Colon separated paths that contain unstripped libraries with debug symbols.\n" - + "e.g.: <android-src>/out/target/product/generic/symbols/system/lib:/path/to/my/app/obj/local/armeabi"; - - private static final String PREFS_SHOW_DIFFS_ONLY = "nativeheap.show.diffs.only"; - private static final String PREFS_SHOW_ZYGOTE_ALLOCATIONS = "nativeheap.show.zygote"; - private static final String PREFS_GROUP_BY_LIBRARY = "nativeheap.grouby.library"; - private static final String PREFS_SYMBOL_SEARCH_PATH = "nativeheap.search.path"; - private static final String PREFS_SASH_HEIGHT_PERCENT = "nativeheap.sash.percent"; - private static final String PREFS_LAST_IMPORTED_HEAPPATH = "nativeheap.last.import.path"; - private IPreferenceStore mPrefStore; - - private List<NativeHeapSnapshot> mNativeHeapSnapshots; - - // Maintain the differences between a snapshot and its predecessor. - // mDiffSnapshots[i] = mNativeHeapSnapshots[i] - mNativeHeapSnapshots[i-1] - // The zeroth entry is null since there is no predecessor. - // The list is filled lazily on demand. - private List<NativeHeapSnapshot> mDiffSnapshots; - - private Map<Integer, List<NativeHeapSnapshot>> mImportedSnapshotsPerPid; - - private Button mSnapshotHeapButton; - private Button mLoadHeapDataButton; - private Text mSymbolSearchPathText; - private Combo mSnapshotIndexCombo; - private Label mMemoryAllocatedText; - - private TreeViewer mDetailsTreeViewer; - private TreeViewer mStackTraceTreeViewer; - private NativeHeapProviderByAllocations mContentProviderByAllocations; - private NativeHeapProviderByLibrary mContentProviderByLibrary; - private NativeHeapLabelProvider mDetailsTreeLabelProvider; - - private ToolBar mDetailsToolBar; - private ToolItem mGroupByButton; - private ToolItem mDiffsOnlyButton; - private ToolItem mShowZygoteAllocationsButton; - private ToolItem mExportHeapDataButton; - - public NativeHeapPanel(IPreferenceStore prefStore) { - mPrefStore = prefStore; - mPrefStore.setDefault(PREFS_SASH_HEIGHT_PERCENT, 75); - mPrefStore.setDefault(PREFS_SYMBOL_SEARCH_PATH, ""); - mPrefStore.setDefault(PREFS_GROUP_BY_LIBRARY, false); - mPrefStore.setDefault(PREFS_SHOW_ZYGOTE_ALLOCATIONS, true); - mPrefStore.setDefault(PREFS_SHOW_DIFFS_ONLY, false); - - mNativeHeapSnapshots = new ArrayList<NativeHeapSnapshot>(); - mDiffSnapshots = new ArrayList<NativeHeapSnapshot>(); - mImportedSnapshotsPerPid = new HashMap<Integer, List<NativeHeapSnapshot>>(); - } - - /** {@inheritDoc} */ - @Override - public void clientChanged(final Client client, int changeMask) { - if (client != getCurrentClient()) { - return; - } - - if ((changeMask & Client.CHANGE_NATIVE_HEAP_DATA) != Client.CHANGE_NATIVE_HEAP_DATA) { - return; - } - - List<NativeAllocationInfo> allocations = client.getClientData().getNativeAllocationList(); - if (allocations.size() == 0) { - return; - } - - // We need to clone this list since getClientData().getNativeAllocationList() clobbers - // the list on future updates - final List<NativeAllocationInfo> nativeAllocations = shallowCloneList(allocations); - - addNativeHeapSnapshot(new NativeHeapSnapshot(nativeAllocations)); - updateDisplay(); - - // Attempt to resolve symbols in a separate thread. - // The UI should be refreshed once the symbols have been resolved. - if (USE_OLD_RESOLVER) { - Thread t = new Thread(new SymbolResolverTask(nativeAllocations, - client.getClientData().getMappedNativeLibraries())); - t.setName("Address to Symbol Resolver"); - t.start(); - } else { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - resolveSymbols(); - mDetailsTreeViewer.refresh(); - mStackTraceTreeViewer.refresh(); - } - - public void resolveSymbols() { - Shell shell = Display.getDefault().getActiveShell(); - ProgressMonitorDialog d = new ProgressMonitorDialog(shell); - - NativeSymbolResolverTask resolver = new NativeSymbolResolverTask( - nativeAllocations, - client.getClientData().getMappedNativeLibraries(), - mSymbolSearchPathText.getText()); - - try { - d.run(true, true, resolver); - } catch (InvocationTargetException e) { - MessageDialog.openError(shell, - "Error Resolving Symbols", - e.getCause().getMessage()); - return; - } catch (InterruptedException e) { - return; - } - - MessageDialog.openInformation(shell, "Symbol Resolution Status", - getResolutionStatusMessage(resolver)); - } - }); - } - } - - private String getResolutionStatusMessage(NativeSymbolResolverTask resolver) { - StringBuilder sb = new StringBuilder(); - sb.append("Symbol Resolution Complete.\n\n"); - - // show addresses that were not mapped - Set<Long> unmappedAddresses = resolver.getUnmappedAddresses(); - if (unmappedAddresses.size() > 0) { - sb.append(String.format("Unmapped addresses (%d): ", - unmappedAddresses.size())); - sb.append(getSampleForDisplay(unmappedAddresses)); - sb.append('\n'); - } - - // show libraries that were not present on disk - Set<String> notFoundLibraries = resolver.getNotFoundLibraries(); - if (notFoundLibraries.size() > 0) { - sb.append(String.format("Libraries not found on disk (%d): ", - notFoundLibraries.size())); - sb.append(getSampleForDisplay(notFoundLibraries)); - sb.append('\n'); - } - - // show addresses that were mapped but not resolved - Set<Long> unresolvableAddresses = resolver.getUnresolvableAddresses(); - if (unresolvableAddresses.size() > 0) { - sb.append(String.format("Unresolved addresses (%d): ", - unresolvableAddresses.size())); - sb.append(getSampleForDisplay(unresolvableAddresses)); - sb.append('\n'); - } - - if (resolver.getAddr2LineErrorMessage() != null) { - sb.append("Error launching addr2line: "); - sb.append(resolver.getAddr2LineErrorMessage()); - } - - return sb.toString(); - } - - /** - * Get the string representation for a collection of items. - * If there are more items than {@link #MAX_DISPLAYED_ERROR_ITEMS}, then only the first - * {@link #MAX_DISPLAYED_ERROR_ITEMS} items are taken into account, - * and an ellipsis is added at the end. - */ - private String getSampleForDisplay(Collection<?> items) { - StringBuilder sb = new StringBuilder(); - - int c = 1; - Iterator<?> it = items.iterator(); - while (it.hasNext()) { - Object item = it.next(); - if (item instanceof Long) { - sb.append(String.format("0x%x", item)); - } else { - sb.append(item); - } - - if (c == MAX_DISPLAYED_ERROR_ITEMS && it.hasNext()) { - sb.append(", ..."); - break; - } else if (it.hasNext()) { - sb.append(", "); - } - - c++; - } - return sb.toString(); - } - - private void addNativeHeapSnapshot(NativeHeapSnapshot snapshot) { - mNativeHeapSnapshots.add(snapshot); - - // The diff snapshots are filled in lazily on demand. - // But the list needs to be the same size as mNativeHeapSnapshots, so we add a null. - mDiffSnapshots.add(null); - } - - private List<NativeAllocationInfo> shallowCloneList(List<NativeAllocationInfo> allocations) { - List<NativeAllocationInfo> clonedList = - new ArrayList<NativeAllocationInfo>(allocations.size()); - - for (NativeAllocationInfo i : allocations) { - clonedList.add(i); - } - - return clonedList; - } - - @Override - public void deviceSelected() { - // pass - } - - @Override - public void clientSelected() { - Client c = getCurrentClient(); - - if (c == null) { - // if there is no client selected, then we disable the buttons but leave the - // display as is so that whatever snapshots are displayed continue to stay - // visible to the user. - mSnapshotHeapButton.setEnabled(false); - mLoadHeapDataButton.setEnabled(false); - return; - } - - mNativeHeapSnapshots = new ArrayList<NativeHeapSnapshot>(); - mDiffSnapshots = new ArrayList<NativeHeapSnapshot>(); - - mSnapshotHeapButton.setEnabled(true); - mLoadHeapDataButton.setEnabled(true); - - List<NativeHeapSnapshot> importedSnapshots = mImportedSnapshotsPerPid.get( - c.getClientData().getPid()); - if (importedSnapshots != null) { - for (NativeHeapSnapshot n : importedSnapshots) { - addNativeHeapSnapshot(n); - } - } - - List<NativeAllocationInfo> allocations = c.getClientData().getNativeAllocationList(); - allocations = shallowCloneList(allocations); - - if (allocations.size() > 0) { - addNativeHeapSnapshot(new NativeHeapSnapshot(allocations)); - } - - updateDisplay(); - } - - private void updateDisplay() { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - updateSnapshotIndexCombo(); - updateToolbars(); - - int lastSnapshotIndex = mNativeHeapSnapshots.size() - 1; - displaySnapshot(lastSnapshotIndex); - displayStackTraceForSelection(); - } - }); - } - - private void displaySelectedSnapshot() { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - int idx = mSnapshotIndexCombo.getSelectionIndex(); - displaySnapshot(idx); - } - }); - } - - private void displaySnapshot(int index) { - if (index < 0 || mNativeHeapSnapshots.size() == 0) { - mDetailsTreeViewer.setInput(null); - mMemoryAllocatedText.setText(""); - return; - } - - assert index < mNativeHeapSnapshots.size() : "Invalid snapshot index"; - - NativeHeapSnapshot snapshot = mNativeHeapSnapshots.get(index); - if (mDiffsOnlyButton.getSelection() && index > 0) { - snapshot = getDiffSnapshot(index); - } - - mMemoryAllocatedText.setText(snapshot.getFormattedMemorySize()); - mMemoryAllocatedText.pack(); - - mDetailsTreeLabelProvider.setTotalSize(snapshot.getTotalSize()); - mDetailsTreeViewer.setInput(snapshot); - mDetailsTreeViewer.refresh(); - } - - /** Obtain the diff of snapshot[index] & snapshot[index-1] */ - private NativeHeapSnapshot getDiffSnapshot(int index) { - // if it was already computed, simply return that - NativeHeapSnapshot diffSnapshot = mDiffSnapshots.get(index); - if (diffSnapshot != null) { - return diffSnapshot; - } - - // compute the diff - NativeHeapSnapshot cur = mNativeHeapSnapshots.get(index); - NativeHeapSnapshot prev = mNativeHeapSnapshots.get(index - 1); - diffSnapshot = new NativeHeapDiffSnapshot(cur, prev); - - // cache for future use - mDiffSnapshots.set(index, diffSnapshot); - - return diffSnapshot; - } - - private void updateDisplayGrouping() { - boolean groupByLibrary = mGroupByButton.getSelection(); - mPrefStore.setValue(PREFS_GROUP_BY_LIBRARY, groupByLibrary); - - if (groupByLibrary) { - mDetailsTreeViewer.setContentProvider(mContentProviderByLibrary); - } else { - mDetailsTreeViewer.setContentProvider(mContentProviderByAllocations); - } - } - - private void updateDisplayForZygotes() { - boolean displayZygoteMemory = mShowZygoteAllocationsButton.getSelection(); - mPrefStore.setValue(PREFS_SHOW_ZYGOTE_ALLOCATIONS, displayZygoteMemory); - - // inform the content providers of the zygote display setting - mContentProviderByLibrary.displayZygoteMemory(displayZygoteMemory); - mContentProviderByAllocations.displayZygoteMemory(displayZygoteMemory); - - // refresh the UI - mDetailsTreeViewer.refresh(); - } - - private void updateSnapshotIndexCombo() { - List<String> items = new ArrayList<String>(); - - int numSnapshots = mNativeHeapSnapshots.size(); - for (int i = 0; i < numSnapshots; i++) { - // offset indices by 1 so that users see index starting at 1 rather than 0 - items.add("Snapshot " + (i + 1)); - } - - mSnapshotIndexCombo.setItems(items.toArray(new String[0])); - - if (numSnapshots > 0) { - mSnapshotIndexCombo.setEnabled(true); - mSnapshotIndexCombo.select(numSnapshots - 1); - } else { - mSnapshotIndexCombo.setEnabled(false); - } - } - - private void updateToolbars() { - int numSnapshots = mNativeHeapSnapshots.size(); - mExportHeapDataButton.setEnabled(numSnapshots > 0); - } - - @Override - protected Control createControl(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(1, false)); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createControlsSection(c); - createDetailsSection(c); - - // Initialize widget state based on whether a client - // is selected or not. - clientSelected(); - - return c; - } - - private void createControlsSection(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(3, false)); - c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - createGetHeapDataSection(c); - - Label l = new Label(c, SWT.SEPARATOR | SWT.VERTICAL); - l.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - - createDisplaySection(c); - } - - private void createGetHeapDataSection(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(1, false)); - - createTakeHeapSnapshotButton(c); - - Label l = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - createLoadHeapDataButton(c); - } - - private void createTakeHeapSnapshotButton(Composite parent) { - mSnapshotHeapButton = new Button(parent, SWT.BORDER | SWT.PUSH); - mSnapshotHeapButton.setText(SNAPSHOT_HEAP_BUTTON_TEXT); - mSnapshotHeapButton.setLayoutData(new GridData()); - - // disable by default, enabled only when a client is selected - mSnapshotHeapButton.setEnabled(false); - - mSnapshotHeapButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent evt) { - snapshotHeap(); - } - }); - } - - private void snapshotHeap() { - Client c = getCurrentClient(); - assert c != null : "Snapshot Heap could not have been enabled w/o a selected client."; - - // send an async request - c.requestNativeHeapInformation(); - } - - private void createLoadHeapDataButton(Composite parent) { - mLoadHeapDataButton = new Button(parent, SWT.BORDER | SWT.PUSH); - mLoadHeapDataButton.setText(LOAD_HEAP_DATA_BUTTON_TEXT); - mLoadHeapDataButton.setLayoutData(new GridData()); - - // disable by default, enabled only when a client is selected - mLoadHeapDataButton.setEnabled(false); - - mLoadHeapDataButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent evt) { - loadHeapDataFromFile(); - } - }); - } - - private void loadHeapDataFromFile() { - // pop up a file dialog and get the file to load - final String path = getHeapDumpToImport(); - if (path == null) { - return; - } - - Reader reader = null; - try { - reader = new FileReader(path); - } catch (FileNotFoundException e) { - // cannot occur since user input was via a FileDialog - } - - Shell shell = Display.getDefault().getActiveShell(); - ProgressMonitorDialog d = new ProgressMonitorDialog(shell); - - NativeHeapDataImporter importer = new NativeHeapDataImporter(reader); - try { - d.run(true, true, importer); - } catch (InvocationTargetException e) { - // exception while parsing, display error to user and then return - MessageDialog.openError(shell, - "Error Importing Heap Data", - e.getCause().getMessage()); - return; - } catch (InterruptedException e) { - // operation cancelled by user, simply return - return; - } - - NativeHeapSnapshot snapshot = importer.getImportedSnapshot(); - - addToImportedSnapshots(snapshot); // save imported snapshot for future use - addNativeHeapSnapshot(snapshot); // add to currently displayed snapshots as well - - updateDisplay(); - } - - private void addToImportedSnapshots(NativeHeapSnapshot snapshot) { - Client c = getCurrentClient(); - - if (c == null) { - return; - } - - Integer pid = c.getClientData().getPid(); - List<NativeHeapSnapshot> importedSnapshots = mImportedSnapshotsPerPid.get(pid); - if (importedSnapshots == null) { - importedSnapshots = new ArrayList<NativeHeapSnapshot>(); - } - - importedSnapshots.add(snapshot); - mImportedSnapshotsPerPid.put(pid, importedSnapshots); - } - - private String getHeapDumpToImport() { - FileDialog fileDialog = new FileDialog(Display.getDefault().getActiveShell(), - SWT.OPEN); - - fileDialog.setText("Import Heap Dump"); - fileDialog.setFilterExtensions(new String[] {"*.txt"}); - fileDialog.setFilterPath(mPrefStore.getString(PREFS_LAST_IMPORTED_HEAPPATH)); - - String selectedFile = fileDialog.open(); - if (selectedFile != null) { - // save the path to restore in future dialog open - mPrefStore.setValue(PREFS_LAST_IMPORTED_HEAPPATH, new File(selectedFile).getParent()); - } - return selectedFile; - } - - private void createDisplaySection(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(2, false)); - c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - // Create: Display: __________________ - createLabel(c, "Display:"); - mSnapshotIndexCombo = new Combo(c, SWT.NONE | SWT.READ_ONLY); - mSnapshotIndexCombo.setItems(new String[] {"No heap snapshots available."}); - mSnapshotIndexCombo.setEnabled(false); - mSnapshotIndexCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - displaySelectedSnapshot(); - } - }); - - // Create: Memory Allocated (bytes): _________________ - createLabel(c, "Memory Allocated:"); - mMemoryAllocatedText = new Label(c, SWT.NONE); - GridData gd = new GridData(); - gd.widthHint = 100; - mMemoryAllocatedText.setLayoutData(gd); - - // Create: Search Path: __________________ - createLabel(c, SYMBOL_SEARCH_PATH_LABEL_TEXT); - mSymbolSearchPathText = new Text(c, SWT.BORDER); - mSymbolSearchPathText.setMessage(SYMBOL_SEARCH_PATH_TEXT_MESSAGE); - mSymbolSearchPathText.setToolTipText(SYMBOL_SEARCH_PATH_TOOLTIP_TEXT); - mSymbolSearchPathText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - String path = mSymbolSearchPathText.getText(); - updateSearchPath(path); - mPrefStore.setValue(PREFS_SYMBOL_SEARCH_PATH, path); - } - }); - mSymbolSearchPathText.setText(mPrefStore.getString(PREFS_SYMBOL_SEARCH_PATH)); - mSymbolSearchPathText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - } - - private void updateSearchPath(String path) { - Addr2Line.setSearchPath(path); - } - - private void createLabel(Composite parent, String text) { - Label l = new Label(parent, SWT.NONE); - l.setText(text); - GridData gd = new GridData(); - gd.horizontalAlignment = SWT.RIGHT; - l.setLayoutData(gd); - } - - /** - * Create the details section displaying the details table and the stack trace - * corresponding to the selection. - * - * The details is laid out like so: - * Details Toolbar - * Details Table - * ------------sash--- - * Stack Trace Label - * Stack Trace Text - * There is a sash in between the two sections, and we need to save/restore the sash - * preferences. Using FormLayout seems like the easiest solution here, but the layout - * code looks ugly as a result. - */ - private void createDetailsSection(Composite parent) { - final Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new FormLayout()); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - mDetailsToolBar = new ToolBar(c, SWT.FLAT | SWT.BORDER); - initializeDetailsToolBar(mDetailsToolBar); - - Tree detailsTree = new Tree(c, SWT.VIRTUAL | SWT.BORDER | SWT.MULTI); - initializeDetailsTree(detailsTree); - - final Sash sash = new Sash(c, SWT.HORIZONTAL | SWT.BORDER); - - Label stackTraceLabel = new Label(c, SWT.NONE); - stackTraceLabel.setText("Stack Trace:"); - - Tree stackTraceTree = new Tree(c, SWT.BORDER | SWT.MULTI); - initializeStackTraceTree(stackTraceTree); - - // layout the widgets created above - FormData data = new FormData(); - data.top = new FormAttachment(0, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - mDetailsToolBar.setLayoutData(data); - - data = new FormData(); - data.top = new FormAttachment(mDetailsToolBar, 0); - data.bottom = new FormAttachment(sash, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - detailsTree.setLayoutData(data); - - final FormData sashData = new FormData(); - sashData.top = new FormAttachment(mPrefStore.getInt(PREFS_SASH_HEIGHT_PERCENT), 0); - sashData.left = new FormAttachment(0, 0); - sashData.right = new FormAttachment(100, 0); - sash.setLayoutData(sashData); - - data = new FormData(); - data.top = new FormAttachment(sash, 0); - data.left = new FormAttachment(0, 0); - data.right = new FormAttachment(100, 0); - stackTraceLabel.setLayoutData(data); - - data = new FormData(); - data.top = new FormAttachment(stackTraceLabel, 0); - data.left = new FormAttachment(0, 0); - data.bottom = new FormAttachment(100, 0); - data.right = new FormAttachment(100, 0); - stackTraceTree.setLayoutData(data); - - sash.addListener(SWT.Selection, new Listener() { - @Override - public void handleEvent(Event e) { - Rectangle sashRect = sash.getBounds(); - Rectangle panelRect = c.getClientArea(); - int sashPercent = sashRect.y * 100 / panelRect.height; - mPrefStore.setValue(PREFS_SASH_HEIGHT_PERCENT, sashPercent); - - sashData.top = new FormAttachment(0, e.y); - c.layout(); - } - }); - } - - private void initializeDetailsToolBar(ToolBar toolbar) { - mGroupByButton = new ToolItem(toolbar, SWT.CHECK); - mGroupByButton.setImage(ImageLoader.getDdmUiLibLoader().loadImage(GROUPBY_IMAGE, - toolbar.getDisplay())); - mGroupByButton.setToolTipText(TOOLTIP_GROUPBY); - mGroupByButton.setSelection(mPrefStore.getBoolean(PREFS_GROUP_BY_LIBRARY)); - mGroupByButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - updateDisplayGrouping(); - } - }); - - mDiffsOnlyButton = new ToolItem(toolbar, SWT.CHECK); - mDiffsOnlyButton.setImage(ImageLoader.getDdmUiLibLoader().loadImage(DIFFS_ONLY_IMAGE, - toolbar.getDisplay())); - mDiffsOnlyButton.setToolTipText(TOOLTIP_DIFFS_ONLY); - mDiffsOnlyButton.setSelection(mPrefStore.getBoolean(PREFS_SHOW_DIFFS_ONLY)); - mDiffsOnlyButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - // simply refresh the display, as the display logic takes care of - // the current state of the diffs only checkbox. - int idx = mSnapshotIndexCombo.getSelectionIndex(); - displaySnapshot(idx); - } - }); - - mShowZygoteAllocationsButton = new ToolItem(toolbar, SWT.CHECK); - mShowZygoteAllocationsButton.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - ZYGOTE_IMAGE, toolbar.getDisplay())); - mShowZygoteAllocationsButton.setToolTipText(TOOLTIP_ZYGOTE_ALLOCATIONS); - mShowZygoteAllocationsButton.setSelection( - mPrefStore.getBoolean(PREFS_SHOW_ZYGOTE_ALLOCATIONS)); - mShowZygoteAllocationsButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - updateDisplayForZygotes(); - } - }); - - mExportHeapDataButton = new ToolItem(toolbar, SWT.PUSH); - mExportHeapDataButton.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - EXPORT_DATA_IMAGE, toolbar.getDisplay())); - mExportHeapDataButton.setToolTipText(TOOLTIP_EXPORT_DATA); - mExportHeapDataButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - exportSnapshot(); - } - }); - } - - /** Export currently displayed snapshot to a file */ - private void exportSnapshot() { - int idx = mSnapshotIndexCombo.getSelectionIndex(); - String snapshotName = mSnapshotIndexCombo.getItem(idx); - - FileDialog fileDialog = new FileDialog(Display.getDefault().getActiveShell(), - SWT.SAVE); - - fileDialog.setText("Save " + snapshotName); - fileDialog.setFileName("allocations.txt"); - - final String fileName = fileDialog.open(); - if (fileName == null) { - return; - } - - final NativeHeapSnapshot snapshot = mNativeHeapSnapshots.get(idx); - Thread t = new Thread(new Runnable() { - @Override - public void run() { - PrintWriter out; - try { - out = new PrintWriter(new BufferedWriter(new FileWriter(fileName))); - } catch (IOException e) { - displayErrorMessage(e.getMessage()); - return; - } - - for (NativeAllocationInfo alloc : snapshot.getAllocations()) { - out.println(alloc.toString()); - } - out.close(); - } - - private void displayErrorMessage(final String message) { - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - MessageDialog.openError(Display.getDefault().getActiveShell(), - "Failed to export heap data", message); - } - }); - } - }); - t.setName("Saving Heap Data to File..."); - t.start(); - } - - private void initializeDetailsTree(Tree tree) { - tree.setHeaderVisible(true); - tree.setLinesVisible(true); - - List<String> properties = Arrays.asList(new String[] { - "Library", - "Total", - "Percentage", - "Count", - "Size", - "Method", - }); - - List<String> sampleValues = Arrays.asList(new String[] { - "/path/in/device/to/system/library.so", - "123456789", - " 100%", - "123456789", - "123456789", - "PossiblyLongDemangledMethodName", - }); - - // right align numeric values - List<Integer> swtFlags = Arrays.asList(new Integer[] { - SWT.LEFT, - SWT.RIGHT, - SWT.RIGHT, - SWT.RIGHT, - SWT.RIGHT, - SWT.LEFT, - }); - - for (int i = 0; i < properties.size(); i++) { - String p = properties.get(i); - String v = sampleValues.get(i); - int flags = swtFlags.get(i); - TableHelper.createTreeColumn(tree, p, flags, v, getPref("details", p), mPrefStore); - } - - mDetailsTreeViewer = new TreeViewer(tree); - - mDetailsTreeViewer.setUseHashlookup(true); - - boolean displayZygotes = mPrefStore.getBoolean(PREFS_SHOW_ZYGOTE_ALLOCATIONS); - mContentProviderByAllocations = new NativeHeapProviderByAllocations(mDetailsTreeViewer, - displayZygotes); - mContentProviderByLibrary = new NativeHeapProviderByLibrary(mDetailsTreeViewer, - displayZygotes); - if (mPrefStore.getBoolean(PREFS_GROUP_BY_LIBRARY)) { - mDetailsTreeViewer.setContentProvider(mContentProviderByLibrary); - } else { - mDetailsTreeViewer.setContentProvider(mContentProviderByAllocations); - } - - mDetailsTreeLabelProvider = new NativeHeapLabelProvider(); - mDetailsTreeViewer.setLabelProvider(mDetailsTreeLabelProvider); - - mDetailsTreeViewer.setInput(null); - - tree.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - displayStackTraceForSelection(); - } - }); - } - - private void initializeStackTraceTree(Tree tree) { - tree.setHeaderVisible(true); - tree.setLinesVisible(true); - - List<String> properties = Arrays.asList(new String[] { - "Address", - "Library", - "Method", - "File", - "Line", - }); - - List<String> sampleValues = Arrays.asList(new String[] { - "0x1234_5678", - "/path/in/device/to/system/library.so", - "PossiblyLongDemangledMethodName", - "/android/out/prefix/in/home/directory/to/path/in/device/to/system/library.so", - "2000", - }); - - for (int i = 0; i < properties.size(); i++) { - String p = properties.get(i); - String v = sampleValues.get(i); - TableHelper.createTreeColumn(tree, p, SWT.LEFT, v, getPref("stack", p), mPrefStore); - } - - mStackTraceTreeViewer = new TreeViewer(tree); - - mStackTraceTreeViewer.setContentProvider(new NativeStackContentProvider()); - mStackTraceTreeViewer.setLabelProvider(new NativeStackLabelProvider()); - - mStackTraceTreeViewer.setInput(null); - } - - private void displayStackTraceForSelection() { - TreeItem []items = mDetailsTreeViewer.getTree().getSelection(); - if (items.length == 0) { - mStackTraceTreeViewer.setInput(null); - return; - } - - Object data = items[0].getData(); - if (!(data instanceof NativeAllocationInfo)) { - mStackTraceTreeViewer.setInput(null); - return; - } - - NativeAllocationInfo info = (NativeAllocationInfo) data; - if (info.isStackCallResolved()) { - mStackTraceTreeViewer.setInput(info.getResolvedStackCall()); - } else { - mStackTraceTreeViewer.setInput(info.getStackCallAddresses()); - } - } - - private String getPref(String prefix, String s) { - return "nativeheap.tree." + prefix + "." + s; - } - - @Override - public void setFocus() { - } - - private ITableFocusListener mTableFocusListener; - - @Override - public void setTableFocusListener(ITableFocusListener listener) { - mTableFocusListener = listener; - - final Tree heapSitesTree = mDetailsTreeViewer.getTree(); - final IFocusedTableActivator heapSitesActivator = new IFocusedTableActivator() { - @Override - public void copy(Clipboard clipboard) { - TreeItem[] items = heapSitesTree.getSelection(); - copyToClipboard(items, clipboard); - } - - @Override - public void selectAll() { - heapSitesTree.selectAll(); - } - }; - - heapSitesTree.addFocusListener(new FocusListener() { - @Override - public void focusLost(FocusEvent arg0) { - mTableFocusListener.focusLost(heapSitesActivator); - } - - @Override - public void focusGained(FocusEvent arg0) { - mTableFocusListener.focusGained(heapSitesActivator); - } - }); - - final Tree stackTraceTree = mStackTraceTreeViewer.getTree(); - final IFocusedTableActivator stackTraceActivator = new IFocusedTableActivator() { - @Override - public void copy(Clipboard clipboard) { - TreeItem[] items = stackTraceTree.getSelection(); - copyToClipboard(items, clipboard); - } - - @Override - public void selectAll() { - stackTraceTree.selectAll(); - } - }; - - stackTraceTree.addFocusListener(new FocusListener() { - @Override - public void focusLost(FocusEvent arg0) { - mTableFocusListener.focusLost(stackTraceActivator); - } - - @Override - public void focusGained(FocusEvent arg0) { - mTableFocusListener.focusGained(stackTraceActivator); - } - }); - } - - private void copyToClipboard(TreeItem[] items, Clipboard clipboard) { - StringBuilder sb = new StringBuilder(); - - for (TreeItem item : items) { - Object data = item.getData(); - if (data != null) { - sb.append(data.toString()); - sb.append('\n'); - } - } - - String content = sb.toString(); - if (content.length() > 0) { - clipboard.setContents( - new Object[] {sb.toString()}, - new Transfer[] {TextTransfer.getInstance()} - ); - } - } - - private class SymbolResolverTask implements Runnable { - private List<NativeAllocationInfo> mCallSites; - private List<NativeLibraryMapInfo> mMappedLibraries; - private Map<Long, NativeStackCallInfo> mResolvedSymbolCache; - - public SymbolResolverTask(List<NativeAllocationInfo> callSites, - List<NativeLibraryMapInfo> mappedLibraries) { - mCallSites = callSites; - mMappedLibraries = mappedLibraries; - - mResolvedSymbolCache = new HashMap<Long, NativeStackCallInfo>(); - } - - @Override - public void run() { - for (NativeAllocationInfo callSite : mCallSites) { - if (callSite.isStackCallResolved()) { - continue; - } - - List<Long> addresses = callSite.getStackCallAddresses(); - List<NativeStackCallInfo> resolvedStackInfo = - new ArrayList<NativeStackCallInfo>(addresses.size()); - - for (Long address : addresses) { - NativeStackCallInfo info = mResolvedSymbolCache.get(address); - - if (info != null) { - resolvedStackInfo.add(info); - } else { - info = resolveAddress(address); - resolvedStackInfo.add(info); - mResolvedSymbolCache.put(address, info); - } - } - - callSite.setResolvedStackCall(resolvedStackInfo); - } - - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - mDetailsTreeViewer.refresh(); - mStackTraceTreeViewer.refresh(); - } - }); - } - - private NativeStackCallInfo resolveAddress(long addr) { - NativeLibraryMapInfo library = getLibraryFor(addr); - - if (library != null) { - Addr2Line process = Addr2Line.getProcess(library); - if (process != null) { - NativeStackCallInfo info = process.getAddress(addr); - if (info != null) { - return info; - } - } - } - - return new NativeStackCallInfo(addr, - library != null ? library.getLibraryName() : null, - Long.toHexString(addr), - ""); - } - - private NativeLibraryMapInfo getLibraryFor(long addr) { - for (NativeLibraryMapInfo info : mMappedLibraries) { - if (info.isWithinLibrary(addr)) { - return info; - } - } - - Log.d("ddm-nativeheap", "Failed finding Library for " + Long.toHexString(addr)); - return null; - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByAllocations.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByAllocations.java deleted file mode 100644 index c31716b..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByAllocations.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; - -import org.eclipse.jface.viewers.ILazyTreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; - -import java.util.List; - -/** - * Content Provider for the native heap tree viewer in {@link NativeHeapPanel}. - * It expects a {@link NativeHeapSnapshot} as input, and provides the list of allocations - * in the heap dump as content to the UI. - */ -public final class NativeHeapProviderByAllocations implements ILazyTreeContentProvider { - private TreeViewer mViewer; - private boolean mDisplayZygoteMemory; - private NativeHeapSnapshot mNativeHeapDump; - - public NativeHeapProviderByAllocations(TreeViewer viewer, boolean displayZygotes) { - mViewer = viewer; - mDisplayZygoteMemory = displayZygotes; - } - - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - mNativeHeapDump = (NativeHeapSnapshot) newInput; - } - - @Override - public Object getParent(Object arg0) { - return null; - } - - @Override - public void updateChildCount(Object element, int currentChildCount) { - int childCount = 0; - - if (element == mNativeHeapDump) { // root element - childCount = getAllocations().size(); - } - - mViewer.setChildCount(element, childCount); - } - - @Override - public void updateElement(Object parent, int index) { - Object item = null; - - if (parent == mNativeHeapDump) { // root element - item = getAllocations().get(index); - } - - mViewer.replace(parent, index, item); - mViewer.setChildCount(item, 0); - } - - public void displayZygoteMemory(boolean en) { - mDisplayZygoteMemory = en; - } - - private List<NativeAllocationInfo> getAllocations() { - if (mDisplayZygoteMemory) { - return mNativeHeapDump.getAllocations(); - } else { - return mNativeHeapDump.getNonZygoteAllocations(); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByLibrary.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByLibrary.java deleted file mode 100644 index b786bfa..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByLibrary.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import org.eclipse.jface.viewers.ILazyTreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; - -import java.util.List; - -/** - * Content Provider for the native heap tree viewer in {@link NativeHeapPanel}. - * It expects input of type {@link NativeHeapSnapshot}, and provides heap allocations - * grouped by library to the UI. - */ -public class NativeHeapProviderByLibrary implements ILazyTreeContentProvider { - private TreeViewer mViewer; - private boolean mDisplayZygoteMemory; - - public NativeHeapProviderByLibrary(TreeViewer viewer, boolean displayZygotes) { - mViewer = viewer; - mDisplayZygoteMemory = displayZygotes; - } - - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - @Override - public Object getParent(Object element) { - return null; - } - - @Override - public void updateChildCount(Object element, int currentChildCount) { - int childCount = 0; - - if (element instanceof NativeHeapSnapshot) { - NativeHeapSnapshot snapshot = (NativeHeapSnapshot) element; - childCount = getLibraryAllocations(snapshot).size(); - } - - mViewer.setChildCount(element, childCount); - } - - @Override - public void updateElement(Object parent, int index) { - Object item = null; - int childCount = 0; - - if (parent instanceof NativeHeapSnapshot) { // root element - NativeHeapSnapshot snapshot = (NativeHeapSnapshot) parent; - item = getLibraryAllocations(snapshot).get(index); - childCount = ((NativeLibraryAllocationInfo) item).getAllocations().size(); - } else if (parent instanceof NativeLibraryAllocationInfo) { - item = ((NativeLibraryAllocationInfo) parent).getAllocations().get(index); - } - - mViewer.replace(parent, index, item); - mViewer.setChildCount(item, childCount); - } - - public void displayZygoteMemory(boolean en) { - mDisplayZygoteMemory = en; - } - - private List<NativeLibraryAllocationInfo> getLibraryAllocations(NativeHeapSnapshot snapshot) { - if (mDisplayZygoteMemory) { - return snapshot.getAllocationsByLibrary(); - } else { - return snapshot.getNonZygoteAllocationsByLibrary(); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapSnapshot.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapSnapshot.java deleted file mode 100644 index e2023d2..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapSnapshot.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; - -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * A Native Heap Snapshot models a single heap dump. - * - * It primarily consists of a list of {@link NativeAllocationInfo} objects. From this list, - * other objects of interest to the UI are computed and cached for future use. - */ -public class NativeHeapSnapshot { - private static final NumberFormat NUMBER_FORMATTER = NumberFormat.getInstance(); - - private List<NativeAllocationInfo> mHeapAllocations; - private List<NativeLibraryAllocationInfo> mHeapAllocationsByLibrary; - - private List<NativeAllocationInfo> mNonZygoteHeapAllocations; - private List<NativeLibraryAllocationInfo> mNonZygoteHeapAllocationsByLibrary; - - private long mTotalSize; - - public NativeHeapSnapshot(List<NativeAllocationInfo> heapAllocations) { - mHeapAllocations = heapAllocations; - - // precompute the total size as this is always needed. - mTotalSize = getTotalMemory(heapAllocations); - } - - protected long getTotalMemory(Collection<NativeAllocationInfo> heapSnapshot) { - long total = 0; - - for (NativeAllocationInfo info : heapSnapshot) { - total += info.getAllocationCount() * info.getSize(); - } - - return total; - } - - public List<NativeAllocationInfo> getAllocations() { - return mHeapAllocations; - } - - public List<NativeLibraryAllocationInfo> getAllocationsByLibrary() { - if (mHeapAllocationsByLibrary != null) { - return mHeapAllocationsByLibrary; - } - - List<NativeLibraryAllocationInfo> heapAllocations = - NativeLibraryAllocationInfo.constructFrom(mHeapAllocations); - - // cache for future uses only if it is fully resolved. - if (isFullyResolved(heapAllocations)) { - mHeapAllocationsByLibrary = heapAllocations; - } - - return heapAllocations; - } - - private boolean isFullyResolved(List<NativeLibraryAllocationInfo> heapAllocations) { - for (NativeLibraryAllocationInfo info : heapAllocations) { - if (info.getLibraryName().equals(NativeLibraryAllocationInfo.UNRESOLVED_LIBRARY_NAME)) { - return false; - } - } - - return true; - } - - public long getTotalSize() { - return mTotalSize; - } - - public String getFormattedMemorySize() { - return String.format("%s bytes", formatMemorySize(getTotalSize())); - } - - protected String formatMemorySize(long memSize) { - return NUMBER_FORMATTER.format(memSize); - } - - public List<NativeAllocationInfo> getNonZygoteAllocations() { - if (mNonZygoteHeapAllocations != null) { - return mNonZygoteHeapAllocations; - } - - // filter out all zygote allocations - mNonZygoteHeapAllocations = new ArrayList<NativeAllocationInfo>(); - for (NativeAllocationInfo info : mHeapAllocations) { - if (info.isZygoteChild()) { - mNonZygoteHeapAllocations.add(info); - } - } - - return mNonZygoteHeapAllocations; - } - - public List<NativeLibraryAllocationInfo> getNonZygoteAllocationsByLibrary() { - if (mNonZygoteHeapAllocationsByLibrary != null) { - return mNonZygoteHeapAllocationsByLibrary; - } - - List<NativeLibraryAllocationInfo> heapAllocations = - NativeLibraryAllocationInfo.constructFrom(getNonZygoteAllocations()); - - // cache for future uses only if it is fully resolved. - if (isFullyResolved(heapAllocations)) { - mNonZygoteHeapAllocationsByLibrary = heapAllocations; - } - - return heapAllocations; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeLibraryAllocationInfo.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeLibraryAllocationInfo.java deleted file mode 100644 index 1722cdb..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeLibraryAllocationInfo.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeStackCallInfo; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A heap dump representation where each call site is associated with its source library. - */ -public final class NativeLibraryAllocationInfo { - /** Library name to use when grouping before symbol resolution is complete. */ - public static final String UNRESOLVED_LIBRARY_NAME = "Resolving.."; - - /** Any call site that cannot be resolved to a specific library goes under this name. */ - private static final String UNKNOWN_LIBRARY_NAME = "unknown"; - - private final String mLibraryName; - private final List<NativeAllocationInfo> mHeapAllocations; - private int mTotalSize; - - private NativeLibraryAllocationInfo(String libraryName) { - mLibraryName = libraryName; - mHeapAllocations = new ArrayList<NativeAllocationInfo>(); - } - - private void addAllocation(NativeAllocationInfo info) { - mHeapAllocations.add(info); - } - - private void updateTotalSize() { - mTotalSize = 0; - for (NativeAllocationInfo i : mHeapAllocations) { - mTotalSize += i.getAllocationCount() * i.getSize(); - } - } - - public String getLibraryName() { - return mLibraryName; - } - - public long getTotalSize() { - return mTotalSize; - } - - public List<NativeAllocationInfo> getAllocations() { - return mHeapAllocations; - } - - /** - * Factory method to create a list of {@link NativeLibraryAllocationInfo} objects, - * given the list of {@link NativeAllocationInfo} objects. - * - * If the {@link NativeAllocationInfo} objects do not have their symbols resolved, - * then they are grouped under the library {@link #UNRESOLVED_LIBRARY_NAME}. If they do - * have their symbols resolved, but map to an unknown library, then they are grouped under - * the library {@link #UNKNOWN_LIBRARY_NAME}. - */ - public static List<NativeLibraryAllocationInfo> constructFrom( - List<NativeAllocationInfo> allocations) { - if (allocations == null) { - return null; - } - - Map<String, NativeLibraryAllocationInfo> allocationsByLibrary = - new HashMap<String, NativeLibraryAllocationInfo>(); - - // go through each native allocation and assign it to the appropriate library - for (NativeAllocationInfo info : allocations) { - String libName = UNRESOLVED_LIBRARY_NAME; - - if (info.isStackCallResolved()) { - NativeStackCallInfo relevantStackCall = info.getRelevantStackCallInfo(); - if (relevantStackCall != null) { - libName = relevantStackCall.getLibraryName(); - } else { - libName = UNKNOWN_LIBRARY_NAME; - } - } - - addtoLibrary(allocationsByLibrary, libName, info); - } - - List<NativeLibraryAllocationInfo> libraryAllocations = - new ArrayList<NativeLibraryAllocationInfo>(allocationsByLibrary.values()); - - // now update some summary statistics for each library - for (NativeLibraryAllocationInfo l : libraryAllocations) { - l.updateTotalSize(); - } - - // finally, sort by total size - Collections.sort(libraryAllocations, new Comparator<NativeLibraryAllocationInfo>() { - @Override - public int compare(NativeLibraryAllocationInfo o1, - NativeLibraryAllocationInfo o2) { - return (int) (o2.getTotalSize() - o1.getTotalSize()); - } - }); - - return libraryAllocations; - } - - private static void addtoLibrary(Map<String, NativeLibraryAllocationInfo> libraryAllocations, - String libName, NativeAllocationInfo info) { - NativeLibraryAllocationInfo libAllocationInfo = libraryAllocations.get(libName); - if (libAllocationInfo == null) { - libAllocationInfo = new NativeLibraryAllocationInfo(libName); - libraryAllocations.put(libName, libAllocationInfo); - } - - libAllocationInfo.addAllocation(info); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackContentProvider.java deleted file mode 100644 index 9a6ddb2..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackContentProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -import java.util.List; - -public class NativeStackContentProvider implements ITreeContentProvider { - @Override - public Object[] getElements(Object arg0) { - return getChildren(arg0); - } - - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - @Override - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof List<?>) { - return ((List<?>) parentElement).toArray(); - } - - return null; - } - - @Override - public Object getParent(Object element) { - return null; - } - - @Override - public boolean hasChildren(Object element) { - return false; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackLabelProvider.java deleted file mode 100644 index b7428b9..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackLabelProvider.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeStackCallInfo; - -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.swt.graphics.Image; - -public class NativeStackLabelProvider extends LabelProvider implements ITableLabelProvider { - @Override - public Image getColumnImage(Object arg0, int arg1) { - return null; - } - - @Override - public String getColumnText(Object element, int index) { - if (element instanceof NativeStackCallInfo) { - return getResolvedStackTraceColumnText((NativeStackCallInfo) element, index); - } - - if (element instanceof Long) { - // if the addresses have not been resolved, then just display the - // addresses alone - return getStackAddressColumnText((Long) element, index); - } - - return null; - } - - public String getResolvedStackTraceColumnText(NativeStackCallInfo info, int index) { - switch (index) { - case 0: - return String.format("0x%08x", info.getAddress()); - case 1: - return info.getLibraryName(); - case 2: - return info.getMethodName(); - case 3: - return info.getSourceFile(); - case 4: - int l = info.getLineNumber(); - return l == -1 ? "" : Integer.toString(l); - } - - return null; - } - - private String getStackAddressColumnText(Long address, int index) { - if (index == 0) { - return String.format("0x%08x", address); - } - - return null; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeSymbolResolverTask.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeSymbolResolverTask.java deleted file mode 100644 index 1a75c6e..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeSymbolResolverTask.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2011 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.heap; - -import com.android.ddmlib.NativeAllocationInfo; -import com.android.ddmlib.NativeLibraryMapInfo; -import com.android.ddmlib.NativeStackCallInfo; -import com.android.ddmuilib.DdmUiPreferences; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.operation.IRunnableWithProgress; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -/** - * A symbol resolver task that can resolve a set of addresses to their corresponding - * source method name + file name:line number. - * - * It first identifies the library that contains the address, and then runs addr2line on - * the library to get the symbol name + source location. - */ -public class NativeSymbolResolverTask implements IRunnableWithProgress { - private static final String ADDR2LINE; - private static final String DEFAULT_SYMBOLS_FOLDER; - - static { - String addr2lineEnv = System.getenv("ANDROID_ADDR2LINE"); - ADDR2LINE = addr2lineEnv != null ? addr2lineEnv : DdmUiPreferences.getAddr2Line(); - - String symbols = System.getenv("ANDROID_SYMBOLS"); - DEFAULT_SYMBOLS_FOLDER = symbols != null ? symbols : DdmUiPreferences.getSymbolDirectory(); - } - - private List<NativeAllocationInfo> mCallSites; - private List<NativeLibraryMapInfo> mMappedLibraries; - private List<String> mSymbolSearchFolders; - - /** All unresolved addresses from all the callsites. */ - private SortedSet<Long> mUnresolvedAddresses; - - /** Set of all addresses that could were not resolved at the end of the resolution process. */ - private Set<Long> mUnresolvableAddresses; - - /** Map of library -> [unresolved addresses mapping to this library]. */ - private Map<NativeLibraryMapInfo, Set<Long>> mUnresolvedAddressesPerLibrary; - - /** Addresses that could not be mapped to a library, should be mostly empty. */ - private Set<Long> mUnmappedAddresses; - - /** Cache of the resolution for every unresolved address. */ - private Map<Long, NativeStackCallInfo> mAddressResolution; - - /** List of libraries that were not located on disk. */ - private Set<String> mNotFoundLibraries; - private String mAddr2LineErrorMessage = null; - - public NativeSymbolResolverTask(List<NativeAllocationInfo> callSites, - List<NativeLibraryMapInfo> mappedLibraries, - String symbolSearchPath) { - mCallSites = callSites; - mMappedLibraries = mappedLibraries; - mSymbolSearchFolders = new ArrayList<String>(); - mSymbolSearchFolders.add(DEFAULT_SYMBOLS_FOLDER); - mSymbolSearchFolders.addAll(Arrays.asList(symbolSearchPath.split(":"))); - - mUnresolvedAddresses = new TreeSet<Long>(); - mUnresolvableAddresses = new HashSet<Long>(); - mUnresolvedAddressesPerLibrary = new HashMap<NativeLibraryMapInfo, Set<Long>>(); - mUnmappedAddresses = new HashSet<Long>(); - mAddressResolution = new HashMap<Long, NativeStackCallInfo>(); - mNotFoundLibraries = new HashSet<String>(); - } - - @Override - public void run(IProgressMonitor monitor) - throws InvocationTargetException, InterruptedException { - monitor.beginTask("Resolving symbols", IProgressMonitor.UNKNOWN); - - collectAllUnresolvedAddresses(); - checkCancellation(monitor); - - mapUnresolvedAddressesToLibrary(); - checkCancellation(monitor); - - resolveLibraryAddresses(monitor); - checkCancellation(monitor); - - resolveCallSites(mCallSites); - - monitor.done(); - } - - private void collectAllUnresolvedAddresses() { - for (NativeAllocationInfo callSite : mCallSites) { - mUnresolvedAddresses.addAll(callSite.getStackCallAddresses()); - } - } - - private void mapUnresolvedAddressesToLibrary() { - Set<Long> mappedAddresses = new HashSet<Long>(); - - for (NativeLibraryMapInfo lib : mMappedLibraries) { - SortedSet<Long> addressesInLibrary = mUnresolvedAddresses.subSet(lib.getStartAddress(), - lib.getEndAddress() + 1); - if (addressesInLibrary.size() > 0) { - mUnresolvedAddressesPerLibrary.put(lib, addressesInLibrary); - mappedAddresses.addAll(addressesInLibrary); - } - } - - // unmapped addresses = unresolved addresses - mapped addresses - mUnmappedAddresses.addAll(mUnresolvedAddresses); - mUnmappedAddresses.removeAll(mappedAddresses); - } - - private void resolveLibraryAddresses(IProgressMonitor monitor) throws InterruptedException { - for (NativeLibraryMapInfo lib : mUnresolvedAddressesPerLibrary.keySet()) { - String libPath = getLibraryLocation(lib); - Set<Long> addressesToResolve = mUnresolvedAddressesPerLibrary.get(lib); - - if (libPath == null) { - mNotFoundLibraries.add(lib.getLibraryName()); - markAddressesNotResolvable(addressesToResolve, lib); - } else { - monitor.subTask(String.format("Resolving addresses mapped to %s.", libPath)); - resolveAddresses(lib, libPath, addressesToResolve); - } - - checkCancellation(monitor); - } - } - - private void resolveAddresses(NativeLibraryMapInfo lib, String libPath, - Set<Long> addressesToResolve) { - Process addr2line = null; - try { - addr2line = new ProcessBuilder(ADDR2LINE, - "-C", // demangle - "-f", // display function names in addition to file:number - "-e", libPath).start(); - } catch (IOException e) { - // Since the library path is known to be valid, the only reason for an exception - // is that addr2line was not found. We just save the message in this case. - mAddr2LineErrorMessage = e.getMessage(); - markAddressesNotResolvable(addressesToResolve, lib); - return; - } - - BufferedReader resultReader = new BufferedReader(new InputStreamReader( - addr2line.getInputStream())); - BufferedWriter addressWriter = new BufferedWriter(new OutputStreamWriter( - addr2line.getOutputStream())); - - long libStartAddress = isExecutable(lib) ? 0 : lib.getStartAddress(); - try { - for (Long addr : addressesToResolve) { - long offset = addr.longValue() - libStartAddress; - addressWriter.write(Long.toHexString(offset)); - addressWriter.newLine(); - addressWriter.flush(); - String method = resultReader.readLine(); - String sourceFile = resultReader.readLine(); - - mAddressResolution.put(addr, - new NativeStackCallInfo(addr.longValue(), - lib.getLibraryName(), - method, - sourceFile)); - } - } catch (IOException e) { - // if there is any error, then mark the addresses not already resolved - // as unresolvable. - for (Long addr : addressesToResolve) { - if (mAddressResolution.get(addr) == null) { - markAddressNotResolvable(lib, addr); - } - } - } - - try { - resultReader.close(); - addressWriter.close(); - } catch (IOException e) { - // we can ignore these exceptions - } - - addr2line.destroy(); - } - - private boolean isExecutable(NativeLibraryMapInfo object) { - // TODO: Use a tool like readelf or nm to determine whether this object is a library - // or an executable. - // For now, we'll just assume that any object present in the bin folder is an executable. - String devicePath = object.getLibraryName(); - return devicePath.contains("/bin/"); - } - - private void markAddressesNotResolvable(Set<Long> addressesToResolve, - NativeLibraryMapInfo lib) { - for (Long addr : addressesToResolve) { - markAddressNotResolvable(lib, addr); - } - } - - private void markAddressNotResolvable(NativeLibraryMapInfo lib, Long addr) { - mAddressResolution.put(addr, - new NativeStackCallInfo(addr.longValue(), - lib.getLibraryName(), - Long.toHexString(addr), - "")); - mUnresolvableAddresses.add(addr); - } - - /** - * Locate on local disk the debug library w/ symbols corresponding to the - * library on the device. It searches for this library in the symbol path. - * @return absolute path if found, null otherwise - */ - private String getLibraryLocation(NativeLibraryMapInfo lib) { - String pathOnDevice = lib.getLibraryName(); - String libName = new File(pathOnDevice).getName(); - - for (String p : mSymbolSearchFolders) { - // try appending the full path on device - String fullPath = p + File.separator + pathOnDevice; - if (new File(fullPath).exists()) { - return fullPath; - } - - // try appending basename(library) - fullPath = p + File.separator + libName; - if (new File(fullPath).exists()) { - return fullPath; - } - } - - return null; - } - - private void resolveCallSites(List<NativeAllocationInfo> callSites) { - for (NativeAllocationInfo callSite : callSites) { - List<NativeStackCallInfo> stackInfo = new ArrayList<NativeStackCallInfo>(); - - for (Long addr : callSite.getStackCallAddresses()) { - NativeStackCallInfo info = mAddressResolution.get(addr); - - if (info != null) { - stackInfo.add(info); - } - } - - callSite.setResolvedStackCall(stackInfo); - } - } - - private void checkCancellation(IProgressMonitor monitor) throws InterruptedException { - if (monitor.isCanceled()) { - throw new InterruptedException(); - } - } - - public String getAddr2LineErrorMessage() { - return mAddr2LineErrorMessage; - } - - public Set<Long> getUnmappedAddresses() { - return mUnmappedAddresses; - } - - public Set<Long> getUnresolvableAddresses() { - return mUnresolvableAddresses; - } - - public Set<String> getNotFoundLibraries() { - return mNotFoundLibraries; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/CoordinateControls.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/CoordinateControls.java deleted file mode 100644 index 2aef53c..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/CoordinateControls.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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.location; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; - -import java.text.DecimalFormat; -import java.text.ParseException; - -/** - * Encapsulation of controls handling a location coordinate in decimal and sexagesimal. - * <p/>This handle the conversion between both modes automatically by using a {@link ModifyListener} - * on all the {@link Text} widgets. - * <p/>To get/set the coordinate, use {@link #setValue(double)} and {@link #getValue()} (preceded by - * a call to {@link #isValueValid()}) - */ -public final class CoordinateControls { - private double mValue; - private boolean mValueValidity = false; - private Text mDecimalText; - private Text mSexagesimalDegreeText; - private Text mSexagesimalMinuteText; - private Text mSexagesimalSecondText; - private final DecimalFormat mDecimalFormat = new DecimalFormat(); - - /** Internal flag to prevent {@link ModifyEvent} to be sent when {@link Text#setText(String)} - * is called. This is an int instead of a boolean to act as a counter. */ - private int mManualTextChange = 0; - - /** - * ModifyListener for the 3 {@link Text} controls of the sexagesimal mode. - */ - private ModifyListener mSexagesimalListener = new ModifyListener() { - @Override - public void modifyText(ModifyEvent event) { - if (mManualTextChange > 0) { - return; - } - try { - mValue = getValueFromSexagesimalControls(); - setValueIntoDecimalControl(mValue); - mValueValidity = true; - } catch (ParseException e) { - // wrong format empty the decimal controls. - mValueValidity = false; - resetDecimalControls(); - } - } - }; - - /** - * Creates the {@link Text} control for the decimal display of the coordinate. - * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}. - * @param parent The {@link Composite} parent of the control. - */ - public void createDecimalText(Composite parent) { - mDecimalText = createTextControl(parent, "-199.999999", new ModifyListener() { - @Override - public void modifyText(ModifyEvent event) { - if (mManualTextChange > 0) { - return; - } - try { - mValue = mDecimalFormat.parse(mDecimalText.getText()).doubleValue(); - setValueIntoSexagesimalControl(mValue); - mValueValidity = true; - } catch (ParseException e) { - // wrong format empty the sexagesimal controls. - mValueValidity = false; - resetSexagesimalControls(); - } - } - }); - } - - /** - * Creates the {@link Text} control for the "degree" display of the coordinate in sexagesimal - * mode. - * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}. - * @param parent The {@link Composite} parent of the control. - */ - public void createSexagesimalDegreeText(Composite parent) { - mSexagesimalDegreeText = createTextControl(parent, "-199", mSexagesimalListener); //$NON-NLS-1$ - } - - /** - * Creates the {@link Text} control for the "minute" display of the coordinate in sexagesimal - * mode. - * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}. - * @param parent The {@link Composite} parent of the control. - */ - public void createSexagesimalMinuteText(Composite parent) { - mSexagesimalMinuteText = createTextControl(parent, "99", mSexagesimalListener); //$NON-NLS-1$ - } - - /** - * Creates the {@link Text} control for the "second" display of the coordinate in sexagesimal - * mode. - * <p/>The control is expected to be placed in a Composite using a {@link GridLayout}. - * @param parent The {@link Composite} parent of the control. - */ - public void createSexagesimalSecondText(Composite parent) { - mSexagesimalSecondText = createTextControl(parent, "99.999", mSexagesimalListener); //$NON-NLS-1$ - } - - /** - * Sets the coordinate into the {@link Text} controls. - * @param value the coordinate value to set. - */ - public void setValue(double value) { - mValue = value; - mValueValidity = true; - setValueIntoDecimalControl(value); - setValueIntoSexagesimalControl(value); - } - - /** - * Returns whether the value in the control(s) is valid. - */ - public boolean isValueValid() { - return mValueValidity; - } - - /** - * Returns the current value set in the control(s). - * <p/>This value can be erroneous, and a check with {@link #isValueValid()} should be performed - * before any call to this method. - */ - public double getValue() { - return mValue; - } - - /** - * Enables or disables all the {@link Text} controls. - * @param enabled the enabled state. - */ - public void setEnabled(boolean enabled) { - mDecimalText.setEnabled(enabled); - mSexagesimalDegreeText.setEnabled(enabled); - mSexagesimalMinuteText.setEnabled(enabled); - mSexagesimalSecondText.setEnabled(enabled); - } - - private void resetDecimalControls() { - mManualTextChange++; - mDecimalText.setText(""); //$NON-NLS-1$ - mManualTextChange--; - } - - private void resetSexagesimalControls() { - mManualTextChange++; - mSexagesimalDegreeText.setText(""); //$NON-NLS-1$ - mSexagesimalMinuteText.setText(""); //$NON-NLS-1$ - mSexagesimalSecondText.setText(""); //$NON-NLS-1$ - mManualTextChange--; - } - - /** - * Creates a {@link Text} with a given parent, default string and a {@link ModifyListener} - * @param parent the parent {@link Composite}. - * @param defaultString the default string to be used to compute the {@link Text} control - * size hint. - * @param listener the {@link ModifyListener} to be called when the {@link Text} control is - * modified. - */ - private Text createTextControl(Composite parent, String defaultString, - ModifyListener listener) { - // create the control - Text text = new Text(parent, SWT.BORDER | SWT.LEFT | SWT.SINGLE); - - // add the standard listener to it. - text.addModifyListener(listener); - - // compute its size/ - mManualTextChange++; - text.setText(defaultString); - text.pack(); - Point size = text.computeSize(SWT.DEFAULT, SWT.DEFAULT); - text.setText(""); //$NON-NLS-1$ - mManualTextChange--; - - GridData gridData = new GridData(); - gridData.widthHint = size.x; - text.setLayoutData(gridData); - - return text; - } - - private double getValueFromSexagesimalControls() throws ParseException { - double degrees = mDecimalFormat.parse(mSexagesimalDegreeText.getText()).doubleValue(); - double minutes = mDecimalFormat.parse(mSexagesimalMinuteText.getText()).doubleValue(); - double seconds = mDecimalFormat.parse(mSexagesimalSecondText.getText()).doubleValue(); - - boolean isPositive = (degrees >= 0.); - degrees = Math.abs(degrees); - - double value = degrees + minutes / 60. + seconds / 3600.; - return isPositive ? value : - value; - } - - private void setValueIntoDecimalControl(double value) { - mManualTextChange++; - mDecimalText.setText(String.format("%.6f", value)); - mManualTextChange--; - } - - private void setValueIntoSexagesimalControl(double value) { - // get the sign and make the number positive no matter what. - boolean isPositive = (value >= 0.); - value = Math.abs(value); - - // get the degree - double degrees = Math.floor(value); - - // get the minutes - double minutes = Math.floor((value - degrees) * 60.); - - // get the seconds. - double seconds = (value - degrees) * 3600. - minutes * 60.; - - mManualTextChange++; - mSexagesimalDegreeText.setText( - Integer.toString(isPositive ? (int)degrees : (int)- degrees)); - mSexagesimalMinuteText.setText(Integer.toString((int)minutes)); - mSexagesimalSecondText.setText(String.format("%.3f", seconds)); //$NON-NLS-1$ - mManualTextChange--; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/GpxParser.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/GpxParser.java deleted file mode 100644 index a30337a..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/GpxParser.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * 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.location; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * A very basic GPX parser to meet the need of the emulator control panel. - * <p/> - * It parses basic waypoint information, and tracks (merging segments). - */ -public class GpxParser { - - private final static String NS_GPX = "http://www.topografix.com/GPX/1/1"; //$NON-NLS-1$ - - private final static String NODE_WAYPOINT = "wpt"; //$NON-NLS-1$ - private final static String NODE_TRACK = "trk"; //$NON-NLS-1$ - private final static String NODE_TRACK_SEGMENT = "trkseg"; //$NON-NLS-1$ - private final static String NODE_TRACK_POINT = "trkpt"; //$NON-NLS-1$ - private final static String NODE_NAME = "name"; //$NON-NLS-1$ - private final static String NODE_TIME = "time"; //$NON-NLS-1$ - private final static String NODE_ELEVATION = "ele"; //$NON-NLS-1$ - private final static String NODE_DESCRIPTION = "desc"; //$NON-NLS-1$ - private final static String ATTR_LONGITUDE = "lon"; //$NON-NLS-1$ - private final static String ATTR_LATITUDE = "lat"; //$NON-NLS-1$ - - private static SAXParserFactory sParserFactory; - - static { - sParserFactory = SAXParserFactory.newInstance(); - sParserFactory.setNamespaceAware(true); - } - - private String mFileName; - - private GpxHandler mHandler; - - /** Pattern to parse time with optional sub-second precision, and optional - * Z indicating the time is in UTC. */ - private final static Pattern ISO8601_TIME = - Pattern.compile("(\\d{4})-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)(?:(\\.\\d+))?(Z)?"); //$NON-NLS-1$ - - /** - * Handler for the SAX parser. - */ - private static class GpxHandler extends DefaultHandler { - // --------- parsed data --------- - List<WayPoint> mWayPoints; - List<Track> mTrackList; - - // --------- state for parsing --------- - Track mCurrentTrack; - TrackPoint mCurrentTrackPoint; - WayPoint mCurrentWayPoint; - final StringBuilder mStringAccumulator = new StringBuilder(); - - boolean mSuccess = true; - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) - throws SAXException { - // we only care about the standard GPX nodes. - try { - if (NS_GPX.equals(uri)) { - if (NODE_WAYPOINT.equals(localName)) { - if (mWayPoints == null) { - mWayPoints = new ArrayList<WayPoint>(); - } - - mWayPoints.add(mCurrentWayPoint = new WayPoint()); - handleLocation(mCurrentWayPoint, attributes); - } else if (NODE_TRACK.equals(localName)) { - if (mTrackList == null) { - mTrackList = new ArrayList<Track>(); - } - - mTrackList.add(mCurrentTrack = new Track()); - } else if (NODE_TRACK_SEGMENT.equals(localName)) { - // for now we do nothing here. This will merge all the segments into - // a single TrackPoint list in the Track. - } else if (NODE_TRACK_POINT.equals(localName)) { - if (mCurrentTrack != null) { - mCurrentTrack.addPoint(mCurrentTrackPoint = new TrackPoint()); - handleLocation(mCurrentTrackPoint, attributes); - } - } - } - } finally { - // no matter the node, we empty the StringBuilder accumulator when we start - // a new node. - mStringAccumulator.setLength(0); - } - } - - /** - * Processes new characters for the node content. The characters are simply stored, - * and will be processed when {@link #endElement(String, String, String)} is called. - */ - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - mStringAccumulator.append(ch, start, length); - } - - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - if (NS_GPX.equals(uri)) { - if (NODE_WAYPOINT.equals(localName)) { - mCurrentWayPoint = null; - } else if (NODE_TRACK.equals(localName)) { - mCurrentTrack = null; - } else if (NODE_TRACK_POINT.equals(localName)) { - mCurrentTrackPoint = null; - } else if (NODE_NAME.equals(localName)) { - if (mCurrentTrack != null) { - mCurrentTrack.setName(mStringAccumulator.toString()); - } else if (mCurrentWayPoint != null) { - mCurrentWayPoint.setName(mStringAccumulator.toString()); - } - } else if (NODE_TIME.equals(localName)) { - if (mCurrentTrackPoint != null) { - mCurrentTrackPoint.setTime(computeTime(mStringAccumulator.toString())); - } - } else if (NODE_ELEVATION.equals(localName)) { - if (mCurrentTrackPoint != null) { - mCurrentTrackPoint.setElevation( - Double.parseDouble(mStringAccumulator.toString())); - } else if (mCurrentWayPoint != null) { - mCurrentWayPoint.setElevation( - Double.parseDouble(mStringAccumulator.toString())); - } - } else if (NODE_DESCRIPTION.equals(localName)) { - if (mCurrentWayPoint != null) { - mCurrentWayPoint.setDescription(mStringAccumulator.toString()); - } - } - } - } - - @Override - public void error(SAXParseException e) throws SAXException { - mSuccess = false; - } - - @Override - public void fatalError(SAXParseException e) throws SAXException { - mSuccess = false; - } - - /** - * Converts the string description of the time into milliseconds since epoch. - * @param timeString the string data. - * @return date in milliseconds. - */ - private long computeTime(String timeString) { - // Time looks like: 2008-04-05T19:24:50Z - Matcher m = ISO8601_TIME.matcher(timeString); - if (m.matches()) { - // get the various elements and reconstruct time as a long. - try { - int year = Integer.parseInt(m.group(1)); - int month = Integer.parseInt(m.group(2)); - int date = Integer.parseInt(m.group(3)); - int hourOfDay = Integer.parseInt(m.group(4)); - int minute = Integer.parseInt(m.group(5)); - int second = Integer.parseInt(m.group(6)); - - // handle the optional parameters. - int milliseconds = 0; - - String subSecondGroup = m.group(7); - if (subSecondGroup != null) { - milliseconds = (int)(1000 * Double.parseDouble(subSecondGroup)); - } - - boolean utcTime = m.group(8) != null; - - // now we convert into milliseconds since epoch. - Calendar c; - if (utcTime) { - c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$ - } else { - c = Calendar.getInstance(); - } - - c.set(year, month, date, hourOfDay, minute, second); - - return c.getTimeInMillis() + milliseconds; - } catch (NumberFormatException e) { - // format is invalid, we'll return -1 below. - } - - } - - // invalid time! - return -1; - } - - /** - * Handles the location attributes and store them into a {@link LocationPoint}. - * @param locationNode the {@link LocationPoint} to receive the location data. - * @param attributes the attributes from the XML node. - */ - private void handleLocation(LocationPoint locationNode, Attributes attributes) { - try { - double longitude = Double.parseDouble(attributes.getValue(ATTR_LONGITUDE)); - double latitude = Double.parseDouble(attributes.getValue(ATTR_LATITUDE)); - - locationNode.setLocation(longitude, latitude); - } catch (NumberFormatException e) { - // wrong data, do nothing. - } - } - - WayPoint[] getWayPoints() { - if (mWayPoints != null) { - return mWayPoints.toArray(new WayPoint[mWayPoints.size()]); - } - - return null; - } - - Track[] getTracks() { - if (mTrackList != null) { - return mTrackList.toArray(new Track[mTrackList.size()]); - } - - return null; - } - - boolean getSuccess() { - return mSuccess; - } - } - - /** - * A GPS track. - * <p/>A track is composed of a list of {@link TrackPoint} and optional name and comment. - */ - public final static class Track { - private String mName; - private String mComment; - private List<TrackPoint> mPoints = new ArrayList<TrackPoint>(); - - void setName(String name) { - mName = name; - } - - public String getName() { - return mName; - } - - void setComment(String comment) { - mComment = comment; - } - - public String getComment() { - return mComment; - } - - void addPoint(TrackPoint trackPoint) { - mPoints.add(trackPoint); - } - - public TrackPoint[] getPoints() { - return mPoints.toArray(new TrackPoint[mPoints.size()]); - } - - public long getFirstPointTime() { - if (mPoints.size() > 0) { - return mPoints.get(0).getTime(); - } - - return -1; - } - - public long getLastPointTime() { - if (mPoints.size() > 0) { - return mPoints.get(mPoints.size()-1).getTime(); - } - - return -1; - } - - public int getPointCount() { - return mPoints.size(); - } - } - - /** - * Creates a new GPX parser for a file specified by its full path. - * @param fileName The full path of the GPX file to parse. - */ - public GpxParser(String fileName) { - mFileName = fileName; - } - - /** - * Parses the GPX file. - * @return <code>true</code> if success. - */ - public boolean parse() { - try { - SAXParser parser = sParserFactory.newSAXParser(); - - mHandler = new GpxHandler(); - - parser.parse(new InputSource(new FileReader(mFileName)), mHandler); - - return mHandler.getSuccess(); - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } finally { - } - - return false; - } - - /** - * Returns the parsed {@link WayPoint} objects, or <code>null</code> if none were found (or - * if the parsing failed. - */ - public WayPoint[] getWayPoints() { - if (mHandler != null) { - return mHandler.getWayPoints(); - } - - return null; - } - - /** - * Returns the parsed {@link Track} objects, or <code>null</code> if none were found (or - * if the parsing failed. - */ - public Track[] getTracks() { - if (mHandler != null) { - return mHandler.getTracks(); - } - - return null; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/KmlParser.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/KmlParser.java deleted file mode 100644 index af485ac..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/KmlParser.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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.location; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * A very basic KML parser to meet the need of the emulator control panel. - * <p/> - * It parses basic Placemark information. - */ -public class KmlParser { - - private final static String NS_KML_2 = "http://earth.google.com/kml/2."; //$NON-NLS-1$ - - private final static String NODE_PLACEMARK = "Placemark"; //$NON-NLS-1$ - private final static String NODE_NAME = "name"; //$NON-NLS-1$ - private final static String NODE_COORDINATES = "coordinates"; //$NON-NLS-1$ - - private final static Pattern sLocationPattern = Pattern.compile("([^,]+),([^,]+)(?:,([^,]+))?"); - - private static SAXParserFactory sParserFactory; - - static { - sParserFactory = SAXParserFactory.newInstance(); - sParserFactory.setNamespaceAware(true); - } - - private String mFileName; - - private KmlHandler mHandler; - - /** - * Handler for the SAX parser. - */ - private static class KmlHandler extends DefaultHandler { - // --------- parsed data --------- - List<WayPoint> mWayPoints; - - // --------- state for parsing --------- - WayPoint mCurrentWayPoint; - final StringBuilder mStringAccumulator = new StringBuilder(); - - boolean mSuccess = true; - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) - throws SAXException { - // we only care about the standard GPX nodes. - try { - if (uri.startsWith(NS_KML_2)) { - if (NODE_PLACEMARK.equals(localName)) { - if (mWayPoints == null) { - mWayPoints = new ArrayList<WayPoint>(); - } - - mWayPoints.add(mCurrentWayPoint = new WayPoint()); - } - } - } finally { - // no matter the node, we empty the StringBuilder accumulator when we start - // a new node. - mStringAccumulator.setLength(0); - } - } - - /** - * Processes new characters for the node content. The characters are simply stored, - * and will be processed when {@link #endElement(String, String, String)} is called. - */ - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - mStringAccumulator.append(ch, start, length); - } - - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - if (uri.startsWith(NS_KML_2)) { - if (NODE_PLACEMARK.equals(localName)) { - mCurrentWayPoint = null; - } else if (NODE_NAME.equals(localName)) { - if (mCurrentWayPoint != null) { - mCurrentWayPoint.setName(mStringAccumulator.toString()); - } - } else if (NODE_COORDINATES.equals(localName)) { - if (mCurrentWayPoint != null) { - parseLocation(mCurrentWayPoint, mStringAccumulator.toString()); - } - } - } - } - - @Override - public void error(SAXParseException e) throws SAXException { - mSuccess = false; - } - - @Override - public void fatalError(SAXParseException e) throws SAXException { - mSuccess = false; - } - - /** - * Parses the location string and store the information into a {@link LocationPoint}. - * @param locationNode the {@link LocationPoint} to receive the location data. - * @param location The string containing the location info. - */ - private void parseLocation(LocationPoint locationNode, String location) { - Matcher m = sLocationPattern.matcher(location); - if (m.matches()) { - try { - double longitude = Double.parseDouble(m.group(1)); - double latitude = Double.parseDouble(m.group(2)); - - locationNode.setLocation(longitude, latitude); - - if (m.groupCount() == 3) { - // looks like we have elevation data. - locationNode.setElevation(Double.parseDouble(m.group(3))); - } - } catch (NumberFormatException e) { - // wrong data, do nothing. - } - } - } - - WayPoint[] getWayPoints() { - if (mWayPoints != null) { - return mWayPoints.toArray(new WayPoint[mWayPoints.size()]); - } - - return null; - } - - boolean getSuccess() { - return mSuccess; - } - } - - /** - * Creates a new GPX parser for a file specified by its full path. - * @param fileName The full path of the GPX file to parse. - */ - public KmlParser(String fileName) { - mFileName = fileName; - } - - /** - * Parses the GPX file. - * @return <code>true</code> if success. - */ - public boolean parse() { - try { - SAXParser parser = sParserFactory.newSAXParser(); - - mHandler = new KmlHandler(); - - parser.parse(new InputSource(new FileReader(mFileName)), mHandler); - - return mHandler.getSuccess(); - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } finally { - } - - return false; - } - - /** - * Returns the parsed {@link WayPoint} objects, or <code>null</code> if none were found (or - * if the parsing failed. - */ - public WayPoint[] getWayPoints() { - if (mHandler != null) { - return mHandler.getWayPoints(); - } - - return null; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/LocationPoint.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/LocationPoint.java deleted file mode 100644 index dbb8f41..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/LocationPoint.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.location; - -/** - * Base class for Location aware points. - */ -class LocationPoint { - private double mLongitude; - private double mLatitude; - private boolean mHasElevation = false; - private double mElevation; - - final void setLocation(double longitude, double latitude) { - mLongitude = longitude; - mLatitude = latitude; - } - - public final double getLongitude() { - return mLongitude; - } - - public final double getLatitude() { - return mLatitude; - } - - final void setElevation(double elevation) { - mElevation = elevation; - mHasElevation = true; - } - - public final boolean hasElevation() { - return mHasElevation; - } - - public final double getElevation() { - return mElevation; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackContentProvider.java deleted file mode 100644 index da21920..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackContentProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.location; - -import com.android.ddmuilib.location.GpxParser.Track; - -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Content provider to display {@link Track} objects in a Table. - * <p/>The expected type for the input is {@link Track}<code>[]</code>. - */ -public class TrackContentProvider implements IStructuredContentProvider { - - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof Track[]) { - return (Track[])inputElement; - } - - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackLabelProvider.java deleted file mode 100644 index 50acb53..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackLabelProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.location; - -import com.android.ddmuilib.location.GpxParser.Track; - -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Table; - -import java.util.Date; - -/** - * Label Provider for {@link Table} objects displaying {@link Track} objects. - */ -public class TrackLabelProvider implements ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof Track) { - Track track = (Track)element; - switch (columnIndex) { - case 0: - return track.getName(); - case 1: - return Integer.toString(track.getPointCount()); - case 2: - long time = track.getFirstPointTime(); - if (time != -1) { - return new Date(time).toString(); - } - break; - case 3: - time = track.getLastPointTime(); - if (time != -1) { - return new Date(time).toString(); - } - break; - case 4: - return track.getComment(); - } - } - - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackPoint.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackPoint.java deleted file mode 100644 index 527f4bf..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackPoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.location; - - -/** - * A Track Point. - * <p/>A track point is a point in time and space. - */ -public class TrackPoint extends LocationPoint { - private long mTime; - - void setTime(long time) { - mTime = time; - } - - public long getTime() { - return mTime; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPoint.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPoint.java deleted file mode 100644 index 32880bd..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPoint.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.location; - -/** - * A GPS/KML way point. - * <p/>A waypoint is a user specified location, with a name and an optional description. - */ -public final class WayPoint extends LocationPoint { - private String mName; - private String mDescription; - - void setName(String name) { - mName = name; - } - - public String getName() { - return mName; - } - - void setDescription(String description) { - mDescription = description; - } - - public String getDescription() { - return mDescription; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointContentProvider.java deleted file mode 100644 index 1b7fe15..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointContentProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.location; - -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Content provider to display {@link WayPoint} objects in a Table. - * <p/>The expected type for the input is {@link WayPoint}<code>[]</code>. - */ -public class WayPointContentProvider implements IStructuredContentProvider { - - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof WayPoint[]) { - return (WayPoint[])inputElement; - } - - return new Object[0]; - } - - @Override - public void dispose() { - // pass - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointLabelProvider.java deleted file mode 100644 index 9f642f1..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointLabelProvider.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.location; - -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Table; - -/** - * Label Provider for {@link Table} objects displaying {@link WayPoint} objects. - */ -public class WayPointLabelProvider implements ITableLabelProvider { - - @Override - public Image getColumnImage(Object element, int columnIndex) { - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof WayPoint) { - WayPoint wayPoint = (WayPoint)element; - switch (columnIndex) { - case 0: - return wayPoint.getName(); - case 1: - return String.format("%.6f", wayPoint.getLongitude()); - case 2: - return String.format("%.6f", wayPoint.getLatitude()); - case 3: - if (wayPoint.hasElevation()) { - return String.format("%.1f", wayPoint.getElevation()); - } else { - return "-"; - } - case 4: - return wayPoint.getDescription(); - } - } - - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/BugReportImporter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/BugReportImporter.java deleted file mode 100644 index da41e70..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/BugReportImporter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; - -public class BugReportImporter { - - private final static String TAG_HEADER = "------ EVENT LOG TAGS ------"; - private final static String LOG_HEADER = "------ EVENT LOG ------"; - private final static String HEADER_TAG = "------"; - - private String[] mTags; - private String[] mLog; - - public BugReportImporter(String filePath) throws FileNotFoundException { - BufferedReader reader = new BufferedReader( - new InputStreamReader(new FileInputStream(filePath))); - - try { - String line; - while ((line = reader.readLine()) != null) { - if (TAG_HEADER.equals(line)) { - readTags(reader); - return; - } - } - } catch (IOException e) { - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException ignore) { - } - } - } - } - - public String[] getTags() { - return mTags; - } - - public String[] getLog() { - return mLog; - } - - private void readTags(BufferedReader reader) throws IOException { - String line; - - ArrayList<String> content = new ArrayList<String>(); - while ((line = reader.readLine()) != null) { - if (LOG_HEADER.equals(line)) { - mTags = content.toArray(new String[content.size()]); - readLog(reader); - return; - } else { - content.add(line); - } - } - } - - private void readLog(BufferedReader reader) throws IOException { - String line; - - ArrayList<String> content = new ArrayList<String>(); - while ((line = reader.readLine()) != null) { - if (line.startsWith(HEADER_TAG) == false) { - content.add(line); - } else { - break; - } - } - - mLog = content.toArray(new String[content.size()]); - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayFilteredLog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayFilteredLog.java deleted file mode 100644 index 473387a..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayFilteredLog.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; - -import java.util.ArrayList; - -public class DisplayFilteredLog extends DisplayLog { - - public DisplayFilteredLog(String name) { - super(name); - } - - /** - * Adds event to the display. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - ArrayList<ValueDisplayDescriptor> valueDescriptors = - new ArrayList<ValueDisplayDescriptor>(); - - ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors = - new ArrayList<OccurrenceDisplayDescriptor>(); - - if (filterEvent(event, valueDescriptors, occurrenceDescriptors)) { - addToLog(event, logParser, valueDescriptors, occurrenceDescriptors); - } - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_FILTERED_LOG; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayGraph.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayGraph.java deleted file mode 100644 index 0cffd7e..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayGraph.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.EventValueDescription; -import com.android.ddmlib.log.InvalidTypeException; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.jfree.chart.axis.AxisLocation; -import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; -import org.jfree.chart.renderer.xy.XYAreaRenderer; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.jfree.data.time.Millisecond; -import org.jfree.data.time.TimeSeries; -import org.jfree.data.time.TimeSeriesCollection; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -public class DisplayGraph extends EventDisplay { - - public DisplayGraph(String name) { - super(name); - } - - /** - * Resets the display. - */ - @Override - void resetUI() { - Collection<TimeSeriesCollection> datasets = mValueTypeDataSetMap.values(); - for (TimeSeriesCollection dataset : datasets) { - dataset.removeAllSeries(); - } - if (mOccurrenceDataSet != null) { - mOccurrenceDataSet.removeAllSeries(); - } - mValueDescriptorSeriesMap.clear(); - mOcurrenceDescriptorSeriesMap.clear(); - } - - /** - * 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). - */ - @Override - public Control createComposite(final Composite parent, EventLogParser logParser, - final ILogColumnListener listener) { - String title = getChartTitle(logParser); - return createCompositeChart(parent, logParser, title); - } - - /** - * Adds event to the display. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - ArrayList<ValueDisplayDescriptor> valueDescriptors = - new ArrayList<ValueDisplayDescriptor>(); - - ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors = - new ArrayList<OccurrenceDisplayDescriptor>(); - - if (filterEvent(event, valueDescriptors, occurrenceDescriptors)) { - updateChart(event, logParser, valueDescriptors, occurrenceDescriptors); - } - } - - /** - * Updates the chart with the {@link EventContainer} by adding the values/occurrences defined - * by the {@link ValueDisplayDescriptor} and {@link OccurrenceDisplayDescriptor} objects from - * the two lists. - * <p/>This method is only called when at least one of the descriptor list is non empty. - * @param event - * @param logParser - * @param valueDescriptors - * @param occurrenceDescriptors - */ - private void updateChart(EventContainer event, EventLogParser logParser, - ArrayList<ValueDisplayDescriptor> valueDescriptors, - ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors) { - Map<Integer, String> tagMap = logParser.getTagMap(); - - Millisecond millisecondTime = null; - long msec = -1; - - // If the event container is a cpu container (tag == 2721), and there is no descriptor - // for the total CPU load, then we do accumulate all the values. - boolean accumulateValues = false; - double accumulatedValue = 0; - - if (event.mTag == 2721) { - accumulateValues = true; - for (ValueDisplayDescriptor descriptor : valueDescriptors) { - accumulateValues &= (descriptor.valueIndex != 0); - } - } - - for (ValueDisplayDescriptor descriptor : valueDescriptors) { - try { - // get the hashmap for this descriptor - HashMap<Integer, TimeSeries> map = mValueDescriptorSeriesMap.get(descriptor); - - // if it's not there yet, we create it. - if (map == null) { - map = new HashMap<Integer, TimeSeries>(); - mValueDescriptorSeriesMap.put(descriptor, map); - } - - // get the TimeSeries for this pid - TimeSeries timeSeries = map.get(event.pid); - - // if it doesn't exist yet, we create it - if (timeSeries == null) { - // get the series name - String seriesFullName = null; - String seriesLabel = getSeriesLabel(event, descriptor); - - switch (mValueDescriptorCheck) { - case EVENT_CHECK_SAME_TAG: - seriesFullName = String.format("%1$s / %2$s", seriesLabel, - descriptor.valueName); - break; - case EVENT_CHECK_SAME_VALUE: - seriesFullName = String.format("%1$s", seriesLabel); - break; - default: - seriesFullName = String.format("%1$s / %2$s: %3$s", seriesLabel, - tagMap.get(descriptor.eventTag), - descriptor.valueName); - break; - } - - // get the data set for this ValueType - TimeSeriesCollection dataset = getValueDataset( - logParser.getEventInfoMap().get(event.mTag)[descriptor.valueIndex] - .getValueType(), - accumulateValues); - - // create the series - timeSeries = new TimeSeries(seriesFullName, Millisecond.class); - if (mMaximumChartItemAge != -1) { - timeSeries.setMaximumItemAge(mMaximumChartItemAge * 1000); - } - - dataset.addSeries(timeSeries); - - // add it to the map. - map.put(event.pid, timeSeries); - } - - // update the timeSeries. - - // get the value from the event - double value = event.getValueAsDouble(descriptor.valueIndex); - - // accumulate the values if needed. - if (accumulateValues) { - accumulatedValue += value; - value = accumulatedValue; - } - - // get the time - if (millisecondTime == null) { - msec = (long)event.sec * 1000L + (event.nsec / 1000000L); - millisecondTime = new Millisecond(new Date(msec)); - } - - // add the value to the time series - timeSeries.addOrUpdate(millisecondTime, value); - } catch (InvalidTypeException e) { - // just ignore this descriptor if there's a type mismatch - } - } - - for (OccurrenceDisplayDescriptor descriptor : occurrenceDescriptors) { - try { - // get the hashmap for this descriptor - HashMap<Integer, TimeSeries> map = mOcurrenceDescriptorSeriesMap.get(descriptor); - - // if it's not there yet, we create it. - if (map == null) { - map = new HashMap<Integer, TimeSeries>(); - mOcurrenceDescriptorSeriesMap.put(descriptor, map); - } - - // get the TimeSeries for this pid - TimeSeries timeSeries = map.get(event.pid); - - // if it doesn't exist yet, we create it. - if (timeSeries == null) { - String seriesLabel = getSeriesLabel(event, descriptor); - - String seriesFullName = String.format("[%1$s:%2$s]", - tagMap.get(descriptor.eventTag), seriesLabel); - - timeSeries = new TimeSeries(seriesFullName, Millisecond.class); - if (mMaximumChartItemAge != -1) { - timeSeries.setMaximumItemAge(mMaximumChartItemAge); - } - - getOccurrenceDataSet().addSeries(timeSeries); - - map.put(event.pid, timeSeries); - } - - // update the series - - // get the time - if (millisecondTime == null) { - msec = (long)event.sec * 1000L + (event.nsec / 1000000L); - millisecondTime = new Millisecond(new Date(msec)); - } - - // add the value to the time series - timeSeries.addOrUpdate(millisecondTime, 0); // the value is unused - } catch (InvalidTypeException e) { - // just ignore this descriptor if there's a type mismatch - } - } - - // go through all the series and remove old values. - if (msec != -1 && mMaximumChartItemAge != -1) { - Collection<HashMap<Integer, TimeSeries>> pidMapValues = - mValueDescriptorSeriesMap.values(); - - for (HashMap<Integer, TimeSeries> pidMapValue : pidMapValues) { - Collection<TimeSeries> seriesCollection = pidMapValue.values(); - - for (TimeSeries timeSeries : seriesCollection) { - timeSeries.removeAgedItems(msec, true); - } - } - - pidMapValues = mOcurrenceDescriptorSeriesMap.values(); - for (HashMap<Integer, TimeSeries> pidMapValue : pidMapValues) { - Collection<TimeSeries> seriesCollection = pidMapValue.values(); - - for (TimeSeries timeSeries : seriesCollection) { - timeSeries.removeAgedItems(msec, true); - } - } - } - } - - /** - * Returns a {@link TimeSeriesCollection} for a specific {@link com.android.ddmlib.log.EventValueDescription.ValueType}. - * If the data set is not yet created, it is first allocated and set up into the - * {@link org.jfree.chart.JFreeChart} object. - * @param type the {@link com.android.ddmlib.log.EventValueDescription.ValueType} of the data set. - * @param accumulateValues - */ - private TimeSeriesCollection getValueDataset(EventValueDescription.ValueType type, boolean accumulateValues) { - TimeSeriesCollection dataset = mValueTypeDataSetMap.get(type); - if (dataset == null) { - // create the data set and store it in the map - dataset = new TimeSeriesCollection(); - mValueTypeDataSetMap.put(type, dataset); - - // create the renderer and configure it depending on the ValueType - AbstractXYItemRenderer renderer; - if (type == EventValueDescription.ValueType.PERCENT && accumulateValues) { - renderer = new XYAreaRenderer(); - } else { - XYLineAndShapeRenderer r = new XYLineAndShapeRenderer(); - r.setBaseShapesVisible(type != EventValueDescription.ValueType.PERCENT); - - renderer = r; - } - - // set both the dataset and the renderer in the plot object. - XYPlot xyPlot = mChart.getXYPlot(); - xyPlot.setDataset(mDataSetCount, dataset); - xyPlot.setRenderer(mDataSetCount, renderer); - - // put a new axis label, and configure it. - NumberAxis axis = new NumberAxis(type.toString()); - - if (type == EventValueDescription.ValueType.PERCENT) { - // force percent range to be (0,100) fixed. - axis.setAutoRange(false); - axis.setRange(0., 100.); - } - - // for the index, we ignore the occurrence dataset - int count = mDataSetCount; - if (mOccurrenceDataSet != null) { - count--; - } - - xyPlot.setRangeAxis(count, axis); - if ((count % 2) == 0) { - xyPlot.setRangeAxisLocation(count, AxisLocation.BOTTOM_OR_LEFT); - } else { - xyPlot.setRangeAxisLocation(count, AxisLocation.TOP_OR_RIGHT); - } - - // now we link the dataset and the axis - xyPlot.mapDatasetToRangeAxis(mDataSetCount, count); - - mDataSetCount++; - } - - return dataset; - } - - /** - * Return the series label for this event. This only contains the pid information. - * @param event the {@link EventContainer} - * @param descriptor the {@link OccurrenceDisplayDescriptor} - * @return the series label. - * @throws InvalidTypeException - */ - private String getSeriesLabel(EventContainer event, OccurrenceDisplayDescriptor descriptor) - throws InvalidTypeException { - if (descriptor.seriesValueIndex != -1) { - if (descriptor.includePid == false) { - return event.getValueAsString(descriptor.seriesValueIndex); - } else { - return String.format("%1$s (%2$d)", - event.getValueAsString(descriptor.seriesValueIndex), event.pid); - } - } - - return Integer.toString(event.pid); - } - - /** - * Returns the {@link TimeSeriesCollection} for the occurrence display. If the data set is not - * yet created, it is first allocated and set up into the {@link org.jfree.chart.JFreeChart} object. - */ - private TimeSeriesCollection getOccurrenceDataSet() { - if (mOccurrenceDataSet == null) { - mOccurrenceDataSet = new TimeSeriesCollection(); - - XYPlot xyPlot = mChart.getXYPlot(); - xyPlot.setDataset(mDataSetCount, mOccurrenceDataSet); - - OccurrenceRenderer renderer = new OccurrenceRenderer(); - renderer.setBaseShapesVisible(false); - xyPlot.setRenderer(mDataSetCount, renderer); - - mDataSetCount++; - } - - return mOccurrenceDataSet; - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_GRAPH; - } - - /** - * Sets the current {@link EventLogParser} object. - */ - @Override - protected void setNewLogParser(EventLogParser logParser) { - if (mChart != null) { - mChart.setTitle(getChartTitle(logParser)); - } - } - /** - * Returns a meaningful chart title based on the value of {@link #mValueDescriptorCheck}. - * - * @param logParser the logParser. - * @return the chart title. - */ - private String getChartTitle(EventLogParser logParser) { - if (mValueDescriptors.size() > 0) { - String chartDesc = null; - switch (mValueDescriptorCheck) { - case EVENT_CHECK_SAME_TAG: - if (logParser != null) { - chartDesc = logParser.getTagMap().get(mValueDescriptors.get(0).eventTag); - } - break; - case EVENT_CHECK_SAME_VALUE: - if (logParser != null) { - chartDesc = String.format("%1$s / %2$s", - logParser.getTagMap().get(mValueDescriptors.get(0).eventTag), - mValueDescriptors.get(0).valueName); - } - break; - } - - if (chartDesc != null) { - return String.format("%1$s - %2$s", mName, chartDesc); - } - } - - return mName; - } -}
\ No newline at end of file diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayLog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayLog.java deleted file mode 100644 index 8e7c1ac..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayLog.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.EventValueDescription; -import com.android.ddmlib.log.InvalidTypeException; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.TableHelper; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.ScrollBar; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; - -import java.util.ArrayList; -import java.util.Calendar; - -public class DisplayLog extends EventDisplay { - public DisplayLog(String name) { - super(name); - } - - private final static String PREFS_COL_DATE = "EventLogPanel.log.Col1"; //$NON-NLS-1$ - private final static String PREFS_COL_PID = "EventLogPanel.log.Col2"; //$NON-NLS-1$ - private final static String PREFS_COL_EVENTTAG = "EventLogPanel.log.Col3"; //$NON-NLS-1$ - private final static String PREFS_COL_VALUENAME = "EventLogPanel.log.Col4"; //$NON-NLS-1$ - private final static String PREFS_COL_VALUE = "EventLogPanel.log.Col5"; //$NON-NLS-1$ - private final static String PREFS_COL_TYPE = "EventLogPanel.log.Col6"; //$NON-NLS-1$ - - /** - * Resets the display. - */ - @Override - void resetUI() { - mLogTable.removeAll(); - } - - /** - * Adds event to the display. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - addToLog(event, logParser); - } - - /** - * 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). - */ - @Override - Control createComposite(Composite parent, EventLogParser logParser, ILogColumnListener listener) { - return createLogUI(parent, listener); - } - - /** - * Adds an {@link EventContainer} to the log. - * - * @param event the event. - * @param logParser the log parser. - */ - private void addToLog(EventContainer event, EventLogParser logParser) { - ScrollBar bar = mLogTable.getVerticalBar(); - boolean scroll = bar.getMaximum() == bar.getSelection() + bar.getThumb(); - - // get the date. - Calendar c = Calendar.getInstance(); - long msec = event.sec * 1000L; - c.setTimeInMillis(msec); - - // convert the time into a string - String date = String.format("%1$tF %1$tT", c); - - String eventName = logParser.getTagMap().get(event.mTag); - String pidName = Integer.toString(event.pid); - - // get the value description - EventValueDescription[] valueDescription = logParser.getEventInfoMap().get(event.mTag); - if (valueDescription != null) { - for (int i = 0; i < valueDescription.length; i++) { - EventValueDescription description = valueDescription[i]; - try { - String value = event.getValueAsString(i); - - logValue(date, pidName, eventName, description.getName(), value, - description.getEventValueType(), description.getValueType()); - } catch (InvalidTypeException e) { - logValue(date, pidName, eventName, description.getName(), e.getMessage(), - description.getEventValueType(), description.getValueType()); - } - } - - // scroll if needed, by showing the last item - if (scroll) { - int itemCount = mLogTable.getItemCount(); - if (itemCount > 0) { - mLogTable.showItem(mLogTable.getItem(itemCount - 1)); - } - } - } - } - - /** - * Adds an {@link EventContainer} to the log. Only add the values/occurrences defined by - * the list of descriptors. If an event is configured to be displayed by value and occurrence, - * only the values are displayed (as they mark an event occurrence anyway). - * <p/>This method is only called when at least one of the descriptor list is non empty. - * - * @param event - * @param logParser - * @param valueDescriptors - * @param occurrenceDescriptors - */ - protected void addToLog(EventContainer event, EventLogParser logParser, - ArrayList<ValueDisplayDescriptor> valueDescriptors, - ArrayList<OccurrenceDisplayDescriptor> occurrenceDescriptors) { - ScrollBar bar = mLogTable.getVerticalBar(); - boolean scroll = bar.getMaximum() == bar.getSelection() + bar.getThumb(); - - // get the date. - Calendar c = Calendar.getInstance(); - long msec = event.sec * 1000L; - c.setTimeInMillis(msec); - - // convert the time into a string - String date = String.format("%1$tF %1$tT", c); - - String eventName = logParser.getTagMap().get(event.mTag); - String pidName = Integer.toString(event.pid); - - if (valueDescriptors.size() > 0) { - for (ValueDisplayDescriptor descriptor : valueDescriptors) { - logDescriptor(event, descriptor, date, pidName, eventName, logParser); - } - } else { - // we display the event. Since the StringBuilder contains the header (date, event name, - // pid) at this point, there isn't anything else to display. - } - - // scroll if needed, by showing the last item - if (scroll) { - int itemCount = mLogTable.getItemCount(); - if (itemCount > 0) { - mLogTable.showItem(mLogTable.getItem(itemCount - 1)); - } - } - } - - - /** - * Logs a value in the ui. - * - * @param date - * @param pid - * @param event - * @param valueName - * @param value - * @param eventValueType - * @param valueType - */ - private void logValue(String date, String pid, String event, String valueName, - String value, EventContainer.EventValueType eventValueType, EventValueDescription.ValueType valueType) { - - TableItem item = new TableItem(mLogTable, SWT.NONE); - item.setText(0, date); - item.setText(1, pid); - item.setText(2, event); - item.setText(3, valueName); - item.setText(4, value); - - String type; - if (valueType != EventValueDescription.ValueType.NOT_APPLICABLE) { - type = String.format("%1$s, %2$s", eventValueType.toString(), valueType.toString()); - } else { - type = eventValueType.toString(); - } - - item.setText(5, type); - } - - /** - * Logs a value from an {@link EventContainer} as defined by the {@link ValueDisplayDescriptor}. - * - * @param event the EventContainer - * @param descriptor the ValueDisplayDescriptor defining which value to display. - * @param date the date of the event in a string. - * @param pidName - * @param eventName - * @param logParser - */ - private void logDescriptor(EventContainer event, ValueDisplayDescriptor descriptor, - String date, String pidName, String eventName, EventLogParser logParser) { - - String value; - try { - value = event.getValueAsString(descriptor.valueIndex); - } catch (InvalidTypeException e) { - value = e.getMessage(); - } - - EventValueDescription[] values = logParser.getEventInfoMap().get(event.mTag); - - EventValueDescription valueDescription = values[descriptor.valueIndex]; - - logValue(date, pidName, eventName, descriptor.valueName, value, - valueDescription.getEventValueType(), valueDescription.getValueType()); - } - - /** - * Creates the UI for a log display. - * - * @param parent the parent {@link Composite} - * @param listener the {@link ILogColumnListener} to notify on column resize events. - * @return the top Composite of the UI. - */ - private Control createLogUI(Composite parent, final ILogColumnListener listener) { - Composite mainComp = new Composite(parent, SWT.NONE); - GridLayout gl; - mainComp.setLayout(gl = new GridLayout(1, false)); - gl.marginHeight = gl.marginWidth = 0; - mainComp.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - mLogTable = null; - } - }); - - Label l = new Label(mainComp, SWT.CENTER); - l.setText(mName); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mLogTable = new Table(mainComp, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL | - SWT.BORDER); - mLogTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - - IPreferenceStore store = DdmUiPreferences.getStore(); - - TableColumn col = TableHelper.createTableColumn( - mLogTable, "Time", - SWT.LEFT, "0000-00-00 00:00:00", PREFS_COL_DATE, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(0, (TableColumn) source); - } - } - }); - - col = TableHelper.createTableColumn( - mLogTable, "pid", - SWT.LEFT, "0000", PREFS_COL_PID, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(1, (TableColumn) source); - } - } - }); - - col = TableHelper.createTableColumn( - mLogTable, "Event", - SWT.LEFT, "abcdejghijklmno", PREFS_COL_EVENTTAG, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(2, (TableColumn) source); - } - } - }); - - col = TableHelper.createTableColumn( - mLogTable, "Name", - SWT.LEFT, "Process Name", PREFS_COL_VALUENAME, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(3, (TableColumn) source); - } - } - }); - - col = TableHelper.createTableColumn( - mLogTable, "Value", - SWT.LEFT, "0000000", PREFS_COL_VALUE, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(4, (TableColumn) source); - } - } - }); - - col = TableHelper.createTableColumn( - mLogTable, "Type", - SWT.LEFT, "long, seconds", PREFS_COL_TYPE, store); //$NON-NLS-1$ - col.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Object source = e.getSource(); - if (source instanceof TableColumn) { - listener.columnResized(5, (TableColumn) source); - } - } - }); - - mLogTable.setHeaderVisible(true); - mLogTable.setLinesVisible(true); - - return mainComp; - } - - /** - * Resizes the <code>index</code>-th column of the log {@link Table} (if applicable). - * <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. - */ - @Override - void resizeColumn(int index, TableColumn sourceColumn) { - if (mLogTable != null) { - TableColumn col = mLogTable.getColumn(index); - if (col != sourceColumn) { - col.setWidth(sourceColumn.getWidth()); - } - } - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_LOG_ALL; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySync.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySync.java deleted file mode 100644 index 6122513..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySync.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.InvalidTypeException; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.jfree.chart.labels.CustomXYToolTipGenerator; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYBarRenderer; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.jfree.data.time.FixedMillisecond; -import org.jfree.data.time.SimpleTimePeriod; -import org.jfree.data.time.TimePeriodValues; -import org.jfree.data.time.TimePeriodValuesCollection; -import org.jfree.data.time.TimeSeries; -import org.jfree.data.time.TimeSeriesCollection; -import org.jfree.util.ShapeUtilities; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; -import java.util.regex.Pattern; - -public class DisplaySync extends SyncCommon { - - // Information to graph for each authority - private TimePeriodValues mDatasetsSync[]; - private List<String> mTooltipsSync[]; - private CustomXYToolTipGenerator mTooltipGenerators[]; - private TimeSeries mDatasetsSyncTickle[]; - - // Dataset of error events to graph - private TimeSeries mDatasetError; - - public DisplaySync(String name) { - super(name); - } - - /** - * 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). - */ - @Override - public Control createComposite(final Composite parent, EventLogParser logParser, - final ILogColumnListener listener) { - Control composite = createCompositeChart(parent, logParser, "Sync Status"); - resetUI(); - return composite; - } - - /** - * Resets the display. - */ - @Override - void resetUI() { - super.resetUI(); - XYPlot xyPlot = mChart.getXYPlot(); - - XYBarRenderer br = new XYBarRenderer(); - mDatasetsSync = new TimePeriodValues[NUM_AUTHS]; - - @SuppressWarnings("unchecked") - List<String> mTooltipsSyncTmp[] = new List[NUM_AUTHS]; - mTooltipsSync = mTooltipsSyncTmp; - - mTooltipGenerators = new CustomXYToolTipGenerator[NUM_AUTHS]; - - TimePeriodValuesCollection tpvc = new TimePeriodValuesCollection(); - xyPlot.setDataset(tpvc); - xyPlot.setRenderer(0, br); - - XYLineAndShapeRenderer ls = new XYLineAndShapeRenderer(); - ls.setBaseLinesVisible(false); - mDatasetsSyncTickle = new TimeSeries[NUM_AUTHS]; - TimeSeriesCollection tsc = new TimeSeriesCollection(); - xyPlot.setDataset(1, tsc); - xyPlot.setRenderer(1, ls); - - mDatasetError = new TimeSeries("Errors", FixedMillisecond.class); - xyPlot.setDataset(2, new TimeSeriesCollection(mDatasetError)); - XYLineAndShapeRenderer errls = new XYLineAndShapeRenderer(); - errls.setBaseLinesVisible(false); - errls.setSeriesPaint(0, Color.RED); - xyPlot.setRenderer(2, errls); - - for (int i = 0; i < NUM_AUTHS; i++) { - br.setSeriesPaint(i, AUTH_COLORS[i]); - ls.setSeriesPaint(i, AUTH_COLORS[i]); - mDatasetsSync[i] = new TimePeriodValues(AUTH_NAMES[i]); - tpvc.addSeries(mDatasetsSync[i]); - mTooltipsSync[i] = new ArrayList<String>(); - mTooltipGenerators[i] = new CustomXYToolTipGenerator(); - br.setSeriesToolTipGenerator(i, mTooltipGenerators[i]); - mTooltipGenerators[i].addToolTipSeries(mTooltipsSync[i]); - - mDatasetsSyncTickle[i] = new TimeSeries(AUTH_NAMES[i] + " tickle", - FixedMillisecond.class); - tsc.addSeries(mDatasetsSyncTickle[i]); - ls.setSeriesShape(i, ShapeUtilities.createUpTriangle(2.5f)); - } - } - - /** - * Updates the display with a new event. - * - * @param event The event - * @param logParser The parser providing the event. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - super.newEvent(event, logParser); // Handle sync operation - try { - if (event.mTag == EVENT_TICKLE) { - int auth = getAuth(event.getValueAsString(0)); - if (auth >= 0) { - long msec = event.sec * 1000L + (event.nsec / 1000000L); - mDatasetsSyncTickle[auth].addOrUpdate(new FixedMillisecond(msec), -1); - } - } - } catch (InvalidTypeException e) { - } - } - - /** - * Generate the height for an event. - * Height is somewhat arbitrarily the count of "things" that happened - * during the sync. - * When network traffic measurements are available, code should be modified - * to use that instead. - * @param details The details string associated with the event - * @return The height in arbirary units (0-100) - */ - private int getHeightFromDetails(String details) { - if (details == null) { - return 1; // Arbitrary - } - int total = 0; - String parts[] = details.split("[a-zA-Z]"); - for (String part : parts) { - if ("".equals(part)) continue; - total += Integer.parseInt(part); - } - if (total == 0) { - total = 1; - } - return total; - } - - /** - * Generates the tooltips text for an event. - * This method decodes the cryptic details string. - * @param auth The authority associated with the event - * @param details The details string - * @param eventSource server, poll, etc. - * @return The text to display in the tooltips - */ - private String getTextFromDetails(int auth, String details, int eventSource) { - - StringBuffer sb = new StringBuffer(); - sb.append(AUTH_NAMES[auth]).append(": \n"); - - Scanner scanner = new Scanner(details); - Pattern charPat = Pattern.compile("[a-zA-Z]"); - Pattern numPat = Pattern.compile("[0-9]+"); - while (scanner.hasNext()) { - String key = scanner.findInLine(charPat); - int val = Integer.parseInt(scanner.findInLine(numPat)); - if (auth == GMAIL && "M".equals(key)) { - sb.append("messages from server: ").append(val).append("\n"); - } else if (auth == GMAIL && "L".equals(key)) { - sb.append("labels from server: ").append(val).append("\n"); - } else if (auth == GMAIL && "C".equals(key)) { - sb.append("check conversation requests from server: ").append(val).append("\n"); - } else if (auth == GMAIL && "A".equals(key)) { - sb.append("attachments from server: ").append(val).append("\n"); - } else if (auth == GMAIL && "U".equals(key)) { - sb.append("op updates from server: ").append(val).append("\n"); - } else if (auth == GMAIL && "u".equals(key)) { - sb.append("op updates to server: ").append(val).append("\n"); - } else if (auth == GMAIL && "S".equals(key)) { - sb.append("send/receive cycles: ").append(val).append("\n"); - } else if ("Q".equals(key)) { - sb.append("queries to server: ").append(val).append("\n"); - } else if ("E".equals(key)) { - sb.append("entries from server: ").append(val).append("\n"); - } else if ("u".equals(key)) { - sb.append("updates from client: ").append(val).append("\n"); - } else if ("i".equals(key)) { - sb.append("inserts from client: ").append(val).append("\n"); - } else if ("d".equals(key)) { - sb.append("deletes from client: ").append(val).append("\n"); - } else if ("f".equals(key)) { - sb.append("full sync requested\n"); - } else if ("r".equals(key)) { - sb.append("partial sync unavailable\n"); - } else if ("X".equals(key)) { - sb.append("hard error\n"); - } else if ("e".equals(key)) { - sb.append("number of parse exceptions: ").append(val).append("\n"); - } else if ("c".equals(key)) { - sb.append("number of conflicts: ").append(val).append("\n"); - } else if ("a".equals(key)) { - sb.append("number of auth exceptions: ").append(val).append("\n"); - } else if ("D".equals(key)) { - sb.append("too many deletions\n"); - } else if ("R".equals(key)) { - sb.append("too many retries: ").append(val).append("\n"); - } else if ("b".equals(key)) { - sb.append("database error\n"); - } else if ("x".equals(key)) { - sb.append("soft error\n"); - } else if ("l".equals(key)) { - sb.append("sync already in progress\n"); - } else if ("I".equals(key)) { - sb.append("io exception\n"); - } else if (auth == CONTACTS && "g".equals(key)) { - sb.append("aggregation query: ").append(val).append("\n"); - } else if (auth == CONTACTS && "G".equals(key)) { - sb.append("aggregation merge: ").append(val).append("\n"); - } else if (auth == CONTACTS && "n".equals(key)) { - sb.append("num entries: ").append(val).append("\n"); - } else if (auth == CONTACTS && "p".equals(key)) { - sb.append("photos uploaded from server: ").append(val).append("\n"); - } else if (auth == CONTACTS && "P".equals(key)) { - sb.append("photos downloaded from server: ").append(val).append("\n"); - } else if (auth == CALENDAR && "F".equals(key)) { - sb.append("server refresh\n"); - } else if (auth == CALENDAR && "s".equals(key)) { - sb.append("server diffs fetched\n"); - } else { - sb.append(key).append("=").append(val); - } - } - if (eventSource == 0) { - sb.append("(server)"); - } else if (eventSource == 1) { - sb.append("(local)"); - } else if (eventSource == 2) { - sb.append("(poll)"); - } else if (eventSource == 3) { - sb.append("(user)"); - } - return sb.toString(); - } - - - /** - * Callback to process a sync event. - */ - @Override - void processSyncEvent(EventContainer event, int auth, long startTime, long stopTime, - String details, boolean newEvent, int syncSource) { - if (!newEvent) { - // Details arrived for a previous sync event - // Remove event before reinserting. - int lastItem = mDatasetsSync[auth].getItemCount(); - mDatasetsSync[auth].delete(lastItem-1, lastItem-1); - mTooltipsSync[auth].remove(lastItem-1); - } - double height = getHeightFromDetails(details); - height = height / (stopTime - startTime + 1) * 10000; - if (height > 30) { - height = 30; - } - mDatasetsSync[auth].add(new SimpleTimePeriod(startTime, stopTime), height); - mTooltipsSync[auth].add(getTextFromDetails(auth, details, syncSource)); - mTooltipGenerators[auth].addToolTipSeries(mTooltipsSync[auth]); - if (details.indexOf('x') >= 0 || details.indexOf('X') >= 0) { - long msec = event.sec * 1000L + (event.nsec / 1000000L); - mDatasetError.addOrUpdate(new FixedMillisecond(msec), -1); - } - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_SYNC; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncHistogram.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncHistogram.java deleted file mode 100644 index 5bfc039..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncHistogram.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; -import org.jfree.chart.renderer.xy.XYBarRenderer; -import org.jfree.data.time.RegularTimePeriod; -import org.jfree.data.time.SimpleTimePeriod; -import org.jfree.data.time.TimePeriodValues; -import org.jfree.data.time.TimePeriodValuesCollection; - -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; - -public class DisplaySyncHistogram extends SyncCommon { - - Map<SimpleTimePeriod, Integer> mTimePeriodMap[]; - - // Information to graph for each authority - private TimePeriodValues mDatasetsSyncHist[]; - - public DisplaySyncHistogram(String name) { - super(name); - } - - /** - * 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). - */ - @Override - public Control createComposite(final Composite parent, EventLogParser logParser, - final ILogColumnListener listener) { - Control composite = createCompositeChart(parent, logParser, "Sync Histogram"); - resetUI(); - return composite; - } - - /** - * Resets the display. - */ - @Override - void resetUI() { - super.resetUI(); - XYPlot xyPlot = mChart.getXYPlot(); - - AbstractXYItemRenderer br = new XYBarRenderer(); - mDatasetsSyncHist = new TimePeriodValues[NUM_AUTHS+1]; - - @SuppressWarnings("unchecked") - Map<SimpleTimePeriod, Integer> mTimePeriodMapTmp[] = new HashMap[NUM_AUTHS + 1]; - mTimePeriodMap = mTimePeriodMapTmp; - - TimePeriodValuesCollection tpvc = new TimePeriodValuesCollection(); - xyPlot.setDataset(tpvc); - xyPlot.setRenderer(br); - - for (int i = 0; i < NUM_AUTHS + 1; i++) { - br.setSeriesPaint(i, AUTH_COLORS[i]); - mDatasetsSyncHist[i] = new TimePeriodValues(AUTH_NAMES[i]); - tpvc.addSeries(mDatasetsSyncHist[i]); - mTimePeriodMap[i] = new HashMap<SimpleTimePeriod, Integer>(); - - } - } - - /** - * Callback to process a sync event. - * - * @param event The sync event - * @param startTime Start time (ms) of events - * @param stopTime Stop time (ms) of events - * @param details Details associated with the event. - * @param newEvent True if this event is a new sync event. False if this event - * @param syncSource - */ - @Override - void processSyncEvent(EventContainer event, int auth, long startTime, long stopTime, - String details, boolean newEvent, int syncSource) { - if (newEvent) { - if (details.indexOf('x') >= 0 || details.indexOf('X') >= 0) { - auth = ERRORS; - } - double delta = (stopTime - startTime) * 100. / 1000 / 3600; // Percent of hour - addHistEvent(0, auth, delta); - } else { - // sync_details arrived for an event that has already been graphed. - if (details.indexOf('x') >= 0 || details.indexOf('X') >= 0) { - // Item turns out to be in error, so transfer time from old auth to error. - double delta = (stopTime - startTime) * 100. / 1000 / 3600; // Percent of hour - addHistEvent(0, auth, -delta); - addHistEvent(0, ERRORS, delta); - } - } - } - - /** - * Helper to add an event to the data series. - * Also updates error series if appropriate (x or X in details). - * @param stopTime Time event ends - * @param auth Sync authority - * @param value Value to graph for event - */ - private void addHistEvent(long stopTime, int auth, double value) { - SimpleTimePeriod hour = getTimePeriod(stopTime, mHistWidth); - - // Loop over all datasets to do the stacking. - for (int i = auth; i <= ERRORS; i++) { - addToPeriod(mDatasetsSyncHist, i, hour, value); - } - } - - private void addToPeriod(TimePeriodValues tpv[], int auth, SimpleTimePeriod period, - double value) { - int index; - if (mTimePeriodMap[auth].containsKey(period)) { - index = mTimePeriodMap[auth].get(period); - double oldValue = tpv[auth].getValue(index).doubleValue(); - tpv[auth].update(index, oldValue + value); - } else { - index = tpv[auth].getItemCount(); - mTimePeriodMap[auth].put(period, index); - tpv[auth].add(period, value); - } - } - - /** - * Creates a multiple-hour time period for the histogram. - * @param time Time in milliseconds. - * @param numHoursWide: should divide into a day. - * @return SimpleTimePeriod covering the number of hours and containing time. - */ - private SimpleTimePeriod getTimePeriod(long time, long numHoursWide) { - Date date = new Date(time); - TimeZone zone = RegularTimePeriod.DEFAULT_TIME_ZONE; - Calendar calendar = Calendar.getInstance(zone); - calendar.setTime(date); - long hoursOfYear = calendar.get(Calendar.HOUR_OF_DAY) + - calendar.get(Calendar.DAY_OF_YEAR) * 24; - int year = calendar.get(Calendar.YEAR); - hoursOfYear = (hoursOfYear / numHoursWide) * numHoursWide; - calendar.clear(); - calendar.set(year, 0, 1, 0, 0); // Jan 1 - long start = calendar.getTimeInMillis() + hoursOfYear * 3600 * 1000; - return new SimpleTimePeriod(start, start + numHoursWide * 3600 * 1000); - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_SYNC_HIST; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncPerf.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncPerf.java deleted file mode 100644 index 10176e3..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncPerf.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2009 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.InvalidTypeException; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.jfree.chart.labels.CustomXYToolTipGenerator; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYBarRenderer; -import org.jfree.data.time.SimpleTimePeriod; -import org.jfree.data.time.TimePeriodValues; -import org.jfree.data.time.TimePeriodValuesCollection; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -public class DisplaySyncPerf extends SyncCommon { - - CustomXYToolTipGenerator mTooltipGenerator; - - List<String> mTooltips[]; - - // The series number for each graphed item. - // sync authorities are 0-3 - private static final int DB_QUERY = 4; - private static final int DB_WRITE = 5; - private static final int HTTP_NETWORK = 6; - private static final int HTTP_PROCESSING = 7; - private static final int NUM_SERIES = (HTTP_PROCESSING + 1); - private static final String SERIES_NAMES[] = {"Calendar", "Gmail", "Feeds", "Contacts", - "DB Query", "DB Write", "HTTP Response", "HTTP Processing",}; - private static final Color SERIES_COLORS[] = {Color.MAGENTA, Color.GREEN, Color.BLUE, - Color.ORANGE, Color.RED, Color.CYAN, Color.PINK, Color.DARK_GRAY}; - private static final double SERIES_YCOORD[] = {0, 0, 0, 0, 1, 1, 2, 2}; - - // Values from data/etc/event-log-tags - private static final int EVENT_DB_OPERATION = 52000; - private static final int EVENT_HTTP_STATS = 52001; - // op types for EVENT_DB_OPERATION - final int EVENT_DB_QUERY = 0; - final int EVENT_DB_WRITE = 1; - - // Information to graph for each authority - private TimePeriodValues mDatasets[]; - - /** - * TimePeriodValuesCollection that supports Y intervals. This allows the - * creation of "floating" bars, rather than bars rooted to the axis. - */ - class YIntervalTimePeriodValuesCollection extends TimePeriodValuesCollection { - /** default serial UID */ - private static final long serialVersionUID = 1L; - - private double yheight; - - /** - * Constructs a collection of bars with a fixed Y height. - * - * @param yheight The height of the bars. - */ - YIntervalTimePeriodValuesCollection(double yheight) { - this.yheight = yheight; - } - - /** - * Returns ending Y value that is a fixed amount greater than the starting value. - * - * @param series the series (zero-based index). - * @param item the item (zero-based index). - * @return The ending Y value for the specified series and item. - */ - @Override - public Number getEndY(int series, int item) { - return getY(series, item).doubleValue() + yheight; - } - } - - /** - * Constructs a graph of network and database stats. - * - * @param name The name of this graph in the graph list. - */ - public DisplaySyncPerf(String name) { - super(name); - } - - /** - * 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). - */ - @Override - public Control createComposite(final Composite parent, EventLogParser logParser, - final ILogColumnListener listener) { - Control composite = createCompositeChart(parent, logParser, "Sync Performance"); - resetUI(); - return composite; - } - - /** - * Resets the display. - */ - @Override - void resetUI() { - super.resetUI(); - XYPlot xyPlot = mChart.getXYPlot(); - xyPlot.getRangeAxis().setVisible(false); - mTooltipGenerator = new CustomXYToolTipGenerator(); - - @SuppressWarnings("unchecked") - List<String>[] mTooltipsTmp = new List[NUM_SERIES]; - mTooltips = mTooltipsTmp; - - XYBarRenderer br = new XYBarRenderer(); - br.setUseYInterval(true); - mDatasets = new TimePeriodValues[NUM_SERIES]; - - TimePeriodValuesCollection tpvc = new YIntervalTimePeriodValuesCollection(1); - xyPlot.setDataset(tpvc); - xyPlot.setRenderer(br); - - for (int i = 0; i < NUM_SERIES; i++) { - br.setSeriesPaint(i, SERIES_COLORS[i]); - mDatasets[i] = new TimePeriodValues(SERIES_NAMES[i]); - tpvc.addSeries(mDatasets[i]); - mTooltips[i] = new ArrayList<String>(); - mTooltipGenerator.addToolTipSeries(mTooltips[i]); - br.setSeriesToolTipGenerator(i, mTooltipGenerator); - } - } - - /** - * Updates the display with a new event. - * - * @param event The event - * @param logParser The parser providing the event. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - super.newEvent(event, logParser); // Handle sync operation - try { - if (event.mTag == EVENT_DB_OPERATION) { - // 52000 db_operation (name|3),(op_type|1|5),(time|2|3) - String tip = event.getValueAsString(0); - long endTime = event.sec * 1000L + (event.nsec / 1000000L); - int opType = Integer.parseInt(event.getValueAsString(1)); - long duration = Long.parseLong(event.getValueAsString(2)); - - if (opType == EVENT_DB_QUERY) { - mDatasets[DB_QUERY].add(new SimpleTimePeriod(endTime - duration, endTime), - SERIES_YCOORD[DB_QUERY]); - mTooltips[DB_QUERY].add(tip); - } else if (opType == EVENT_DB_WRITE) { - mDatasets[DB_WRITE].add(new SimpleTimePeriod(endTime - duration, endTime), - SERIES_YCOORD[DB_WRITE]); - mTooltips[DB_WRITE].add(tip); - } - } else if (event.mTag == EVENT_HTTP_STATS) { - // 52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2) - String tip = event.getValueAsString(0) + ", tx:" + event.getValueAsString(3) + - ", rx: " + event.getValueAsString(4); - long endTime = event.sec * 1000L + (event.nsec / 1000000L); - long netEndTime = endTime - Long.parseLong(event.getValueAsString(2)); - long netStartTime = netEndTime - Long.parseLong(event.getValueAsString(1)); - mDatasets[HTTP_NETWORK].add(new SimpleTimePeriod(netStartTime, netEndTime), - SERIES_YCOORD[HTTP_NETWORK]); - mDatasets[HTTP_PROCESSING].add(new SimpleTimePeriod(netEndTime, endTime), - SERIES_YCOORD[HTTP_PROCESSING]); - mTooltips[HTTP_NETWORK].add(tip); - mTooltips[HTTP_PROCESSING].add(tip); - } - } catch (NumberFormatException e) { - // This can happen when parsing events from froyo+ where the event with id 52000 - // as a completely different format. For now, skip this event if this happens. - } catch (InvalidTypeException e) { - } - } - - /** - * Callback from super.newEvent to process a sync event. - * - * @param event The sync event - * @param startTime Start time (ms) of events - * @param stopTime Stop time (ms) of events - * @param details Details associated with the event. - * @param newEvent True if this event is a new sync event. False if this event - * @param syncSource - */ - @Override - void processSyncEvent(EventContainer event, int auth, long startTime, long stopTime, - String details, boolean newEvent, int syncSource) { - if (newEvent) { - mDatasets[auth].add(new SimpleTimePeriod(startTime, stopTime), SERIES_YCOORD[auth]); - } - } - - /** - * Gets display type - * - * @return display type as an integer - */ - @Override - int getDisplayType() { - return DISPLAY_TYPE_SYNC_PERF; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplay.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplay.java deleted file mode 100644 index d0d2789..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplay.java +++ /dev/null @@ -1,975 +0,0 @@ -/* - * 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) { - throw new InvalidParameterException(); - } - - mPidFilterList = pids; - } - - ArrayList<Integer> getPidFilterList() { - return mPidFilterList; - } - - void addPidFiler(int pid) { - if (mPidFiltering == false) { - throw 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() { - @Override - 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() { - @Override - 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() { - @Override - 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; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplayOptions.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplayOptions.java deleted file mode 100644 index b13f3f4..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplayOptions.java +++ /dev/null @@ -1,961 +0,0 @@ -/* - * 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.EventValueDescription; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.ImageLoader; -import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor; -import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Dialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.List; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; - -class EventDisplayOptions extends Dialog { - private static final int DLG_WIDTH = 700; - private static final int DLG_HEIGHT = 700; - - private Shell mParent; - private Shell mShell; - - private boolean mEditStatus = false; - private final ArrayList<EventDisplay> mDisplayList = new ArrayList<EventDisplay>(); - - /* LEFT LIST */ - private List mEventDisplayList; - private Button mEventDisplayNewButton; - private Button mEventDisplayDeleteButton; - private Button mEventDisplayUpButton; - private Button mEventDisplayDownButton; - private Text mDisplayWidthText; - private Text mDisplayHeightText; - - /* WIDGETS ON THE RIGHT */ - private Text mDisplayNameText; - private Combo mDisplayTypeCombo; - private Group mChartOptions; - private Group mHistOptions; - private Button mPidFilterCheckBox; - private Text mPidText; - - /** Map with (event-tag, event name) */ - private Map<Integer, String> mEventTagMap; - - /** Map with (event-tag, array of value info for the event) */ - private Map<Integer, EventValueDescription[]> mEventDescriptionMap; - - /** list of current pids */ - private ArrayList<Integer> mPidList; - - private EventLogParser mLogParser; - - private Group mInfoGroup; - - private static class SelectionWidgets { - private List mList; - private Button mNewButton; - private Button mEditButton; - private Button mDeleteButton; - - private void setEnabled(boolean enable) { - mList.setEnabled(enable); - mNewButton.setEnabled(enable); - mEditButton.setEnabled(enable); - mDeleteButton.setEnabled(enable); - } - } - - private SelectionWidgets mValueSelection; - private SelectionWidgets mOccurrenceSelection; - - /** flag to temporarly disable processing of {@link Text} changes, so that - * {@link Text#setText(String)} can be called safely. */ - private boolean mProcessTextChanges = true; - private Text mTimeLimitText; - private Text mHistWidthText; - - EventDisplayOptions(Shell parent) { - super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); - } - - /** - * Opens the display option dialog, to edit the {@link EventDisplay} objects provided in the - * list. - * @param logParser - * @param displayList - * @param eventList - * @return true if the list of {@link EventDisplay} objects was updated. - */ - boolean open(EventLogParser logParser, ArrayList<EventDisplay> displayList, - ArrayList<EventContainer> eventList) { - mLogParser = logParser; - - if (logParser != null) { - // we need 2 things from the parser. - // the event tag / event name map - mEventTagMap = logParser.getTagMap(); - - // the event info map - mEventDescriptionMap = logParser.getEventInfoMap(); - } - - // make a copy of the EventDisplay list since we'll use working copies. - duplicateEventDisplay(displayList); - - // build a list of pid from the list of events. - buildPidList(eventList); - - createUI(); - - if (mParent == null || mShell == null) { - return false; - } - - // Set the dialog size. - mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); - Rectangle r = mParent.getBounds(); - // get the center new top left. - int cx = r.x + r.width/2; - int x = cx - DLG_WIDTH / 2; - int cy = r.y + r.height/2; - int y = cy - DLG_HEIGHT / 2; - mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); - - mShell.layout(); - - // actually open the dialog - mShell.open(); - - // event loop until the dialog is closed. - Display display = mParent.getDisplay(); - while (!mShell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - - return mEditStatus; - } - - ArrayList<EventDisplay> getEventDisplays() { - return mDisplayList; - } - - private void createUI() { - mParent = getParent(); - mShell = new Shell(mParent, getStyle()); - mShell.setText("Event Display Configuration"); - - mShell.setLayout(new GridLayout(1, true)); - - final Composite topPanel = new Composite(mShell, SWT.NONE); - topPanel.setLayoutData(new GridData(GridData.FILL_BOTH)); - topPanel.setLayout(new GridLayout(2, false)); - - // create the tree on the left and the controls on the right. - Composite leftPanel = new Composite(topPanel, SWT.NONE); - Composite rightPanel = new Composite(topPanel, SWT.NONE); - - createLeftPanel(leftPanel); - createRightPanel(rightPanel); - - mShell.addListener(SWT.Close, new Listener() { - @Override - public void handleEvent(Event event) { - event.doit = true; - } - }); - - Label separator = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL); - separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - Composite bottomButtons = new Composite(mShell, SWT.NONE); - bottomButtons.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - GridLayout gl; - bottomButtons.setLayout(gl = new GridLayout(2, true)); - gl.marginHeight = gl.marginWidth = 0; - - Button okButton = new Button(bottomButtons, SWT.PUSH); - okButton.setText("OK"); - okButton.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - mShell.close(); - } - }); - - Button cancelButton = new Button(bottomButtons, SWT.PUSH); - cancelButton.setText("Cancel"); - cancelButton.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - // cancel the modification flag. - mEditStatus = false; - - // and close - mShell.close(); - } - }); - - enable(false); - - // fill the list with the current display - fillEventDisplayList(); - } - - private void createLeftPanel(Composite leftPanel) { - final IPreferenceStore store = DdmUiPreferences.getStore(); - - GridLayout gl; - - leftPanel.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - leftPanel.setLayout(gl = new GridLayout(1, false)); - gl.verticalSpacing = 1; - - mEventDisplayList = new List(leftPanel, - SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL | SWT.FULL_SELECTION); - mEventDisplayList.setLayoutData(new GridData(GridData.FILL_BOTH)); - mEventDisplayList.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - handleEventDisplaySelection(); - } - }); - - Composite bottomControls = new Composite(leftPanel, SWT.NONE); - bottomControls.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - bottomControls.setLayout(gl = new GridLayout(5, false)); - gl.marginHeight = gl.marginWidth = 0; - gl.verticalSpacing = 0; - gl.horizontalSpacing = 0; - - ImageLoader loader = ImageLoader.getDdmUiLibLoader(); - mEventDisplayNewButton = new Button(bottomControls, SWT.PUSH | SWT.FLAT); - mEventDisplayNewButton.setImage(loader.loadImage("add.png", //$NON-NLS-1$ - leftPanel.getDisplay())); - mEventDisplayNewButton.setToolTipText("Adds a new event display"); - mEventDisplayNewButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); - mEventDisplayNewButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - createNewEventDisplay(); - } - }); - - mEventDisplayDeleteButton = new Button(bottomControls, SWT.PUSH | SWT.FLAT); - mEventDisplayDeleteButton.setImage(loader.loadImage("delete.png", //$NON-NLS-1$ - leftPanel.getDisplay())); - mEventDisplayDeleteButton.setToolTipText("Deletes the selected event display"); - mEventDisplayDeleteButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); - mEventDisplayDeleteButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - deleteEventDisplay(); - } - }); - - mEventDisplayUpButton = new Button(bottomControls, SWT.PUSH | SWT.FLAT); - mEventDisplayUpButton.setImage(loader.loadImage("up.png", //$NON-NLS-1$ - leftPanel.getDisplay())); - mEventDisplayUpButton.setToolTipText("Moves the selected event display up"); - mEventDisplayUpButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // get current selection. - int selection = mEventDisplayList.getSelectionIndex(); - if (selection > 0) { - // update the list of EventDisplay. - EventDisplay display = mDisplayList.remove(selection); - mDisplayList.add(selection - 1, display); - - // update the list widget - mEventDisplayList.remove(selection); - mEventDisplayList.add(display.getName(), selection - 1); - - // update the selection and reset the ui. - mEventDisplayList.select(selection - 1); - handleEventDisplaySelection(); - mEventDisplayList.showSelection(); - - setModified(); - } - } - }); - - mEventDisplayDownButton = new Button(bottomControls, SWT.PUSH | SWT.FLAT); - mEventDisplayDownButton.setImage(loader.loadImage("down.png", //$NON-NLS-1$ - leftPanel.getDisplay())); - mEventDisplayDownButton.setToolTipText("Moves the selected event display down"); - mEventDisplayDownButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // get current selection. - int selection = mEventDisplayList.getSelectionIndex(); - if (selection != -1 && selection < mEventDisplayList.getItemCount() - 1) { - // update the list of EventDisplay. - EventDisplay display = mDisplayList.remove(selection); - mDisplayList.add(selection + 1, display); - - // update the list widget - mEventDisplayList.remove(selection); - mEventDisplayList.add(display.getName(), selection + 1); - - // update the selection and reset the ui. - mEventDisplayList.select(selection + 1); - handleEventDisplaySelection(); - mEventDisplayList.showSelection(); - - setModified(); - } - } - }); - - Group sizeGroup = new Group(leftPanel, SWT.NONE); - sizeGroup.setText("Display Size:"); - sizeGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - sizeGroup.setLayout(new GridLayout(2, false)); - - Label l = new Label(sizeGroup, SWT.NONE); - l.setText("Width:"); - - mDisplayWidthText = new Text(sizeGroup, SWT.LEFT | SWT.SINGLE | SWT.BORDER); - mDisplayWidthText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mDisplayWidthText.setText(Integer.toString( - store.getInt(EventLogPanel.PREFS_DISPLAY_WIDTH))); - mDisplayWidthText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - String text = mDisplayWidthText.getText().trim(); - try { - store.setValue(EventLogPanel.PREFS_DISPLAY_WIDTH, Integer.parseInt(text)); - setModified(); - } catch (NumberFormatException nfe) { - // do something? - } - } - }); - - l = new Label(sizeGroup, SWT.NONE); - l.setText("Height:"); - - mDisplayHeightText = new Text(sizeGroup, SWT.LEFT | SWT.SINGLE | SWT.BORDER); - mDisplayHeightText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mDisplayHeightText.setText(Integer.toString( - store.getInt(EventLogPanel.PREFS_DISPLAY_HEIGHT))); - mDisplayHeightText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - String text = mDisplayHeightText.getText().trim(); - try { - store.setValue(EventLogPanel.PREFS_DISPLAY_HEIGHT, Integer.parseInt(text)); - setModified(); - } catch (NumberFormatException nfe) { - // do something? - } - } - }); - } - - private void createRightPanel(Composite rightPanel) { - rightPanel.setLayout(new GridLayout(1, true)); - rightPanel.setLayoutData(new GridData(GridData.FILL_BOTH)); - - mInfoGroup = new Group(rightPanel, SWT.NONE); - mInfoGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mInfoGroup.setLayout(new GridLayout(2, false)); - - Label nameLabel = new Label(mInfoGroup, SWT.LEFT); - nameLabel.setText("Name:"); - - mDisplayNameText = new Text(mInfoGroup, SWT.BORDER | SWT.LEFT | SWT.SINGLE); - mDisplayNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mDisplayNameText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - if (mProcessTextChanges) { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - eventDisplay.setName(mDisplayNameText.getText()); - int index = mEventDisplayList.getSelectionIndex(); - mEventDisplayList.remove(index); - mEventDisplayList.add(eventDisplay.getName(), index); - mEventDisplayList.select(index); - handleEventDisplaySelection(); - setModified(); - } - } - } - }); - - Label displayLabel = new Label(mInfoGroup, SWT.LEFT); - displayLabel.setText("Type:"); - - mDisplayTypeCombo = new Combo(mInfoGroup, SWT.READ_ONLY | SWT.DROP_DOWN); - mDisplayTypeCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - // add the combo values. This must match the values EventDisplay.DISPLAY_TYPE_* - mDisplayTypeCombo.add("Log All"); - mDisplayTypeCombo.add("Filtered Log"); - mDisplayTypeCombo.add("Graph"); - mDisplayTypeCombo.add("Sync"); - mDisplayTypeCombo.add("Sync Histogram"); - mDisplayTypeCombo.add("Sync Performance"); - mDisplayTypeCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null && eventDisplay.getDisplayType() != mDisplayTypeCombo.getSelectionIndex()) { - /* Replace the EventDisplay object with a different subclass */ - setModified(); - String name = eventDisplay.getName(); - EventDisplay newEventDisplay = EventDisplay.eventDisplayFactory(mDisplayTypeCombo.getSelectionIndex(), name); - setCurrentEventDisplay(newEventDisplay); - fillUiWith(newEventDisplay); - } - } - }); - - mChartOptions = new Group(mInfoGroup, SWT.NONE); - mChartOptions.setText("Chart Options"); - GridData gd; - mChartOptions.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 2; - mChartOptions.setLayout(new GridLayout(2, false)); - - Label l = new Label(mChartOptions, SWT.NONE); - l.setText("Time Limit (seconds):"); - - mTimeLimitText = new Text(mChartOptions, SWT.BORDER); - mTimeLimitText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTimeLimitText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - String text = mTimeLimitText.getText().trim(); - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - try { - if (text.length() == 0) { - eventDisplay.resetChartTimeLimit(); - } else { - eventDisplay.setChartTimeLimit(Long.parseLong(text)); - } - } catch (NumberFormatException nfe) { - eventDisplay.resetChartTimeLimit(); - } finally { - setModified(); - } - } - } - }); - - mHistOptions = new Group(mInfoGroup, SWT.NONE); - mHistOptions.setText("Histogram Options"); - GridData gdh; - mHistOptions.setLayoutData(gdh = new GridData(GridData.FILL_HORIZONTAL)); - gdh.horizontalSpan = 2; - mHistOptions.setLayout(new GridLayout(2, false)); - - Label lh = new Label(mHistOptions, SWT.NONE); - lh.setText("Histogram width (hours):"); - - mHistWidthText = new Text(mHistOptions, SWT.BORDER); - mHistWidthText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mHistWidthText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - String text = mHistWidthText.getText().trim(); - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - try { - if (text.length() == 0) { - eventDisplay.resetHistWidth(); - } else { - eventDisplay.setHistWidth(Long.parseLong(text)); - } - } catch (NumberFormatException nfe) { - eventDisplay.resetHistWidth(); - } finally { - setModified(); - } - } - } - }); - - mPidFilterCheckBox = new Button(mInfoGroup, SWT.CHECK); - mPidFilterCheckBox.setText("Enable filtering by pid"); - mPidFilterCheckBox.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 2; - mPidFilterCheckBox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - eventDisplay.setPidFiltering(mPidFilterCheckBox.getSelection()); - mPidText.setEnabled(mPidFilterCheckBox.getSelection()); - setModified(); - } - } - }); - - Label pidLabel = new Label(mInfoGroup, SWT.NONE); - pidLabel.setText("Pid Filter:"); - pidLabel.setToolTipText("Enter all pids, separated by commas"); - - mPidText = new Text(mInfoGroup, SWT.BORDER); - mPidText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mPidText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - if (mProcessTextChanges) { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null && eventDisplay.getPidFiltering()) { - String pidText = mPidText.getText().trim(); - String[] pids = pidText.split("\\s*,\\s*"); //$NON-NLS-1$ - - ArrayList<Integer> list = new ArrayList<Integer>(); - for (String pid : pids) { - try { - list.add(Integer.valueOf(pid)); - } catch (NumberFormatException nfe) { - // just ignore non valid pid - } - } - - eventDisplay.setPidFilterList(list); - setModified(); - } - } - } - }); - - /* ------------------ - * EVENT VALUE/OCCURRENCE SELECTION - * ------------------ */ - mValueSelection = createEventSelection(rightPanel, ValueDisplayDescriptor.class, - "Event Value Display"); - mOccurrenceSelection = createEventSelection(rightPanel, OccurrenceDisplayDescriptor.class, - "Event Occurrence Display"); - } - - private SelectionWidgets createEventSelection(Composite rightPanel, - final Class<? extends OccurrenceDisplayDescriptor> descriptorClass, - String groupMessage) { - - Group eventSelectionPanel = new Group(rightPanel, SWT.NONE); - eventSelectionPanel.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl; - eventSelectionPanel.setLayout(gl = new GridLayout(2, false)); - gl.marginHeight = gl.marginWidth = 0; - eventSelectionPanel.setText(groupMessage); - - final SelectionWidgets widgets = new SelectionWidgets(); - - widgets.mList = new List(eventSelectionPanel, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL); - widgets.mList.setLayoutData(new GridData(GridData.FILL_BOTH)); - widgets.mList.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int index = widgets.mList.getSelectionIndex(); - if (index != -1) { - widgets.mDeleteButton.setEnabled(true); - widgets.mEditButton.setEnabled(true); - } else { - widgets.mDeleteButton.setEnabled(false); - widgets.mEditButton.setEnabled(false); - } - } - }); - - Composite rightControls = new Composite(eventSelectionPanel, SWT.NONE); - rightControls.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - rightControls.setLayout(gl = new GridLayout(1, false)); - gl.marginHeight = gl.marginWidth = 0; - gl.verticalSpacing = 0; - gl.horizontalSpacing = 0; - - widgets.mNewButton = new Button(rightControls, SWT.PUSH | SWT.FLAT); - widgets.mNewButton.setText("New..."); - widgets.mNewButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - widgets.mNewButton.setEnabled(false); - widgets.mNewButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // current event - try { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - EventValueSelector dialog = new EventValueSelector(mShell); - if (dialog.open(descriptorClass, mLogParser)) { - eventDisplay.addDescriptor(dialog.getDescriptor()); - fillUiWith(eventDisplay); - setModified(); - } - } - } catch (Exception e1) { - e1.printStackTrace(); - } - } - }); - - widgets.mEditButton = new Button(rightControls, SWT.PUSH | SWT.FLAT); - widgets.mEditButton.setText("Edit..."); - widgets.mEditButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - widgets.mEditButton.setEnabled(false); - widgets.mEditButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // current event - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - // get the current descriptor index - int index = widgets.mList.getSelectionIndex(); - if (index != -1) { - // get the descriptor itself - OccurrenceDisplayDescriptor descriptor = eventDisplay.getDescriptor( - descriptorClass, index); - - // open the edit dialog. - EventValueSelector dialog = new EventValueSelector(mShell); - if (dialog.open(descriptor, mLogParser)) { - descriptor.replaceWith(dialog.getDescriptor()); - eventDisplay.updateValueDescriptorCheck(); - fillUiWith(eventDisplay); - - // reselect the item since fillUiWith remove the selection. - widgets.mList.select(index); - widgets.mList.notifyListeners(SWT.Selection, null); - - setModified(); - } - } - } - } - }); - - widgets.mDeleteButton = new Button(rightControls, SWT.PUSH | SWT.FLAT); - widgets.mDeleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - widgets.mDeleteButton.setText("Delete"); - widgets.mDeleteButton.setEnabled(false); - widgets.mDeleteButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // current event - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - // get the current descriptor index - int index = widgets.mList.getSelectionIndex(); - if (index != -1) { - eventDisplay.removeDescriptor(descriptorClass, index); - fillUiWith(eventDisplay); - setModified(); - } - } - } - }); - - return widgets; - } - - - private void duplicateEventDisplay(ArrayList<EventDisplay> displayList) { - for (EventDisplay eventDisplay : displayList) { - mDisplayList.add(EventDisplay.clone(eventDisplay)); - } - } - - private void buildPidList(ArrayList<EventContainer> eventList) { - mPidList = new ArrayList<Integer>(); - for (EventContainer event : eventList) { - if (mPidList.indexOf(event.pid) == -1) { - mPidList.add(event.pid); - } - } - } - - private void setModified() { - mEditStatus = true; - } - - - private void enable(boolean status) { - mEventDisplayDeleteButton.setEnabled(status); - - // enable up/down - int selection = mEventDisplayList.getSelectionIndex(); - int count = mEventDisplayList.getItemCount(); - mEventDisplayUpButton.setEnabled(status && selection > 0); - mEventDisplayDownButton.setEnabled(status && selection != -1 && selection < count - 1); - - mDisplayNameText.setEnabled(status); - mDisplayTypeCombo.setEnabled(status); - mPidFilterCheckBox.setEnabled(status); - - mValueSelection.setEnabled(status); - mOccurrenceSelection.setEnabled(status); - mValueSelection.mNewButton.setEnabled(status); - mOccurrenceSelection.mNewButton.setEnabled(status); - if (status == false) { - mPidText.setEnabled(false); - } - } - - private void fillEventDisplayList() { - for (EventDisplay eventDisplay : mDisplayList) { - mEventDisplayList.add(eventDisplay.getName()); - } - } - - private void createNewEventDisplay() { - int count = mDisplayList.size(); - - String name = String.format("display %1$d", count + 1); - - EventDisplay eventDisplay = EventDisplay.eventDisplayFactory(0 /* type*/, name); - - mDisplayList.add(eventDisplay); - mEventDisplayList.add(name); - - mEventDisplayList.select(count); - handleEventDisplaySelection(); - mEventDisplayList.showSelection(); - - setModified(); - } - - private void deleteEventDisplay() { - int selection = mEventDisplayList.getSelectionIndex(); - if (selection != -1) { - mDisplayList.remove(selection); - mEventDisplayList.remove(selection); - if (mDisplayList.size() < selection) { - selection--; - } - mEventDisplayList.select(selection); - handleEventDisplaySelection(); - - setModified(); - } - } - - private EventDisplay getCurrentEventDisplay() { - int selection = mEventDisplayList.getSelectionIndex(); - if (selection != -1) { - return mDisplayList.get(selection); - } - - return null; - } - - private void setCurrentEventDisplay(EventDisplay eventDisplay) { - int selection = mEventDisplayList.getSelectionIndex(); - if (selection != -1) { - mDisplayList.set(selection, eventDisplay); - } - } - - private void handleEventDisplaySelection() { - EventDisplay eventDisplay = getCurrentEventDisplay(); - if (eventDisplay != null) { - // enable the UI - enable(true); - - // and fill it - fillUiWith(eventDisplay); - } else { - // disable the UI - enable(false); - - // and empty it. - emptyUi(); - } - } - - private void emptyUi() { - mDisplayNameText.setText(""); - mDisplayTypeCombo.clearSelection(); - mValueSelection.mList.removeAll(); - mOccurrenceSelection.mList.removeAll(); - } - - private void fillUiWith(EventDisplay eventDisplay) { - mProcessTextChanges = false; - - mDisplayNameText.setText(eventDisplay.getName()); - int displayMode = eventDisplay.getDisplayType(); - mDisplayTypeCombo.select(displayMode); - if (displayMode == EventDisplay.DISPLAY_TYPE_GRAPH) { - GridData gd = (GridData) mChartOptions.getLayoutData(); - gd.exclude = false; - mChartOptions.setVisible(!gd.exclude); - long limit = eventDisplay.getChartTimeLimit(); - if (limit != -1) { - mTimeLimitText.setText(Long.toString(limit)); - } else { - mTimeLimitText.setText(""); //$NON-NLS-1$ - } - } else { - GridData gd = (GridData) mChartOptions.getLayoutData(); - gd.exclude = true; - mChartOptions.setVisible(!gd.exclude); - mTimeLimitText.setText(""); //$NON-NLS-1$ - } - - if (displayMode == EventDisplay.DISPLAY_TYPE_SYNC_HIST) { - GridData gd = (GridData) mHistOptions.getLayoutData(); - gd.exclude = false; - mHistOptions.setVisible(!gd.exclude); - long limit = eventDisplay.getHistWidth(); - if (limit != -1) { - mHistWidthText.setText(Long.toString(limit)); - } else { - mHistWidthText.setText(""); //$NON-NLS-1$ - } - } else { - GridData gd = (GridData) mHistOptions.getLayoutData(); - gd.exclude = true; - mHistOptions.setVisible(!gd.exclude); - mHistWidthText.setText(""); //$NON-NLS-1$ - } - mInfoGroup.layout(true); - mShell.layout(true); - mShell.pack(); - - if (eventDisplay.getPidFiltering()) { - mPidFilterCheckBox.setSelection(true); - mPidText.setEnabled(true); - - // build the pid list. - ArrayList<Integer> list = eventDisplay.getPidFilterList(); - if (list != null) { - StringBuilder sb = new StringBuilder(); - int count = list.size(); - for (int i = 0 ; i < count ; i++) { - sb.append(list.get(i)); - if (i < count - 1) { - sb.append(", ");//$NON-NLS-1$ - } - } - mPidText.setText(sb.toString()); - } else { - mPidText.setText(""); //$NON-NLS-1$ - } - } else { - mPidFilterCheckBox.setSelection(false); - mPidText.setEnabled(false); - mPidText.setText(""); //$NON-NLS-1$ - } - - mProcessTextChanges = true; - - mValueSelection.mList.removeAll(); - mOccurrenceSelection.mList.removeAll(); - - if (eventDisplay.getDisplayType() == EventDisplay.DISPLAY_TYPE_FILTERED_LOG || - eventDisplay.getDisplayType() == EventDisplay.DISPLAY_TYPE_GRAPH) { - mOccurrenceSelection.setEnabled(true); - mValueSelection.setEnabled(true); - - Iterator<ValueDisplayDescriptor> valueIterator = eventDisplay.getValueDescriptors(); - - while (valueIterator.hasNext()) { - ValueDisplayDescriptor descriptor = valueIterator.next(); - mValueSelection.mList.add(String.format("%1$s: %2$s [%3$s]%4$s", - mEventTagMap.get(descriptor.eventTag), descriptor.valueName, - getSeriesLabelDescription(descriptor), getFilterDescription(descriptor))); - } - - Iterator<OccurrenceDisplayDescriptor> occurrenceIterator = - eventDisplay.getOccurrenceDescriptors(); - - while (occurrenceIterator.hasNext()) { - OccurrenceDisplayDescriptor descriptor = occurrenceIterator.next(); - - mOccurrenceSelection.mList.add(String.format("%1$s [%2$s]%3$s", - mEventTagMap.get(descriptor.eventTag), - getSeriesLabelDescription(descriptor), - getFilterDescription(descriptor))); - } - - mValueSelection.mList.notifyListeners(SWT.Selection, null); - mOccurrenceSelection.mList.notifyListeners(SWT.Selection, null); - } else { - mOccurrenceSelection.setEnabled(false); - mValueSelection.setEnabled(false); - } - - } - - /** - * Returns a String describing what is used as the series label - * @param descriptor the descriptor of the display. - */ - private String getSeriesLabelDescription(OccurrenceDisplayDescriptor descriptor) { - if (descriptor.seriesValueIndex != -1) { - if (descriptor.includePid) { - return String.format("%1$s + pid", - mEventDescriptionMap.get( - descriptor.eventTag)[descriptor.seriesValueIndex].getName()); - } else { - return mEventDescriptionMap.get(descriptor.eventTag)[descriptor.seriesValueIndex] - .getName(); - } - } - return "pid"; - } - - private String getFilterDescription(OccurrenceDisplayDescriptor descriptor) { - if (descriptor.filterValueIndex != -1) { - return String.format(" [%1$s %2$s %3$s]", - mEventDescriptionMap.get( - descriptor.eventTag)[descriptor.filterValueIndex].getName(), - descriptor.filterCompareMethod.testString(), - descriptor.filterValue != null ? - descriptor.filterValue.toString() : "?"); //$NON-NLS-1$ - } - return ""; //$NON-NLS-1$ - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogImporter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogImporter.java deleted file mode 100644 index 011bcf1..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogImporter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; - -/** - * Imports a textual event log. Gets tags from build path. - */ -public class EventLogImporter { - - private String[] mTags; - private String[] mLog; - - public EventLogImporter(String filePath) throws FileNotFoundException { - String top = System.getenv("ANDROID_BUILD_TOP"); - if (top == null) { - throw new FileNotFoundException(); - } - final String tagFile = top + "/system/core/logcat/event-log-tags"; - BufferedReader tagReader = new BufferedReader( - new InputStreamReader(new FileInputStream(tagFile))); - BufferedReader eventReader = new BufferedReader( - new InputStreamReader(new FileInputStream(filePath))); - try { - readTags(tagReader); - readLog(eventReader); - } catch (IOException e) { - } finally { - if (tagReader != null) { - try { - tagReader.close(); - } catch (IOException ignore) { - } - } - if (eventReader != null) { - try { - eventReader.close(); - } catch (IOException ignore) { - } - } - } - } - - public String[] getTags() { - return mTags; - } - - public String[] getLog() { - return mLog; - } - - private void readTags(BufferedReader reader) throws IOException { - String line; - - ArrayList<String> content = new ArrayList<String>(); - while ((line = reader.readLine()) != null) { - content.add(line); - } - mTags = content.toArray(new String[content.size()]); - } - - private void readLog(BufferedReader reader) throws IOException { - String line; - - ArrayList<String> content = new ArrayList<String>(); - while ((line = reader.readLine()) != null) { - content.add(line); - } - - mLog = content.toArray(new String[content.size()]); - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java deleted file mode 100644 index 937ee40..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java +++ /dev/null @@ -1,938 +0,0 @@ -/* - * 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.Client; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log; -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.log.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.LogReceiver; -import com.android.ddmlib.log.LogReceiver.ILogListener; -import com.android.ddmlib.log.LogReceiver.LogEntry; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.TablePanel; -import com.android.ddmuilib.actions.ICommonAction; -import com.android.ddmuilib.annotation.UiThread; -import com.android.ddmuilib.annotation.WorkerThread; -import com.android.ddmuilib.log.event.EventDisplay.ILogColumnListener; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.custom.ScrolledComposite; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.RowData; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.regex.Pattern; - -/** - * Event log viewer - */ -public class EventLogPanel extends TablePanel implements ILogListener, - ILogColumnListener { - - private final static String TAG_FILE_EXT = ".tag"; //$NON-NLS-1$ - - private final static String PREFS_EVENT_DISPLAY = "EventLogPanel.eventDisplay"; //$NON-NLS-1$ - private final static String EVENT_DISPLAY_STORAGE_SEPARATOR = "|"; //$NON-NLS-1$ - - static final String PREFS_DISPLAY_WIDTH = "EventLogPanel.width"; //$NON-NLS-1$ - static final String PREFS_DISPLAY_HEIGHT = "EventLogPanel.height"; //$NON-NLS-1$ - - private final static int DEFAULT_DISPLAY_WIDTH = 500; - private final static int DEFAULT_DISPLAY_HEIGHT = 400; - - private IDevice mCurrentLoggedDevice; - private String mCurrentLogFile; - private LogReceiver mCurrentLogReceiver; - private EventLogParser mCurrentEventLogParser; - - private Object mLock = new Object(); - - /** list of all the events. */ - private final ArrayList<EventContainer> mEvents = new ArrayList<EventContainer>(); - - /** list of all the new events, that have yet to be displayed by the ui */ - private final ArrayList<EventContainer> mNewEvents = new ArrayList<EventContainer>(); - /** indicates a pending ui thread display */ - private boolean mPendingDisplay = false; - - /** list of all the custom event displays */ - private final ArrayList<EventDisplay> mEventDisplays = new ArrayList<EventDisplay>(); - - private final NumberFormat mFormatter = NumberFormat.getInstance(); - private Composite mParent; - private ScrolledComposite mBottomParentPanel; - private Composite mBottomPanel; - private ICommonAction mOptionsAction; - private ICommonAction mClearAction; - private ICommonAction mSaveAction; - private ICommonAction mLoadAction; - private ICommonAction mImportAction; - - /** file containing the current log raw data. */ - private File mTempFile = null; - - public EventLogPanel() { - super(); - mFormatter.setGroupingUsed(true); - } - - /** - * Sets the external actions. - * <p/>This method sets up the {@link ICommonAction} objects to execute the proper code - * when triggered by using {@link ICommonAction#setRunnable(Runnable)}. - * <p/>It will also make sure they are enabled only when possible. - * @param optionsAction - * @param clearAction - * @param saveAction - * @param loadAction - * @param importAction - */ - public void setActions(ICommonAction optionsAction, ICommonAction clearAction, - ICommonAction saveAction, ICommonAction loadAction, ICommonAction importAction) { - mOptionsAction = optionsAction; - mOptionsAction.setRunnable(new Runnable() { - @Override - public void run() { - openOptionPanel(); - } - }); - - mClearAction = clearAction; - mClearAction.setRunnable(new Runnable() { - @Override - public void run() { - clearLog(); - } - }); - - mSaveAction = saveAction; - mSaveAction.setRunnable(new Runnable() { - @Override - public void run() { - try { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.SAVE); - - fileDialog.setText("Save Event Log"); - fileDialog.setFileName("event.log"); - - String fileName = fileDialog.open(); - if (fileName != null) { - saveLog(fileName); - } - } catch (IOException e1) { - } - } - }); - - mLoadAction = loadAction; - mLoadAction.setRunnable(new Runnable() { - @Override - public void run() { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); - - fileDialog.setText("Load Event Log"); - - String fileName = fileDialog.open(); - if (fileName != null) { - loadLog(fileName); - } - } - }); - - mImportAction = importAction; - mImportAction.setRunnable(new Runnable() { - @Override - public void run() { - FileDialog fileDialog = new FileDialog(mParent.getShell(), SWT.OPEN); - - fileDialog.setText("Import Bug Report"); - - String fileName = fileDialog.open(); - if (fileName != null) { - importBugReport(fileName); - } - } - }); - - mOptionsAction.setEnabled(false); - mClearAction.setEnabled(false); - mSaveAction.setEnabled(false); - } - - /** - * Opens the option panel. - * </p> - * <b>This must be called from the UI thread</b> - */ - @UiThread - public void openOptionPanel() { - try { - EventDisplayOptions dialog = new EventDisplayOptions(mParent.getShell()); - if (dialog.open(mCurrentEventLogParser, mEventDisplays, mEvents)) { - synchronized (mLock) { - // get the new EventDisplay list - mEventDisplays.clear(); - mEventDisplays.addAll(dialog.getEventDisplays()); - - // since the list of EventDisplay changed, we store it. - saveEventDisplays(); - - rebuildUi(); - } - } - } catch (SWTException e) { - Log.e("EventLog", e); //$NON-NLS-1$ - } - } - - /** - * Clears the log. - * <p/> - * <b>This must be called from the UI thread</b> - */ - public void clearLog() { - try { - synchronized (mLock) { - mEvents.clear(); - mNewEvents.clear(); - mPendingDisplay = false; - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.resetUI(); - } - } - } catch (SWTException e) { - Log.e("EventLog", e); //$NON-NLS-1$ - } - } - - /** - * Saves the content of the event log into a file. The log is saved in the same - * binary format than on the device. - * @param filePath - * @throws IOException - */ - public void saveLog(String filePath) throws IOException { - if (mCurrentLoggedDevice != null && mCurrentEventLogParser != null) { - File destFile = new File(filePath); - destFile.createNewFile(); - FileInputStream fis = new FileInputStream(mTempFile); - FileOutputStream fos = new FileOutputStream(destFile); - byte[] buffer = new byte[1024]; - - int count; - - while ((count = fis.read(buffer)) != -1) { - fos.write(buffer, 0, count); - } - - fos.close(); - fis.close(); - - // now we save the tag file - filePath = filePath + TAG_FILE_EXT; - mCurrentEventLogParser.saveTags(filePath); - } - } - - /** - * Loads a binary event log (if has associated .tag file) or - * otherwise loads a textual event log. - * @param filePath Event log path (and base of potential tag file) - */ - public void loadLog(String filePath) { - if ((new File(filePath + TAG_FILE_EXT)).exists()) { - startEventLogFromFiles(filePath); - } else { - try { - EventLogImporter importer = new EventLogImporter(filePath); - String[] tags = importer.getTags(); - String[] log = importer.getLog(); - startEventLogFromContent(tags, log); - } catch (FileNotFoundException e) { - // If this fails, display the error message from startEventLogFromFiles, - // and pretend we never tried EventLogImporter - Log.logAndDisplay(Log.LogLevel.ERROR, "EventLog", - String.format("Failure to read %1$s", filePath + TAG_FILE_EXT)); - } - - } - } - - public void importBugReport(String filePath) { - try { - BugReportImporter importer = new BugReportImporter(filePath); - - String[] tags = importer.getTags(); - String[] log = importer.getLog(); - - startEventLogFromContent(tags, log); - - } catch (FileNotFoundException e) { - Log.logAndDisplay(LogLevel.ERROR, "Import", - "Unable to import bug report: " + e.getMessage()); - } - } - - /* (non-Javadoc) - * @see com.android.ddmuilib.SelectionDependentPanel#clientSelected() - */ - @Override - public void clientSelected() { - // pass - } - - /* (non-Javadoc) - * @see com.android.ddmuilib.SelectionDependentPanel#deviceSelected() - */ - @Override - public void deviceSelected() { - startEventLog(getCurrentDevice()); - } - - /* - * (non-Javadoc) - * @see com.android.ddmlib.AndroidDebugBridge.IClientChangeListener#clientChanged(com.android.ddmlib.Client, int) - */ - @Override - public void clientChanged(Client client, int changeMask) { - // pass - } - - /* (non-Javadoc) - * @see com.android.ddmuilib.Panel#createControl(org.eclipse.swt.widgets.Composite) - */ - @Override - protected Control createControl(Composite parent) { - mParent = parent; - mParent.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent e) { - synchronized (mLock) { - if (mCurrentLogReceiver != null) { - mCurrentLogReceiver.cancel(); - mCurrentLogReceiver = null; - mCurrentEventLogParser = null; - mCurrentLoggedDevice = null; - mEventDisplays.clear(); - mEvents.clear(); - } - } - } - }); - - final IPreferenceStore store = DdmUiPreferences.getStore(); - - // init some store stuff - store.setDefault(PREFS_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH); - store.setDefault(PREFS_DISPLAY_HEIGHT, DEFAULT_DISPLAY_HEIGHT); - - mBottomParentPanel = new ScrolledComposite(parent, SWT.V_SCROLL); - mBottomParentPanel.setLayoutData(new GridData(GridData.FILL_BOTH)); - mBottomParentPanel.setExpandHorizontal(true); - mBottomParentPanel.setExpandVertical(true); - - mBottomParentPanel.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - if (mBottomPanel != null) { - Rectangle r = mBottomParentPanel.getClientArea(); - mBottomParentPanel.setMinSize(mBottomPanel.computeSize(r.width, - SWT.DEFAULT)); - } - } - }); - - prepareDisplayUi(); - - // load the EventDisplay from storage. - loadEventDisplays(); - - // create the ui - createDisplayUi(); - - return mBottomParentPanel; - } - - /* (non-Javadoc) - * @see com.android.ddmuilib.Panel#postCreation() - */ - @Override - protected void postCreation() { - // pass - } - - /* (non-Javadoc) - * @see com.android.ddmuilib.Panel#setFocus() - */ - @Override - public void setFocus() { - mBottomParentPanel.setFocus(); - } - - /** - * Starts a new logcat and set mCurrentLogCat as the current receiver. - * @param device the device to connect logcat to. - */ - private void startEventLog(final IDevice device) { - if (device == mCurrentLoggedDevice) { - return; - } - - // if we have a logcat already running - if (mCurrentLogReceiver != null) { - stopEventLog(false); - } - mCurrentLoggedDevice = null; - mCurrentLogFile = null; - - if (device != null) { - // create a new output receiver - mCurrentLogReceiver = new LogReceiver(this); - - // start the logcat in a different thread - new Thread("EventLog") { //$NON-NLS-1$ - @Override - public void run() { - while (device.isOnline() == false && - mCurrentLogReceiver != null && - mCurrentLogReceiver.isCancelled() == false) { - try { - sleep(2000); - } catch (InterruptedException e) { - return; - } - } - - if (mCurrentLogReceiver == null || mCurrentLogReceiver.isCancelled()) { - // logcat was stopped/cancelled before the device became ready. - return; - } - - try { - mCurrentLoggedDevice = device; - synchronized (mLock) { - mCurrentEventLogParser = new EventLogParser(); - mCurrentEventLogParser.init(device); - } - - // update the event display with the new parser. - updateEventDisplays(); - - // prepare the temp file that will contain the raw data - mTempFile = File.createTempFile("android-event-", ".log"); - - device.runEventLogService(mCurrentLogReceiver); - } catch (Exception e) { - Log.e("EventLog", e); - } finally { - } - } - }.start(); - } - } - - private void startEventLogFromFiles(final String fileName) { - // if we have a logcat already running - if (mCurrentLogReceiver != null) { - stopEventLog(false); - } - mCurrentLoggedDevice = null; - mCurrentLogFile = null; - - // create a new output receiver - mCurrentLogReceiver = new LogReceiver(this); - - mSaveAction.setEnabled(false); - - // start the logcat in a different thread - new Thread("EventLog") { //$NON-NLS-1$ - @Override - public void run() { - try { - mCurrentLogFile = fileName; - synchronized (mLock) { - mCurrentEventLogParser = new EventLogParser(); - if (mCurrentEventLogParser.init(fileName + TAG_FILE_EXT) == false) { - mCurrentEventLogParser = null; - Log.logAndDisplay(LogLevel.ERROR, "EventLog", - String.format("Failure to read %1$s", fileName + TAG_FILE_EXT)); - return; - } - } - - // update the event display with the new parser. - updateEventDisplays(); - - runLocalEventLogService(fileName, mCurrentLogReceiver); - } catch (Exception e) { - Log.e("EventLog", e); - } finally { - } - } - }.start(); - } - - private void startEventLogFromContent(final String[] tags, final String[] log) { - // if we have a logcat already running - if (mCurrentLogReceiver != null) { - stopEventLog(false); - } - mCurrentLoggedDevice = null; - mCurrentLogFile = null; - - // create a new output receiver - mCurrentLogReceiver = new LogReceiver(this); - - mSaveAction.setEnabled(false); - - // start the logcat in a different thread - new Thread("EventLog") { //$NON-NLS-1$ - @Override - public void run() { - try { - synchronized (mLock) { - mCurrentEventLogParser = new EventLogParser(); - if (mCurrentEventLogParser.init(tags) == false) { - mCurrentEventLogParser = null; - return; - } - } - - // update the event display with the new parser. - updateEventDisplays(); - - runLocalEventLogService(log, mCurrentLogReceiver); - } catch (Exception e) { - Log.e("EventLog", e); - } finally { - } - } - }.start(); - } - - - public void stopEventLog(boolean inUiThread) { - if (mCurrentLogReceiver != null) { - mCurrentLogReceiver.cancel(); - - // when the thread finishes, no one will reference that object - // and it'll be destroyed - synchronized (mLock) { - mCurrentLogReceiver = null; - mCurrentEventLogParser = null; - - mCurrentLoggedDevice = null; - mEvents.clear(); - mNewEvents.clear(); - mPendingDisplay = false; - } - - resetUI(inUiThread); - } - - if (mTempFile != null) { - mTempFile.delete(); - mTempFile = null; - } - } - - private void resetUI(boolean inUiThread) { - mEvents.clear(); - - // the ui is static we just empty it. - if (inUiThread) { - resetUiFromUiThread(); - } else { - try { - Display d = mBottomParentPanel.getDisplay(); - - // run sync as we need to update right now. - d.syncExec(new Runnable() { - @Override - public void run() { - if (mBottomParentPanel.isDisposed() == false) { - resetUiFromUiThread(); - } - } - }); - } catch (SWTException e) { - // display is disposed, we're quitting. Do nothing. - } - } - } - - private void resetUiFromUiThread() { - synchronized (mLock) { - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.resetUI(); - } - } - mOptionsAction.setEnabled(false); - mClearAction.setEnabled(false); - mSaveAction.setEnabled(false); - } - - private void prepareDisplayUi() { - mBottomPanel = new Composite(mBottomParentPanel, SWT.NONE); - mBottomParentPanel.setContent(mBottomPanel); - } - - private void createDisplayUi() { - RowLayout rowLayout = new RowLayout(); - rowLayout.wrap = true; - rowLayout.pack = false; - rowLayout.justify = true; - rowLayout.fill = true; - rowLayout.type = SWT.HORIZONTAL; - mBottomPanel.setLayout(rowLayout); - - IPreferenceStore store = DdmUiPreferences.getStore(); - int displayWidth = store.getInt(PREFS_DISPLAY_WIDTH); - int displayHeight = store.getInt(PREFS_DISPLAY_HEIGHT); - - for (EventDisplay eventDisplay : mEventDisplays) { - Control c = eventDisplay.createComposite(mBottomPanel, mCurrentEventLogParser, this); - if (c != null) { - RowData rd = new RowData(); - rd.height = displayHeight; - rd.width = displayWidth; - c.setLayoutData(rd); - } - - Table table = eventDisplay.getTable(); - if (table != null) { - addTableToFocusListener(table); - } - } - - mBottomPanel.layout(); - mBottomParentPanel.setMinSize(mBottomPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT)); - mBottomParentPanel.layout(); - } - - /** - * Rebuild the display ui. - */ - @UiThread - private void rebuildUi() { - synchronized (mLock) { - // we need to rebuild the ui. First we get rid of it. - mBottomPanel.dispose(); - mBottomPanel = null; - - prepareDisplayUi(); - createDisplayUi(); - - // and fill it - - boolean start_event = false; - synchronized (mNewEvents) { - mNewEvents.addAll(0, mEvents); - - if (mPendingDisplay == false) { - mPendingDisplay = true; - start_event = true; - } - } - - if (start_event) { - scheduleUIEventHandler(); - } - - Rectangle r = mBottomParentPanel.getClientArea(); - mBottomParentPanel.setMinSize(mBottomPanel.computeSize(r.width, - SWT.DEFAULT)); - } - } - - - /** - * Processes a new {@link LogEntry} by parsing it with {@link EventLogParser} and displaying it. - * @param entry The new log entry - * @see LogReceiver.ILogListener#newEntry(LogEntry) - */ - @Override - @WorkerThread - public void newEntry(LogEntry entry) { - synchronized (mLock) { - if (mCurrentEventLogParser != null) { - EventContainer event = mCurrentEventLogParser.parse(entry); - if (event != null) { - handleNewEvent(event); - } - } - } - } - - @WorkerThread - private void handleNewEvent(EventContainer event) { - // add the event to the generic list - mEvents.add(event); - - // add to the list of events that needs to be displayed, and trigger a - // new display if needed. - boolean start_event = false; - synchronized (mNewEvents) { - mNewEvents.add(event); - - if (mPendingDisplay == false) { - mPendingDisplay = true; - start_event = true; - } - } - - if (start_event == false) { - // we're done - return; - } - - scheduleUIEventHandler(); - } - - /** - * Schedules the UI thread to execute a {@link Runnable} calling {@link #displayNewEvents()}. - */ - private void scheduleUIEventHandler() { - try { - Display d = mBottomParentPanel.getDisplay(); - d.asyncExec(new Runnable() { - @Override - public void run() { - if (mBottomParentPanel.isDisposed() == false) { - if (mCurrentEventLogParser != null) { - displayNewEvents(); - } - } - } - }); - } catch (SWTException e) { - // if the ui is disposed, do nothing - } - } - - /** - * Processes raw data coming from the log service. - * @see LogReceiver.ILogListener#newData(byte[], int, int) - */ - @Override - public void newData(byte[] data, int offset, int length) { - if (mTempFile != null) { - try { - FileOutputStream fos = new FileOutputStream(mTempFile, true /* append */); - fos.write(data, offset, length); - fos.close(); - } catch (FileNotFoundException e) { - } catch (IOException e) { - } - } - } - - @UiThread - private void displayNewEvents() { - // never display more than 1,000 events in this loop. We can't do too much in the UI thread. - int count = 0; - - // prepare the displays - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.startMultiEventDisplay(); - } - - // display the new events - EventContainer event = null; - boolean need_to_reloop = false; - do { - // get the next event to display. - synchronized (mNewEvents) { - if (mNewEvents.size() > 0) { - if (count > 200) { - // there are still events to be displayed, but we don't want to hog the - // UI thread for too long, so we stop this runnable, but launch a new - // one to keep going. - need_to_reloop = true; - event = null; - } else { - event = mNewEvents.remove(0); - count++; - } - } else { - // we're done. - event = null; - mPendingDisplay = false; - } - } - - if (event != null) { - // notify the event display - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.newEvent(event, mCurrentEventLogParser); - } - } - } while (event != null); - - // we're done displaying events. - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.endMultiEventDisplay(); - } - - // if needed, ask the UI thread to re-run this method. - if (need_to_reloop) { - scheduleUIEventHandler(); - } - } - - /** - * Loads the {@link EventDisplay}s from the preference store. - */ - private void loadEventDisplays() { - IPreferenceStore store = DdmUiPreferences.getStore(); - String storage = store.getString(PREFS_EVENT_DISPLAY); - - if (storage.length() > 0) { - String[] values = storage.split(Pattern.quote(EVENT_DISPLAY_STORAGE_SEPARATOR)); - - for (String value : values) { - EventDisplay eventDisplay = EventDisplay.load(value); - if (eventDisplay != null) { - mEventDisplays.add(eventDisplay); - } - } - } - } - - /** - * Saves the {@link EventDisplay}s into the {@link DdmUiPreferences} store. - */ - private void saveEventDisplays() { - IPreferenceStore store = DdmUiPreferences.getStore(); - - boolean first = true; - StringBuilder sb = new StringBuilder(); - - for (EventDisplay eventDisplay : mEventDisplays) { - String storage = eventDisplay.getStorageString(); - if (storage != null) { - if (first == false) { - sb.append(EVENT_DISPLAY_STORAGE_SEPARATOR); - } else { - first = false; - } - - sb.append(storage); - } - } - - store.setValue(PREFS_EVENT_DISPLAY, sb.toString()); - } - - /** - * Updates the {@link EventDisplay} with the new {@link EventLogParser}. - * <p/> - * This will run asynchronously in the UI thread. - */ - @WorkerThread - private void updateEventDisplays() { - try { - Display d = mBottomParentPanel.getDisplay(); - - d.asyncExec(new Runnable() { - @Override - public void run() { - if (mBottomParentPanel.isDisposed() == false) { - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.setNewLogParser(mCurrentEventLogParser); - } - - mOptionsAction.setEnabled(true); - mClearAction.setEnabled(true); - if (mCurrentLogFile == null) { - mSaveAction.setEnabled(true); - } else { - mSaveAction.setEnabled(false); - } - } - } - }); - } catch (SWTException e) { - // display is disposed: do nothing. - } - } - - @Override - @UiThread - public void columnResized(int index, TableColumn sourceColumn) { - for (EventDisplay eventDisplay : mEventDisplays) { - eventDisplay.resizeColumn(index, sourceColumn); - } - } - - /** - * Runs an event log service out of a local file. - * @param fileName the full file name of the local file containing the event log. - * @param logReceiver the receiver that will handle the log - * @throws IOException - */ - @WorkerThread - private void runLocalEventLogService(String fileName, LogReceiver logReceiver) - throws IOException { - byte[] buffer = new byte[256]; - - FileInputStream fis = new FileInputStream(fileName); - try { - int count; - while ((count = fis.read(buffer)) != -1) { - logReceiver.parseNewData(buffer, 0, count); - } - } finally { - fis.close(); - } - } - - @WorkerThread - private void runLocalEventLogService(String[] log, LogReceiver currentLogReceiver) { - synchronized (mLock) { - for (String line : log) { - EventContainer event = mCurrentEventLogParser.parse(line); - if (event != null) { - handleNewEvent(event); - } - } - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventValueSelector.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventValueSelector.java deleted file mode 100644 index e7c5196..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventValueSelector.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * 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.EventContainer.CompareMethod; -import com.android.ddmlib.log.EventContainer.EventValueType; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.EventValueDescription; -import com.android.ddmuilib.log.event.EventDisplay.OccurrenceDisplayDescriptor; -import com.android.ddmuilib.log.event.EventDisplay.ValueDisplayDescriptor; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Dialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; - -final class EventValueSelector extends Dialog { - private static final int DLG_WIDTH = 400; - private static final int DLG_HEIGHT = 300; - - private Shell mParent; - private Shell mShell; - private boolean mEditStatus; - private Combo mEventCombo; - private Combo mValueCombo; - private Combo mSeriesCombo; - private Button mDisplayPidCheckBox; - private Combo mFilterCombo; - private Combo mFilterMethodCombo; - private Text mFilterValue; - private Button mOkButton; - - private EventLogParser mLogParser; - private OccurrenceDisplayDescriptor mDescriptor; - - /** list of event integer in the order of the combo. */ - private Integer[] mEventTags; - - /** list of indices in the {@link EventValueDescription} array of the current event - * that are of type string. This lets us get back the {@link EventValueDescription} from the - * index in the Series {@link Combo}. - */ - private final ArrayList<Integer> mSeriesIndices = new ArrayList<Integer>(); - - public EventValueSelector(Shell parent) { - super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); - } - - /** - * Opens the display option dialog to edit a new descriptor. - * @param decriptorClass the class of the object to instantiate. Must extend - * {@link OccurrenceDisplayDescriptor} - * @param logParser - * @return true if the object is to be created, false if the creation was canceled. - */ - boolean open(Class<? extends OccurrenceDisplayDescriptor> descriptorClass, - EventLogParser logParser) { - try { - OccurrenceDisplayDescriptor descriptor = descriptorClass.newInstance(); - setModified(); - return open(descriptor, logParser); - } catch (InstantiationException e) { - return false; - } catch (IllegalAccessException e) { - return false; - } - } - - /** - * Opens the display option dialog, to edit a {@link OccurrenceDisplayDescriptor} object or - * a {@link ValueDisplayDescriptor} object. - * @param descriptor The descriptor to edit. - * @return true if the object was modified. - */ - boolean open(OccurrenceDisplayDescriptor descriptor, EventLogParser logParser) { - // make a copy of the descriptor as we'll use a working copy. - if (descriptor instanceof ValueDisplayDescriptor) { - mDescriptor = new ValueDisplayDescriptor((ValueDisplayDescriptor)descriptor); - } else if (descriptor instanceof OccurrenceDisplayDescriptor) { - mDescriptor = new OccurrenceDisplayDescriptor(descriptor); - } else { - return false; - } - - mLogParser = logParser; - - createUI(); - - if (mParent == null || mShell == null) { - return false; - } - - loadValueDescriptor(); - - checkValidity(); - - // Set the dialog size. - try { - mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); - Rectangle r = mParent.getBounds(); - // get the center new top left. - int cx = r.x + r.width/2; - int x = cx - DLG_WIDTH / 2; - int cy = r.y + r.height/2; - int y = cy - DLG_HEIGHT / 2; - mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); - } catch (Exception e) { - e.printStackTrace(); - } - - mShell.layout(); - - // actually open the dialog - mShell.open(); - - // event loop until the dialog is closed. - Display display = mParent.getDisplay(); - while (!mShell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - - return mEditStatus; - } - - OccurrenceDisplayDescriptor getDescriptor() { - return mDescriptor; - } - - private void createUI() { - GridData gd; - - mParent = getParent(); - mShell = new Shell(mParent, getStyle()); - mShell.setText("Event Display Configuration"); - - mShell.setLayout(new GridLayout(2, false)); - - Label l = new Label(mShell, SWT.NONE); - l.setText("Event:"); - - mEventCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); - mEventCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - // the event tag / event name map - Map<Integer, String> eventTagMap = mLogParser.getTagMap(); - Map<Integer, EventValueDescription[]> eventInfoMap = mLogParser.getEventInfoMap(); - Set<Integer> keys = eventTagMap.keySet(); - ArrayList<Integer> list = new ArrayList<Integer>(); - for (Integer i : keys) { - if (eventInfoMap.get(i) != null) { - String eventName = eventTagMap.get(i); - mEventCombo.add(eventName); - - list.add(i); - } - } - mEventTags = list.toArray(new Integer[list.size()]); - - mEventCombo.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - handleEventComboSelection(); - setModified(); - } - }); - - l = new Label(mShell, SWT.NONE); - l.setText("Value:"); - - mValueCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); - mValueCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mValueCombo.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - handleValueComboSelection(); - setModified(); - } - }); - - l = new Label(mShell, SWT.NONE); - l.setText("Series Name:"); - - mSeriesCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); - mSeriesCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mSeriesCombo.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - handleSeriesComboSelection(); - setModified(); - } - }); - - // empty comp - new Composite(mShell, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = gd.widthHint = 0; - - mDisplayPidCheckBox = new Button(mShell, SWT.CHECK); - mDisplayPidCheckBox.setText("Also Show pid"); - mDisplayPidCheckBox.setEnabled(false); - mDisplayPidCheckBox.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - mDescriptor.includePid = mDisplayPidCheckBox.getSelection(); - setModified(); - } - }); - - l = new Label(mShell, SWT.NONE); - l.setText("Filter By:"); - - mFilterCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); - mFilterCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFilterCombo.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - handleFilterComboSelection(); - setModified(); - } - }); - - l = new Label(mShell, SWT.NONE); - l.setText("Filter Method:"); - - mFilterMethodCombo = new Combo(mShell, SWT.DROP_DOWN | SWT.READ_ONLY); - mFilterMethodCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - for (CompareMethod method : CompareMethod.values()) { - mFilterMethodCombo.add(method.toString()); - } - mFilterMethodCombo.select(0); - mFilterMethodCombo.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - handleFilterMethodComboSelection(); - setModified(); - } - }); - - l = new Label(mShell, SWT.NONE); - l.setText("Filter Value:"); - - mFilterValue = new Text(mShell, SWT.BORDER | SWT.SINGLE); - mFilterValue.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFilterValue.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - if (mDescriptor.filterValueIndex != -1) { - // get the current selection in the event combo - int index = mEventCombo.getSelectionIndex(); - - if (index != -1) { - // match it to an event - int eventTag = mEventTags[index]; - mDescriptor.eventTag = eventTag; - - // get the EventValueDescription for this tag - EventValueDescription valueDesc = mLogParser.getEventInfoMap() - .get(eventTag)[mDescriptor.filterValueIndex]; - - // let the EventValueDescription convert the String value into an object - // of the proper type. - mDescriptor.filterValue = valueDesc.getObjectFromString( - mFilterValue.getText().trim()); - setModified(); - } - } - } - }); - - // add a separator spanning the 2 columns - - l = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - l.setLayoutData(gd); - - // add a composite to hold the ok/cancel button, no matter what the columns size are. - Composite buttonComp = new Composite(mShell, SWT.NONE); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - buttonComp.setLayoutData(gd); - GridLayout gl; - buttonComp.setLayout(gl = new GridLayout(6, true)); - gl.marginHeight = gl.marginWidth = 0; - - Composite padding = new Composite(mShell, SWT.NONE); - padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mOkButton = new Button(buttonComp, SWT.PUSH); - mOkButton.setText("OK"); - mOkButton.setLayoutData(new GridData(GridData.CENTER)); - mOkButton.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - mShell.close(); - } - }); - - padding = new Composite(mShell, SWT.NONE); - padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - padding = new Composite(mShell, SWT.NONE); - padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - Button cancelButton = new Button(buttonComp, SWT.PUSH); - cancelButton.setText("Cancel"); - cancelButton.setLayoutData(new GridData(GridData.CENTER)); - cancelButton.addSelectionListener(new SelectionAdapter() { - /* (non-Javadoc) - * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) - */ - @Override - public void widgetSelected(SelectionEvent e) { - // cancel the edit - mEditStatus = false; - mShell.close(); - } - }); - - padding = new Composite(mShell, SWT.NONE); - padding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mShell.addListener(SWT.Close, new Listener() { - @Override - public void handleEvent(Event event) { - event.doit = true; - } - }); - } - - private void setModified() { - mEditStatus = true; - } - - private void handleEventComboSelection() { - // get the current selection in the event combo - int index = mEventCombo.getSelectionIndex(); - - if (index != -1) { - // match it to an event - int eventTag = mEventTags[index]; - mDescriptor.eventTag = eventTag; - - // get the EventValueDescription for this tag - EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag); - - // fill the combo for the values - mValueCombo.removeAll(); - if (values != null) { - if (mDescriptor instanceof ValueDisplayDescriptor) { - ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor; - - mValueCombo.setEnabled(true); - for (EventValueDescription value : values) { - mValueCombo.add(value.toString()); - } - - if (valueDescriptor.valueIndex != -1) { - mValueCombo.select(valueDescriptor.valueIndex); - } else { - mValueCombo.clearSelection(); - } - } else { - mValueCombo.setEnabled(false); - } - - // fill the axis combo - mSeriesCombo.removeAll(); - mSeriesCombo.setEnabled(false); - mSeriesIndices.clear(); - int axisIndex = 0; - int selectionIndex = -1; - for (EventValueDescription value : values) { - if (value.getEventValueType() == EventValueType.STRING) { - mSeriesCombo.add(value.getName()); - mSeriesCombo.setEnabled(true); - mSeriesIndices.add(axisIndex); - - if (mDescriptor.seriesValueIndex != -1 && - mDescriptor.seriesValueIndex == axisIndex) { - selectionIndex = axisIndex; - } - } - axisIndex++; - } - - if (mSeriesCombo.isEnabled()) { - mSeriesCombo.add("default (pid)", 0 /* index */); - mSeriesIndices.add(0 /* index */, -1 /* value */); - - // +1 because we added another item at index 0 - mSeriesCombo.select(selectionIndex + 1); - - if (selectionIndex >= 0) { - mDisplayPidCheckBox.setSelection(mDescriptor.includePid); - mDisplayPidCheckBox.setEnabled(true); - } else { - mDisplayPidCheckBox.setEnabled(false); - mDisplayPidCheckBox.setSelection(false); - } - } else { - mDisplayPidCheckBox.setSelection(false); - mDisplayPidCheckBox.setEnabled(false); - } - - // fill the filter combo - mFilterCombo.setEnabled(true); - mFilterCombo.removeAll(); - mFilterCombo.add("(no filter)"); - for (EventValueDescription value : values) { - mFilterCombo.add(value.toString()); - } - - // select the current filter - mFilterCombo.select(mDescriptor.filterValueIndex + 1); - mFilterMethodCombo.select(getFilterMethodIndex(mDescriptor.filterCompareMethod)); - - // fill the current filter value - if (mDescriptor.filterValueIndex != -1) { - EventValueDescription valueInfo = values[mDescriptor.filterValueIndex]; - if (valueInfo.checkForType(mDescriptor.filterValue)) { - mFilterValue.setText(mDescriptor.filterValue.toString()); - } else { - mFilterValue.setText(""); - } - } else { - mFilterValue.setText(""); - } - } else { - disableSubCombos(); - } - } else { - disableSubCombos(); - } - - checkValidity(); - } - - /** - * - */ - private void disableSubCombos() { - mValueCombo.removeAll(); - mValueCombo.clearSelection(); - mValueCombo.setEnabled(false); - - mSeriesCombo.removeAll(); - mSeriesCombo.clearSelection(); - mSeriesCombo.setEnabled(false); - - mDisplayPidCheckBox.setEnabled(false); - mDisplayPidCheckBox.setSelection(false); - - mFilterCombo.removeAll(); - mFilterCombo.clearSelection(); - mFilterCombo.setEnabled(false); - - mFilterValue.setEnabled(false); - mFilterValue.setText(""); - mFilterMethodCombo.setEnabled(false); - } - - private void handleValueComboSelection() { - ValueDisplayDescriptor valueDescriptor = (ValueDisplayDescriptor)mDescriptor; - - // get the current selection in the value combo - int index = mValueCombo.getSelectionIndex(); - valueDescriptor.valueIndex = index; - - // for now set the built-in name - - // get the current selection in the event combo - int eventIndex = mEventCombo.getSelectionIndex(); - - // match it to an event - int eventTag = mEventTags[eventIndex]; - - // get the EventValueDescription for this tag - EventValueDescription[] values = mLogParser.getEventInfoMap().get(eventTag); - - valueDescriptor.valueName = values[index].getName(); - - checkValidity(); - } - - private void handleSeriesComboSelection() { - // get the current selection in the axis combo - int index = mSeriesCombo.getSelectionIndex(); - - // get the actual value index from the list. - int valueIndex = mSeriesIndices.get(index); - - mDescriptor.seriesValueIndex = valueIndex; - - if (index > 0) { - mDisplayPidCheckBox.setEnabled(true); - mDisplayPidCheckBox.setSelection(mDescriptor.includePid); - } else { - mDisplayPidCheckBox.setSelection(false); - mDisplayPidCheckBox.setEnabled(false); - } - } - - private void handleFilterComboSelection() { - // get the current selection in the axis combo - int index = mFilterCombo.getSelectionIndex(); - - // decrement index by 1 since the item 0 means - // no filter (index = -1), and the rest is offset by 1 - index--; - - mDescriptor.filterValueIndex = index; - - if (index != -1) { - mFilterValue.setEnabled(true); - mFilterMethodCombo.setEnabled(true); - if (mDescriptor.filterValue instanceof String) { - mFilterValue.setText((String)mDescriptor.filterValue); - } - } else { - mFilterValue.setText(""); - mFilterValue.setEnabled(false); - mFilterMethodCombo.setEnabled(false); - } - } - - private void handleFilterMethodComboSelection() { - // get the current selection in the axis combo - int index = mFilterMethodCombo.getSelectionIndex(); - CompareMethod method = CompareMethod.values()[index]; - - mDescriptor.filterCompareMethod = method; - } - - /** - * Returns the index of the filter method - * @param filterCompareMethod the {@link CompareMethod} enum. - */ - private int getFilterMethodIndex(CompareMethod filterCompareMethod) { - CompareMethod[] values = CompareMethod.values(); - for (int i = 0 ; i < values.length ; i++) { - if (values[i] == filterCompareMethod) { - return i; - } - } - return -1; - } - - - private void loadValueDescriptor() { - // get the index from the eventTag. - int eventIndex = 0; - int comboIndex = -1; - for (int i : mEventTags) { - if (i == mDescriptor.eventTag) { - comboIndex = eventIndex; - break; - } - eventIndex++; - } - - if (comboIndex == -1) { - mEventCombo.clearSelection(); - } else { - mEventCombo.select(comboIndex); - } - - // get the event from the descriptor - handleEventComboSelection(); - } - - private void checkValidity() { - mOkButton.setEnabled(mEventCombo.getSelectionIndex() != -1 && - (((mDescriptor instanceof ValueDisplayDescriptor) == false) || - mValueCombo.getSelectionIndex() != -1)); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/OccurrenceRenderer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/OccurrenceRenderer.java deleted file mode 100644 index 3af1447..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/OccurrenceRenderer.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 org.jfree.chart.axis.ValueAxis; -import org.jfree.chart.plot.CrosshairState; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.plot.PlotRenderingInfo; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYItemRendererState; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.jfree.data.time.TimeSeriesCollection; -import org.jfree.data.xy.XYDataset; -import org.jfree.ui.RectangleEdge; - -import java.awt.Graphics2D; -import java.awt.Paint; -import java.awt.Stroke; -import java.awt.geom.Line2D; -import java.awt.geom.Rectangle2D; - -/** - * Custom renderer to render event occurrence. This rendered ignores the y value, and simply - * draws a line from min to max at the time of the item. - */ -public class OccurrenceRenderer extends XYLineAndShapeRenderer { - - private static final long serialVersionUID = 1L; - - @Override - public void drawItem(Graphics2D g2, - XYItemRendererState state, - Rectangle2D dataArea, - PlotRenderingInfo info, - XYPlot plot, - ValueAxis domainAxis, - ValueAxis rangeAxis, - XYDataset dataset, - int series, - int item, - CrosshairState crosshairState, - int pass) { - TimeSeriesCollection timeDataSet = (TimeSeriesCollection)dataset; - - // get the x value for the series/item. - double x = timeDataSet.getX(series, item).doubleValue(); - - // get the min/max of the range axis - double yMin = rangeAxis.getLowerBound(); - double yMax = rangeAxis.getUpperBound(); - - RectangleEdge domainEdge = plot.getDomainAxisEdge(); - RectangleEdge rangeEdge = plot.getRangeAxisEdge(); - - // convert the coordinates to java2d. - double x2D = domainAxis.valueToJava2D(x, dataArea, domainEdge); - double yMin2D = rangeAxis.valueToJava2D(yMin, dataArea, rangeEdge); - double yMax2D = rangeAxis.valueToJava2D(yMax, dataArea, rangeEdge); - - // get the paint information for the series/item - Paint p = getItemPaint(series, item); - Stroke s = getItemStroke(series, item); - - Line2D line = null; - PlotOrientation orientation = plot.getOrientation(); - if (orientation == PlotOrientation.HORIZONTAL) { - line = new Line2D.Double(yMin2D, x2D, yMax2D, x2D); - } - else if (orientation == PlotOrientation.VERTICAL) { - line = new Line2D.Double(x2D, yMin2D, x2D, yMax2D); - } - g2.setPaint(p); - g2.setStroke(s); - g2.draw(line); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/SyncCommon.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/SyncCommon.java deleted file mode 100644 index 0fa6f28..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/SyncCommon.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2009 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.EventContainer; -import com.android.ddmlib.log.EventLogParser; -import com.android.ddmlib.log.InvalidTypeException; - -import java.awt.Color; - -abstract public class SyncCommon extends EventDisplay { - - // State information while processing the event stream - private int mLastState; // 0 if event started, 1 if event stopped - private long mLastStartTime; // ms - private long mLastStopTime; //ms - private String mLastDetails; - private int mLastSyncSource; // poll, server, user, etc. - - // Some common variables for sync display. These define the sync backends - //and how they should be displayed. - protected static final int CALENDAR = 0; - protected static final int GMAIL = 1; - protected static final int FEEDS = 2; - protected static final int CONTACTS = 3; - protected static final int ERRORS = 4; - protected static final int NUM_AUTHS = (CONTACTS + 1); - protected static final String AUTH_NAMES[] = {"Calendar", "Gmail", "Feeds", "Contacts", - "Errors"}; - protected static final Color AUTH_COLORS[] = {Color.MAGENTA, Color.GREEN, Color.BLUE, - Color.ORANGE, Color.RED}; - - // Values from data/etc/event-log-tags - final int EVENT_SYNC = 2720; - final int EVENT_TICKLE = 2742; - final int EVENT_SYNC_DETAILS = 2743; - final int EVENT_CONTACTS_AGGREGATION = 2747; - - protected SyncCommon(String name) { - super(name); - } - - /** - * Resets the display. - */ - @Override - void resetUI() { - mLastStartTime = 0; - mLastStopTime = 0; - mLastState = -1; - mLastSyncSource = -1; - mLastDetails = ""; - } - - /** - * Updates the display with a new event. This is the main entry point for - * each event. This method has the logic to tie together the start event, - * stop event, and details event into one graph item. The combined sync event - * is handed to the subclass via processSycnEvent. Note that the details - * can happen before or after the stop event. - * - * @param event The event - * @param logParser The parser providing the event. - */ - @Override - void newEvent(EventContainer event, EventLogParser logParser) { - try { - if (event.mTag == EVENT_SYNC) { - int state = Integer.parseInt(event.getValueAsString(1)); - if (state == 0) { // start - mLastStartTime = (long) event.sec * 1000L + (event.nsec / 1000000L); - mLastState = 0; - mLastSyncSource = Integer.parseInt(event.getValueAsString(2)); - mLastDetails = ""; - } else if (state == 1) { // stop - if (mLastState == 0) { - mLastStopTime = (long) event.sec * 1000L + (event.nsec / 1000000L); - if (mLastStartTime == 0) { - // Log starts with a stop event - mLastStartTime = mLastStopTime; - } - int auth = getAuth(event.getValueAsString(0)); - processSyncEvent(event, auth, mLastStartTime, mLastStopTime, mLastDetails, - true, mLastSyncSource); - mLastState = 1; - } - } - } else if (event.mTag == EVENT_SYNC_DETAILS) { - mLastDetails = event.getValueAsString(3); - if (mLastState != 0) { // Not inside event - long updateTime = (long) event.sec * 1000L + (event.nsec / 1000000L); - if (updateTime - mLastStopTime <= 250) { - // Got details within 250ms after event, so delete and re-insert - // Details later than 250ms (arbitrary) are discarded as probably - // unrelated. - int auth = getAuth(event.getValueAsString(0)); - processSyncEvent(event, auth, mLastStartTime, mLastStopTime, mLastDetails, - false, mLastSyncSource); - } - } - } else if (event.mTag == EVENT_CONTACTS_AGGREGATION) { - long stopTime = (long) event.sec * 1000L + (event.nsec / 1000000L); - long startTime = stopTime - Long.parseLong(event.getValueAsString(0)); - String details; - int count = Integer.parseInt(event.getValueAsString(1)); - if (count < 0) { - details = "g" + (-count); - } else { - details = "G" + count; - } - processSyncEvent(event, CONTACTS, startTime, stopTime, details, - true /* newEvent */, mLastSyncSource); - } - } catch (InvalidTypeException e) { - } - } - - /** - * Callback hook for subclass to process a sync event. newEvent has the logic - * to combine start and stop events and passes a processed event to the - * subclass. - * - * @param event The sync event - * @param auth The sync authority - * @param startTime Start time (ms) of events - * @param stopTime Stop time (ms) of events - * @param details Details associated with the event. - * @param newEvent True if this event is a new sync event. False if this event - * @param syncSource Poll, user, server, etc. - */ - abstract void processSyncEvent(EventContainer event, int auth, long startTime, long stopTime, - String details, boolean newEvent, int syncSource); - - /** - * Converts authority name to auth number. - * - * @param authname "calendar", etc. - * @return number series number associated with the authority - */ - protected int getAuth(String authname) throws InvalidTypeException { - if ("calendar".equals(authname) || "cl".equals(authname) || - "com.android.calendar".equals(authname)) { - return CALENDAR; - } else if ("contacts".equals(authname) || "cp".equals(authname) || - "com.android.contacts".equals(authname)) { - return CONTACTS; - } else if ("subscribedfeeds".equals(authname)) { - return FEEDS; - } else if ("gmail-ls".equals(authname) || "mail".equals(authname)) { - return GMAIL; - } else if ("gmail-live".equals(authname)) { - return GMAIL; - } else if ("unknown".equals(authname)) { - return -1; // Unknown tickles; discard - } else { - throw new InvalidTypeException("Unknown authname " + authname); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/EditFilterDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/EditFilterDialog.java deleted file mode 100644 index 0e302ce..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/EditFilterDialog.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2007 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.logcat; - -import com.android.ddmuilib.ImageLoader; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Dialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -/** - * Small dialog box to edit a static port number. - */ -public class EditFilterDialog extends Dialog { - - private static final int DLG_WIDTH = 400; - private static final int DLG_HEIGHT = 260; - - private static final String IMAGE_WARNING = "warning.png"; //$NON-NLS-1$ - private static final String IMAGE_EMPTY = "empty.png"; //$NON-NLS-1$ - - private Shell mParent; - - private Shell mShell; - - private boolean mOk = false; - - /** - * Filter being edited or created - */ - private LogFilter mFilter; - - private String mName; - private String mTag; - private String mPid; - - /** Log level as an index of the drop-down combo - * @see getLogLevel - * @see getComboIndex - */ - private int mLogLevel; - - private Button mOkButton; - - private Label mNameWarning; - private Label mTagWarning; - private Label mPidWarning; - - public EditFilterDialog(Shell parent) { - super(parent, SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL); - } - - public EditFilterDialog(Shell shell, LogFilter filter) { - this(shell); - mFilter = filter; - } - - /** - * Opens the dialog. The method will return when the user closes the dialog - * somehow. - * - * @return true if ok was pressed, false if cancelled. - */ - public boolean open() { - createUI(); - - if (mParent == null || mShell == null) { - return false; - } - - mShell.setMinimumSize(DLG_WIDTH, DLG_HEIGHT); - Rectangle r = mParent.getBounds(); - // get the center new top left. - int cx = r.x + r.width/2; - int x = cx - DLG_WIDTH / 2; - int cy = r.y + r.height/2; - int y = cy - DLG_HEIGHT / 2; - mShell.setBounds(x, y, DLG_WIDTH, DLG_HEIGHT); - - mShell.open(); - - Display display = mParent.getDisplay(); - while (!mShell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - - // we're quitting with OK. - // Lets update the filter if needed - if (mOk) { - // if it was a "Create filter" action we need to create it first. - if (mFilter == null) { - mFilter = new LogFilter(mName); - } - - // setup the filter - mFilter.setTagMode(mTag); - - if (mPid != null && mPid.length() > 0) { - mFilter.setPidMode(Integer.parseInt(mPid)); - } else { - mFilter.setPidMode(-1); - } - - mFilter.setLogLevel(getLogLevel(mLogLevel)); - } - - return mOk; - } - - public LogFilter getFilter() { - return mFilter; - } - - private void createUI() { - mParent = getParent(); - mShell = new Shell(mParent, getStyle()); - mShell.setText("Log Filter"); - - mShell.setLayout(new GridLayout(1, false)); - - mShell.addListener(SWT.Close, new Listener() { - @Override - public void handleEvent(Event event) { - } - }); - - // top part with the filter name - Composite nameComposite = new Composite(mShell, SWT.NONE); - nameComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - nameComposite.setLayout(new GridLayout(3, false)); - - Label l = new Label(nameComposite, SWT.NONE); - l.setText("Filter Name:"); - - final Text filterNameText = new Text(nameComposite, - SWT.SINGLE | SWT.BORDER); - if (mFilter != null) { - mName = mFilter.getName(); - if (mName != null) { - filterNameText.setText(mName); - } - } - filterNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - filterNameText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mName = filterNameText.getText().trim(); - validate(); - } - }); - - mNameWarning = new Label(nameComposite, SWT.NONE); - mNameWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_EMPTY, - mShell.getDisplay())); - - // separator - l = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - - // center part with the filter parameters - Composite main = new Composite(mShell, SWT.NONE); - main.setLayoutData(new GridData(GridData.FILL_BOTH)); - main.setLayout(new GridLayout(3, false)); - - l = new Label(main, SWT.NONE); - l.setText("by Log Tag:"); - - final Text tagText = new Text(main, SWT.SINGLE | SWT.BORDER); - if (mFilter != null) { - mTag = mFilter.getTagFilter(); - if (mTag != null) { - tagText.setText(mTag); - } - } - - tagText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - tagText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mTag = tagText.getText().trim(); - validate(); - } - }); - - mTagWarning = new Label(main, SWT.NONE); - mTagWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_EMPTY, - mShell.getDisplay())); - - l = new Label(main, SWT.NONE); - l.setText("by pid:"); - - final Text pidText = new Text(main, SWT.SINGLE | SWT.BORDER); - if (mFilter != null) { - if (mFilter.getPidFilter() != -1) { - mPid = Integer.toString(mFilter.getPidFilter()); - } else { - mPid = ""; - } - pidText.setText(mPid); - } - pidText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - pidText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mPid = pidText.getText().trim(); - validate(); - } - }); - - mPidWarning = new Label(main, SWT.NONE); - mPidWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_EMPTY, - mShell.getDisplay())); - - l = new Label(main, SWT.NONE); - l.setText("by Log level:"); - - final Combo logCombo = new Combo(main, SWT.DROP_DOWN | SWT.READ_ONLY); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - logCombo.setLayoutData(gd); - - // add the labels - logCombo.add("<none>"); - logCombo.add("Error"); - logCombo.add("Warning"); - logCombo.add("Info"); - logCombo.add("Debug"); - logCombo.add("Verbose"); - - if (mFilter != null) { - mLogLevel = getComboIndex(mFilter.getLogLevel()); - logCombo.select(mLogLevel); - } else { - logCombo.select(0); - } - - logCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // get the selection - mLogLevel = logCombo.getSelectionIndex(); - validate(); - } - }); - - // separator - l = new Label(mShell, SWT.SEPARATOR | SWT.HORIZONTAL); - l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - // bottom part with the ok/cancel - Composite bottomComp = new Composite(mShell, SWT.NONE); - bottomComp - .setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); - bottomComp.setLayout(new GridLayout(2, true)); - - mOkButton = new Button(bottomComp, SWT.NONE); - mOkButton.setText("OK"); - mOkButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mOk = true; - mShell.close(); - } - }); - mOkButton.setEnabled(false); - mShell.setDefaultButton(mOkButton); - - Button cancelButton = new Button(bottomComp, SWT.NONE); - cancelButton.setText("Cancel"); - cancelButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mShell.close(); - } - }); - - validate(); - } - - /** - * Returns the log level from a combo index. - * @param index the Combo index - * @return a log level valid for the Log class. - */ - protected int getLogLevel(int index) { - if (index == 0) { - return -1; - } - - return 7 - index; - } - - /** - * Returns the index in the combo that matches the log level - * @param logLevel The Log level. - * @return the combo index - */ - private int getComboIndex(int logLevel) { - if (logLevel == -1) { - return 0; - } - - return 7 - logLevel; - } - - /** - * Validates the content of the 2 text fields and enable/disable "ok", while - * setting up the warning/error message. - */ - private void validate() { - - boolean result = true; - - // then we check it only contains digits. - if (mPid != null) { - if (mPid.matches("[0-9]*") == false) { //$NON-NLS-1$ - mPidWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_WARNING, - mShell.getDisplay())); - mPidWarning.setToolTipText("PID must be a number"); //$NON-NLS-1$ - result = false; - } else { - mPidWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_EMPTY, - mShell.getDisplay())); - mPidWarning.setToolTipText(null); - } - } - - // then we check it not contains character | or : - if (mTag != null) { - if (mTag.matches(".*[:|].*") == true) { //$NON-NLS-1$ - mTagWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_WARNING, - mShell.getDisplay())); - mTagWarning.setToolTipText("Tag cannot contain | or :"); //$NON-NLS-1$ - result = false; - } else { - mTagWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_EMPTY, - mShell.getDisplay())); - mTagWarning.setToolTipText(null); - } - } - - // then we check it not contains character | or : - if (mName != null && mName.length() > 0) { - if (mName.matches(".*[:|].*") == true) { //$NON-NLS-1$ - mNameWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_WARNING, - mShell.getDisplay())); - mNameWarning.setToolTipText("Name cannot contain | or :"); //$NON-NLS-1$ - result = false; - } else { - mNameWarning.setImage(ImageLoader.getDdmUiLibLoader().loadImage( - IMAGE_EMPTY, - mShell.getDisplay())); - mNameWarning.setToolTipText(null); - } - } else { - result = false; - } - - mOkButton.setEnabled(result); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java deleted file mode 100644 index 2804629..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.logcat.LogCatMessage; - -import java.util.List; - -/** - * Listeners interested in changes in the logcat buffer should implement this interface. - */ -public interface ILogCatBufferChangeListener { - /** - * Called when the logcat buffer changes. - * @param addedMessages list of messages that were added to the logcat buffer - * @param deletedMessages list of messages that were removed from the logcat buffer - */ - void bufferChanged(List<LogCatMessage> addedMessages, List<LogCatMessage> deletedMessages); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java deleted file mode 100644 index 728b518..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.logcat.LogCatMessage; - -/** - * Classes interested in listening to user selection of logcat - * messages should implement this interface. - */ -public interface ILogCatMessageSelectionListener { - void messageDoubleClicked(LogCatMessage m); -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java deleted file mode 100644 index 629b0e0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.logcat.LogCatFilter; - -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.Viewer; - -import java.util.List; - -/** - * A JFace content provider for logcat filter list, used in {@link LogCatPanel}. - */ -public final class LogCatFilterContentProvider implements IStructuredContentProvider { - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer arg0, Object arg1, Object arg2) { - } - - /** - * Obtain the list of filters currently in use. - * @param model list of {@link LogCatFilter}'s - * @return array of {@link LogCatFilter} objects, or null. - */ - @Override - public Object[] getElements(Object model) { - return ((List<?>) model).toArray(); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java deleted file mode 100644 index dbc34d8..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2013 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.logcat; - -import com.android.ddmlib.logcat.LogCatFilter; -import com.android.ddmlib.logcat.LogCatMessage; - -import java.util.List; - -public class LogCatFilterData { - private final LogCatFilter mFilter; - - /** Indicates the number of messages that match this filter, but have not - * yet been read by the user. This is really metadata about this filter - * necessary for the UI. If we ever end up needing to store more metadata, - * then it is probably better to move it out into a separate class. */ - private int mUnreadCount; - - /** Indicates that this filter is transient, and should not be persisted - * across Eclipse sessions. */ - private boolean mTransient; - - public LogCatFilterData(LogCatFilter f) { - mFilter = f; - - // By default, all filters are persistent. Transient filters should explicitly - // mark it so by calling setTransient. - mTransient = false; - } - - /** - * Update the unread count based on new messages received. The unread count - * is incremented by the count of messages in the received list that will be - * accepted by this filter. - * @param newMessages list of new messages. - */ - public void updateUnreadCount(List<LogCatMessage> newMessages) { - for (LogCatMessage m : newMessages) { - if (mFilter.matches(m)) { - mUnreadCount++; - } - } - } - - /** - * Reset count of unread messages. - */ - public void resetUnreadCount() { - mUnreadCount = 0; - } - - /** - * Get current value for the unread message counter. - */ - public int getUnreadCount() { - return mUnreadCount; - } - - /** Make this filter transient: It will not be persisted across sessions. */ - public void setTransient() { - mTransient = true; - } - - public boolean isTransient() { - return mTransient; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java deleted file mode 100644 index fe24ddd..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.logcat.LogCatFilter; - -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.swt.graphics.Image; - -import java.util.Map; - -/** - * A JFace label provider for the LogCat filters. It expects elements of type - * {@link LogCatFilter}. - */ -public final class LogCatFilterLabelProvider extends LabelProvider implements ITableLabelProvider { - private Map<LogCatFilter, LogCatFilterData> mFilterData; - - public LogCatFilterLabelProvider(Map<LogCatFilter, LogCatFilterData> filterData) { - mFilterData = filterData; - } - - @Override - public Image getColumnImage(Object arg0, int arg1) { - return null; - } - - /** - * Implements {@link ITableLabelProvider#getColumnText(Object, int)}. - * @param element an instance of {@link LogCatFilter} - * @param index index of the column - * @return text to use in the column - */ - @Override - public String getColumnText(Object element, int index) { - if (!(element instanceof LogCatFilter)) { - return null; - } - - LogCatFilter f = (LogCatFilter) element; - LogCatFilterData fd = mFilterData.get(f); - - if (fd != null && fd.getUnreadCount() > 0) { - return String.format("%s (%d)", f.getName(), fd.getUnreadCount()); - } else { - return f.getName(); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java deleted file mode 100644 index 39b3fa9..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.Log.LogLevel; - -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.TitleAreaDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Dialog used to create or edit settings for a logcat filter. - */ -public final class LogCatFilterSettingsDialog extends TitleAreaDialog { - private static final String TITLE = "Logcat Message Filter Settings"; - private static final String DEFAULT_MESSAGE = - "Filter logcat messages by the source's tag, pid or minimum log level.\n" - + "Empty fields will match all messages."; - - private String mFilterName; - private String mTag; - private String mText; - private String mPid; - private String mAppName; - private String mLogLevel; - - private Text mFilterNameText; - private Text mTagFilterText; - private Text mTextFilterText; - private Text mPidFilterText; - private Text mAppNameFilterText; - private Combo mLogLevelCombo; - private Button mOkButton; - - /** - * Construct the filter settings dialog with default values for all fields. - * @param parentShell . - */ - public LogCatFilterSettingsDialog(Shell parentShell) { - super(parentShell); - setDefaults("", "", "", "", "", LogLevel.VERBOSE); - } - - /** - * Set the default values to show when the dialog is opened. - * @param filterName name for the filter. - * @param tag value for filter by tag - * @param text value for filter by text - * @param pid value for filter by pid - * @param appName value for filter by app name - * @param level value for filter by log level - */ - public void setDefaults(String filterName, String tag, String text, String pid, String appName, - LogLevel level) { - mFilterName = filterName; - mTag = tag; - mText = text; - mPid = pid; - mAppName = appName; - mLogLevel = level.getStringValue(); - } - - @Override - protected Control createDialogArea(Composite shell) { - setTitle(TITLE); - setMessage(DEFAULT_MESSAGE); - - Composite parent = (Composite) super.createDialogArea(shell); - Composite c = new Composite(parent, SWT.BORDER); - c.setLayout(new GridLayout(2, false)); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createLabel(c, "Filter Name:"); - mFilterNameText = new Text(c, SWT.BORDER); - mFilterNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFilterNameText.setText(mFilterName); - - createSeparator(c); - - createLabel(c, "by Log Tag:"); - mTagFilterText = new Text(c, SWT.BORDER); - mTagFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTagFilterText.setText(mTag); - - createLabel(c, "by Log Message:"); - mTextFilterText = new Text(c, SWT.BORDER); - mTextFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTextFilterText.setText(mText); - - createLabel(c, "by PID:"); - mPidFilterText = new Text(c, SWT.BORDER); - mPidFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mPidFilterText.setText(mPid); - - createLabel(c, "by Application Name:"); - mAppNameFilterText = new Text(c, SWT.BORDER); - mAppNameFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mAppNameFilterText.setText(mAppName); - - createLabel(c, "by Log Level:"); - mLogLevelCombo = new Combo(c, SWT.READ_ONLY | SWT.DROP_DOWN); - mLogLevelCombo.setItems(getLogLevels().toArray(new String[0])); - mLogLevelCombo.select(getLogLevels().indexOf(mLogLevel)); - - /* call validateDialog() whenever user modifies any text field */ - ModifyListener m = new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - DialogStatus status = validateDialog(); - mOkButton.setEnabled(status.valid); - setErrorMessage(status.message); - } - }; - mFilterNameText.addModifyListener(m); - mTagFilterText.addModifyListener(m); - mTextFilterText.addModifyListener(m); - mPidFilterText.addModifyListener(m); - mAppNameFilterText.addModifyListener(m); - - return c; - } - - - @Override - protected void createButtonsForButtonBar(Composite parent) { - super.createButtonsForButtonBar(parent); - - mOkButton = getButton(IDialogConstants.OK_ID); - - DialogStatus status = validateDialog(); - mOkButton.setEnabled(status.valid); - } - - /** - * A tuple that specifies whether the current state of the inputs - * on the dialog is valid or not. If it is not valid, the message - * field stores the reason why it isn't. - */ - private static final class DialogStatus { - final boolean valid; - final String message; - - private DialogStatus(boolean isValid, String errMessage) { - valid = isValid; - message = errMessage; - } - } - - private DialogStatus validateDialog() { - /* check that there is some name for the filter */ - if (mFilterNameText.getText().trim().equals("")) { - return new DialogStatus(false, - "Please provide a name for this filter."); - } - - /* if a pid is provided, it should be a +ve integer */ - String pidText = mPidFilterText.getText().trim(); - if (pidText.trim().length() > 0) { - int pid = 0; - try { - pid = Integer.parseInt(pidText); - } catch (NumberFormatException e) { - return new DialogStatus(false, - "PID should be a positive integer."); - } - - if (pid < 0) { - return new DialogStatus(false, - "PID should be a positive integer."); - } - } - - /* tag field must use a valid regex pattern */ - String tagText = mTagFilterText.getText().trim(); - if (tagText.trim().length() > 0) { - try { - Pattern.compile(tagText); - } catch (PatternSyntaxException e) { - return new DialogStatus(false, - "Invalid regex used in tag field: " + e.getMessage()); - } - } - - /* text field must use a valid regex pattern */ - String messageText = mTextFilterText.getText().trim(); - if (messageText.trim().length() > 0) { - try { - Pattern.compile(messageText); - } catch (PatternSyntaxException e) { - return new DialogStatus(false, - "Invalid regex used in text field: " + e.getMessage()); - } - } - - /* app name field must use a valid regex pattern */ - String appNameText = mAppNameFilterText.getText().trim(); - if (appNameText.trim().length() > 0) { - try { - Pattern.compile(appNameText); - } catch (PatternSyntaxException e) { - return new DialogStatus(false, - "Invalid regex used in application name field: " + e.getMessage()); - } - } - - return new DialogStatus(true, null); - } - - private void createSeparator(Composite c) { - Label l = new Label(c, SWT.SEPARATOR | SWT.HORIZONTAL); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - l.setLayoutData(gd); - } - - private void createLabel(Composite c, String text) { - Label l = new Label(c, SWT.NONE); - l.setText(text); - GridData gd = new GridData(); - gd.horizontalAlignment = SWT.RIGHT; - l.setLayoutData(gd); - } - - @Override - protected void okPressed() { - /* save values from the widgets before the shell is closed. */ - mFilterName = mFilterNameText.getText(); - mTag = mTagFilterText.getText(); - mText = mTextFilterText.getText(); - mLogLevel = mLogLevelCombo.getText(); - mPid = mPidFilterText.getText(); - mAppName = mAppNameFilterText.getText(); - - super.okPressed(); - } - - /** - * Obtain the name for this filter. - * @return user provided filter name, maybe empty. - */ - public String getFilterName() { - return mFilterName; - } - - /** - * Obtain the tag regex to filter by. - * @return user provided tag regex, maybe empty. - */ - public String getTag() { - return mTag; - } - - /** - * Obtain the text regex to filter by. - * @return user provided tag regex, maybe empty. - */ - public String getText() { - return mText; - } - - /** - * Obtain user provided PID to filter by. - * @return user provided pid, maybe empty. - */ - public String getPid() { - return mPid; - } - - /** - * Obtain user provided application name to filter by. - * @return user provided app name regex, maybe empty - */ - public String getAppName() { - return mAppName; - } - - /** - * Obtain log level to filter by. - * @return log level string. - */ - public String getLogLevel() { - return mLogLevel; - } - - /** - * Obtain the string representation of all supported log levels. - * @return an array of strings, each representing a certain log level. - */ - public static List<String> getLogLevels() { - List<String> logLevels = new ArrayList<String>(); - - for (LogLevel l : LogLevel.values()) { - logLevels.add(l.getStringValue()); - } - - return logLevels; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java deleted file mode 100644 index de35162..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.logcat.LogCatFilter; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Class to help save/restore user created filters. - * - * Users can create multiple filters in the logcat view. These filters could have regexes - * in their settings. All of the user created filters are saved into a single Eclipse - * preference. This class helps in generating the string to be saved given a list of - * {@link LogCatFilter}'s, and also does the reverse of creating the list of filters - * given the encoded string. - */ -public final class LogCatFilterSettingsSerializer { - private static final char SINGLE_QUOTE = '\''; - private static final char ESCAPE_CHAR = '\\'; - - private static final String ATTR_DELIM = ", "; - private static final String KW_DELIM = ": "; - - private static final String KW_NAME = "name"; - private static final String KW_TAG = "tag"; - private static final String KW_TEXT = "text"; - private static final String KW_PID = "pid"; - private static final String KW_APP = "app"; - private static final String KW_LOGLEVEL = "level"; - - /** - * Encode the settings from a list of {@link LogCatFilter}'s into a string for saving to - * the preference store. See - * {@link LogCatFilterSettingsSerializer#decodeFromPreferenceString(String)} for the - * reverse operation. - * @param filters list of filters to save. - * @param filterData mapping from filter to per filter UI data - * @return an encoded string that can be saved in Eclipse preference store. The encoded string - * is of a list of key:'value' pairs. - */ - public String encodeToPreferenceString(List<LogCatFilter> filters, - Map<LogCatFilter, LogCatFilterData> filterData) { - StringBuffer sb = new StringBuffer(); - - for (LogCatFilter f : filters) { - LogCatFilterData fd = filterData.get(f); - if (fd != null && fd.isTransient()) { - // do not persist transient filters - continue; - } - - sb.append(KW_NAME); sb.append(KW_DELIM); sb.append(quoteString(f.getName())); - sb.append(ATTR_DELIM); - sb.append(KW_TAG); sb.append(KW_DELIM); sb.append(quoteString(f.getTag())); - sb.append(ATTR_DELIM); - sb.append(KW_TEXT); sb.append(KW_DELIM); sb.append(quoteString(f.getText())); - sb.append(ATTR_DELIM); - sb.append(KW_PID); sb.append(KW_DELIM); sb.append(quoteString(f.getPid())); - sb.append(ATTR_DELIM); - sb.append(KW_APP); sb.append(KW_DELIM); sb.append(quoteString(f.getAppName())); - sb.append(ATTR_DELIM); - sb.append(KW_LOGLEVEL); sb.append(KW_DELIM); - sb.append(quoteString(f.getLogLevel().getStringValue())); - sb.append(ATTR_DELIM); - } - return sb.toString(); - } - - /** - * Decode an encoded string representing the settings of a list of logcat - * filters into a list of {@link LogCatFilter}'s. - * @param pref encoded preference string - * @return a list of {@link LogCatFilter} - */ - public List<LogCatFilter> decodeFromPreferenceString(String pref) { - List<LogCatFilter> fs = new ArrayList<LogCatFilter>(); - - /* first split the string into a list of key, value pairs */ - List<String> kv = getKeyValues(pref); - if (kv.size() == 0) { - return fs; - } - - /* construct filter settings from the key value pairs */ - int index = 0; - while (index < kv.size()) { - String name = ""; - String tag = ""; - String pid = ""; - String app = ""; - String text = ""; - LogLevel level = LogLevel.VERBOSE; - - assert kv.get(index).equals(KW_NAME); - name = kv.get(index + 1); - - index += 2; - while (index < kv.size() && !kv.get(index).equals(KW_NAME)) { - String key = kv.get(index); - String value = kv.get(index + 1); - index += 2; - - if (key.equals(KW_TAG)) { - tag = value; - } else if (key.equals(KW_TEXT)) { - text = value; - } else if (key.equals(KW_PID)) { - pid = value; - } else if (key.equals(KW_APP)) { - app = value; - } else if (key.equals(KW_LOGLEVEL)) { - level = LogLevel.getByString(value); - } - } - - fs.add(new LogCatFilter(name, tag, text, pid, app, level)); - } - - return fs; - } - - private List<String> getKeyValues(String pref) { - List<String> kv = new ArrayList<String>(); - int index = 0; - while (index < pref.length()) { - String kw = getKeyword(pref.substring(index)); - if (kw == null) { - break; - } - index += kw.length() + KW_DELIM.length(); - - String value = getNextString(pref.substring(index)); - index += value.length() + ATTR_DELIM.length(); - - value = unquoteString(value); - - kv.add(kw); - kv.add(value); - } - - return kv; - } - - /** - * Enclose a string in quotes, escaping all the quotes within the string. - */ - private String quoteString(String s) { - return SINGLE_QUOTE + s.replace(Character.toString(SINGLE_QUOTE), "\\'") - + SINGLE_QUOTE; - } - - /** - * Recover original string from its escaped version created using - * {@link LogCatFilterSettingsSerializer#quoteString(String)}. - */ - private String unquoteString(String s) { - s = s.substring(1, s.length() - 1); /* remove start and end QUOTES */ - return s.replace("\\'", Character.toString(SINGLE_QUOTE)); - } - - private String getKeyword(String pref) { - int kwlen = pref.indexOf(KW_DELIM); - if (kwlen == -1) { - return null; - } - - return pref.substring(0, kwlen); - } - - /** - * Get the next quoted string from the input stream of characters. - */ - private String getNextString(String s) { - assert s.charAt(0) == SINGLE_QUOTE; - - StringBuffer sb = new StringBuffer(); - - int index = 0; - while (index < s.length()) { - sb.append(s.charAt(index)); - - if (index > 0 - && s.charAt(index) == SINGLE_QUOTE // current char is a single quote - && s.charAt(index - 1) != ESCAPE_CHAR) { // prev char wasn't a backslash - /* break if an unescaped SINGLE QUOTE (end of string) is seen */ - break; - } - - index++; - } - - return sb.toString(); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java deleted file mode 100644 index c5cd548..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.logcat.LogCatMessage; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; - -/** - * Container for a list of log messages. The list of messages are - * maintained in a circular buffer (FIFO). - */ -public final class LogCatMessageList { - /** Preference key for size of the FIFO. */ - public static final String MAX_MESSAGES_PREFKEY = - "logcat.messagelist.max.size"; - - /** Default value for max # of messages. */ - public static final int MAX_MESSAGES_DEFAULT = 5000; - - private int mFifoSize; - private BlockingQueue<LogCatMessage> mQ; - - /** - * Construct an empty message list. - * @param maxMessages capacity of the circular buffer - */ - public LogCatMessageList(int maxMessages) { - mFifoSize = maxMessages; - - mQ = new ArrayBlockingQueue<LogCatMessage>(mFifoSize); - } - - /** - * Resize the message list. - * @param n new size for the list - */ - public synchronized void resize(int n) { - mFifoSize = n; - - if (mFifoSize > mQ.size()) { - /* if resizing to a bigger fifo, we can copy over all elements from the current mQ */ - mQ = new ArrayBlockingQueue<LogCatMessage>(mFifoSize, true, mQ); - } else { - /* for a smaller fifo, copy over the last n entries */ - LogCatMessage[] curMessages = mQ.toArray(new LogCatMessage[mQ.size()]); - mQ = new ArrayBlockingQueue<LogCatMessage>(mFifoSize); - for (int i = curMessages.length - mFifoSize; i < curMessages.length; i++) { - mQ.offer(curMessages[i]); - } - } - } - - /** - * Append a message to the list. If the list is full, the first - * message will be popped off of it. - * @param m log to be inserted - */ - public synchronized void appendMessages(final List<LogCatMessage> messages) { - ensureSpace(messages.size()); - for (LogCatMessage m: messages) { - mQ.offer(m); - } - } - - /** - * Ensure that there is sufficient space for given number of messages. - * @return list of messages that were deleted to create additional space. - */ - public synchronized List<LogCatMessage> ensureSpace(int messageCount) { - List<LogCatMessage> l = new ArrayList<LogCatMessage>(messageCount); - - while (mQ.remainingCapacity() < messageCount) { - l.add(mQ.poll()); - } - - return l; - } - - /** - * Returns the number of additional elements that this queue can - * ideally (in the absence of memory or resource constraints) - * accept without blocking. - * @return the remaining capacity - */ - public synchronized int remainingCapacity() { - return mQ.remainingCapacity(); - } - - /** Clear all messages in the list. */ - public synchronized void clear() { - mQ.clear(); - } - - /** Obtain a copy of the message list. */ - public synchronized List<LogCatMessage> getAllMessages() { - return new ArrayList<LogCatMessage>(mQ); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java deleted file mode 100644 index bda742c..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java +++ /dev/null @@ -1,1607 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.DdmConstants; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.logcat.LogCatFilter; -import com.android.ddmlib.logcat.LogCatMessage; -import com.android.ddmuilib.AbstractBufferFindTarget; -import com.android.ddmuilib.FindDialog; -import com.android.ddmuilib.ITableFocusListener; -import com.android.ddmuilib.ITableFocusListener.IFocusedTableActivator; -import com.android.ddmuilib.ImageLoader; -import com.android.ddmuilib.SelectionDependentPanel; -import com.android.ddmuilib.TableHelper; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.PreferenceConverter; -import org.eclipse.jface.util.IPropertyChangeListener; -import org.eclipse.jface.util.PropertyChangeEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.SashForm; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.ScrollBar; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.ToolItem; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * LogCatPanel displays a table listing the logcat messages. - */ -public final class LogCatPanel extends SelectionDependentPanel - implements ILogCatBufferChangeListener { - /** Preference key to use for storing list of logcat filters. */ - public static final String LOGCAT_FILTERS_LIST = "logcat.view.filters.list"; - - /** Preference key to use for storing font settings. */ - public static final String LOGCAT_VIEW_FONT_PREFKEY = "logcat.view.font"; - - /** Preference key to use for deciding whether to automatically en/disable scroll lock. */ - public static final String AUTO_SCROLL_LOCK_PREFKEY = "logcat.view.auto-scroll-lock"; - - // Preference keys for message colors based on severity level - private static final String MSG_COLOR_PREFKEY_PREFIX = "logcat.msg.color."; - public static final String VERBOSE_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "verbose"; //$NON-NLS-1$ - public static final String DEBUG_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "debug"; //$NON-NLS-1$ - public static final String INFO_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "info"; //$NON-NLS-1$ - public static final String WARN_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "warn"; //$NON-NLS-1$ - public static final String ERROR_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "error"; //$NON-NLS-1$ - public static final String ASSERT_COLOR_PREFKEY = MSG_COLOR_PREFKEY_PREFIX + "assert"; //$NON-NLS-1$ - - // Use a monospace font family - private static final String FONT_FAMILY = - DdmConstants.CURRENT_PLATFORM == DdmConstants.PLATFORM_DARWIN ? "Monaco":"Courier New"; - - // Use the default system font size - private static final FontData DEFAULT_LOGCAT_FONTDATA; - static { - int h = Display.getDefault().getSystemFont().getFontData()[0].getHeight(); - DEFAULT_LOGCAT_FONTDATA = new FontData(FONT_FAMILY, h, SWT.NORMAL); - } - - private static final String LOGCAT_VIEW_COLSIZE_PREFKEY_PREFIX = "logcat.view.colsize."; - private static final String DISPLAY_FILTERS_COLUMN_PREFKEY = "logcat.view.display.filters"; - - /** Default message to show in the message search field. */ - private static final String DEFAULT_SEARCH_MESSAGE = - "Search for messages. Accepts Java regexes. " - + "Prefix with pid:, app:, tag: or text: to limit scope."; - - /** Tooltip to show in the message search field. */ - private static final String DEFAULT_SEARCH_TOOLTIP = - "Example search patterns:\n" - + " sqlite (search for sqlite in text field)\n" - + " app:browser (search for messages generated by the browser application)"; - - private static final String IMAGE_ADD_FILTER = "add.png"; //$NON-NLS-1$ - private static final String IMAGE_DELETE_FILTER = "delete.png"; //$NON-NLS-1$ - private static final String IMAGE_EDIT_FILTER = "edit.png"; //$NON-NLS-1$ - private static final String IMAGE_SAVE_LOG_TO_FILE = "save.png"; //$NON-NLS-1$ - private static final String IMAGE_CLEAR_LOG = "clear.png"; //$NON-NLS-1$ - private static final String IMAGE_DISPLAY_FILTERS = "displayfilters.png"; //$NON-NLS-1$ - private static final String IMAGE_SCROLL_LOCK = "scroll_lock.png"; //$NON-NLS-1$ - - private static final int[] WEIGHTS_SHOW_FILTERS = new int[] {15, 85}; - private static final int[] WEIGHTS_LOGCAT_ONLY = new int[] {0, 100}; - - /** Index of the default filter in the saved filters column. */ - private static final int DEFAULT_FILTER_INDEX = 0; - - /* Text colors for the filter box */ - private static final Color VALID_FILTER_REGEX_COLOR = - Display.getDefault().getSystemColor(SWT.COLOR_BLACK); - private static final Color INVALID_FILTER_REGEX_COLOR = - Display.getDefault().getSystemColor(SWT.COLOR_RED); - - private LogCatReceiver mReceiver; - private IPreferenceStore mPrefStore; - - private List<LogCatFilter> mLogCatFilters; - private Map<LogCatFilter, LogCatFilterData> mLogCatFilterData; - private int mCurrentSelectedFilterIndex; - - private ToolItem mNewFilterToolItem; - private ToolItem mDeleteFilterToolItem; - private ToolItem mEditFilterToolItem; - private TableViewer mFiltersTableViewer; - - private Combo mLiveFilterLevelCombo; - private Text mLiveFilterText; - - private List<LogCatFilter> mCurrentFilters = Collections.emptyList(); - - private Table mTable; - - private boolean mShouldScrollToLatestLog = true; - private ToolItem mScrollLockCheckBox; - private boolean mAutoScrollLock; - - // Lock under which the vertical scroll bar listener should be added - private final Object mScrollBarSelectionListenerLock = new Object(); - private SelectionListener mScrollBarSelectionListener; - private boolean mScrollBarListenerSet = false; - - private String mLogFileExportFolder; - - private Font mFont; - private int mWrapWidthInChars; - - private Color mVerboseColor; - private Color mDebugColor; - private Color mInfoColor; - private Color mWarnColor; - private Color mErrorColor; - private Color mAssertColor; - - private SashForm mSash; - - // messages added since last refresh, synchronized on mLogBuffer - private List<LogCatMessage> mLogBuffer; - - // # of messages deleted since last refresh, synchronized on mLogBuffer - private int mDeletedLogCount; - - /** - * Construct a logcat panel. - * @param prefStore preference store where UI preferences will be saved - */ - public LogCatPanel(IPreferenceStore prefStore) { - mPrefStore = prefStore; - mLogBuffer = new ArrayList<LogCatMessage>(LogCatMessageList.MAX_MESSAGES_DEFAULT); - - initializeFilters(); - - setupDefaultPreferences(); - initializePreferenceUpdateListeners(); - - mFont = getFontFromPrefStore(); - loadMessageColorPreferences(); - mAutoScrollLock = mPrefStore.getBoolean(AUTO_SCROLL_LOCK_PREFKEY); - } - - private void loadMessageColorPreferences() { - if (mVerboseColor != null) { - disposeMessageColors(); - } - - mVerboseColor = getColorFromPrefStore(VERBOSE_COLOR_PREFKEY); - mDebugColor = getColorFromPrefStore(DEBUG_COLOR_PREFKEY); - mInfoColor = getColorFromPrefStore(INFO_COLOR_PREFKEY); - mWarnColor = getColorFromPrefStore(WARN_COLOR_PREFKEY); - mErrorColor = getColorFromPrefStore(ERROR_COLOR_PREFKEY); - mAssertColor = getColorFromPrefStore(ASSERT_COLOR_PREFKEY); - } - - private void initializeFilters() { - mLogCatFilters = new ArrayList<LogCatFilter>(); - mLogCatFilterData = new ConcurrentHashMap<LogCatFilter, LogCatFilterData>(); - - /* add default filter matching all messages */ - String tag = ""; - String text = ""; - String pid = ""; - String app = ""; - LogCatFilter defaultFilter = new LogCatFilter("All messages (no filters)", - tag, text, pid, app, LogLevel.VERBOSE); - - mLogCatFilters.add(defaultFilter); - mLogCatFilterData.put(defaultFilter, new LogCatFilterData(defaultFilter)); - - /* restore saved filters from prefStore */ - List<LogCatFilter> savedFilters = getSavedFilters(); - for (LogCatFilter f: savedFilters) { - mLogCatFilters.add(f); - mLogCatFilterData.put(f, new LogCatFilterData(f)); - } - } - - private void setupDefaultPreferences() { - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.LOGCAT_VIEW_FONT_PREFKEY, - DEFAULT_LOGCAT_FONTDATA); - mPrefStore.setDefault(LogCatMessageList.MAX_MESSAGES_PREFKEY, - LogCatMessageList.MAX_MESSAGES_DEFAULT); - mPrefStore.setDefault(DISPLAY_FILTERS_COLUMN_PREFKEY, true); - mPrefStore.setDefault(AUTO_SCROLL_LOCK_PREFKEY, true); - - /* Default Colors for different log levels. */ - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.VERBOSE_COLOR_PREFKEY, - new RGB(0, 0, 0)); - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.DEBUG_COLOR_PREFKEY, - new RGB(0, 0, 127)); - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.INFO_COLOR_PREFKEY, - new RGB(0, 127, 0)); - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.WARN_COLOR_PREFKEY, - new RGB(255, 127, 0)); - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.ERROR_COLOR_PREFKEY, - new RGB(255, 0, 0)); - PreferenceConverter.setDefault(mPrefStore, LogCatPanel.ASSERT_COLOR_PREFKEY, - new RGB(255, 0, 0)); - } - - private void initializePreferenceUpdateListeners() { - mPrefStore.addPropertyChangeListener(new IPropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent event) { - String changedProperty = event.getProperty(); - if (changedProperty.equals(LogCatPanel.LOGCAT_VIEW_FONT_PREFKEY)) { - if (mFont != null) { - mFont.dispose(); - } - mFont = getFontFromPrefStore(); - recomputeWrapWidth(); - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - for (TableItem it: mTable.getItems()) { - it.setFont(mFont); - } - } - }); - } else if (changedProperty.startsWith(MSG_COLOR_PREFKEY_PREFIX)) { - loadMessageColorPreferences(); - Display.getDefault().syncExec(new Runnable() { - @Override - public void run() { - Color c = mVerboseColor; - for (TableItem it: mTable.getItems()) { - Object data = it.getData(); - if (data instanceof LogCatMessage) { - c = getForegroundColor((LogCatMessage) data); - } - it.setForeground(c); - } - } - }); - } else if (changedProperty.equals(LogCatMessageList.MAX_MESSAGES_PREFKEY)) { - mReceiver.resizeFifo(mPrefStore.getInt( - LogCatMessageList.MAX_MESSAGES_PREFKEY)); - reloadLogBuffer(); - } else if (changedProperty.equals(AUTO_SCROLL_LOCK_PREFKEY)) { - mAutoScrollLock = mPrefStore.getBoolean(AUTO_SCROLL_LOCK_PREFKEY); - } - } - }); - } - - private void saveFilterPreferences() { - LogCatFilterSettingsSerializer serializer = new LogCatFilterSettingsSerializer(); - - /* save all filter settings except the first one which is the default */ - String e = serializer.encodeToPreferenceString( - mLogCatFilters.subList(1, mLogCatFilters.size()), mLogCatFilterData); - mPrefStore.setValue(LOGCAT_FILTERS_LIST, e); - } - - private List<LogCatFilter> getSavedFilters() { - LogCatFilterSettingsSerializer serializer = new LogCatFilterSettingsSerializer(); - String e = mPrefStore.getString(LOGCAT_FILTERS_LIST); - return serializer.decodeFromPreferenceString(e); - } - - @Override - public void deviceSelected() { - IDevice device = getCurrentDevice(); - if (device == null) { - // If the device is not working properly, getCurrentDevice() could return null. - // In such a case, we don't launch logcat, nor switch the display. - return; - } - - if (mReceiver != null) { - // Don't need to listen to new logcat messages from previous device anymore. - mReceiver.removeMessageReceivedEventListener(this); - - // When switching between devices, existing filter match count should be reset. - for (LogCatFilter f : mLogCatFilters) { - LogCatFilterData fd = mLogCatFilterData.get(f); - fd.resetUnreadCount(); - } - } - - mReceiver = LogCatReceiverFactory.INSTANCE.newReceiver(device, mPrefStore); - mReceiver.addMessageReceivedEventListener(this); - reloadLogBuffer(); - - // Always scroll to last line whenever the selected device changes. - // Run this in a separate async thread to give the table some time to update after the - // setInput above. - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - scrollToLatestLog(); - } - }); - } - - @Override - public void clientSelected() { - } - - @Override - protected void postCreation() { - } - - @Override - protected Control createControl(Composite parent) { - GridLayout layout = new GridLayout(1, false); - parent.setLayout(layout); - - createViews(parent); - setupDefaults(); - - return null; - } - - private void createViews(Composite parent) { - mSash = createSash(parent); - - createListOfFilters(mSash); - createLogTableView(mSash); - - boolean showFilters = mPrefStore.getBoolean(DISPLAY_FILTERS_COLUMN_PREFKEY); - updateFiltersColumn(showFilters); - } - - private SashForm createSash(Composite parent) { - SashForm sash = new SashForm(parent, SWT.HORIZONTAL); - sash.setLayoutData(new GridData(GridData.FILL_BOTH)); - return sash; - } - - private void createListOfFilters(SashForm sash) { - Composite c = new Composite(sash, SWT.BORDER); - GridLayout layout = new GridLayout(2, false); - c.setLayout(layout); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createFiltersToolbar(c); - createFiltersTable(c); - } - - private void createFiltersToolbar(Composite parent) { - Label l = new Label(parent, SWT.NONE); - l.setText("Saved Filters"); - GridData gd = new GridData(); - gd.horizontalAlignment = SWT.LEFT; - l.setLayoutData(gd); - - ToolBar t = new ToolBar(parent, SWT.FLAT); - gd = new GridData(); - gd.horizontalAlignment = SWT.RIGHT; - t.setLayoutData(gd); - - /* new filter */ - mNewFilterToolItem = new ToolItem(t, SWT.PUSH); - mNewFilterToolItem.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_ADD_FILTER, t.getDisplay())); - mNewFilterToolItem.setToolTipText("Add a new logcat filter"); - mNewFilterToolItem.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - addNewFilter(); - } - }); - - /* delete filter */ - mDeleteFilterToolItem = new ToolItem(t, SWT.PUSH); - mDeleteFilterToolItem.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_DELETE_FILTER, t.getDisplay())); - mDeleteFilterToolItem.setToolTipText("Delete selected logcat filter"); - mDeleteFilterToolItem.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - deleteSelectedFilter(); - } - }); - - /* edit filter */ - mEditFilterToolItem = new ToolItem(t, SWT.PUSH); - mEditFilterToolItem.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_EDIT_FILTER, t.getDisplay())); - mEditFilterToolItem.setToolTipText("Edit selected logcat filter"); - mEditFilterToolItem.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - editSelectedFilter(); - } - }); - } - - private void addNewFilter(String defaultTag, String defaultText, String defaultPid, - String defaultAppName, LogLevel defaultLevel) { - LogCatFilterSettingsDialog d = new LogCatFilterSettingsDialog( - Display.getCurrent().getActiveShell()); - d.setDefaults("", defaultTag, defaultText, defaultPid, defaultAppName, defaultLevel); - if (d.open() != Window.OK) { - return; - } - - LogCatFilter f = new LogCatFilter(d.getFilterName().trim(), - d.getTag().trim(), - d.getText().trim(), - d.getPid().trim(), - d.getAppName().trim(), - LogLevel.getByString(d.getLogLevel())); - - mLogCatFilters.add(f); - mLogCatFilterData.put(f, new LogCatFilterData(f)); - mFiltersTableViewer.refresh(); - - /* select the newly added entry */ - int idx = mLogCatFilters.size() - 1; - mFiltersTableViewer.getTable().setSelection(idx); - - filterSelectionChanged(); - saveFilterPreferences(); - } - - private void addNewFilter() { - addNewFilter("", "", "", "", LogLevel.VERBOSE); - } - - private void deleteSelectedFilter() { - int selectedIndex = mFiltersTableViewer.getTable().getSelectionIndex(); - if (selectedIndex <= 0) { - /* return if no selected filter, or the default filter was selected (0th). */ - return; - } - - LogCatFilter f = mLogCatFilters.get(selectedIndex); - mLogCatFilters.remove(selectedIndex); - mLogCatFilterData.remove(f); - - mFiltersTableViewer.refresh(); - mFiltersTableViewer.getTable().setSelection(selectedIndex - 1); - - filterSelectionChanged(); - saveFilterPreferences(); - } - - private void editSelectedFilter() { - int selectedIndex = mFiltersTableViewer.getTable().getSelectionIndex(); - if (selectedIndex < 0) { - return; - } - - LogCatFilter curFilter = mLogCatFilters.get(selectedIndex); - - LogCatFilterSettingsDialog dialog = new LogCatFilterSettingsDialog( - Display.getCurrent().getActiveShell()); - dialog.setDefaults(curFilter.getName(), curFilter.getTag(), curFilter.getText(), - curFilter.getPid(), curFilter.getAppName(), curFilter.getLogLevel()); - if (dialog.open() != Window.OK) { - return; - } - - LogCatFilter f = new LogCatFilter(dialog.getFilterName(), - dialog.getTag(), - dialog.getText(), - dialog.getPid(), - dialog.getAppName(), - LogLevel.getByString(dialog.getLogLevel())); - mLogCatFilters.set(selectedIndex, f); - mFiltersTableViewer.refresh(); - - mFiltersTableViewer.getTable().setSelection(selectedIndex); - filterSelectionChanged(); - saveFilterPreferences(); - } - - /** - * Select the transient filter for the specified application. If no such filter - * exists, then create one and then select that. This method should be called from - * the UI thread. - * @param appName application name to filter by - */ - public void selectTransientAppFilter(String appName) { - assert mTable.getDisplay().getThread() == Thread.currentThread(); - - LogCatFilter f = findTransientAppFilter(appName); - if (f == null) { - f = createTransientAppFilter(appName); - mLogCatFilters.add(f); - - LogCatFilterData fd = new LogCatFilterData(f); - fd.setTransient(); - mLogCatFilterData.put(f, fd); - } - - selectFilterAt(mLogCatFilters.indexOf(f)); - } - - private LogCatFilter findTransientAppFilter(String appName) { - for (LogCatFilter f : mLogCatFilters) { - LogCatFilterData fd = mLogCatFilterData.get(f); - if (fd != null && fd.isTransient() && f.getAppName().equals(appName)) { - return f; - } - } - return null; - } - - private LogCatFilter createTransientAppFilter(String appName) { - LogCatFilter f = new LogCatFilter(appName + " (Session Filter)", - "", - "", - "", - appName, - LogLevel.VERBOSE); - return f; - } - - private void selectFilterAt(final int index) { - mFiltersTableViewer.refresh(); - - if (index != mFiltersTableViewer.getTable().getSelectionIndex()) { - mFiltersTableViewer.getTable().setSelection(index); - filterSelectionChanged(); - } - } - - private void createFiltersTable(Composite parent) { - final Table table = new Table(parent, SWT.FULL_SELECTION); - - GridData gd = new GridData(GridData.FILL_BOTH); - gd.horizontalSpan = 2; - table.setLayoutData(gd); - - mFiltersTableViewer = new TableViewer(table); - mFiltersTableViewer.setContentProvider(new LogCatFilterContentProvider()); - mFiltersTableViewer.setLabelProvider(new LogCatFilterLabelProvider(mLogCatFilterData)); - mFiltersTableViewer.setInput(mLogCatFilters); - - mFiltersTableViewer.getTable().addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - filterSelectionChanged(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent arg0) { - editSelectedFilter(); - } - }); - } - - private void createLogTableView(SashForm sash) { - Composite c = new Composite(sash, SWT.NONE); - c.setLayout(new GridLayout()); - c.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createLiveFilters(c); - createLogcatViewTable(c); - } - - /** Create the search bar at the top of the logcat messages table. */ - private void createLiveFilters(Composite parent) { - Composite c = new Composite(parent, SWT.NONE); - c.setLayout(new GridLayout(3, false)); - c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mLiveFilterText = new Text(c, SWT.BORDER | SWT.SEARCH); - mLiveFilterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mLiveFilterText.setMessage(DEFAULT_SEARCH_MESSAGE); - mLiveFilterText.setToolTipText(DEFAULT_SEARCH_TOOLTIP); - mLiveFilterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent arg0) { - updateFilterTextColor(); - updateAppliedFilters(); - } - }); - - mLiveFilterLevelCombo = new Combo(c, SWT.READ_ONLY | SWT.DROP_DOWN); - mLiveFilterLevelCombo.setItems( - LogCatFilterSettingsDialog.getLogLevels().toArray(new String[0])); - mLiveFilterLevelCombo.select(0); - mLiveFilterLevelCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - updateAppliedFilters(); - } - }); - - ToolBar toolBar = new ToolBar(c, SWT.FLAT); - - ToolItem saveToLog = new ToolItem(toolBar, SWT.PUSH); - saveToLog.setImage(ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_SAVE_LOG_TO_FILE, - toolBar.getDisplay())); - saveToLog.setToolTipText("Export Selected Items To Text File.."); - saveToLog.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - saveLogToFile(); - } - }); - - ToolItem clearLog = new ToolItem(toolBar, SWT.PUSH); - clearLog.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_CLEAR_LOG, toolBar.getDisplay())); - clearLog.setToolTipText("Clear Log"); - clearLog.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent arg0) { - if (mReceiver != null) { - mReceiver.clearMessages(); - refreshLogCatTable(); - resetUnreadCountForAllFilters(); - - // the filters view is not cleared unless the filters are re-applied. - updateAppliedFilters(); - } - } - }); - - final ToolItem showFiltersColumn = new ToolItem(toolBar, SWT.CHECK); - showFiltersColumn.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_DISPLAY_FILTERS, - toolBar.getDisplay())); - showFiltersColumn.setSelection(mPrefStore.getBoolean(DISPLAY_FILTERS_COLUMN_PREFKEY)); - showFiltersColumn.setToolTipText("Display Saved Filters View"); - showFiltersColumn.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - boolean showFilters = showFiltersColumn.getSelection(); - mPrefStore.setValue(DISPLAY_FILTERS_COLUMN_PREFKEY, showFilters); - updateFiltersColumn(showFilters); - } - }); - - mScrollLockCheckBox = new ToolItem(toolBar, SWT.CHECK); - mScrollLockCheckBox.setImage( - ImageLoader.getDdmUiLibLoader().loadImage(IMAGE_SCROLL_LOCK, - toolBar.getDisplay())); - mScrollLockCheckBox.setSelection(true); - mScrollLockCheckBox.setToolTipText("Scroll Lock"); - mScrollLockCheckBox.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - boolean scrollLock = mScrollLockCheckBox.getSelection(); - setScrollToLatestLog(scrollLock); - } - }); - } - - /** Sets the foreground color of filter text based on whether the regex is valid. */ - private void updateFilterTextColor() { - String text = mLiveFilterText.getText(); - Color c; - try { - Pattern.compile(text.trim()); - c = VALID_FILTER_REGEX_COLOR; - } catch (PatternSyntaxException e) { - c = INVALID_FILTER_REGEX_COLOR; - } - mLiveFilterText.setForeground(c); - } - - private void updateFiltersColumn(boolean showFilters) { - if (showFilters) { - mSash.setWeights(WEIGHTS_SHOW_FILTERS); - } else { - mSash.setWeights(WEIGHTS_LOGCAT_ONLY); - } - } - - /** - * Save logcat messages selected in the table to a file. - */ - private void saveLogToFile() { - /* show dialog box and get target file name */ - final String fName = getLogFileTargetLocation(); - if (fName == null) { - return; - } - - /* obtain list of selected messages */ - final List<LogCatMessage> selectedMessages = getSelectedLogCatMessages(); - - /* save messages to file in a different (non UI) thread */ - Thread t = new Thread(new Runnable() { - @Override - public void run() { - BufferedWriter w = null; - try { - w = new BufferedWriter(new FileWriter(fName)); - for (LogCatMessage m : selectedMessages) { - w.append(m.toString()); - w.newLine(); - } - } catch (final IOException e) { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - MessageDialog.openError(Display.getCurrent().getActiveShell(), - "Unable to export selection to file.", - "Unexpected error while saving selected messages to file: " - + e.getMessage()); - } - }); - } finally { - if (w != null) { - try { - w.close(); - } catch (IOException e) { - // ignore - } - } - } - } - }); - t.setName("Saving selected items to logfile.."); - t.start(); - } - - /** - * Display a {@link FileDialog} to the user and obtain the location for the log file. - * @return path to target file, null if user canceled the dialog - */ - private String getLogFileTargetLocation() { - FileDialog fd = new FileDialog(Display.getCurrent().getActiveShell(), SWT.SAVE); - - fd.setText("Save Log.."); - fd.setFileName("log.txt"); - - if (mLogFileExportFolder == null) { - mLogFileExportFolder = System.getProperty("user.home"); - } - fd.setFilterPath(mLogFileExportFolder); - - fd.setFilterNames(new String[] { - "Text Files (*.txt)" - }); - fd.setFilterExtensions(new String[] { - "*.txt" - }); - - String fName = fd.open(); - if (fName != null) { - mLogFileExportFolder = fd.getFilterPath(); /* save path to restore on future calls */ - } - - return fName; - } - - private List<LogCatMessage> getSelectedLogCatMessages() { - int[] indices = mTable.getSelectionIndices(); - Arrays.sort(indices); /* Table.getSelectionIndices() does not specify an order */ - - List<LogCatMessage> selectedMessages = new ArrayList<LogCatMessage>(indices.length); - for (int i : indices) { - Object data = mTable.getItem(i).getData(); - if (data instanceof LogCatMessage) { - selectedMessages.add((LogCatMessage) data); - } - } - - return selectedMessages; - } - - private List<LogCatMessage> applyCurrentFilters(List<LogCatMessage> msgList) { - List<LogCatMessage> filteredItems = new ArrayList<LogCatMessage>(msgList.size()); - - for (LogCatMessage msg: msgList) { - if (isMessageAccepted(msg, mCurrentFilters)) { - filteredItems.add(msg); - } - } - - return filteredItems; - } - - private boolean isMessageAccepted(LogCatMessage msg, List<LogCatFilter> filters) { - for (LogCatFilter f : filters) { - if (!f.matches(msg)) { - // not accepted by this filter - return false; - } - } - - // accepted by all filters - return true; - } - - private void createLogcatViewTable(Composite parent) { - mTable = new Table(parent, SWT.FULL_SELECTION | SWT.MULTI); - - mTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - mTable.getHorizontalBar().setVisible(true); - - /** Columns to show in the table. */ - String[] properties = { - "Level", - "Time", - "PID", - "TID", - "Application", - "Tag", - "Text", - }; - - /** The sampleText for each column is used to determine the default widths - * for each column. The contents do not matter, only their lengths are needed. */ - String[] sampleText = { - " ", - " 00-00 00:00:00.0000 ", - " 0000", - " 0000", - " com.android.launcher", - " SampleTagText", - " Log Message field should be pretty long by default. As long as possible for correct display on Mac.", - }; - - for (int i = 0; i < properties.length; i++) { - TableHelper.createTableColumn(mTable, - properties[i], /* Column title */ - SWT.LEFT, /* Column Style */ - sampleText[i], /* String to compute default col width */ - getColPreferenceKey(properties[i]), /* Preference Store key for this column */ - mPrefStore); - } - - // don't zebra stripe the table: When the buffer is full, and scroll lock is on, having - // zebra striping means that the background could keep changing depending on the number - // of new messages added to the bottom of the log. - mTable.setLinesVisible(false); - mTable.setHeaderVisible(true); - - // Set the row height to be sufficient enough to display the current font. - // This is not strictly necessary, except that on WinXP, the rows showed up clipped. So - // we explicitly set it to be sure. - mTable.addListener(SWT.MeasureItem, new Listener() { - @Override - public void handleEvent(Event event) { - event.height = event.gc.getFontMetrics().getHeight(); - } - }); - - // Update the label provider whenever the text column's width changes - TableColumn textColumn = mTable.getColumn(properties.length - 1); - textColumn.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent event) { - recomputeWrapWidth(); - } - }); - - addRightClickMenu(mTable); - initDoubleClickListener(); - recomputeWrapWidth(); - - mTable.addDisposeListener(new DisposeListener() { - @Override - public void widgetDisposed(DisposeEvent arg0) { - dispose(); - } - }); - - final ScrollBar vbar = mTable.getVerticalBar(); - mScrollBarSelectionListener = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (!mAutoScrollLock) { - return; - } - - // thumb + selection < max => bar is not at the bottom. - // We subtract an arbitrary amount (thumbSize/2) from this difference to allow - // for cases like half a line being displayed at the end from affecting this - // calculation. The thumbSize/2 number seems to work experimentally across - // Linux/Mac & Windows, but might possibly need tweaking. - int diff = vbar.getThumb() + vbar.getSelection() - vbar.getMaximum(); - boolean isAtBottom = Math.abs(diff) < vbar.getThumb() / 2; - - if (isAtBottom != mShouldScrollToLatestLog) { - setScrollToLatestLog(isAtBottom); - mScrollLockCheckBox.setSelection(isAtBottom); - } - } - }; - startScrollBarMonitor(vbar); - - // Explicitly set the values to use for the scroll bar. In particular, we want these values - // to have a high enough accuracy that even small movements of the scroll bar have an - // effect on the selection. The auto scroll lock detection assumes that the scroll bar is - // at the bottom iff selection + thumb == max. - final int MAX = 10000; - final int THUMB = 10; - vbar.setValues(MAX - THUMB, // selection - 0, // min - MAX, // max - THUMB, // thumb - 1, // increment - THUMB); // page increment - } - - private void startScrollBarMonitor(ScrollBar vbar) { - synchronized (mScrollBarSelectionListenerLock) { - if (!mScrollBarListenerSet) { - mScrollBarListenerSet = true; - vbar.addSelectionListener(mScrollBarSelectionListener); - } - } - } - - private void stopScrollBarMonitor(ScrollBar vbar) { - synchronized (mScrollBarSelectionListenerLock) { - if (mScrollBarListenerSet) { - mScrollBarListenerSet = false; - vbar.removeSelectionListener(mScrollBarSelectionListener); - } - } - } - - /** Setup menu to be displayed when right clicking a log message. */ - private void addRightClickMenu(final Table table) { - // This action will pop up a create filter dialog pre-populated with current selection - final Action filterAction = new Action("Filter similar messages...") { - @Override - public void run() { - List<LogCatMessage> selectedMessages = getSelectedLogCatMessages(); - if (selectedMessages.size() == 0) { - addNewFilter(); - } else { - LogCatMessage m = selectedMessages.get(0); - addNewFilter(m.getTag(), m.getMessage(), m.getPid(), m.getAppName(), - m.getLogLevel()); - } - } - }; - - final Action findAction = new Action("Find...") { - @Override - public void run() { - showFindDialog(); - }; - }; - - final MenuManager mgr = new MenuManager(); - mgr.add(filterAction); - mgr.add(findAction); - final Menu menu = mgr.createContextMenu(table); - - table.addListener(SWT.MenuDetect, new Listener() { - @Override - public void handleEvent(Event event) { - Point pt = table.getDisplay().map(null, table, new Point(event.x, event.y)); - Rectangle clientArea = table.getClientArea(); - - // The click location is in the header if it is between - // clientArea.y and clientArea.y + header height - boolean header = pt.y > clientArea.y - && pt.y < (clientArea.y + table.getHeaderHeight()); - - // Show the menu only if it is not inside the header - table.setMenu(header ? null : menu); - } - }); - } - - public void recomputeWrapWidth() { - if (mTable == null || mTable.isDisposed()) { - return; - } - - // get width of the last column (log message) - TableColumn tc = mTable.getColumn(mTable.getColumnCount() - 1); - int colWidth = tc.getWidth(); - - // get font width - GC gc = new GC(tc.getParent()); - gc.setFont(mFont); - int avgCharWidth = gc.getFontMetrics().getAverageCharWidth(); - gc.dispose(); - - int MIN_CHARS_PER_LINE = 50; // show atleast these many chars per line - mWrapWidthInChars = Math.max(colWidth/avgCharWidth, MIN_CHARS_PER_LINE); - - int OFFSET_AT_END_OF_LINE = 10; // leave some space at the end of the line - mWrapWidthInChars -= OFFSET_AT_END_OF_LINE; - } - - private void setScrollToLatestLog(boolean scroll) { - mShouldScrollToLatestLog = scroll; - if (scroll) { - scrollToLatestLog(); - } - } - - private String getColPreferenceKey(String field) { - return LOGCAT_VIEW_COLSIZE_PREFKEY_PREFIX + field; - } - - private Font getFontFromPrefStore() { - FontData fd = PreferenceConverter.getFontData(mPrefStore, - LogCatPanel.LOGCAT_VIEW_FONT_PREFKEY); - return new Font(Display.getDefault(), fd); - } - - private Color getColorFromPrefStore(String key) { - RGB rgb = PreferenceConverter.getColor(mPrefStore, key); - return new Color(Display.getDefault(), rgb); - } - - private void setupDefaults() { - int defaultFilterIndex = 0; - mFiltersTableViewer.getTable().setSelection(defaultFilterIndex); - - filterSelectionChanged(); - } - - /** - * Perform all necessary updates whenever a filter is selected (by user or programmatically). - */ - private void filterSelectionChanged() { - int idx = mFiltersTableViewer.getTable().getSelectionIndex(); - if (idx == -1) { - /* One of the filters should always be selected. - * On Linux, there is no way to deselect an item. - * On Mac, clicking inside the list view, but not an any item will result - * in all items being deselected. In such a case, we simply reselect the - * first entry. */ - idx = 0; - mFiltersTableViewer.getTable().setSelection(idx); - } - - mCurrentSelectedFilterIndex = idx; - - resetUnreadCountForAllFilters(); - updateFiltersToolBar(); - updateAppliedFilters(); - } - - private void resetUnreadCountForAllFilters() { - for (LogCatFilterData fd: mLogCatFilterData.values()) { - fd.resetUnreadCount(); - } - refreshFiltersTable(); - } - - private void updateFiltersToolBar() { - /* The default filter at index 0 can neither be edited, nor removed. */ - boolean en = mCurrentSelectedFilterIndex != DEFAULT_FILTER_INDEX; - mEditFilterToolItem.setEnabled(en); - mDeleteFilterToolItem.setEnabled(en); - } - - private void updateAppliedFilters() { - mCurrentFilters = getFiltersToApply(); - reloadLogBuffer(); - } - - private List<LogCatFilter> getFiltersToApply() { - /* list of filters to apply = saved filter + live filters */ - List<LogCatFilter> filters = new ArrayList<LogCatFilter>(); - - if (mCurrentSelectedFilterIndex != DEFAULT_FILTER_INDEX) { - filters.add(getSelectedSavedFilter()); - } - - filters.addAll(getCurrentLiveFilters()); - return filters; - } - - private List<LogCatFilter> getCurrentLiveFilters() { - return LogCatFilter.fromString( - mLiveFilterText.getText(), /* current query */ - LogLevel.getByString(mLiveFilterLevelCombo.getText())); /* current log level */ - } - - private LogCatFilter getSelectedSavedFilter() { - return mLogCatFilters.get(mCurrentSelectedFilterIndex); - } - - @Override - public void setFocus() { - } - - @Override - public void bufferChanged(List<LogCatMessage> addedMessages, - List<LogCatMessage> deletedMessages) { - updateUnreadCount(addedMessages); - refreshFiltersTable(); - - synchronized (mLogBuffer) { - addedMessages = applyCurrentFilters(addedMessages); - deletedMessages = applyCurrentFilters(deletedMessages); - - mLogBuffer.addAll(addedMessages); - mDeletedLogCount += deletedMessages.size(); - } - - refreshLogCatTable(); - } - - private void reloadLogBuffer() { - mTable.removeAll(); - - synchronized (mLogBuffer) { - mLogBuffer.clear(); - mDeletedLogCount = 0; - } - - if (mReceiver == null || mReceiver.getMessages() == null) { - return; - } - - List<LogCatMessage> addedMessages = mReceiver.getMessages().getAllMessages(); - List<LogCatMessage> deletedMessages = Collections.emptyList(); - bufferChanged(addedMessages, deletedMessages); - } - - /** - * When new messages are received, and they match a saved filter, update - * the unread count associated with that filter. - * @param receivedMessages list of new messages received - */ - private void updateUnreadCount(List<LogCatMessage> receivedMessages) { - for (int i = 0; i < mLogCatFilters.size(); i++) { - if (i == mCurrentSelectedFilterIndex) { - /* no need to update unread count for currently selected filter */ - continue; - } - LogCatFilter f = mLogCatFilters.get(i); - LogCatFilterData fd = mLogCatFilterData.get(f); - fd.updateUnreadCount(receivedMessages); - } - } - - private void refreshFiltersTable() { - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (mFiltersTableViewer.getTable().isDisposed()) { - return; - } - mFiltersTableViewer.refresh(); - } - }); - } - - /** Task currently submitted to {@link Display#asyncExec} to be run in UI thread. */ - private LogCatTableRefresherTask mCurrentRefresher; - - /** - * Refresh the logcat table asynchronously from the UI thread. - * This method adds a new async refresh only if there are no pending refreshes for the table. - * Doing so eliminates redundant refresh threads from being queued up to be run on the - * display thread. - */ - private void refreshLogCatTable() { - synchronized (this) { - if (mCurrentRefresher == null) { - mCurrentRefresher = new LogCatTableRefresherTask(); - Display.getDefault().asyncExec(mCurrentRefresher); - } - } - } - - /** - * The {@link LogCatTableRefresherTask} takes care of refreshing the table with the - * new log messages that have been received. Since the log behaves like a circular buffer, - * the first step is to remove items from the top of the table (if necessary). This step - * is complicated by the fact that a single log message may span multiple rows if the message - * was wrapped. Once the deleted items are removed, the new messages are added to the bottom - * of the table. If scroll lock is enabled, the item that was original visible is made visible - * again, if not, the last item is made visible. - */ - private class LogCatTableRefresherTask implements Runnable { - @Override - public void run() { - if (mTable.isDisposed()) { - return; - } - synchronized (LogCatPanel.this) { - mCurrentRefresher = null; - } - - // Current topIndex so that it can be restored if scroll locked. - int topIndex = mTable.getTopIndex(); - - mTable.setRedraw(false); - - // the scroll bar should only listen to user generated scroll events, not the - // scroll events that happen due to the addition of logs - stopScrollBarMonitor(mTable.getVerticalBar()); - - // Obtain the list of new messages, and the number of deleted messages. - List<LogCatMessage> newMessages; - int deletedMessageCount; - synchronized (mLogBuffer) { - newMessages = new ArrayList<LogCatMessage>(mLogBuffer); - mLogBuffer.clear(); - - deletedMessageCount = mDeletedLogCount; - mDeletedLogCount = 0; - - mFindTarget.scrollBy(deletedMessageCount); - } - - int originalItemCount = mTable.getItemCount(); - - // Remove entries from the start of the table if they were removed in the log buffer - // This is complicated by the fact that a single message may span multiple TableItems - // if it was word-wrapped. - deletedMessageCount -= removeFromTable(mTable, deletedMessageCount); - - // Compute number of table items that were deleted from the table. - int deletedItemCount = originalItemCount - mTable.getItemCount(); - - // If there are more messages to delete (after deleting messages from the table), - // then delete them from the start of the newly added messages list - if (deletedMessageCount > 0) { - assert deletedMessageCount < newMessages.size(); - for (int i = 0; i < deletedMessageCount; i++) { - newMessages.remove(0); - } - } - - // Add the remaining messages to the table. - for (LogCatMessage m: newMessages) { - List<String> wrappedMessageList = wrapMessage(m.getMessage(), mWrapWidthInChars); - Color c = getForegroundColor(m); - for (int i = 0; i < wrappedMessageList.size(); i++) { - TableItem item = new TableItem(mTable, SWT.NONE); - - if (i == 0) { - // Only set the message data in the first item. This allows code that - // examines the table item data (such as copy selection) to distinguish - // between real messages versus lines that are really just wrapped - // content from the previous message. - item.setData(m); - - item.setText(new String[] { - Character.toString(m.getLogLevel().getPriorityLetter()), - m.getTime(), - m.getPid(), - m.getTid(), - m.getAppName(), - m.getTag(), - wrappedMessageList.get(i) - }); - } else { - item.setText(new String[] { - "", "", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - "", "", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - wrappedMessageList.get(i) - }); - } - item.setForeground(c); - item.setFont(mFont); - } - } - - if (mShouldScrollToLatestLog) { - scrollToLatestLog(); - } else { - // If scroll locked, show the same item that was original visible in the table. - int index = Math.max(topIndex - deletedItemCount, 0); - mTable.setTopIndex(index); - } - - mTable.setRedraw(true); - - // re-enable listening to scroll bar events, but do so in a separate thread to make - // sure that the current task (LogCatRefresherTask) has completed first - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (!mTable.isDisposed()) { - startScrollBarMonitor(mTable.getVerticalBar()); - } - } - }); - } - - /** - * Removes given number of messages from the table, starting at the top of the table. - * Note that the number of messages deleted is not equal to the number of rows - * deleted since a single message could span multiple rows. This method first calculates - * the number of rows that correspond to the number of messages to delete, and then - * removes all those rows. - * @param table table from which messages should be removed - * @param msgCount number of messages to be removed - * @return number of messages that were actually removed - */ - private int removeFromTable(Table table, int msgCount) { - int deletedMessageCount = 0; // # of messages that have been deleted - int lastItemToDelete = 0; // index of the last item that should be deleted - - while (deletedMessageCount < msgCount && lastItemToDelete < table.getItemCount()) { - // only rows that begin a message have their item data set - TableItem item = table.getItem(lastItemToDelete); - if (item.getData() != null) { - deletedMessageCount++; - } - - lastItemToDelete++; - } - - // If there are any table items left over at the end that are wrapped over from the - // previous message, mark them for deletion as well. - if (lastItemToDelete < table.getItemCount() - && table.getItem(lastItemToDelete).getData() == null) { - lastItemToDelete++; - } - - table.remove(0, lastItemToDelete - 1); - - return deletedMessageCount; - } - } - - /** Scroll to the last line. */ - private void scrollToLatestLog() { - if (!mTable.isDisposed()) { - mTable.setTopIndex(mTable.getItemCount() - 1); - } - } - - /** - * Splits the message into multiple lines if the message length exceeds given width. - * If the message was split, then a wrap character \u23ce is appended to the end of all - * lines but the last one. - */ - private List<String> wrapMessage(String msg, int wrapWidth) { - if (msg.length() < wrapWidth) { - return Collections.singletonList(msg); - } - - List<String> wrappedMessages = new ArrayList<String>(); - - int offset = 0; - int len = msg.length(); - - while (len > 0) { - int copylen = Math.min(wrapWidth, len); - String s = msg.substring(offset, offset + copylen); - - offset += copylen; - len -= copylen; - - if (len > 0) { // if there are more lines following, then append a wrap marker - s += " \u23ce"; //$NON-NLS-1$ - } - - wrappedMessages.add(s); - } - - return wrappedMessages; - } - - private Color getForegroundColor(LogCatMessage m) { - LogLevel l = m.getLogLevel(); - - if (l.equals(LogLevel.VERBOSE)) { - return mVerboseColor; - } else if (l.equals(LogLevel.INFO)) { - return mInfoColor; - } else if (l.equals(LogLevel.DEBUG)) { - return mDebugColor; - } else if (l.equals(LogLevel.ERROR)) { - return mErrorColor; - } else if (l.equals(LogLevel.WARN)) { - return mWarnColor; - } else if (l.equals(LogLevel.ASSERT)) { - return mAssertColor; - } - - return mVerboseColor; - } - - private List<ILogCatMessageSelectionListener> mMessageSelectionListeners; - - private void initDoubleClickListener() { - mMessageSelectionListeners = new ArrayList<ILogCatMessageSelectionListener>(1); - - mTable.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent arg0) { - List<LogCatMessage> selectedMessages = getSelectedLogCatMessages(); - if (selectedMessages.size() == 0) { - return; - } - - for (ILogCatMessageSelectionListener l : mMessageSelectionListeners) { - l.messageDoubleClicked(selectedMessages.get(0)); - } - } - }); - } - - public void addLogCatMessageSelectionListener(ILogCatMessageSelectionListener l) { - mMessageSelectionListeners.add(l); - } - - private ITableFocusListener mTableFocusListener; - - /** - * Specify the listener to be called when the logcat view gets focus. This interface is - * required by DDMS to hook up the menu items for Copy and Select All. - * @param listener listener to be notified when logcat view is in focus - */ - public void setTableFocusListener(ITableFocusListener listener) { - mTableFocusListener = listener; - - final IFocusedTableActivator activator = new IFocusedTableActivator() { - @Override - public void copy(Clipboard clipboard) { - copySelectionToClipboard(clipboard); - } - - @Override - public void selectAll() { - mTable.selectAll(); - } - }; - - mTable.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - mTableFocusListener.focusGained(activator); - } - - @Override - public void focusLost(FocusEvent e) { - mTableFocusListener.focusLost(activator); - } - }); - } - - /** Copy all selected messages to clipboard. */ - public void copySelectionToClipboard(Clipboard clipboard) { - StringBuilder sb = new StringBuilder(); - - for (LogCatMessage m : getSelectedLogCatMessages()) { - sb.append(m.toString()); - sb.append('\n'); - } - - if (sb.length() > 0) { - clipboard.setContents( - new Object[] {sb.toString()}, - new Transfer[] {TextTransfer.getInstance()} - ); - } - } - - /** Select all items in the logcat table. */ - public void selectAll() { - mTable.selectAll(); - } - - private void dispose() { - if (mFont != null && !mFont.isDisposed()) { - mFont.dispose(); - } - - if (mVerboseColor != null && !mVerboseColor.isDisposed()) { - disposeMessageColors(); - } - } - - private void disposeMessageColors() { - mVerboseColor.dispose(); - mDebugColor.dispose(); - mInfoColor.dispose(); - mWarnColor.dispose(); - mErrorColor.dispose(); - mAssertColor.dispose(); - } - - private class LogcatFindTarget extends AbstractBufferFindTarget { - @Override - public void selectAndReveal(int index) { - mTable.deselectAll(); - mTable.select(index); - mTable.showSelection(); - } - - @Override - public int getItemCount() { - return mTable.getItemCount(); - } - - @Override - public String getItem(int index) { - Object data = mTable.getItem(index).getData(); - if (data != null) { - return data.toString(); - } - - return null; - } - - @Override - public int getStartingIndex() { - // start searches from current selection if present, otherwise from the tail end - // of the buffer - int s = mTable.getSelectionIndex(); - if (s != -1) { - return s; - } else { - return getItemCount() - 1; - } - }; - }; - - private FindDialog mFindDialog; - private LogcatFindTarget mFindTarget = new LogcatFindTarget(); - public void showFindDialog() { - if (mFindDialog != null) { - // if the dialog is already displayed - return; - } - - mFindDialog = new FindDialog(Display.getDefault().getActiveShell(), mFindTarget); - mFindDialog.open(); // blocks until find dialog is closed - mFindDialog = null; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java deleted file mode 100644 index a85cd03..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.logcat.LogCatListener; -import com.android.ddmlib.logcat.LogCatMessage; -import com.android.ddmlib.logcat.LogCatReceiverTask; - -import org.eclipse.jface.preference.IPreferenceStore; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * A class to monitor a device for logcat messages. It stores the received - * log messages in a circular buffer. - */ -public final class LogCatReceiver implements LogCatListener { - private static LogCatMessage DEVICE_DISCONNECTED_MESSAGE = - new LogCatMessage(LogLevel.ERROR, "", "", "", - "", "", "Device disconnected"); - - private LogCatMessageList mLogMessages; - private IDevice mCurrentDevice; - private LogCatReceiverTask mLogCatReceiverTask; - private Set<ILogCatBufferChangeListener> mLogCatMessageListeners; - private IPreferenceStore mPrefStore; - - /** - * Construct a LogCat message receiver for provided device. This will launch a - * logcat command on the device, and monitor the output of that command in - * a separate thread. All logcat messages are then stored in a circular - * buffer, which can be retrieved using {@link LogCatReceiver#getMessages()}. - * @param device device to monitor for logcat messages - * @param prefStore - */ - public LogCatReceiver(IDevice device, IPreferenceStore prefStore) { - mCurrentDevice = device; - mPrefStore = prefStore; - - mLogCatMessageListeners = new HashSet<ILogCatBufferChangeListener>(); - mLogMessages = new LogCatMessageList(getFifoSize()); - - startReceiverThread(); - } - - /** - * Stop receiving messages from currently active device. - */ - public void stop() { - if (mLogCatReceiverTask != null) { - /* stop the current logcat command */ - mLogCatReceiverTask.removeLogCatListener(this); - mLogCatReceiverTask.stop(); - mLogCatReceiverTask = null; - - // add a message to the log indicating that the device has been disconnected. - log(Collections.singletonList(DEVICE_DISCONNECTED_MESSAGE)); - } - - mCurrentDevice = null; - } - - private int getFifoSize() { - int n = mPrefStore.getInt(LogCatMessageList.MAX_MESSAGES_PREFKEY); - return n == 0 ? LogCatMessageList.MAX_MESSAGES_DEFAULT : n; - } - - private void startReceiverThread() { - if (mCurrentDevice == null) { - return; - } - - mLogCatReceiverTask = new LogCatReceiverTask(mCurrentDevice); - mLogCatReceiverTask.addLogCatListener(this); - - Thread t = new Thread(mLogCatReceiverTask); - t.setName("LogCat output receiver for " + mCurrentDevice.getSerialNumber()); - t.start(); - } - - @Override - public void log(List<LogCatMessage> newMessages) { - List<LogCatMessage> deletedMessages; - synchronized (mLogMessages) { - deletedMessages = mLogMessages.ensureSpace(newMessages.size()); - mLogMessages.appendMessages(newMessages); - } - sendLogChangedEvent(newMessages, deletedMessages); - } - - /** - * Get the list of logcat messages received from currently active device. - * @return list of messages if currently listening, null otherwise - */ - public LogCatMessageList getMessages() { - return mLogMessages; - } - - /** - * Clear the list of messages received from the currently active device. - */ - public void clearMessages() { - mLogMessages.clear(); - } - - /** - * Add to list of message event listeners. - * @param l listener to notified when messages are received from the device - */ - public void addMessageReceivedEventListener(ILogCatBufferChangeListener l) { - mLogCatMessageListeners.add(l); - } - - public void removeMessageReceivedEventListener(ILogCatBufferChangeListener l) { - mLogCatMessageListeners.remove(l); - } - - private void sendLogChangedEvent(List<LogCatMessage> addedMessages, - List<LogCatMessage> deletedMessages) { - for (ILogCatBufferChangeListener l : mLogCatMessageListeners) { - l.bufferChanged(addedMessages, deletedMessages); - } - } - - /** - * Resize the internal FIFO. - * @param size new size - */ - public void resizeFifo(int size) { - mLogMessages.resize(size); - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiverFactory.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiverFactory.java deleted file mode 100644 index 5b25e17..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiverFactory.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; -import com.android.ddmlib.IDevice; - -import org.eclipse.jface.preference.IPreferenceStore; - -import java.util.HashMap; -import java.util.Map; - -/** - * A factory for {@link LogCatReceiver} objects. Its primary objective is to cache - * constructed {@link LogCatReceiver}'s per device and hand them back when requested. - */ -public class LogCatReceiverFactory { - /** Singleton instance. */ - public static final LogCatReceiverFactory INSTANCE = new LogCatReceiverFactory(); - - private Map<String, LogCatReceiver> mReceiverCache = new HashMap<String, LogCatReceiver>(); - - /** Private constructor: cannot instantiate. */ - private LogCatReceiverFactory() { - AndroidDebugBridge.addDeviceChangeListener(new IDeviceChangeListener() { - @Override - public void deviceDisconnected(final IDevice device) { - // The deviceDisconnected() is called from DDMS code that holds - // multiple locks regarding list of clients, etc. - // It so happens that #newReceiver() below adds a clientChangeListener - // which requires those locks as well. So if we call - // #removeReceiverFor from a DDMS/Monitor thread, we could end up - // in a deadlock. As a result, we spawn a separate thread that - // doesn't hold any of the DDMS locks to remove the receiver. - Thread t = new Thread(new Runnable() { - @Override - public void run() { - removeReceiverFor(device); } - }, "Remove logcat receiver for " + device.getSerialNumber()); - t.start(); - } - - @Override - public void deviceConnected(IDevice device) { - } - - @Override - public void deviceChanged(IDevice device, int changeMask) { - } - }); - } - - /** - * Remove existing logcat receivers. This method should not be called from a DDMS thread - * context that might be holding locks. Doing so could result in a deadlock with the following - * two threads locked up: <ul> - * <li> {@link #removeReceiverFor(IDevice)} waiting to lock {@link LogCatReceiverFactory}, - * while holding a DDMS monitor internal lock. </li> - * <li> {@link #newReceiver(IDevice, IPreferenceStore)} holding {@link LogCatReceiverFactory} - * while attempting to obtain a DDMS monitor lock. </li> - * </ul> - */ - private synchronized void removeReceiverFor(IDevice device) { - LogCatReceiver r = mReceiverCache.get(device.getSerialNumber()); - if (r != null) { - r.stop(); - mReceiverCache.remove(device.getSerialNumber()); - } - } - - public synchronized LogCatReceiver newReceiver(IDevice device, IPreferenceStore prefs) { - LogCatReceiver r = mReceiverCache.get(device.getSerialNumber()); - if (r != null) { - return r; - } - - r = new LogCatReceiver(device, prefs); - mReceiverCache.put(device.getSerialNumber(), r); - return r; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatStackTraceParser.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatStackTraceParser.java deleted file mode 100644 index 3da9fd0..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatStackTraceParser.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2011 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.logcat; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Helper class that can determine if a string matches the exception - * stack trace pattern, and if so, can provide the java source file - * and line where the exception occured. - */ -public final class LogCatStackTraceParser { - /** Regex to match a stack trace line. E.g.: - * at com.foo.Class.method(FileName.extension:10) - * extension is typically java, but can be anything (java/groovy/scala/..). - */ - private static final String EXCEPTION_LINE_REGEX = - "\\s*at\\ (.*)\\((.*)\\..*\\:(\\d+)\\)"; //$NON-NLS-1$ - - private static final Pattern EXCEPTION_LINE_PATTERN = - Pattern.compile(EXCEPTION_LINE_REGEX); - - /** - * Identify if a input line matches the expected pattern - * for a stack trace from an exception. - */ - public boolean isValidExceptionTrace(String line) { - return EXCEPTION_LINE_PATTERN.matcher(line).find(); - } - - /** - * Get fully qualified method name that threw the exception. - * @param line line from the stack trace, must have been validated with - * {@link LogCatStackTraceParser#isValidExceptionTrace(String)} before calling this method. - * @return fully qualified method name - */ - public String getMethodName(String line) { - Matcher m = EXCEPTION_LINE_PATTERN.matcher(line); - m.find(); - return m.group(1); - } - - /** - * Get source file name where exception was generated. Input line must be first validated with - * {@link LogCatStackTraceParser#isValidExceptionTrace(String)}. - */ - public String getFileName(String line) { - Matcher m = EXCEPTION_LINE_PATTERN.matcher(line); - m.find(); - return m.group(2); - } - - /** - * Get line number where exception was generated. Input line must be first validated with - * {@link LogCatStackTraceParser#isValidExceptionTrace(String)}. - */ - public int getLineNumber(String line) { - Matcher m = EXCEPTION_LINE_PATTERN.matcher(line); - m.find(); - try { - return Integer.parseInt(m.group(3)); - } catch (NumberFormatException e) { - return 0; - } - } - -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogColors.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogColors.java deleted file mode 100644 index 9cff656..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogColors.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2007 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.logcat; - -import org.eclipse.swt.graphics.Color; - -public class LogColors { - public Color infoColor; - public Color debugColor; - public Color errorColor; - public Color warningColor; - public Color verboseColor; -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogFilter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogFilter.java deleted file mode 100644 index 74a5e37..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogFilter.java +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (C) 2007 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.logcat; - -import com.android.ddmlib.Log; -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmuilib.annotation.UiThread; -import com.android.ddmuilib.logcat.LogPanel.LogMessage; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.widgets.ScrollBar; -import org.eclipse.swt.widgets.TabItem; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableItem; - -import java.util.ArrayList; -import java.util.regex.PatternSyntaxException; - -/** logcat output filter class */ -public class LogFilter { - - public final static int MODE_PID = 0x01; - public final static int MODE_TAG = 0x02; - public final static int MODE_LEVEL = 0x04; - - private String mName; - - /** - * Filtering mode. Value can be a mix of MODE_PID, MODE_TAG, MODE_LEVEL - */ - private int mMode = 0; - - /** - * pid used for filtering. Only valid if mMode is MODE_PID. - */ - private int mPid; - - /** Single level log level as defined in Log.mLevelChar. Only valid - * if mMode is MODE_LEVEL */ - private int mLogLevel; - - /** - * log tag filtering. Only valid if mMode is MODE_TAG - */ - private String mTag; - - private Table mTable; - private TabItem mTabItem; - private boolean mIsCurrentTabItem = false; - private int mUnreadCount = 0; - - /** Temp keyword filtering */ - private String[] mTempKeywordFilters; - - /** temp pid filtering */ - private int mTempPid = -1; - - /** temp tag filtering */ - private String mTempTag; - - /** temp log level filtering */ - private int mTempLogLevel = -1; - - private LogColors mColors; - - private boolean mTempFilteringStatus = false; - - private final ArrayList<LogMessage> mMessages = new ArrayList<LogMessage>(); - private final ArrayList<LogMessage> mNewMessages = new ArrayList<LogMessage>(); - - private boolean mSupportsDelete = true; - private boolean mSupportsEdit = true; - private int mRemovedMessageCount = 0; - - /** - * Creates a filter with a particular mode. - * @param name The name to be displayed in the UI - */ - public LogFilter(String name) { - mName = name; - } - - public LogFilter() { - - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(mName); - - sb.append(':'); - sb.append(mMode); - if ((mMode & MODE_PID) == MODE_PID) { - sb.append(':'); - sb.append(mPid); - } - - if ((mMode & MODE_LEVEL) == MODE_LEVEL) { - sb.append(':'); - sb.append(mLogLevel); - } - - if ((mMode & MODE_TAG) == MODE_TAG) { - sb.append(':'); - sb.append(mTag); - } - - return sb.toString(); - } - - public boolean loadFromString(String string) { - String[] segments = string.split(":"); //$NON-NLS-1$ - int index = 0; - - // get the name - mName = segments[index++]; - - // get the mode - mMode = Integer.parseInt(segments[index++]); - - if ((mMode & MODE_PID) == MODE_PID) { - mPid = Integer.parseInt(segments[index++]); - } - - if ((mMode & MODE_LEVEL) == MODE_LEVEL) { - mLogLevel = Integer.parseInt(segments[index++]); - } - - if ((mMode & MODE_TAG) == MODE_TAG) { - mTag = segments[index++]; - } - - return true; - } - - - /** Sets the name of the filter. */ - void setName(String name) { - mName = name; - } - - /** - * Returns the UI display name. - */ - public String getName() { - return mName; - } - - /** - * Set the Table ui widget associated with this filter. - * @param tabItem The item in the TabFolder - * @param table The Table object - */ - public void setWidgets(TabItem tabItem, Table table) { - mTable = table; - mTabItem = tabItem; - } - - /** - * Returns true if the filter is ready for ui. - */ - public boolean uiReady() { - return (mTable != null && mTabItem != null); - } - - /** - * Returns the UI table object. - * @return - */ - public Table getTable() { - return mTable; - } - - public void dispose() { - mTable.dispose(); - mTabItem.dispose(); - mTable = null; - mTabItem = null; - } - - /** - * Resets the filtering mode to be 0 (i.e. no filter). - */ - public void resetFilteringMode() { - mMode = 0; - } - - /** - * Returns the current filtering mode. - * @return A bitmask. Possible values are MODE_PID, MODE_TAG, MODE_LEVEL - */ - public int getFilteringMode() { - return mMode; - } - - /** - * Adds PID to the current filtering mode. - * @param pid - */ - public void setPidMode(int pid) { - if (pid != -1) { - mMode |= MODE_PID; - } else { - mMode &= ~MODE_PID; - } - mPid = pid; - } - - /** Returns the pid filter if valid, otherwise -1 */ - public int getPidFilter() { - if ((mMode & MODE_PID) == MODE_PID) - return mPid; - return -1; - } - - public void setTagMode(String tag) { - if (tag != null && tag.length() > 0) { - mMode |= MODE_TAG; - } else { - mMode &= ~MODE_TAG; - } - mTag = tag; - } - - public String getTagFilter() { - if ((mMode & MODE_TAG) == MODE_TAG) - return mTag; - return null; - } - - public void setLogLevel(int level) { - if (level == -1) { - mMode &= ~MODE_LEVEL; - } else { - mMode |= MODE_LEVEL; - mLogLevel = level; - } - - } - - public int getLogLevel() { - if ((mMode & MODE_LEVEL) == MODE_LEVEL) { - return mLogLevel; - } - - return -1; - } - - - public boolean supportsDelete() { - return mSupportsDelete ; - } - - public boolean supportsEdit() { - return mSupportsEdit; - } - - /** - * Sets the selected state of the filter. - * @param selected selection state. - */ - public void setSelectedState(boolean selected) { - if (selected) { - if (mTabItem != null) { - mTabItem.setText(mName); - } - mUnreadCount = 0; - } - mIsCurrentTabItem = selected; - } - - /** - * Adds a new message and optionally removes an old message. - * <p/>The new message is filtered through {@link #accept(LogMessage)}. - * Calls to {@link #flush()} from a UI thread will display it (and other - * pending messages) to the associated {@link Table}. - * @param logMessage the MessageData object to filter - * @return true if the message was accepted. - */ - public boolean addMessage(LogMessage newMessage, LogMessage oldMessage) { - synchronized (mMessages) { - if (oldMessage != null) { - int index = mMessages.indexOf(oldMessage); - if (index != -1) { - // TODO check that index will always be -1 or 0, as only the oldest message is ever removed. - mMessages.remove(index); - mRemovedMessageCount++; - } - - // now we look for it in mNewMessages. This can happen if the new message is added - // and then removed because too many messages are added between calls to #flush() - index = mNewMessages.indexOf(oldMessage); - if (index != -1) { - // TODO check that index will always be -1 or 0, as only the oldest message is ever removed. - mNewMessages.remove(index); - } - } - - boolean filter = accept(newMessage); - - if (filter) { - // at this point the message is accepted, we add it to the list - mMessages.add(newMessage); - mNewMessages.add(newMessage); - } - - return filter; - } - } - - /** - * Removes all the items in the filter and its {@link Table}. - */ - public void clear() { - mRemovedMessageCount = 0; - mNewMessages.clear(); - mMessages.clear(); - mTable.removeAll(); - } - - /** - * Filters a message. - * @param logMessage the Message - * @return true if the message is accepted by the filter. - */ - boolean accept(LogMessage logMessage) { - // do the regular filtering now - if ((mMode & MODE_PID) == MODE_PID && mPid != logMessage.data.pid) { - return false; - } - - if ((mMode & MODE_TAG) == MODE_TAG && ( - logMessage.data.tag == null || - logMessage.data.tag.equals(mTag) == false)) { - return false; - } - - int msgLogLevel = logMessage.data.logLevel.getPriority(); - - // test the temp log filtering first, as it replaces the old one - if (mTempLogLevel != -1) { - if (mTempLogLevel > msgLogLevel) { - return false; - } - } else if ((mMode & MODE_LEVEL) == MODE_LEVEL && - mLogLevel > msgLogLevel) { - return false; - } - - // do the temp filtering now. - if (mTempKeywordFilters != null) { - String msg = logMessage.msg; - - for (String kw : mTempKeywordFilters) { - try { - if (msg.contains(kw) == false && msg.matches(kw) == false) { - return false; - } - } catch (PatternSyntaxException e) { - // if the string is not a valid regular expression, - // this exception is thrown. - return false; - } - } - } - - if (mTempPid != -1 && mTempPid != logMessage.data.pid) { - return false; - } - - if (mTempTag != null && mTempTag.length() > 0) { - if (mTempTag.equals(logMessage.data.tag) == false) { - return false; - } - } - - return true; - } - - /** - * Takes all the accepted messages and display them. - * This must be called from a UI thread. - */ - @UiThread - public void flush() { - // if scroll bar is at the bottom, we will scroll - ScrollBar bar = mTable.getVerticalBar(); - boolean scroll = bar.getMaximum() == bar.getSelection() + bar.getThumb(); - - // if we are not going to scroll, get the current first item being shown. - int topIndex = mTable.getTopIndex(); - - // disable drawing - mTable.setRedraw(false); - - int totalCount = mNewMessages.size(); - - try { - // remove the items of the old messages. - for (int i = 0 ; i < mRemovedMessageCount && mTable.getItemCount() > 0 ; i++) { - mTable.remove(0); - } - mRemovedMessageCount = 0; - - if (mUnreadCount > mTable.getItemCount()) { - mUnreadCount = mTable.getItemCount(); - } - - // add the new items - for (int i = 0 ; i < totalCount ; i++) { - LogMessage msg = mNewMessages.get(i); - addTableItem(msg); - } - } catch (SWTException e) { - // log the error and keep going. Content of the logcat table maybe unexpected - // but at least ddms won't crash. - Log.e("LogFilter", e); - } - - // redraw - mTable.setRedraw(true); - - // scroll if needed, by showing the last item - if (scroll) { - totalCount = mTable.getItemCount(); - if (totalCount > 0) { - mTable.showItem(mTable.getItem(totalCount-1)); - } - } else if (mRemovedMessageCount > 0) { - // we need to make sure the topIndex is still visible. - // Because really old items are removed from the list, this could make it disappear - // if we don't change the scroll value at all. - - topIndex -= mRemovedMessageCount; - if (topIndex < 0) { - // looks like it disappeared. Lets just show the first item - mTable.showItem(mTable.getItem(0)); - } else { - mTable.showItem(mTable.getItem(topIndex)); - } - } - - // if this filter is not the current one, we update the tab text - // with the amount of unread message - if (mIsCurrentTabItem == false) { - mUnreadCount += mNewMessages.size(); - totalCount = mTable.getItemCount(); - if (mUnreadCount > 0) { - mTabItem.setText(mName + " (" //$NON-NLS-1$ - + (mUnreadCount > totalCount ? totalCount : mUnreadCount) - + ")"); //$NON-NLS-1$ - } else { - mTabItem.setText(mName); //$NON-NLS-1$ - } - } - - mNewMessages.clear(); - } - - void setColors(LogColors colors) { - mColors = colors; - } - - int getUnreadCount() { - return mUnreadCount; - } - - void setUnreadCount(int unreadCount) { - mUnreadCount = unreadCount; - } - - void setSupportsDelete(boolean support) { - mSupportsDelete = support; - } - - void setSupportsEdit(boolean support) { - mSupportsEdit = support; - } - - void setTempKeywordFiltering(String[] segments) { - mTempKeywordFilters = segments; - mTempFilteringStatus = true; - } - - void setTempPidFiltering(int pid) { - mTempPid = pid; - mTempFilteringStatus = true; - } - - void setTempTagFiltering(String tag) { - mTempTag = tag; - mTempFilteringStatus = true; - } - - void resetTempFiltering() { - if (mTempPid != -1 || mTempTag != null || mTempKeywordFilters != null) { - mTempFilteringStatus = true; - } - - mTempPid = -1; - mTempTag = null; - mTempKeywordFilters = null; - } - - void resetTempFilteringStatus() { - mTempFilteringStatus = false; - } - - boolean getTempFilterStatus() { - return mTempFilteringStatus; - } - - - /** - * Add a TableItem for the index-th item of the buffer - * @param filter The index of the table in which to insert the item. - */ - private void addTableItem(LogMessage msg) { - TableItem item = new TableItem(mTable, SWT.NONE); - item.setText(0, msg.data.time); - item.setText(1, new String(new char[] { msg.data.logLevel.getPriorityLetter() })); - item.setText(2, msg.data.pidString); - item.setText(3, msg.data.tag); - item.setText(4, msg.msg); - - // add the buffer index as data - item.setData(msg); - - if (msg.data.logLevel == LogLevel.INFO) { - item.setForeground(mColors.infoColor); - } else if (msg.data.logLevel == LogLevel.DEBUG) { - item.setForeground(mColors.debugColor); - } else if (msg.data.logLevel == LogLevel.ERROR) { - item.setForeground(mColors.errorColor); - } else if (msg.data.logLevel == LogLevel.WARN) { - item.setForeground(mColors.warningColor); - } else { - item.setForeground(mColors.verboseColor); - } - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java deleted file mode 100644 index a347155..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * Copyright (C) 2007 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.logcat; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log; -import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.MultiLineReceiver; -import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.ITableFocusListener; -import com.android.ddmuilib.ITableFocusListener.IFocusedTableActivator; -import com.android.ddmuilib.SelectionDependentPanel; -import com.android.ddmuilib.TableHelper; -import com.android.ddmuilib.actions.ICommonAction; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.TabFolder; -import org.eclipse.swt.widgets.TabItem; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; - -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class LogPanel extends SelectionDependentPanel { - - private static final int STRING_BUFFER_LENGTH = 10000; - - /** no filtering. Only one tab with everything. */ - public static final int FILTER_NONE = 0; - /** manual mode for filter. all filters are manually created. */ - public static final int FILTER_MANUAL = 1; - /** automatic mode for filter (pid mode). - * All filters are automatically created. */ - public static final int FILTER_AUTO_PID = 2; - /** automatic mode for filter (tag mode). - * All filters are automatically created. */ - public static final int FILTER_AUTO_TAG = 3; - /** Manual filtering mode + new filter for debug app, if needed */ - public static final int FILTER_DEBUG = 4; - - public static final int COLUMN_MODE_MANUAL = 0; - public static final int COLUMN_MODE_AUTO = 1; - - public static String PREFS_TIME; - public static String PREFS_LEVEL; - public static String PREFS_PID; - public static String PREFS_TAG; - public static String PREFS_MESSAGE; - - /** - * This pattern is meant to parse the first line of a log message with the option - * 'logcat -v long'. The first line represents the date, tag, severity, etc.. while the - * following lines are the message (can be several line).<br> - * This first line looks something like<br> - * <code>"[ 00-00 00:00:00.000 <pid>:0x<???> <severity>/<tag>]"</code> - * <br> - * Note: severity is one of V, D, I, W, or EM<br> - * Note: the fraction of second value can have any number of digit. - * Note the tag should be trim as it may have spaces at the end. - */ - private static Pattern sLogPattern = Pattern.compile( - "^\\[\\s(\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d+)" + //$NON-NLS-1$ - "\\s+(\\d*):(0x[0-9a-fA-F]+)\\s([VDIWE])/(.*)\\]$"); //$NON-NLS-1$ - - /** - * Interface for Storage Filter manager. Implementation of this interface - * provide a custom way to archive an reload filters. - */ - public interface ILogFilterStorageManager { - - public LogFilter[] getFilterFromStore(); - - public void saveFilters(LogFilter[] filters); - - public boolean requiresDefaultFilter(); - } - - private Composite mParent; - private IPreferenceStore mStore; - - /** top object in the view */ - private TabFolder mFolders; - - private LogColors mColors; - - private ILogFilterStorageManager mFilterStorage; - - private LogCatOuputReceiver mCurrentLogCat; - - /** - * Circular buffer containing the logcat output. This is unfiltered. - * The valid content goes from <code>mBufferStart</code> to - * <code>mBufferEnd - 1</code>. Therefore its number of item is - * <code>mBufferEnd - mBufferStart</code>. - */ - private LogMessage[] mBuffer = new LogMessage[STRING_BUFFER_LENGTH]; - - /** Represents the oldest message in the buffer */ - private int mBufferStart = -1; - - /** - * Represents the next usable item in the buffer to receive new message. - * This can be equal to mBufferStart, but when used mBufferStart will be - * incremented as well. - */ - private int mBufferEnd = -1; - - /** Filter list */ - private LogFilter[] mFilters; - - /** Default filter */ - private LogFilter mDefaultFilter; - - /** Current filter being displayed */ - private LogFilter mCurrentFilter; - - /** Filtering mode */ - private int mFilterMode = FILTER_NONE; - - /** Device currently running logcat */ - private IDevice mCurrentLoggedDevice = null; - - private ICommonAction mDeleteFilterAction; - private ICommonAction mEditFilterAction; - - private ICommonAction[] mLogLevelActions; - - /** message data, separated from content for multi line messages */ - protected static class LogMessageInfo { - public LogLevel logLevel; - public int pid; - public String pidString; - public String tag; - public String time; - } - - /** pointer to the latest LogMessageInfo. this is used for multi line - * log message, to reuse the info regarding level, pid, etc... - */ - private LogMessageInfo mLastMessageInfo = null; - - private boolean mPendingAsyncRefresh = false; - - private String mDefaultLogSave; - - private int mColumnMode = COLUMN_MODE_MANUAL; - private Font mDisplayFont; - - private ITableFocusListener mGlobalListener; - - private LogCatViewInterface mLogCatViewInterface = null; - - /** message data, separated from content for multi line messages */ - protected static class LogMessage { - public LogMessageInfo data; - public String msg; - - @Override - public String toString() { - return data.time + ": " //$NON-NLS-1$ - + data.logLevel + "/" //$NON-NLS-1$ - + data.tag + "(" //$NON-NLS-1$ - + data.pidString + "): " //$NON-NLS-1$ - + msg; - } - } - - /** - * objects able to receive the output of a remote shell command, - * specifically a logcat command in this case - */ - private final class LogCatOuputReceiver extends MultiLineReceiver { - - public boolean isCancelled = false; - - public LogCatOuputReceiver() { - super(); - - setTrimLine(false); - } - - @Override - public void processNewLines(String[] lines) { - if (isCancelled == false) { - processLogLines(lines); - } - } - - @Override - public boolean isCancelled() { - return isCancelled; - } - } - - /** - * Parser class for the output of a "ps" shell command executed on a device. - * This class looks for a specific pid to find the process name from it. - * Once found, the name is used to update a filter and a tab object - * - */ - private class PsOutputReceiver extends MultiLineReceiver { - - private LogFilter mFilter; - - private TabItem mTabItem; - - private int mPid; - - /** set to true when we've found the pid we're looking for */ - private boolean mDone = false; - - PsOutputReceiver(int pid, LogFilter filter, TabItem tabItem) { - mPid = pid; - mFilter = filter; - mTabItem = tabItem; - } - - @Override - public boolean isCancelled() { - return mDone; - } - - @Override - public void processNewLines(String[] lines) { - for (String line : lines) { - if (line.startsWith("USER")) { //$NON-NLS-1$ - continue; - } - // get the pid. - int index = line.indexOf(' '); - if (index == -1) { - continue; - } - // look for the next non blank char - index++; - while (line.charAt(index) == ' ') { - index++; - } - - // this is the start of the pid. - // look for the end. - int index2 = line.indexOf(' ', index); - - // get the line - String pidStr = line.substring(index, index2); - int pid = Integer.parseInt(pidStr); - if (pid != mPid) { - continue; - } else { - // get the process name - index = line.lastIndexOf(' '); - final String name = line.substring(index + 1); - - mFilter.setName(name); - - // update the tab - Display d = mFolders.getDisplay(); - d.asyncExec(new Runnable() { - @Override - public void run() { - mTabItem.setText(name); - } - }); - - // we're done with this ps. - mDone = true; - return; - } - } - } - - } - - /** - * Interface implemented by the LogCatView in Eclipse for particular action on double-click. - */ - public interface LogCatViewInterface { - public void onDoubleClick(); - } - - /** - * Create the log view with some default parameters - * @param colors The display color object - * @param filterStorage the storage for user defined filters. - * @param mode The filtering mode - */ - public LogPanel(LogColors colors, - ILogFilterStorageManager filterStorage, int mode) { - mColors = colors; - mFilterMode = mode; - mFilterStorage = filterStorage; - mStore = DdmUiPreferences.getStore(); - } - - public void setActions(ICommonAction deleteAction, ICommonAction editAction, - ICommonAction[] logLevelActions) { - mDeleteFilterAction = deleteAction; - mEditFilterAction = editAction; - mLogLevelActions = logLevelActions; - } - - /** - * Sets the column mode. Must be called before creatUI - * @param mode the column mode. Valid values are COLUMN_MOD_MANUAL and - * COLUMN_MODE_AUTO - */ - public void setColumnMode(int mode) { - mColumnMode = mode; - } - - /** - * Sets the display font. - * @param font The display font. - */ - public void setFont(Font font) { - mDisplayFont = font; - - if (mFilters != null) { - for (LogFilter f : mFilters) { - Table table = f.getTable(); - if (table != null) { - table.setFont(font); - } - } - } - - if (mDefaultFilter != null) { - Table table = mDefaultFilter.getTable(); - if (table != null) { - table.setFont(font); - } - } - } - - /** - * Sent when a new device is selected. The new device can be accessed - * with {@link #getCurrentDevice()}. - */ - @Override - public void deviceSelected() { - startLogCat(getCurrentDevice()); - } - - /** - * Sent when a new client is selected. The new client can be accessed - * with {@link #getCurrentClient()}. - */ - @Override - public void clientSelected() { - // pass - } - - - /** - * Creates a control capable of displaying some information. This is - * called once, when the application is initializing, from the UI thread. - */ - @Override - protected Control createControl(Composite parent) { - mParent = parent; - - Composite top = new Composite(parent, SWT.NONE); - top.setLayoutData(new GridData(GridData.FILL_BOTH)); - top.setLayout(new GridLayout(1, false)); - - // create the tab folder - mFolders = new TabFolder(top, SWT.NONE); - mFolders.setLayoutData(new GridData(GridData.FILL_BOTH)); - mFolders.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mCurrentFilter != null) { - mCurrentFilter.setSelectedState(false); - } - mCurrentFilter = getCurrentFilter(); - mCurrentFilter.setSelectedState(true); - updateColumns(mCurrentFilter.getTable()); - if (mCurrentFilter.getTempFilterStatus()) { - initFilter(mCurrentFilter); - } - selectionChanged(mCurrentFilter); - } - }); - - - Composite bottom = new Composite(top, SWT.NONE); - bottom.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - bottom.setLayout(new GridLayout(3, false)); - - Label label = new Label(bottom, SWT.NONE); - label.setText("Filter:"); - - final Text filterText = new Text(bottom, SWT.SINGLE | SWT.BORDER); - filterText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - filterText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - updateFilteringWith(filterText.getText()); - } - }); - - /* - Button addFilterBtn = new Button(bottom, SWT.NONE); - addFilterBtn.setImage(mImageLoader.loadImage("add.png", //$NON-NLS-1$ - addFilterBtn.getDisplay())); - */ - - // get the filters - createFilters(); - - // for each filter, create a tab. - int index = 0; - - if (mDefaultFilter != null) { - createTab(mDefaultFilter, index++, false); - } - - if (mFilters != null) { - for (LogFilter f : mFilters) { - createTab(f, index++, false); - } - } - - return top; - } - - @Override - protected void postCreation() { - // pass - } - - /** - * Sets the focus to the proper object. - */ - @Override - public void setFocus() { - mFolders.setFocus(); - } - - - /** - * Starts a new logcat and set mCurrentLogCat as the current receiver. - * @param device the device to connect logcat to. - */ - public void startLogCat(final IDevice device) { - if (device == mCurrentLoggedDevice) { - return; - } - - // if we have a logcat already running - if (mCurrentLoggedDevice != null) { - stopLogCat(false); - mCurrentLoggedDevice = null; - } - - resetUI(false); - - if (device != null) { - // create a new output receiver - mCurrentLogCat = new LogCatOuputReceiver(); - - // start the logcat in a different thread - new Thread("Logcat") { //$NON-NLS-1$ - @Override - public void run() { - - while (device.isOnline() == false && - mCurrentLogCat != null && - mCurrentLogCat.isCancelled == false) { - try { - sleep(2000); - } catch (InterruptedException e) { - return; - } - } - - if (mCurrentLogCat == null || mCurrentLogCat.isCancelled) { - // logcat was stopped/cancelled before the device became ready. - return; - } - - try { - mCurrentLoggedDevice = device; - device.executeShellCommand("logcat -v long", mCurrentLogCat, 0 /*timeout*/); //$NON-NLS-1$ - } catch (Exception e) { - Log.e("Logcat", e); - } finally { - // at this point the command is terminated. - mCurrentLogCat = null; - mCurrentLoggedDevice = null; - } - } - }.start(); - } - } - - /** Stop the current logcat */ - public void stopLogCat(boolean inUiThread) { - if (mCurrentLogCat != null) { - mCurrentLogCat.isCancelled = true; - - // when the thread finishes, no one will reference that object - // and it'll be destroyed - mCurrentLogCat = null; - - // reset the content buffer - for (int i = 0 ; i < STRING_BUFFER_LENGTH; i++) { - mBuffer[i] = null; - } - - // because it's a circular buffer, it's hard to know if - // the array is empty with both start/end at 0 or if it's full - // with both start/end at 0 as well. So to mean empty, we use -1 - mBufferStart = -1; - mBufferEnd = -1; - - resetFilters(); - resetUI(inUiThread); - } - } - - /** - * Adds a new Filter. This methods displays the UI to create the filter - * and set up its parameters.<br> - * <b>MUST</b> be called from the ui thread. - * - */ - public void addFilter() { - EditFilterDialog dlg = new EditFilterDialog(mFolders.getShell()); - if (dlg.open()) { - synchronized (mBuffer) { - // get the new filter in the array - LogFilter filter = dlg.getFilter(); - addFilterToArray(filter); - - int index = mFilters.length - 1; - if (mDefaultFilter != null) { - index++; - } - - if (false) { - - for (LogFilter f : mFilters) { - if (f.uiReady()) { - f.dispose(); - } - } - if (mDefaultFilter != null && mDefaultFilter.uiReady()) { - mDefaultFilter.dispose(); - } - - // for each filter, create a tab. - int i = 0; - if (mFilters != null) { - for (LogFilter f : mFilters) { - createTab(f, i++, true); - } - } - if (mDefaultFilter != null) { - createTab(mDefaultFilter, i++, true); - } - } else { - - // create ui for the filter. - createTab(filter, index, true); - - // reset the default as it shouldn't contain the content of - // this new filter. - if (mDefaultFilter != null) { - initDefaultFilter(); - } - } - - // select the new filter - if (mCurrentFilter != null) { - mCurrentFilter.setSelectedState(false); - } - mFolders.setSelection(index); - filter.setSelectedState(true); - mCurrentFilter = filter; - - selectionChanged(filter); - - // finally we update the filtering mode if needed - if (mFilterMode == FILTER_NONE) { - mFilterMode = FILTER_MANUAL; - } - - mFilterStorage.saveFilters(mFilters); - - } - } - } - - /** - * Edits the current filter. The method displays the UI to edit the filter. - */ - public void editFilter() { - if (mCurrentFilter != null && mCurrentFilter != mDefaultFilter) { - EditFilterDialog dlg = new EditFilterDialog( - mFolders.getShell(), mCurrentFilter); - if (dlg.open()) { - synchronized (mBuffer) { - // at this point the filter has been updated. - // so we update its content - initFilter(mCurrentFilter); - - // and the content of the "other" filter as well. - if (mDefaultFilter != null) { - initDefaultFilter(); - } - - mFilterStorage.saveFilters(mFilters); - } - } - } - } - - /** - * Deletes the current filter. - */ - public void deleteFilter() { - synchronized (mBuffer) { - if (mCurrentFilter != null && mCurrentFilter != mDefaultFilter) { - // remove the filter from the list - removeFilterFromArray(mCurrentFilter); - mCurrentFilter.dispose(); - - // select the new filter - mFolders.setSelection(0); - if (mFilters.length > 0) { - mCurrentFilter = mFilters[0]; - } else { - mCurrentFilter = mDefaultFilter; - } - - selectionChanged(mCurrentFilter); - - // update the content of the "other" filter to include what was filtered out - // by the deleted filter. - if (mDefaultFilter != null) { - initDefaultFilter(); - } - - mFilterStorage.saveFilters(mFilters); - } - } - } - - /** - * saves the current selection in a text file. - * @return false if the saving failed. - */ - public boolean save() { - synchronized (mBuffer) { - FileDialog dlg = new FileDialog(mParent.getShell(), SWT.SAVE); - String fileName; - - dlg.setText("Save log..."); - dlg.setFileName("log.txt"); - String defaultPath = mDefaultLogSave; - if (defaultPath == null) { - defaultPath = System.getProperty("user.home"); //$NON-NLS-1$ - } - dlg.setFilterPath(defaultPath); - dlg.setFilterNames(new String[] { - "Text Files (*.txt)" - }); - dlg.setFilterExtensions(new String[] { - "*.txt" - }); - - fileName = dlg.open(); - if (fileName != null) { - mDefaultLogSave = dlg.getFilterPath(); - - // get the current table and its selection - Table currentTable = mCurrentFilter.getTable(); - - int[] selection = currentTable.getSelectionIndices(); - - // we need to sort the items to be sure. - Arrays.sort(selection); - - // loop on the selection and output the file. - FileWriter writer = null; - try { - writer = new FileWriter(fileName); - - for (int i : selection) { - TableItem item = currentTable.getItem(i); - LogMessage msg = (LogMessage)item.getData(); - String line = msg.toString(); - writer.write(line); - writer.write('\n'); - } - writer.flush(); - - } catch (IOException e) { - return false; - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - // ignore - } - } - } - } - } - - return true; - } - - /** - * Empty the current circular buffer. - */ - public void clear() { - synchronized (mBuffer) { - for (int i = 0 ; i < STRING_BUFFER_LENGTH; i++) { - mBuffer[i] = null; - } - - mBufferStart = -1; - mBufferEnd = -1; - - // now we clear the existing filters - for (LogFilter filter : mFilters) { - filter.clear(); - } - - // and the default one - if (mDefaultFilter != null) { - mDefaultFilter.clear(); - } - } - } - - /** - * Copies the current selection of the current filter as multiline text. - * - * @param clipboard The clipboard to place the copied content. - */ - public void copy(Clipboard clipboard) { - // get the current table and its selection - Table currentTable = mCurrentFilter.getTable(); - - copyTable(clipboard, currentTable); - } - - /** - * Selects all lines. - */ - public void selectAll() { - Table currentTable = mCurrentFilter.getTable(); - currentTable.selectAll(); - } - - /** - * Sets a TableFocusListener which will be notified when one of the tables - * gets or loses focus. - * - * @param listener - */ - public void setTableFocusListener(ITableFocusListener listener) { - // record the global listener, to make sure table created after - // this call will still be setup. - mGlobalListener = listener; - - // now we setup the existing filters - for (LogFilter filter : mFilters) { - Table table = filter.getTable(); - - addTableToFocusListener(table); - } - - // and the default one - if (mDefaultFilter != null) { - addTableToFocusListener(mDefaultFilter.getTable()); - } - } - - /** - * Sets up a Table object to notify the global Table Focus listener when it - * gets or loses the focus. - * - * @param table the Table object. - */ - private void addTableToFocusListener(final Table table) { - // create the activator for this table - final IFocusedTableActivator activator = new IFocusedTableActivator() { - @Override - public void copy(Clipboard clipboard) { - copyTable(clipboard, table); - } - - @Override - public void selectAll() { - table.selectAll(); - } - }; - - // add the focus listener on the table to notify the global listener - table.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - mGlobalListener.focusGained(activator); - } - - @Override - public void focusLost(FocusEvent e) { - mGlobalListener.focusLost(activator); - } - }); - } - - /** - * Copies the current selection of a Table into the provided Clipboard, as - * multi-line text. - * - * @param clipboard The clipboard to place the copied content. - * @param table The table to copy from. - */ - private static void copyTable(Clipboard clipboard, Table table) { - int[] selection = table.getSelectionIndices(); - - // we need to sort the items to be sure. - Arrays.sort(selection); - - // all lines must be concatenated. - StringBuilder sb = new StringBuilder(); - - // loop on the selection and output the file. - for (int i : selection) { - TableItem item = table.getItem(i); - LogMessage msg = (LogMessage)item.getData(); - String line = msg.toString(); - sb.append(line); - sb.append('\n'); - } - - // now add that to the clipboard - clipboard.setContents(new Object[] { - sb.toString() - }, new Transfer[] { - TextTransfer.getInstance() - }); - } - - /** - * Sets the log level for the current filter, but does not save it. - * @param i - */ - public void setCurrentFilterLogLevel(int i) { - LogFilter filter = getCurrentFilter(); - - filter.setLogLevel(i); - - initFilter(filter); - } - - /** - * Creates a new tab in the folderTab item. Must be called from the ui - * thread. - * @param filter The filter associated with the tab. - * @param index the index of the tab. if -1, the tab will be added at the - * end. - * @param fillTable If true the table is filled with the current content of - * the buffer. - * @return The TabItem object that was created. - */ - private TabItem createTab(LogFilter filter, int index, boolean fillTable) { - synchronized (mBuffer) { - TabItem item = null; - if (index != -1) { - item = new TabItem(mFolders, SWT.NONE, index); - } else { - item = new TabItem(mFolders, SWT.NONE); - } - item.setText(filter.getName()); - - // set the control (the parent is the TabFolder item, always) - Composite top = new Composite(mFolders, SWT.NONE); - item.setControl(top); - - top.setLayout(new FillLayout()); - - // create the ui, first the table - final Table t = new Table(top, SWT.MULTI | SWT.FULL_SELECTION); - t.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - if (mLogCatViewInterface != null) { - mLogCatViewInterface.onDoubleClick(); - } - } - }); - - if (mDisplayFont != null) { - t.setFont(mDisplayFont); - } - - // give the ui objects to the filters. - filter.setWidgets(item, t); - - t.setHeaderVisible(true); - t.setLinesVisible(false); - - if (mGlobalListener != null) { - addTableToFocusListener(t); - } - - // create a controllistener that will handle the resizing of all the - // columns (except the last) and of the table itself. - ControlListener listener = null; - if (mColumnMode == COLUMN_MODE_AUTO) { - listener = new ControlListener() { - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - Rectangle r = t.getClientArea(); - - // get the size of all but the last column - int total = t.getColumn(0).getWidth(); - total += t.getColumn(1).getWidth(); - total += t.getColumn(2).getWidth(); - total += t.getColumn(3).getWidth(); - - if (r.width > total) { - t.getColumn(4).setWidth(r.width-total); - } - } - }; - - t.addControlListener(listener); - } - - // then its column - TableColumn col = TableHelper.createTableColumn(t, "Time", SWT.LEFT, - "00-00 00:00:00", //$NON-NLS-1$ - PREFS_TIME, mStore); - if (mColumnMode == COLUMN_MODE_AUTO) { - col.addControlListener(listener); - } - - col = TableHelper.createTableColumn(t, "", SWT.CENTER, - "D", //$NON-NLS-1$ - PREFS_LEVEL, mStore); - if (mColumnMode == COLUMN_MODE_AUTO) { - col.addControlListener(listener); - } - - col = TableHelper.createTableColumn(t, "pid", SWT.LEFT, - "9999", //$NON-NLS-1$ - PREFS_PID, mStore); - if (mColumnMode == COLUMN_MODE_AUTO) { - col.addControlListener(listener); - } - - col = TableHelper.createTableColumn(t, "tag", SWT.LEFT, - "abcdefgh", //$NON-NLS-1$ - PREFS_TAG, mStore); - if (mColumnMode == COLUMN_MODE_AUTO) { - col.addControlListener(listener); - } - - col = TableHelper.createTableColumn(t, "Message", SWT.LEFT, - "abcdefghijklmnopqrstuvwxyz0123456789", //$NON-NLS-1$ - PREFS_MESSAGE, mStore); - if (mColumnMode == COLUMN_MODE_AUTO) { - // instead of listening on resize for the last column, we make - // it non resizable. - col.setResizable(false); - } - - if (fillTable) { - initFilter(filter); - } - return item; - } - } - - protected void updateColumns(Table table) { - if (table != null) { - int index = 0; - TableColumn col; - - col = table.getColumn(index++); - col.setWidth(mStore.getInt(PREFS_TIME)); - - col = table.getColumn(index++); - col.setWidth(mStore.getInt(PREFS_LEVEL)); - - col = table.getColumn(index++); - col.setWidth(mStore.getInt(PREFS_PID)); - - col = table.getColumn(index++); - col.setWidth(mStore.getInt(PREFS_TAG)); - - col = table.getColumn(index++); - col.setWidth(mStore.getInt(PREFS_MESSAGE)); - } - } - - public void resetUI(boolean inUiThread) { - if (mFilterMode == FILTER_AUTO_PID || mFilterMode == FILTER_AUTO_TAG) { - if (inUiThread) { - mFolders.dispose(); - mParent.pack(true); - createControl(mParent); - } else { - Display d = mFolders.getDisplay(); - - // run sync as we need to update right now. - d.syncExec(new Runnable() { - @Override - public void run() { - mFolders.dispose(); - mParent.pack(true); - createControl(mParent); - } - }); - } - } else { - // the ui is static we just empty it. - if (mFolders.isDisposed() == false) { - if (inUiThread) { - emptyTables(); - } else { - Display d = mFolders.getDisplay(); - - // run sync as we need to update right now. - d.syncExec(new Runnable() { - @Override - public void run() { - if (mFolders.isDisposed() == false) { - emptyTables(); - } - } - }); - } - } - } - } - - /** - * Process new Log lines coming from {@link LogCatOuputReceiver}. - * @param lines the new lines - */ - protected void processLogLines(String[] lines) { - // WARNING: this will not work if the string contains more line than - // the buffer holds. - - if (lines.length > STRING_BUFFER_LENGTH) { - Log.e("LogCat", "Receiving more lines than STRING_BUFFER_LENGTH"); - } - - // parse the lines and create LogMessage that are stored in a temporary list - final ArrayList<LogMessage> newMessages = new ArrayList<LogMessage>(); - - synchronized (mBuffer) { - for (String line : lines) { - // ignore empty lines. - if (line.length() > 0) { - // check for header lines. - Matcher matcher = sLogPattern.matcher(line); - if (matcher.matches()) { - // this is a header line, parse the header and keep it around. - mLastMessageInfo = new LogMessageInfo(); - - mLastMessageInfo.time = matcher.group(1); - mLastMessageInfo.pidString = matcher.group(2); - mLastMessageInfo.pid = Integer.valueOf(mLastMessageInfo.pidString); - mLastMessageInfo.logLevel = LogLevel.getByLetterString(matcher.group(4)); - mLastMessageInfo.tag = matcher.group(5).trim(); - } else { - // This is not a header line. - // Create a new LogMessage and process it. - LogMessage mc = new LogMessage(); - - if (mLastMessageInfo == null) { - // The first line of output wasn't preceded - // by a header line; make something up so - // that users of mc.data don't NPE. - mLastMessageInfo = new LogMessageInfo(); - mLastMessageInfo.time = "??-?? ??:??:??.???"; //$NON-NLS1$ - mLastMessageInfo.pidString = "<unknown>"; //$NON-NLS1$ - mLastMessageInfo.pid = 0; - mLastMessageInfo.logLevel = LogLevel.INFO; - mLastMessageInfo.tag = "<unknown>"; //$NON-NLS1$ - } - - // If someone printed a log message with - // embedded '\n' characters, there will - // one header line followed by multiple text lines. - // Use the last header that we saw. - mc.data = mLastMessageInfo; - - // tabs seem to display as only 1 tab so we replace the leading tabs - // by 4 spaces. - mc.msg = line.replaceAll("\t", " "); //$NON-NLS-1$ //$NON-NLS-2$ - - // process the new LogMessage. - processNewMessage(mc); - - // store the new LogMessage - newMessages.add(mc); - } - } - } - - // if we don't have a pending Runnable that will do the refresh, we ask the Display - // to run one in the UI thread. - if (mPendingAsyncRefresh == false) { - mPendingAsyncRefresh = true; - - try { - Display display = mFolders.getDisplay(); - - // run in sync because this will update the buffer start/end indices - display.asyncExec(new Runnable() { - @Override - public void run() { - asyncRefresh(); - } - }); - } catch (SWTException e) { - // display is disposed, we're probably quitting. Let's stop. - stopLogCat(false); - } - } - } - } - - /** - * Refreshes the UI with new messages. - */ - private void asyncRefresh() { - if (mFolders.isDisposed() == false) { - synchronized (mBuffer) { - try { - // the circular buffer has been updated, let have the filter flush their - // display with the new messages. - if (mFilters != null) { - for (LogFilter f : mFilters) { - f.flush(); - } - } - - if (mDefaultFilter != null) { - mDefaultFilter.flush(); - } - } finally { - // the pending refresh is done. - mPendingAsyncRefresh = false; - } - } - } else { - stopLogCat(true); - } - } - - /** - * Processes a new Message. - * <p/>This adds the new message to the buffer, and gives it to the existing filters. - * @param newMessage - */ - private void processNewMessage(LogMessage newMessage) { - // if we are in auto filtering mode, make sure we have - // a filter for this - if (mFilterMode == FILTER_AUTO_PID || - mFilterMode == FILTER_AUTO_TAG) { - checkFilter(newMessage.data); - } - - // compute the index where the message goes. - // was the buffer empty? - int messageIndex = -1; - if (mBufferStart == -1) { - messageIndex = mBufferStart = 0; - mBufferEnd = 1; - } else { - messageIndex = mBufferEnd; - - // increment the next usable slot index - mBufferEnd = (mBufferEnd + 1) % STRING_BUFFER_LENGTH; - - // check we aren't overwriting start - if (mBufferEnd == mBufferStart) { - mBufferStart = (mBufferStart + 1) % STRING_BUFFER_LENGTH; - } - } - - LogMessage oldMessage = null; - - // record the message that was there before - if (mBuffer[messageIndex] != null) { - oldMessage = mBuffer[messageIndex]; - } - - // then add the new one - mBuffer[messageIndex] = newMessage; - - // give the new message to every filters. - boolean filtered = false; - if (mFilters != null) { - for (LogFilter f : mFilters) { - filtered |= f.addMessage(newMessage, oldMessage); - } - } - if (filtered == false && mDefaultFilter != null) { - mDefaultFilter.addMessage(newMessage, oldMessage); - } - } - - private void createFilters() { - if (mFilterMode == FILTER_DEBUG || mFilterMode == FILTER_MANUAL) { - // unarchive the filters. - mFilters = mFilterStorage.getFilterFromStore(); - - // set the colors - if (mFilters != null) { - for (LogFilter f : mFilters) { - f.setColors(mColors); - } - } - - if (mFilterStorage.requiresDefaultFilter()) { - mDefaultFilter = new LogFilter("Log"); - mDefaultFilter.setColors(mColors); - mDefaultFilter.setSupportsDelete(false); - mDefaultFilter.setSupportsEdit(false); - } - } else if (mFilterMode == FILTER_NONE) { - // if the filtering mode is "none", we create a single filter that - // will receive all - mDefaultFilter = new LogFilter("Log"); - mDefaultFilter.setColors(mColors); - mDefaultFilter.setSupportsDelete(false); - mDefaultFilter.setSupportsEdit(false); - } - } - - /** Checks if there's an automatic filter for this md and if not - * adds the filter and the ui. - * This must be called from the UI! - * @param md - * @return true if the filter existed already - */ - private boolean checkFilter(final LogMessageInfo md) { - if (true) - return true; - // look for a filter that matches the pid - if (mFilterMode == FILTER_AUTO_PID) { - for (LogFilter f : mFilters) { - if (f.getPidFilter() == md.pid) { - return true; - } - } - } else if (mFilterMode == FILTER_AUTO_TAG) { - for (LogFilter f : mFilters) { - if (f.getTagFilter().equals(md.tag)) { - return true; - } - } - } - - // if we reach this point, no filter was found. - // create a filter with a temporary name of the pid - final LogFilter newFilter = new LogFilter(md.pidString); - String name = null; - if (mFilterMode == FILTER_AUTO_PID) { - newFilter.setPidMode(md.pid); - - // ask the monitor thread if it knows the pid. - name = mCurrentLoggedDevice.getClientName(md.pid); - } else { - newFilter.setTagMode(md.tag); - name = md.tag; - } - addFilterToArray(newFilter); - - final String fname = name; - - // create the tabitem - final TabItem newTabItem = createTab(newFilter, -1, true); - - // if the name is unknown - if (fname == null) { - // we need to find the process running under that pid. - // launch a thread do a ps on the device - new Thread("remote PS") { //$NON-NLS-1$ - @Override - public void run() { - // create the receiver - PsOutputReceiver psor = new PsOutputReceiver(md.pid, - newFilter, newTabItem); - - // execute ps - try { - mCurrentLoggedDevice.executeShellCommand("ps", psor); //$NON-NLS-1$ - } catch (IOException e) { - // Ignore - } catch (TimeoutException e) { - // Ignore - } catch (AdbCommandRejectedException e) { - // Ignore - } catch (ShellCommandUnresponsiveException e) { - // Ignore - } - } - }.start(); - } - - return false; - } - - /** - * Adds a new filter to the current filter array, and set its colors - * @param newFilter The filter to add - */ - private void addFilterToArray(LogFilter newFilter) { - // set the colors - newFilter.setColors(mColors); - - // add it to the array. - if (mFilters != null && mFilters.length > 0) { - LogFilter[] newFilters = new LogFilter[mFilters.length+1]; - System.arraycopy(mFilters, 0, newFilters, 0, mFilters.length); - newFilters[mFilters.length] = newFilter; - mFilters = newFilters; - } else { - mFilters = new LogFilter[1]; - mFilters[0] = newFilter; - } - } - - private void removeFilterFromArray(LogFilter oldFilter) { - // look for the index - int index = -1; - for (int i = 0 ; i < mFilters.length ; i++) { - if (mFilters[i] == oldFilter) { - index = i; - break; - } - } - - if (index != -1) { - LogFilter[] newFilters = new LogFilter[mFilters.length-1]; - System.arraycopy(mFilters, 0, newFilters, 0, index); - System.arraycopy(mFilters, index + 1, newFilters, index, - newFilters.length-index); - mFilters = newFilters; - } - } - - /** - * Initialize the filter with already existing buffer. - * @param filter - */ - private void initFilter(LogFilter filter) { - // is it empty - if (filter.uiReady() == false) { - return; - } - - if (filter == mDefaultFilter) { - initDefaultFilter(); - return; - } - - filter.clear(); - - if (mBufferStart != -1) { - int max = mBufferEnd; - if (mBufferEnd < mBufferStart) { - max += STRING_BUFFER_LENGTH; - } - - for (int i = mBufferStart; i < max; i++) { - int realItemIndex = i % STRING_BUFFER_LENGTH; - - filter.addMessage(mBuffer[realItemIndex], null /* old message */); - } - } - - filter.flush(); - filter.resetTempFilteringStatus(); - } - - /** - * Refill the default filter. Not to be called directly. - * @see initFilter() - */ - private void initDefaultFilter() { - mDefaultFilter.clear(); - - if (mBufferStart != -1) { - int max = mBufferEnd; - if (mBufferEnd < mBufferStart) { - max += STRING_BUFFER_LENGTH; - } - - for (int i = mBufferStart; i < max; i++) { - int realItemIndex = i % STRING_BUFFER_LENGTH; - LogMessage msg = mBuffer[realItemIndex]; - - // first we check that the other filters don't take this message - boolean filtered = false; - for (LogFilter f : mFilters) { - filtered |= f.accept(msg); - } - - if (filtered == false) { - mDefaultFilter.addMessage(msg, null /* old message */); - } - } - } - - mDefaultFilter.flush(); - mDefaultFilter.resetTempFilteringStatus(); - } - - /** - * Reset the filters, to handle change in device in automatic filter mode - */ - private void resetFilters() { - // if we are in automatic mode, then we need to rmove the current - // filter. - if (mFilterMode == FILTER_AUTO_PID || mFilterMode == FILTER_AUTO_TAG) { - mFilters = null; - - // recreate the filters. - createFilters(); - } - } - - - private LogFilter getCurrentFilter() { - int index = mFolders.getSelectionIndex(); - - // if mFilters is null or index is invalid, we return the default - // filter. It doesn't matter if that one is null as well, since we - // would return null anyway. - if (index == 0 || mFilters == null) { - return mDefaultFilter; - } - - return mFilters[index-1]; - } - - - private void emptyTables() { - for (LogFilter f : mFilters) { - f.getTable().removeAll(); - } - - if (mDefaultFilter != null) { - mDefaultFilter.getTable().removeAll(); - } - } - - protected void updateFilteringWith(String text) { - synchronized (mBuffer) { - // reset the temp filtering for all the filters - for (LogFilter f : mFilters) { - f.resetTempFiltering(); - } - if (mDefaultFilter != null) { - mDefaultFilter.resetTempFiltering(); - } - - // now we need to figure out the new temp filtering - // split each word - String[] segments = text.split(" "); //$NON-NLS-1$ - - ArrayList<String> keywords = new ArrayList<String>(segments.length); - - // loop and look for temp id/tag - int tempPid = -1; - String tempTag = null; - for (int i = 0 ; i < segments.length; i++) { - String s = segments[i]; - if (tempPid == -1 && s.startsWith("pid:")) { //$NON-NLS-1$ - // get the pid - String[] seg = s.split(":"); //$NON-NLS-1$ - if (seg.length == 2) { - if (seg[1].matches("^[0-9]*$")) { //$NON-NLS-1$ - tempPid = Integer.valueOf(seg[1]); - } - } - } else if (tempTag == null && s.startsWith("tag:")) { //$NON-NLS-1$ - String seg[] = segments[i].split(":"); //$NON-NLS-1$ - if (seg.length == 2) { - tempTag = seg[1]; - } - } else { - keywords.add(s); - } - } - - // set the temp filtering in the filters - if (tempPid != -1 || tempTag != null || keywords.size() > 0) { - String[] keywordsArray = keywords.toArray( - new String[keywords.size()]); - - for (LogFilter f : mFilters) { - if (tempPid != -1) { - f.setTempPidFiltering(tempPid); - } - if (tempTag != null) { - f.setTempTagFiltering(tempTag); - } - f.setTempKeywordFiltering(keywordsArray); - } - - if (mDefaultFilter != null) { - if (tempPid != -1) { - mDefaultFilter.setTempPidFiltering(tempPid); - } - if (tempTag != null) { - mDefaultFilter.setTempTagFiltering(tempTag); - } - mDefaultFilter.setTempKeywordFiltering(keywordsArray); - - } - } - - initFilter(mCurrentFilter); - } - } - - /** - * Called when the current filter selection changes. - * @param selectedFilter - */ - private void selectionChanged(LogFilter selectedFilter) { - if (mLogLevelActions != null) { - // get the log level - int level = selectedFilter.getLogLevel(); - for (int i = 0 ; i < mLogLevelActions.length; i++) { - ICommonAction a = mLogLevelActions[i]; - if (i == level - 2) { - a.setChecked(true); - } else { - a.setChecked(false); - } - } - } - - if (mDeleteFilterAction != null) { - mDeleteFilterAction.setEnabled(selectedFilter.supportsDelete()); - } - if (mEditFilterAction != null) { - mEditFilterAction.setEnabled(selectedFilter.supportsEdit()); - } - } - - public String getSelectedErrorLineMessage() { - Table table = mCurrentFilter.getTable(); - int[] selection = table.getSelectionIndices(); - - if (selection.length == 1) { - TableItem item = table.getItem(selection[0]); - LogMessage msg = (LogMessage)item.getData(); - if (msg.data.logLevel == LogLevel.ERROR || msg.data.logLevel == LogLevel.WARN) - return msg.msg; - } - return null; - } - - public void setLogCatViewInterface(LogCatViewInterface i) { - mLogCatViewInterface = i; - } -} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java deleted file mode 100644 index 15b8b56..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * Copyright (C) 2012 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.net; - -import com.android.ddmlib.AdbCommandRejectedException; -import com.android.ddmlib.Client; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.MultiLineReceiver; -import com.android.ddmlib.ShellCommandUnresponsiveException; -import com.android.ddmlib.TimeoutException; -import com.android.ddmuilib.DdmUiPreferences; -import com.android.ddmuilib.TableHelper; -import com.android.ddmuilib.TablePanel; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FormAttachment; -import org.eclipse.swt.layout.FormData; -import org.eclipse.swt.layout.FormLayout; -import org.eclipse.swt.layout.RowLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.AxisLocation; -import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.axis.ValueAxis; -import org.jfree.chart.plot.DatasetRenderingOrder; -import org.jfree.chart.plot.ValueMarker; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.StackedXYAreaRenderer2; -import org.jfree.chart.renderer.xy.XYAreaRenderer; -import org.jfree.data.DefaultKeyedValues2D; -import org.jfree.data.time.Millisecond; -import org.jfree.data.time.TimePeriod; -import org.jfree.data.time.TimeSeries; -import org.jfree.data.time.TimeSeriesCollection; -import org.jfree.data.xy.AbstractIntervalXYDataset; -import org.jfree.data.xy.TableXYDataset; -import org.jfree.experimental.chart.swt.ChartComposite; -import org.jfree.ui.RectangleAnchor; -import org.jfree.ui.TextAnchor; - -import java.io.IOException; -import java.text.DecimalFormat; -import java.text.FieldPosition; -import java.text.NumberFormat; -import java.text.ParsePosition; -import java.util.ArrayList; -import java.util.Date; -import java.util.Formatter; -import java.util.Iterator; - -/** - * Displays live network statistics for currently selected {@link Client}. - */ -public class NetworkPanel extends TablePanel { - - // TODO: enable view of packets and bytes/packet - // TODO: add sash to resize chart and table - // TODO: let user edit tags to be meaningful - - /** Amount of historical data to display. */ - private static final long HISTORY_MILLIS = 30 * 1000; - - private final static String PREFS_NETWORK_COL_TITLE = "networkPanel.title"; - private final static String PREFS_NETWORK_COL_RX_BYTES = "networkPanel.rxBytes"; - private final static String PREFS_NETWORK_COL_RX_PACKETS = "networkPanel.rxPackets"; - private final static String PREFS_NETWORK_COL_TX_BYTES = "networkPanel.txBytes"; - private final static String PREFS_NETWORK_COL_TX_PACKETS = "networkPanel.txPackets"; - - /** Path to network statistics on remote device. */ - private static final String PROC_XT_QTAGUID = "/proc/net/xt_qtaguid/stats"; - - private static final java.awt.Color TOTAL_COLOR = java.awt.Color.GRAY; - - /** Colors used for tag series data. */ - private static final java.awt.Color[] SERIES_COLORS = new java.awt.Color[] { - java.awt.Color.decode("0x2bc4c1"), // teal - java.awt.Color.decode("0xD50F25"), // red - java.awt.Color.decode("0x3369E8"), // blue - java.awt.Color.decode("0xEEB211"), // orange - java.awt.Color.decode("0x00bd2e"), // green - java.awt.Color.decode("0xae26ae"), // purple - }; - - private Display mDisplay; - - private Composite mPanel; - - /** Header panel with configuration options. */ - private Composite mHeader; - - private Label mSpeedLabel; - private Combo mSpeedCombo; - - /** Current sleep between each sample, from {@link #mSpeedCombo}. */ - private long mSpeedMillis; - - private Button mRunningButton; - private Button mResetButton; - - /** Chart of recent network activity. */ - private JFreeChart mChart; - private ChartComposite mChartComposite; - - private ValueAxis mDomainAxis; - - /** Data for total traffic (tag 0x0). */ - private TimeSeriesCollection mTotalCollection; - private TimeSeries mRxTotalSeries; - private TimeSeries mTxTotalSeries; - - /** Data for detailed tagged traffic. */ - private LiveTimeTableXYDataset mRxDetailDataset; - private LiveTimeTableXYDataset mTxDetailDataset; - - private XYAreaRenderer mTotalRenderer; - private StackedXYAreaRenderer2 mRenderer; - - /** Table showing summary of network activity. */ - private Table mTable; - private TableViewer mTableViewer; - - /** UID of currently selected {@link Client}. */ - private int mActiveUid = -1; - - /** List of traffic flows being actively tracked. */ - private ArrayList<TrackedItem> mTrackedItems = new ArrayList<TrackedItem>(); - - private SampleThread mSampleThread; - - private class SampleThread extends Thread { - private volatile boolean mFinish; - - public void finish() { - mFinish = true; - interrupt(); - } - - @Override - public void run() { - while (!mFinish && !mDisplay.isDisposed()) { - performSample(); - - try { - Thread.sleep(mSpeedMillis); - } catch (InterruptedException e) { - // ignored - } - } - } - } - - /** Last snapshot taken by {@link #performSample()}. */ - private NetworkSnapshot mLastSnapshot; - - @Override - protected Control createControl(Composite parent) { - mDisplay = parent.getDisplay(); - - mPanel = new Composite(parent, SWT.NONE); - - final FormLayout formLayout = new FormLayout(); - mPanel.setLayout(formLayout); - - createHeader(); - createChart(); - createTable(); - - return mPanel; - } - - /** - * Create header panel with configuration options. - */ - private void createHeader() { - - mHeader = new Composite(mPanel, SWT.NONE); - final RowLayout layout = new RowLayout(); - layout.center = true; - mHeader.setLayout(layout); - - mSpeedLabel = new Label(mHeader, SWT.NONE); - mSpeedLabel.setText("Speed:"); - mSpeedCombo = new Combo(mHeader, SWT.PUSH); - mSpeedCombo.add("Fast (100ms)"); - mSpeedCombo.add("Medium (250ms)"); - mSpeedCombo.add("Slow (500ms)"); - mSpeedCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateSpeed(); - } - }); - - mSpeedCombo.select(1); - updateSpeed(); - - mRunningButton = new Button(mHeader, SWT.PUSH); - mRunningButton.setText("Start"); - mRunningButton.setEnabled(false); - mRunningButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - final boolean alreadyRunning = mSampleThread != null; - updateRunning(!alreadyRunning); - } - }); - - mResetButton = new Button(mHeader, SWT.PUSH); - mResetButton.setText("Reset"); - mResetButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - clearTrackedItems(); - } - }); - - final FormData data = new FormData(); - data.top = new FormAttachment(0); - data.left = new FormAttachment(0); - data.right = new FormAttachment(100); - mHeader.setLayoutData(data); - } - - /** - * Create chart of recent network activity. - */ - private void createChart() { - - mChart = ChartFactory.createTimeSeriesChart(null, null, null, null, false, false, false); - - // create backing datasets and series - mRxTotalSeries = new TimeSeries("RX total"); - mTxTotalSeries = new TimeSeries("TX total"); - - mRxTotalSeries.setMaximumItemAge(HISTORY_MILLIS); - mTxTotalSeries.setMaximumItemAge(HISTORY_MILLIS); - - mTotalCollection = new TimeSeriesCollection(); - mTotalCollection.addSeries(mRxTotalSeries); - mTotalCollection.addSeries(mTxTotalSeries); - - mRxDetailDataset = new LiveTimeTableXYDataset(); - mTxDetailDataset = new LiveTimeTableXYDataset(); - - mTotalRenderer = new XYAreaRenderer(XYAreaRenderer.AREA); - mRenderer = new StackedXYAreaRenderer2(); - - final XYPlot xyPlot = mChart.getXYPlot(); - - xyPlot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); - - xyPlot.setDataset(0, mTotalCollection); - xyPlot.setDataset(1, mRxDetailDataset); - xyPlot.setDataset(2, mTxDetailDataset); - xyPlot.setRenderer(0, mTotalRenderer); - xyPlot.setRenderer(1, mRenderer); - xyPlot.setRenderer(2, mRenderer); - - // we control domain axis manually when taking samples - mDomainAxis = xyPlot.getDomainAxis(); - mDomainAxis.setAutoRange(false); - - final NumberAxis axis = new NumberAxis(); - axis.setNumberFormatOverride(new BytesFormat(true)); - axis.setAutoRangeMinimumSize(50); - xyPlot.setRangeAxis(axis); - xyPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT); - - // draw thick line to separate RX versus TX traffic - xyPlot.addRangeMarker( - new ValueMarker(0, java.awt.Color.BLACK, new java.awt.BasicStroke(2))); - - // label to indicate that positive axis is RX traffic - final ValueMarker rxMarker = new ValueMarker(0); - rxMarker.setStroke(new java.awt.BasicStroke(0)); - rxMarker.setLabel("RX"); - rxMarker.setLabelFont(rxMarker.getLabelFont().deriveFont(30f)); - rxMarker.setLabelPaint(java.awt.Color.LIGHT_GRAY); - rxMarker.setLabelAnchor(RectangleAnchor.TOP_RIGHT); - rxMarker.setLabelTextAnchor(TextAnchor.BOTTOM_RIGHT); - xyPlot.addRangeMarker(rxMarker); - - // label to indicate that negative axis is TX traffic - final ValueMarker txMarker = new ValueMarker(0); - txMarker.setStroke(new java.awt.BasicStroke(0)); - txMarker.setLabel("TX"); - txMarker.setLabelFont(txMarker.getLabelFont().deriveFont(30f)); - txMarker.setLabelPaint(java.awt.Color.LIGHT_GRAY); - txMarker.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT); - txMarker.setLabelTextAnchor(TextAnchor.TOP_RIGHT); - xyPlot.addRangeMarker(txMarker); - - mChartComposite = new ChartComposite(mPanel, SWT.BORDER, mChart, - ChartComposite.DEFAULT_WIDTH, ChartComposite.DEFAULT_HEIGHT, - ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH, - ChartComposite.DEFAULT_MINIMUM_DRAW_HEIGHT, 4096, 4096, true, true, true, true, - false, true); - - final FormData data = new FormData(); - data.top = new FormAttachment(mHeader); - data.left = new FormAttachment(0); - data.bottom = new FormAttachment(70); - data.right = new FormAttachment(100); - mChartComposite.setLayoutData(data); - } - - /** - * Create table showing summary of network activity. - */ - private void createTable() { - mTable = new Table(mPanel, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); - - final FormData data = new FormData(); - data.top = new FormAttachment(mChartComposite); - data.left = new FormAttachment(mChartComposite, 0, SWT.CENTER); - data.bottom = new FormAttachment(100); - mTable.setLayoutData(data); - - mTable.setHeaderVisible(true); - mTable.setLinesVisible(true); - - final IPreferenceStore store = DdmUiPreferences.getStore(); - - TableHelper.createTableColumn(mTable, "", SWT.CENTER, buildSampleText(2), null, null); - TableHelper.createTableColumn( - mTable, "Tag", SWT.LEFT, buildSampleText(32), PREFS_NETWORK_COL_TITLE, store); - TableHelper.createTableColumn(mTable, "RX bytes", SWT.RIGHT, buildSampleText(12), - PREFS_NETWORK_COL_RX_BYTES, store); - TableHelper.createTableColumn(mTable, "RX packets", SWT.RIGHT, buildSampleText(12), - PREFS_NETWORK_COL_RX_PACKETS, store); - TableHelper.createTableColumn(mTable, "TX bytes", SWT.RIGHT, buildSampleText(12), - PREFS_NETWORK_COL_TX_BYTES, store); - TableHelper.createTableColumn(mTable, "TX packets", SWT.RIGHT, buildSampleText(12), - PREFS_NETWORK_COL_TX_PACKETS, store); - - mTableViewer = new TableViewer(mTable); - mTableViewer.setContentProvider(new ContentProvider()); - mTableViewer.setLabelProvider(new LabelProvider()); - } - - /** - * Update {@link #mSpeedMillis} to match {@link #mSpeedCombo} selection. - */ - private void updateSpeed() { - switch (mSpeedCombo.getSelectionIndex()) { - case 0: - mSpeedMillis = 100; - break; - case 1: - mSpeedMillis = 250; - break; - case 2: - mSpeedMillis = 500; - break; - } - } - - /** - * Update if {@link SampleThread} should be actively running. Will create - * new thread or finish existing thread to match requested state. - */ - private void updateRunning(boolean shouldRun) { - final boolean alreadyRunning = mSampleThread != null; - if (alreadyRunning && !shouldRun) { - mSampleThread.finish(); - mSampleThread = null; - - mRunningButton.setText("Start"); - mHeader.pack(); - } else if (!alreadyRunning && shouldRun) { - mSampleThread = new SampleThread(); - mSampleThread.start(); - - mRunningButton.setText("Stop"); - mHeader.pack(); - } - } - - @Override - public void setFocus() { - mPanel.setFocus(); - } - - private static java.awt.Color nextSeriesColor(int index) { - return SERIES_COLORS[index % SERIES_COLORS.length]; - } - - /** - * Find a {@link TrackedItem} that matches the requested UID and tag, or - * create one if none exists. - */ - public TrackedItem findOrCreateTrackedItem(int uid, int tag) { - // try searching for existing item - for (TrackedItem item : mTrackedItems) { - if (item.uid == uid && item.tag == tag) { - return item; - } - } - - // nothing found; create new item - final TrackedItem item = new TrackedItem(uid, tag); - if (item.isTotal()) { - item.color = TOTAL_COLOR; - item.label = "Total"; - } else { - final int size = mTrackedItems.size(); - item.color = nextSeriesColor(size); - Formatter formatter = new Formatter(); - item.label = "0x" + formatter.format("%08x", tag); - formatter.close(); - } - - // create color chip to display as legend in table - item.colorImage = new Image(mDisplay, 20, 20); - final GC gc = new GC(item.colorImage); - gc.setBackground(new org.eclipse.swt.graphics.Color(mDisplay, item.color - .getRed(), item.color.getGreen(), item.color.getBlue())); - gc.fillRectangle(item.colorImage.getBounds()); - gc.dispose(); - - mTrackedItems.add(item); - return item; - } - - /** - * Clear all {@link TrackedItem} and chart history. - */ - public void clearTrackedItems() { - mRxTotalSeries.clear(); - mTxTotalSeries.clear(); - - mRxDetailDataset.clear(); - mTxDetailDataset.clear(); - - mTrackedItems.clear(); - mTableViewer.setInput(mTrackedItems); - } - - /** - * Update the {@link #mRenderer} colors to match {@link TrackedItem#color}. - */ - private void updateSeriesPaint() { - for (TrackedItem item : mTrackedItems) { - final int seriesIndex = mRxDetailDataset.getColumnIndex(item.label); - if (seriesIndex >= 0) { - mRenderer.setSeriesPaint(seriesIndex, item.color); - mRenderer.setSeriesFillPaint(seriesIndex, item.color); - } - } - - // series data is always the same color - final int count = mTotalCollection.getSeriesCount(); - for (int i = 0; i < count; i++) { - mTotalRenderer.setSeriesPaint(i, TOTAL_COLOR); - mTotalRenderer.setSeriesFillPaint(i, TOTAL_COLOR); - } - } - - /** - * Traffic flow being actively tracked, uniquely defined by UID and tag. Can - * record {@link NetworkSnapshot} deltas into {@link TimeSeries} for - * charting, and into summary statistics for {@link Table} display. - */ - private class TrackedItem { - public final int uid; - public final int tag; - - public java.awt.Color color; - public Image colorImage; - - public String label; - public long rxBytes; - public long rxPackets; - public long txBytes; - public long txPackets; - - public TrackedItem(int uid, int tag) { - this.uid = uid; - this.tag = tag; - } - - public boolean isTotal() { - return tag == 0x0; - } - - /** - * Record the given {@link NetworkSnapshot} delta, updating - * {@link TimeSeries} and summary statistics. - * - * @param time Timestamp when delta was observed. - * @param deltaMillis Time duration covered by delta, in milliseconds. - */ - public void recordDelta(Millisecond time, long deltaMillis, NetworkSnapshot.Entry delta) { - final long rxBytesPerSecond = (delta.rxBytes * 1000) / deltaMillis; - final long txBytesPerSecond = (delta.txBytes * 1000) / deltaMillis; - - // record values under correct series - if (isTotal()) { - mRxTotalSeries.addOrUpdate(time, rxBytesPerSecond); - mTxTotalSeries.addOrUpdate(time, -txBytesPerSecond); - } else { - mRxDetailDataset.addValue(rxBytesPerSecond, time, label); - mTxDetailDataset.addValue(-txBytesPerSecond, time, label); - } - - rxBytes += delta.rxBytes; - rxPackets += delta.rxPackets; - txBytes += delta.txBytes; - txPackets += delta.txPackets; - } - } - - @Override - public void deviceSelected() { - // treat as client selection to update enabled states - clientSelected(); - } - - @Override - public void clientSelected() { - mActiveUid = -1; - - final Client client = getCurrentClient(); - if (client != null) { - final int pid = client.getClientData().getPid(); - try { - // map PID to UID from device - final UidParser uidParser = new UidParser(); - getCurrentDevice().executeShellCommand("cat /proc/" + pid + "/status", uidParser); - mActiveUid = uidParser.uid; - } catch (TimeoutException e) { - e.printStackTrace(); - } catch (AdbCommandRejectedException e) { - e.printStackTrace(); - } catch (ShellCommandUnresponsiveException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - clearTrackedItems(); - updateRunning(false); - - final boolean validUid = mActiveUid != -1; - mRunningButton.setEnabled(validUid); - } - - @Override - public void clientChanged(Client client, int changeMask) { - // ignored - } - - /** - * Take a snapshot from {@link #getCurrentDevice()}, recording any delta - * network traffic to {@link TrackedItem}. - */ - public void performSample() { - final IDevice device = getCurrentDevice(); - if (device == null) return; - - try { - final NetworkSnapshotParser parser = new NetworkSnapshotParser(); - device.executeShellCommand("cat " + PROC_XT_QTAGUID, parser); - - if (parser.isError()) { - mDisplay.asyncExec(new Runnable() { - @Override - public void run() { - updateRunning(false); - - final String title = "Problem reading stats"; - final String message = "Problem reading xt_qtaguid network " - + "statistics from selected device."; - Status status = new Status(IStatus.ERROR, "NetworkPanel", 0, message, null); - ErrorDialog.openError(mPanel.getShell(), title, title, status); - } - }); - - return; - } - - final NetworkSnapshot snapshot = parser.getParsedSnapshot(); - - // use first snapshot as baseline - if (mLastSnapshot == null) { - mLastSnapshot = snapshot; - return; - } - - final NetworkSnapshot delta = NetworkSnapshot.subtract(snapshot, mLastSnapshot); - mLastSnapshot = snapshot; - - // perform delta updates over on UI thread - if (!mDisplay.isDisposed()) { - mDisplay.syncExec(new UpdateDeltaRunnable(delta, snapshot.timestamp)); - } - - } catch (TimeoutException e) { - e.printStackTrace(); - } catch (AdbCommandRejectedException e) { - e.printStackTrace(); - } catch (ShellCommandUnresponsiveException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Task that updates UI with given {@link NetworkSnapshot} delta. - */ - private class UpdateDeltaRunnable implements Runnable { - private final NetworkSnapshot mDelta; - private final long mEndTime; - - public UpdateDeltaRunnable(NetworkSnapshot delta, long endTime) { - mDelta = delta; - mEndTime = endTime; - } - - @Override - public void run() { - if (mDisplay.isDisposed()) return; - - final Millisecond time = new Millisecond(new Date(mEndTime)); - for (NetworkSnapshot.Entry entry : mDelta) { - if (mActiveUid != entry.uid) continue; - - final TrackedItem item = findOrCreateTrackedItem(entry.uid, entry.tag); - item.recordDelta(time, mDelta.timestamp, entry); - } - - // remove any historical detail data - final long beforeMillis = mEndTime - HISTORY_MILLIS; - mRxDetailDataset.removeBefore(beforeMillis); - mTxDetailDataset.removeBefore(beforeMillis); - - // trigger refresh from bulk changes above - mRxDetailDataset.fireDatasetChanged(); - mTxDetailDataset.fireDatasetChanged(); - - // update axis to show latest 30 second time period - mDomainAxis.setRange(mEndTime - HISTORY_MILLIS, mEndTime); - - updateSeriesPaint(); - - // kick table viewer to update - mTableViewer.setInput(mTrackedItems); - } - } - - /** - * Parser that extracts UID from remote {@code /proc/pid/status} file. - */ - private static class UidParser extends MultiLineReceiver { - public int uid = -1; - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public void processNewLines(String[] lines) { - for (String line : lines) { - if (line.startsWith("Uid:")) { - // we care about the "real" UID - final String[] cols = line.split("\t"); - uid = Integer.parseInt(cols[1]); - } - } - } - } - - /** - * Parser that populates {@link NetworkSnapshot} based on contents of remote - * {@link NetworkPanel#PROC_XT_QTAGUID} file. - */ - private static class NetworkSnapshotParser extends MultiLineReceiver { - private NetworkSnapshot mSnapshot; - - public NetworkSnapshotParser() { - mSnapshot = new NetworkSnapshot(System.currentTimeMillis()); - } - - public boolean isError() { - return mSnapshot == null; - } - - public NetworkSnapshot getParsedSnapshot() { - return mSnapshot; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public void processNewLines(String[] lines) { - for (String line : lines) { - if (line.endsWith("No such file or directory")) { - mSnapshot = null; - return; - } - - // ignore header line - if (line.startsWith("idx")) { - continue; - } - - final String[] cols = line.split(" "); - if (cols.length < 9) continue; - - // iface and set are currently ignored, which groups those - // entries together. - final NetworkSnapshot.Entry entry = new NetworkSnapshot.Entry(); - - entry.iface = null; //cols[1]; - entry.uid = Integer.parseInt(cols[3]); - entry.set = -1; //Integer.parseInt(cols[4]); - entry.tag = kernelToTag(cols[2]); - entry.rxBytes = Long.parseLong(cols[5]); - entry.rxPackets = Long.parseLong(cols[6]); - entry.txBytes = Long.parseLong(cols[7]); - entry.txPackets = Long.parseLong(cols[8]); - - mSnapshot.combine(entry); - } - } - - /** - * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming - * format like {@code 0x7fffffff00000000}. - * Matches code in android.server.NetworkManagementSocketTagger - */ - public static int kernelToTag(String string) { - int length = string.length(); - if (length > 10) { - return Long.decode(string.substring(0, length - 8)).intValue(); - } else { - return 0; - } - } - } - - /** - * Parsed snapshot of {@link NetworkPanel#PROC_XT_QTAGUID} at specific time. - */ - private static class NetworkSnapshot implements Iterable<NetworkSnapshot.Entry> { - private ArrayList<Entry> mStats = new ArrayList<Entry>(); - - public final long timestamp; - - /** Single parsed statistics row. */ - public static class Entry { - public String iface; - public int uid; - public int set; - public int tag; - public long rxBytes; - public long rxPackets; - public long txBytes; - public long txPackets; - - public boolean isEmpty() { - return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0; - } - } - - public NetworkSnapshot(long timestamp) { - this.timestamp = timestamp; - } - - public void clear() { - mStats.clear(); - } - - /** - * Combine the given {@link Entry} with any existing {@link Entry}, or - * insert if none exists. - */ - public void combine(Entry entry) { - final Entry existing = findEntry(entry.iface, entry.uid, entry.set, entry.tag); - if (existing != null) { - existing.rxBytes += entry.rxBytes; - existing.rxPackets += entry.rxPackets; - existing.txBytes += entry.txBytes; - existing.txPackets += entry.txPackets; - } else { - mStats.add(entry); - } - } - - @Override - public Iterator<Entry> iterator() { - return mStats.iterator(); - } - - public Entry findEntry(String iface, int uid, int set, int tag) { - for (Entry entry : mStats) { - if (entry.uid == uid && entry.set == set && entry.tag == tag - && equal(entry.iface, iface)) { - return entry; - } - } - return null; - } - - /** - * Subtract the two given {@link NetworkSnapshot} objects, returning the - * delta between them. - */ - public static NetworkSnapshot subtract(NetworkSnapshot left, NetworkSnapshot right) { - final NetworkSnapshot result = new NetworkSnapshot(left.timestamp - right.timestamp); - - // for each row on left, subtract value from right side - for (Entry leftEntry : left) { - final Entry rightEntry = right.findEntry( - leftEntry.iface, leftEntry.uid, leftEntry.set, leftEntry.tag); - if (rightEntry == null) continue; - - final Entry resultEntry = new Entry(); - resultEntry.iface = leftEntry.iface; - resultEntry.uid = leftEntry.uid; - resultEntry.set = leftEntry.set; - resultEntry.tag = leftEntry.tag; - resultEntry.rxBytes = leftEntry.rxBytes - rightEntry.rxBytes; - resultEntry.rxPackets = leftEntry.rxPackets - rightEntry.rxPackets; - resultEntry.txBytes = leftEntry.txBytes - rightEntry.txBytes; - resultEntry.txPackets = leftEntry.txPackets - rightEntry.txPackets; - - result.combine(resultEntry); - } - - return result; - } - } - - /** - * Provider of {@link #mTrackedItems}. - */ - private class ContentProvider implements IStructuredContentProvider { - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public Object[] getElements(Object inputElement) { - return mTrackedItems.toArray(); - } - } - - /** - * Provider of labels for {@Link TrackedItem} values. - */ - private static class LabelProvider implements ITableLabelProvider { - private final DecimalFormat mFormat = new DecimalFormat("#,###"); - - @Override - public Image getColumnImage(Object element, int columnIndex) { - if (element instanceof TrackedItem) { - final TrackedItem item = (TrackedItem) element; - switch (columnIndex) { - case 0: - return item.colorImage; - } - } - return null; - } - - @Override - public String getColumnText(Object element, int columnIndex) { - if (element instanceof TrackedItem) { - final TrackedItem item = (TrackedItem) element; - switch (columnIndex) { - case 0: - return null; - case 1: - return item.label; - case 2: - return mFormat.format(item.rxBytes); - case 3: - return mFormat.format(item.rxPackets); - case 4: - return mFormat.format(item.txBytes); - case 5: - return mFormat.format(item.txPackets); - } - } - return null; - } - - @Override - public void addListener(ILabelProviderListener listener) { - // pass - } - - @Override - public void dispose() { - // pass - } - - @Override - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - @Override - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Format that displays simplified byte units for when given values are - * large enough. - */ - private static class BytesFormat extends NumberFormat { - private final String[] mUnits; - private final DecimalFormat mFormat = new DecimalFormat("#.#"); - - public BytesFormat(boolean perSecond) { - if (perSecond) { - mUnits = new String[] { "B/s", "KB/s", "MB/s" }; - } else { - mUnits = new String[] { "B", "KB", "MB" }; - } - } - - @Override - public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) { - double value = Math.abs(number); - - int i = 0; - while (value > 1024 && i < mUnits.length - 1) { - value /= 1024; - i++; - } - - toAppendTo.append(mFormat.format(value)); - toAppendTo.append(mUnits[i]); - - return toAppendTo; - } - - @Override - public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) { - return format((long) number, toAppendTo, pos); - } - - @Override - public Number parse(String source, ParsePosition parsePosition) { - return null; - } - } - - public static boolean equal(Object a, Object b) { - return a == b || (a != null && a.equals(b)); - } - - /** - * Build stub string of requested length, usually for measurement. - */ - private static String buildSampleText(int length) { - final StringBuilder builder = new StringBuilder(length); - for (int i = 0; i < length; i++) { - builder.append("X"); - } - return builder.toString(); - } - - /** - * Dataset that contains live measurements. Exposes - * {@link #removeBefore(long)} to efficiently remove old data, and enables - * batched {@link #fireDatasetChanged()} events. - */ - public static class LiveTimeTableXYDataset extends AbstractIntervalXYDataset implements - TableXYDataset { - private DefaultKeyedValues2D mValues = new DefaultKeyedValues2D(true); - - /** - * Caller is responsible for triggering {@link #fireDatasetChanged()}. - */ - public void addValue(Number value, TimePeriod rowKey, String columnKey) { - mValues.addValue(value, rowKey, columnKey); - } - - /** - * Caller is responsible for triggering {@link #fireDatasetChanged()}. - */ - public void removeBefore(long beforeMillis) { - while(mValues.getRowCount() > 0) { - final TimePeriod period = (TimePeriod) mValues.getRowKey(0); - if (period.getEnd().getTime() < beforeMillis) { - mValues.removeRow(0); - } else { - break; - } - } - } - - public int getColumnIndex(String key) { - return mValues.getColumnIndex(key); - } - - public void clear() { - mValues.clear(); - fireDatasetChanged(); - } - - @Override - public void fireDatasetChanged() { - super.fireDatasetChanged(); - } - - @Override - public int getItemCount() { - return mValues.getRowCount(); - } - - @Override - public int getItemCount(int series) { - return mValues.getRowCount(); - } - - @Override - public int getSeriesCount() { - return mValues.getColumnCount(); - } - - @Override - public Comparable getSeriesKey(int series) { - return mValues.getColumnKey(series); - } - - @Override - public double getXValue(int series, int item) { - final TimePeriod period = (TimePeriod) mValues.getRowKey(item); - return period.getStart().getTime(); - } - - @Override - public double getStartXValue(int series, int item) { - return getXValue(series, item); - } - - @Override - public double getEndXValue(int series, int item) { - return getXValue(series, item); - } - - @Override - public Number getX(int series, int item) { - return getXValue(series, item); - } - - @Override - public Number getStartX(int series, int item) { - return getXValue(series, item); - } - - @Override - public Number getEndX(int series, int item) { - return getXValue(series, item); - } - - @Override - public Number getY(int series, int item) { - return mValues.getValue(item, series); - } - - @Override - public Number getStartY(int series, int item) { - return getY(series, item); - } - - @Override - public Number getEndY(int series, int item) { - return getY(series, item); - } - } -} diff --git a/ddms/libs/ddmuilib/src/images/add.png b/ddms/libs/ddmuilib/src/images/add.png Binary files differdeleted file mode 100644 index eefc2ca..0000000 --- a/ddms/libs/ddmuilib/src/images/add.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/android.png b/ddms/libs/ddmuilib/src/images/android.png Binary files differdeleted file mode 100644 index 3779d4d..0000000 --- a/ddms/libs/ddmuilib/src/images/android.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/backward.png b/ddms/libs/ddmuilib/src/images/backward.png Binary files differdeleted file mode 100644 index 90a9713..0000000 --- a/ddms/libs/ddmuilib/src/images/backward.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/capture.png b/ddms/libs/ddmuilib/src/images/capture.png Binary files differdeleted file mode 100644 index da5c10b..0000000 --- a/ddms/libs/ddmuilib/src/images/capture.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/clear.png b/ddms/libs/ddmuilib/src/images/clear.png Binary files differdeleted file mode 100644 index 0009cf6..0000000 --- a/ddms/libs/ddmuilib/src/images/clear.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/d.png b/ddms/libs/ddmuilib/src/images/d.png Binary files differdeleted file mode 100644 index d45506e..0000000 --- a/ddms/libs/ddmuilib/src/images/d.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/debug-attach.png b/ddms/libs/ddmuilib/src/images/debug-attach.png Binary files differdeleted file mode 100644 index 9b8a11c..0000000 --- a/ddms/libs/ddmuilib/src/images/debug-attach.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/debug-error.png b/ddms/libs/ddmuilib/src/images/debug-error.png Binary files differdeleted file mode 100644 index f22da1f..0000000 --- a/ddms/libs/ddmuilib/src/images/debug-error.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/debug-wait.png b/ddms/libs/ddmuilib/src/images/debug-wait.png Binary files differdeleted file mode 100644 index 322be63..0000000 --- a/ddms/libs/ddmuilib/src/images/debug-wait.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/delete.png b/ddms/libs/ddmuilib/src/images/delete.png Binary files differdeleted file mode 100644 index db5fab8..0000000 --- a/ddms/libs/ddmuilib/src/images/delete.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/device.png b/ddms/libs/ddmuilib/src/images/device.png Binary files differdeleted file mode 100644 index 7dbbbb6..0000000 --- a/ddms/libs/ddmuilib/src/images/device.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/diff.png b/ddms/libs/ddmuilib/src/images/diff.png Binary files differdeleted file mode 100644 index bdd9e5c..0000000 --- a/ddms/libs/ddmuilib/src/images/diff.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/displayfilters.png b/ddms/libs/ddmuilib/src/images/displayfilters.png Binary files differdeleted file mode 100644 index d110c2c..0000000 --- a/ddms/libs/ddmuilib/src/images/displayfilters.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/down.png b/ddms/libs/ddmuilib/src/images/down.png Binary files differdeleted file mode 100644 index f9426cb..0000000 --- a/ddms/libs/ddmuilib/src/images/down.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/e.png b/ddms/libs/ddmuilib/src/images/e.png Binary files differdeleted file mode 100644 index dee7c97..0000000 --- a/ddms/libs/ddmuilib/src/images/e.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/edit.png b/ddms/libs/ddmuilib/src/images/edit.png Binary files differdeleted file mode 100644 index b8f65bc..0000000 --- a/ddms/libs/ddmuilib/src/images/edit.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/empty.png b/ddms/libs/ddmuilib/src/images/empty.png Binary files differdeleted file mode 100644 index f021542..0000000 --- a/ddms/libs/ddmuilib/src/images/empty.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/emulator.png b/ddms/libs/ddmuilib/src/images/emulator.png Binary files differdeleted file mode 100644 index a718042..0000000 --- a/ddms/libs/ddmuilib/src/images/emulator.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/file.png b/ddms/libs/ddmuilib/src/images/file.png Binary files differdeleted file mode 100644 index 043a814..0000000 --- a/ddms/libs/ddmuilib/src/images/file.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/folder.png b/ddms/libs/ddmuilib/src/images/folder.png Binary files differdeleted file mode 100644 index 7e29b1a..0000000 --- a/ddms/libs/ddmuilib/src/images/folder.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/forward.png b/ddms/libs/ddmuilib/src/images/forward.png Binary files differdeleted file mode 100644 index a97a605..0000000 --- a/ddms/libs/ddmuilib/src/images/forward.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/gc.png b/ddms/libs/ddmuilib/src/images/gc.png Binary files differdeleted file mode 100644 index 5194806..0000000 --- a/ddms/libs/ddmuilib/src/images/gc.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/groupby.png b/ddms/libs/ddmuilib/src/images/groupby.png Binary files differdeleted file mode 100644 index 250b982..0000000 --- a/ddms/libs/ddmuilib/src/images/groupby.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/halt.png b/ddms/libs/ddmuilib/src/images/halt.png Binary files differdeleted file mode 100644 index 10e3720..0000000 --- a/ddms/libs/ddmuilib/src/images/halt.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/heap.png b/ddms/libs/ddmuilib/src/images/heap.png Binary files differdeleted file mode 100644 index e3aa3f0..0000000 --- a/ddms/libs/ddmuilib/src/images/heap.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/hprof.png b/ddms/libs/ddmuilib/src/images/hprof.png Binary files differdeleted file mode 100644 index 123d062..0000000 --- a/ddms/libs/ddmuilib/src/images/hprof.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/i.png b/ddms/libs/ddmuilib/src/images/i.png Binary files differdeleted file mode 100644 index 98385c5..0000000 --- a/ddms/libs/ddmuilib/src/images/i.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/importBug.png b/ddms/libs/ddmuilib/src/images/importBug.png Binary files differdeleted file mode 100644 index f5da179..0000000 --- a/ddms/libs/ddmuilib/src/images/importBug.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/load.png b/ddms/libs/ddmuilib/src/images/load.png Binary files differdeleted file mode 100644 index 9e7bf6e..0000000 --- a/ddms/libs/ddmuilib/src/images/load.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/pause.png b/ddms/libs/ddmuilib/src/images/pause.png Binary files differdeleted file mode 100644 index 19d286d..0000000 --- a/ddms/libs/ddmuilib/src/images/pause.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/play.png b/ddms/libs/ddmuilib/src/images/play.png Binary files differdeleted file mode 100644 index d54f013..0000000 --- a/ddms/libs/ddmuilib/src/images/play.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/pull.png b/ddms/libs/ddmuilib/src/images/pull.png Binary files differdeleted file mode 100644 index f48f1b1..0000000 --- a/ddms/libs/ddmuilib/src/images/pull.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/push.png b/ddms/libs/ddmuilib/src/images/push.png Binary files differdeleted file mode 100644 index 6222864..0000000 --- a/ddms/libs/ddmuilib/src/images/push.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/save.png b/ddms/libs/ddmuilib/src/images/save.png Binary files differdeleted file mode 100644 index 040ebda..0000000 --- a/ddms/libs/ddmuilib/src/images/save.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/scroll_lock.png b/ddms/libs/ddmuilib/src/images/scroll_lock.png Binary files differdeleted file mode 100644 index 5d26689..0000000 --- a/ddms/libs/ddmuilib/src/images/scroll_lock.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/sort_down.png b/ddms/libs/ddmuilib/src/images/sort_down.png Binary files differdeleted file mode 100644 index 2d4ccc1..0000000 --- a/ddms/libs/ddmuilib/src/images/sort_down.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/sort_up.png b/ddms/libs/ddmuilib/src/images/sort_up.png Binary files differdeleted file mode 100644 index 3a0bc3c..0000000 --- a/ddms/libs/ddmuilib/src/images/sort_up.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/thread.png b/ddms/libs/ddmuilib/src/images/thread.png Binary files differdeleted file mode 100644 index ac839e8..0000000 --- a/ddms/libs/ddmuilib/src/images/thread.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/tracing_start.png b/ddms/libs/ddmuilib/src/images/tracing_start.png Binary files differdeleted file mode 100644 index 88771cc..0000000 --- a/ddms/libs/ddmuilib/src/images/tracing_start.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/tracing_stop.png b/ddms/libs/ddmuilib/src/images/tracing_stop.png Binary files differdeleted file mode 100644 index 71bd215..0000000 --- a/ddms/libs/ddmuilib/src/images/tracing_stop.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/up.png b/ddms/libs/ddmuilib/src/images/up.png Binary files differdeleted file mode 100644 index 92edf5a..0000000 --- a/ddms/libs/ddmuilib/src/images/up.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/v.png b/ddms/libs/ddmuilib/src/images/v.png Binary files differdeleted file mode 100644 index 8044051..0000000 --- a/ddms/libs/ddmuilib/src/images/v.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/w.png b/ddms/libs/ddmuilib/src/images/w.png Binary files differdeleted file mode 100644 index 129d0f9..0000000 --- a/ddms/libs/ddmuilib/src/images/w.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/warning.png b/ddms/libs/ddmuilib/src/images/warning.png Binary files differdeleted file mode 100644 index ca3b6ed..0000000 --- a/ddms/libs/ddmuilib/src/images/warning.png +++ /dev/null diff --git a/ddms/libs/ddmuilib/src/images/zygote.png b/ddms/libs/ddmuilib/src/images/zygote.png Binary files differdeleted file mode 100644 index 5cbb1d2..0000000 --- a/ddms/libs/ddmuilib/src/images/zygote.png +++ /dev/null |