1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.ide.eclipse.ddms; 17 18 import com.android.ddmlib.AndroidDebugBridge; 19 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; 20 import com.android.ddmlib.IDevice; 21 import com.android.ddmlib.Log.LogLevel; 22 import com.android.ddmuilib.logcat.ILogCatMessageEventListener; 23 import com.android.ddmuilib.logcat.LogCatMessage; 24 import com.android.ddmuilib.logcat.LogCatReceiver; 25 import com.android.ddmuilib.logcat.LogCatReceiverFactory; 26 import com.android.ide.eclipse.ddms.views.LogCatView; 27 28 import org.eclipse.jface.preference.IPreferenceStore; 29 import org.eclipse.jface.util.IPropertyChangeListener; 30 import org.eclipse.jface.util.PropertyChangeEvent; 31 import org.eclipse.swt.widgets.Display; 32 import org.eclipse.ui.IViewPart; 33 import org.eclipse.ui.IWorkbenchPage; 34 import org.eclipse.ui.IWorkbenchWindow; 35 import org.eclipse.ui.PartInitException; 36 import org.eclipse.ui.PlatformUI; 37 38 import java.util.HashMap; 39 import java.util.List; 40 import java.util.Map; 41 42 /** 43 * LogCatMonitor helps in monitoring the logcat output from a set of devices. 44 * It scans through the received logcat messages, and activates the logcat view 45 * if any message is deemed important. 46 */ 47 public class LogCatMonitor { 48 public static final String AUTO_MONITOR_PREFKEY = "ddms.logcat.automonitor"; 49 50 private IPreferenceStore mPrefStore; 51 private Map<String, DeviceData> mMonitoredDevices; 52 private IDebuggerConnector[] mConnectors; 53 54 public LogCatMonitor(IDebuggerConnector[] debuggerConnectors, IPreferenceStore prefStore) { 55 mConnectors = debuggerConnectors; 56 mPrefStore = prefStore; 57 58 mMonitoredDevices = new HashMap<String, DeviceData>(); 59 60 AndroidDebugBridge.addDeviceChangeListener(new IDeviceChangeListener() { 61 public void deviceDisconnected(IDevice device) { 62 unmonitorDevice(device.getSerialNumber()); 63 mMonitoredDevices.remove(device.getSerialNumber()); 64 } 65 66 public void deviceConnected(IDevice device) { 67 } 68 69 public void deviceChanged(IDevice device, int changeMask) { 70 } 71 }); 72 73 mPrefStore.addPropertyChangeListener(new IPropertyChangeListener() { 74 public void propertyChange(PropertyChangeEvent event) { 75 if (AUTO_MONITOR_PREFKEY.equals(event.getProperty()) 76 && event.getNewValue().equals(false)) { 77 unmonitorAllDevices(); 78 } 79 } 80 }); 81 } 82 83 private void unmonitorAllDevices() { 84 for (String device : mMonitoredDevices.keySet()) { 85 unmonitorDevice(device); 86 } 87 88 mMonitoredDevices.clear(); 89 } 90 91 private void unmonitorDevice(String deviceSerial) { 92 DeviceData data = mMonitoredDevices.get(deviceSerial); 93 if (data == null) { 94 return; 95 } 96 97 data.receiver.removeMessageReceivedEventListener(data.messageEventListener); 98 } 99 100 public void monitorDevice(final IDevice device) { 101 if (!mPrefStore.getBoolean(AUTO_MONITOR_PREFKEY)) { 102 // do not monitor device if auto monitoring is off 103 return; 104 } 105 106 if (mMonitoredDevices.keySet().contains(device.getSerialNumber())) { 107 // the device is already monitored 108 return; 109 } 110 111 LogCatReceiver r = LogCatReceiverFactory.INSTANCE.newReceiver(device, mPrefStore); 112 ILogCatMessageEventListener l = new ILogCatMessageEventListener() { 113 public void messageReceived(List<LogCatMessage> receivedMessages) { 114 checkMessages(receivedMessages, device); 115 } 116 }; 117 r.addMessageReceivedEventListener(l); 118 119 mMonitoredDevices.put(device.getSerialNumber(), new DeviceData(r, l)); 120 } 121 122 private void checkMessages(List<LogCatMessage> receivedMessages, IDevice device) { 123 // check the received list of messages to see if any of them are 124 // significant enough to be seen by the user. If so, activate the logcat view 125 // to display those messages 126 for (LogCatMessage m : receivedMessages) { 127 if (isImportantMessage(m)) { 128 focusLogCatView(device, m.getAppName()); 129 break; 130 } 131 } 132 } 133 134 /** 135 * Check whether a message is "important". Currently, we assume that a message is important if 136 * it is of severity level error or higher, and it belongs to an app currently in the workspace. 137 */ 138 private boolean isImportantMessage(LogCatMessage m) { 139 if (m.getLogLevel().getPriority() < LogLevel.ERROR.getPriority()) { 140 return false; 141 } 142 143 String app = m.getAppName(); 144 for (IDebuggerConnector c : mConnectors) { 145 if (c.isWorkspaceApp(app)) { 146 return true; 147 } 148 } 149 150 return false; 151 } 152 153 private void focusLogCatView(final IDevice device, final String appName) { 154 Display.getDefault().asyncExec(new Runnable() { 155 public void run() { 156 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 157 if (window == null) { 158 return; 159 } 160 161 IWorkbenchPage page = window.getActivePage(); 162 if (page == null) { 163 return; 164 } 165 166 // display view 167 final LogCatView v = displayLogCatView(page); 168 if (v == null) { 169 return; 170 } 171 172 // select correct device 173 v.selectionChanged(device); 174 175 // select appropriate filter 176 v.selectTransientAppFilter(appName); 177 } 178 179 private LogCatView displayLogCatView(IWorkbenchPage page) { 180 // if the view is already in the page, just bring it to the front 181 // without giving it focus. 182 IViewPart view = page.findView(LogCatView.ID); 183 if (view != null) { 184 page.bringToTop(view); 185 if (view instanceof LogCatView) { 186 return (LogCatView)view; 187 } 188 } 189 190 // if the view is not in the page, then create and show it. 191 try { 192 return (LogCatView) page.showView(LogCatView.ID); 193 } catch (PartInitException e) { 194 return null; 195 } 196 } 197 }); 198 } 199 200 private static class DeviceData { 201 public final LogCatReceiver receiver; 202 public final ILogCatMessageEventListener messageEventListener; 203 204 public DeviceData(LogCatReceiver r, ILogCatMessageEventListener l) { 205 receiver = r; 206 messageEventListener = l; 207 } 208 } 209 } 210