Home | History | Annotate | Download | only in ddms
      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