diff options
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.java | 277 |
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; + } + } +} |