aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java277
1 files changed, 277 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
new file mode 100644
index 000000000..e99a637be
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
@@ -0,0 +1,277 @@
+/*
+ * 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.ide.eclipse.ddms;
+
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.logcat.LogCatMessage;
+import com.android.ddmuilib.logcat.ILogCatBufferChangeListener;
+import com.android.ddmuilib.logcat.LogCatReceiver;
+import com.android.ddmuilib.logcat.LogCatReceiverFactory;
+import com.android.ide.eclipse.ddms.views.LogCatView;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * LogCatMonitor helps in monitoring the logcat output from a set of devices.
+ * It scans through the received logcat messages, and activates the logcat view
+ * if any message is deemed important.
+ */
+public class LogCatMonitor {
+ public static final String AUTO_MONITOR_PREFKEY = "ddms.logcat.automonitor"; //$NON-NLS-1$
+ public static final String AUTO_MONITOR_LOGLEVEL = "ddms.logcat.auotmonitor.level"; //$NON-NLS-1$
+ private static final String AUTO_MONITOR_PROMPT_SHOWN = "ddms.logcat.automonitor.userprompt"; //$NON-NLS-1$
+
+ private IPreferenceStore mPrefStore;
+ private Map<String, DeviceData> mMonitoredDevices;
+ private IDebuggerConnector[] mConnectors;
+
+ private int mMinMessagePriority;
+
+ /**
+ * Flag that controls when the logcat stream is checked. This flag is set when the user
+ * performs a launch, and is reset as soon as the logcat view is displayed.
+ */
+ final AtomicBoolean mMonitorEnabled = new AtomicBoolean(false);
+
+ public LogCatMonitor(IDebuggerConnector[] debuggerConnectors, IPreferenceStore prefStore) {
+ mConnectors = debuggerConnectors;
+ mPrefStore = prefStore;
+ mMinMessagePriority =
+ LogLevel.getByString(mPrefStore.getString(AUTO_MONITOR_LOGLEVEL)).getPriority();
+
+ mMonitoredDevices = new HashMap<String, DeviceData>();
+
+ AndroidDebugBridge.addDeviceChangeListener(new IDeviceChangeListener() {
+ @Override
+ public void deviceDisconnected(IDevice device) {
+ unmonitorDevice(device.getSerialNumber());
+ mMonitoredDevices.remove(device.getSerialNumber());
+ }
+
+ @Override
+ public void deviceConnected(IDevice device) {
+ }
+
+ @Override
+ public void deviceChanged(IDevice device, int changeMask) {
+ }
+ });
+
+ mPrefStore.addPropertyChangeListener(new IPropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (AUTO_MONITOR_PREFKEY.equals(event.getProperty())
+ && event.getNewValue().equals(false)) {
+ unmonitorAllDevices();
+ } else if (AUTO_MONITOR_LOGLEVEL.equals(event.getProperty())) {
+ mMinMessagePriority =
+ LogLevel.getByString((String) event.getNewValue()).getPriority();
+ }
+ }
+ });
+ }
+
+ private void unmonitorAllDevices() {
+ for (String device : mMonitoredDevices.keySet()) {
+ unmonitorDevice(device);
+ }
+
+ mMonitoredDevices.clear();
+ }
+
+ private void unmonitorDevice(String deviceSerial) {
+ DeviceData data = mMonitoredDevices.get(deviceSerial);
+ if (data == null) {
+ return;
+ }
+
+ data.receiver.removeMessageReceivedEventListener(data.bufferChangeListener);
+ }
+
+ public void monitorDevice(final IDevice device) {
+ if (!mPrefStore.getBoolean(AUTO_MONITOR_PREFKEY)) {
+ // do not monitor device if auto monitoring is off
+ return;
+ }
+
+ mMonitorEnabled.set(true);
+
+ if (mMonitoredDevices.keySet().contains(device.getSerialNumber())) {
+ // the device is already monitored
+ return;
+ }
+
+ LogCatReceiver r = LogCatReceiverFactory.INSTANCE.newReceiver(device, mPrefStore);
+ ILogCatBufferChangeListener l = new ILogCatBufferChangeListener() {
+ @Override
+ public void bufferChanged(List<LogCatMessage> addedMessages,
+ List<LogCatMessage> deletedMessages) {
+ checkMessages(addedMessages, device);
+ }
+ };
+ r.addMessageReceivedEventListener(l);
+
+ mMonitoredDevices.put(device.getSerialNumber(), new DeviceData(r, l));
+ }
+
+ private void checkMessages(List<LogCatMessage> receivedMessages, IDevice device) {
+ if (!mMonitorEnabled.get()) {
+ return;
+ }
+
+ // check the received list of messages to see if any of them are
+ // significant enough to be seen by the user. If so, activate the logcat view
+ // to display those messages
+ for (LogCatMessage m : receivedMessages) {
+ if (isImportantMessage(m)) {
+ focusLogCatView(device, m.getAppName());
+
+ // now that logcat view is active, no need to check messages until the next
+ // time user launches an application.
+ mMonitorEnabled.set(false);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Check whether a message is "important". Currently, we assume that a message is important if
+ * it is of severity level error or higher, and it belongs to an app currently in the workspace.
+ */
+ private boolean isImportantMessage(LogCatMessage m) {
+ if (m.getLogLevel().getPriority() < mMinMessagePriority) {
+ return false;
+ }
+
+ String app = m.getAppName();
+ for (IDebuggerConnector c : mConnectors) {
+ if (c.isWorkspaceApp(app)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void focusLogCatView(final IDevice device, final String appName) {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return;
+ }
+
+ IWorkbenchPage page = window.getActivePage();
+ if (page == null) {
+ return;
+ }
+
+ // if the logcat view is not visible, then prompt the user once to set
+ // logcat monitoring preferences
+ if (!isLogCatViewVisible(page)) {
+ boolean showLogCatView = promptUserOnce(page.getWorkbenchWindow().getShell());
+ if (!showLogCatView) {
+ return;
+ }
+ }
+
+ // display view
+ final LogCatView v = displayLogCatView(page);
+ if (v == null) {
+ return;
+ }
+
+ // select correct device
+ v.selectionChanged(device);
+
+ // select appropriate filter
+ v.selectTransientAppFilter(appName);
+ }
+
+ private boolean isLogCatViewVisible(IWorkbenchPage page) {
+ IViewPart view = page.findView(LogCatView.ID);
+ return view != null && page.isPartVisible(view);
+ }
+
+ private LogCatView displayLogCatView(IWorkbenchPage page) {
+ // if the view is already in the page, just bring it to the front
+ // without giving it focus.
+ IViewPart view = page.findView(LogCatView.ID);
+ if (view != null) {
+ page.bringToTop(view);
+ if (view instanceof LogCatView) {
+ return (LogCatView)view;
+ }
+ }
+
+ // if the view is not in the page, then create and show it.
+ try {
+ return (LogCatView) page.showView(LogCatView.ID);
+ } catch (PartInitException e) {
+ return null;
+ }
+ }
+
+ private boolean promptUserOnce(Shell shell) {
+ // see if this prompt was already displayed
+ boolean promptShown = mPrefStore.getBoolean(AUTO_MONITOR_PROMPT_SHOWN);
+ if (promptShown) {
+ return mPrefStore.getBoolean(AUTO_MONITOR_PREFKEY);
+ }
+
+ LogCatMonitorDialog dlg = new LogCatMonitorDialog(shell);
+ int r = dlg.open();
+
+ // save preference indicating that this dialog has been displayed once
+ mPrefStore.setValue(AUTO_MONITOR_PROMPT_SHOWN, true);
+ mPrefStore.setValue(AUTO_MONITOR_PREFKEY, dlg.shouldMonitor());
+ mPrefStore.setValue(AUTO_MONITOR_LOGLEVEL, dlg.getMinimumPriority());
+
+ return r == Window.OK && dlg.shouldMonitor();
+ }
+
+ });
+ }
+
+ private static class DeviceData {
+ public final LogCatReceiver receiver;
+ public final ILogCatBufferChangeListener bufferChangeListener;
+
+ public DeviceData(LogCatReceiver r, ILogCatBufferChangeListener l) {
+ receiver = r;
+ bufferChangeListener = l;
+ }
+ }
+}