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 @Override 62 public void deviceDisconnected(IDevice device) { 63 unmonitorDevice(device.getSerialNumber()); 64 mMonitoredDevices.remove(device.getSerialNumber()); 65 } 66 67 @Override 68 public void deviceConnected(IDevice device) { 69 } 70 71 @Override 72 public void deviceChanged(IDevice device, int changeMask) { 73 } 74 }); 75 76 mPrefStore.addPropertyChangeListener(new IPropertyChangeListener() { 77 @Override 78 public void propertyChange(PropertyChangeEvent event) { 79 if (AUTO_MONITOR_PREFKEY.equals(event.getProperty()) 80 && event.getNewValue().equals(false)) { 81 unmonitorAllDevices(); 82 } 83 } 84 }); 85 } 86 87 private void unmonitorAllDevices() { 88 for (String device : mMonitoredDevices.keySet()) { 89 unmonitorDevice(device); 90 } 91 92 mMonitoredDevices.clear(); 93 } 94 95 private void unmonitorDevice(String deviceSerial) { 96 DeviceData data = mMonitoredDevices.get(deviceSerial); 97 if (data == null) { 98 return; 99 } 100 101 data.receiver.removeMessageReceivedEventListener(data.messageEventListener); 102 } 103 104 public void monitorDevice(final IDevice device) { 105 if (!mPrefStore.getBoolean(AUTO_MONITOR_PREFKEY)) { 106 // do not monitor device if auto monitoring is off 107 return; 108 } 109 110 if (mMonitoredDevices.keySet().contains(device.getSerialNumber())) { 111 // the device is already monitored 112 return; 113 } 114 115 LogCatReceiver r = LogCatReceiverFactory.INSTANCE.newReceiver(device, mPrefStore); 116 ILogCatMessageEventListener l = new ILogCatMessageEventListener() { 117 @Override 118 public void messageReceived(List<LogCatMessage> receivedMessages) { 119 checkMessages(receivedMessages, device); 120 } 121 }; 122 r.addMessageReceivedEventListener(l); 123 124 mMonitoredDevices.put(device.getSerialNumber(), new DeviceData(r, l)); 125 } 126 127 private void checkMessages(List<LogCatMessage> receivedMessages, IDevice device) { 128 // check the received list of messages to see if any of them are 129 // significant enough to be seen by the user. If so, activate the logcat view 130 // to display those messages 131 for (LogCatMessage m : receivedMessages) { 132 if (isImportantMessage(m)) { 133 focusLogCatView(device, m.getAppName()); 134 break; 135 } 136 } 137 } 138 139 /** 140 * Check whether a message is "important". Currently, we assume that a message is important if 141 * it is of severity level error or higher, and it belongs to an app currently in the workspace. 142 */ 143 private boolean isImportantMessage(LogCatMessage m) { 144 if (m.getLogLevel().getPriority() < LogLevel.ERROR.getPriority()) { 145 return false; 146 } 147 148 String app = m.getAppName(); 149 for (IDebuggerConnector c : mConnectors) { 150 if (c.isWorkspaceApp(app)) { 151 return true; 152 } 153 } 154 155 return false; 156 } 157 158 private void focusLogCatView(final IDevice device, final String appName) { 159 Display.getDefault().asyncExec(new Runnable() { 160 @Override 161 public void run() { 162 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 163 if (window == null) { 164 return; 165 } 166 167 IWorkbenchPage page = window.getActivePage(); 168 if (page == null) { 169 return; 170 } 171 172 // display view 173 final LogCatView v = displayLogCatView(page); 174 if (v == null) { 175 return; 176 } 177 178 // select correct device 179 v.selectionChanged(device); 180 181 // select appropriate filter 182 v.selectTransientAppFilter(appName); 183 } 184 185 private LogCatView displayLogCatView(IWorkbenchPage page) { 186 // if the view is already in the page, just bring it to the front 187 // without giving it focus. 188 IViewPart view = page.findView(LogCatView.ID); 189 if (view != null) { 190 page.bringToTop(view); 191 if (view instanceof LogCatView) { 192 return (LogCatView)view; 193 } 194 } 195 196 // if the view is not in the page, then create and show it. 197 try { 198 return (LogCatView) page.showView(LogCatView.ID); 199 } catch (PartInitException e) { 200 return null; 201 } 202 } 203 }); 204 } 205 206 private static class DeviceData { 207 public final LogCatReceiver receiver; 208 public final ILogCatMessageEventListener messageEventListener; 209 210 public DeviceData(LogCatReceiver r, ILogCatMessageEventListener l) { 211 receiver = r; 212 messageEventListener = l; 213 } 214 } 215 } 216