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             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