aboutsummaryrefslogtreecommitdiffstats
path: root/ddms/libs/ddmuilib/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'ddms/libs/ddmuilib/src/com')
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/AbstractBufferFindTarget.java117
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java355
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/AllocationPanel.java651
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/BackgroundThread.java50
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/BaseHeapPanel.java193
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/ClientDisplayPanel.java33
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/DdmUiPreferences.java79
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java784
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/EmulatorControlPanel.java1463
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/FindDialog.java142
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/HeapPanel.java1310
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/IFindTarget.java21
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/ITableFocusListener.java38
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/ImageLoader.java206
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/InfoPanel.java199
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/NativeHeapPanel.java1648
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/Panel.java49
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/PortFieldEditor.java73
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java350
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/SelectionDependentPanel.java78
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/StackTracePanel.java223
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java100
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressMonitor.java60
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java907
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/TableHelper.java209
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/TablePanel.java132
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/ThreadPanel.java573
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ICommonAction.java42
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/actions/ToolItemAction.java71
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/UiThread.java31
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/annotation/WorkerThread.java31
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/console/DdmConsole.java91
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/console/IDdmConsole.java47
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceContentProvider.java177
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java922
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/FileLabelProvider.java160
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java184
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java195
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDataImporter.java222
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapDiffSnapshot.java65
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapLabelProvider.java112
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapPanel.java1150
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByAllocations.java90
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapProviderByLibrary.java92
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeHeapSnapshot.java133
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeLibraryAllocationInfo.java135
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackContentProvider.java56
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeStackLabelProvider.java71
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/heap/NativeSymbolResolverTask.java306
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/CoordinateControls.java249
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/GpxParser.java373
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/KmlParser.java210
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/LocationPoint.java53
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackContentProvider.java48
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackLabelProvider.java87
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/TrackPoint.java34
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPoint.java42
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointContentProvider.java46
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/location/WayPointLabelProvider.java79
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/BugReportImporter.java96
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayFilteredLog.java55
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayGraph.java422
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplayLog.java381
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySync.java304
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncHistogram.java181
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/DisplaySyncPerf.java227
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplay.java975
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventDisplayOptions.java961
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogImporter.java95
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java938
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventValueSelector.java630
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/OccurrenceRenderer.java90
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/SyncCommon.java173
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/EditFilterDialog.java397
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java33
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java26
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java46
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java81
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java63
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsDialog.java327
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java211
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java116
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java1607
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java151
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiverFactory.java95
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatStackTraceParser.java81
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogColors.java27
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogFilter.java556
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java1626
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java1125
90 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 &lt;pid&gt;:0x&lt;???&gt; &lt;severity&gt;/&lt;tag&gt;]"</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);
- }
- }
-}