1 /*
2  * Copyright (C) 2010 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 
17 package com.android.ide.eclipse.hierarchyviewer;
18 
19 import com.android.ddmlib.AndroidDebugBridge;
20 import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
21 import com.android.ddmlib.Log;
22 import com.android.ddmlib.Log.ILogOutput;
23 import com.android.ddmlib.Log.LogLevel;
24 import com.android.hierarchyviewerlib.HierarchyViewerDirector;
25 
26 import org.eclipse.jface.dialogs.MessageDialog;
27 import org.eclipse.swt.graphics.Color;
28 import org.eclipse.swt.widgets.Display;
29 import org.eclipse.swt.widgets.Shell;
30 import org.eclipse.ui.console.ConsolePlugin;
31 import org.eclipse.ui.console.IConsole;
32 import org.eclipse.ui.console.MessageConsole;
33 import org.eclipse.ui.console.MessageConsoleStream;
34 import org.eclipse.ui.plugin.AbstractUIPlugin;
35 import org.osgi.framework.BundleContext;
36 
37 import java.util.Calendar;
38 
39 /**
40  * The activator class controls the plug-in life cycle
41  */
42 public class HierarchyViewerPlugin extends AbstractUIPlugin {
43 
44     public static final String PLUGIN_ID = "com.android.ide.eclipse.hierarchyviewer"; //$NON-NLS-1$
45 
46     public static final String ADB_LOCATION = PLUGIN_ID + ".adb"; //$NON-NLS-1$
47 
48     // The shared instance
49     private static HierarchyViewerPlugin sPlugin;
50 
51     private Color mRedColor;
52 
53     /**
54      * The constructor
55      */
HierarchyViewerPlugin()56     public HierarchyViewerPlugin() {
57     }
58 
59     @Override
start(BundleContext context)60     public void start(BundleContext context) throws Exception {
61         super.start(context);
62         sPlugin = this;
63 
64 
65         // set the consoles.
66         final MessageConsole messageConsole = new MessageConsole("Hierarchy Viewer", null); //$NON-NLS-1$
67         ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] {
68             messageConsole
69         });
70 
71         final MessageConsoleStream consoleStream = messageConsole.newMessageStream();
72         final MessageConsoleStream errorConsoleStream = messageConsole.newMessageStream();
73         mRedColor = new Color(Display.getDefault(), 0xFF, 0x00, 0x00);
74 
75         // because this can be run, in some cases, by a non UI thread, and
76         // because
77         // changing the console properties update the UI, we need to make this
78         // change
79         // in the UI thread.
80         Display.getDefault().asyncExec(new Runnable() {
81             @Override
82             public void run() {
83                 errorConsoleStream.setColor(mRedColor);
84             }
85         });
86 
87         // set up the ddms log to use the ddms console.
88         Log.setLogOutput(new ILogOutput() {
89             @Override
90             public void printLog(LogLevel logLevel, String tag, String message) {
91                 if (logLevel.getPriority() >= LogLevel.ERROR.getPriority()) {
92                     printToStream(errorConsoleStream, tag, message);
93                     ConsolePlugin.getDefault().getConsoleManager().showConsoleView(messageConsole);
94                 } else {
95                     printToStream(consoleStream, tag, message);
96                 }
97             }
98 
99             @Override
100             public void printAndPromptLog(final LogLevel logLevel, final String tag,
101                     final String message) {
102                 printLog(logLevel, tag, message);
103                 // dialog box only run in UI thread..
104                 Display.getDefault().asyncExec(new Runnable() {
105                     @Override
106                     public void run() {
107                         Shell shell = Display.getDefault().getActiveShell();
108                         if (logLevel == LogLevel.ERROR) {
109                             MessageDialog.openError(shell, tag, message);
110                         } else {
111                             MessageDialog.openWarning(shell, tag, message);
112                         }
113                     }
114                 });
115             }
116 
117         });
118 
119         final HierarchyViewerDirector director = HierarchyViewerPluginDirector.createDirector();
120         director.startListenForDevices();
121 
122         // make the director receive change in ADB.
123         AndroidDebugBridge.addDebugBridgeChangeListener(new IDebugBridgeChangeListener() {
124             @Override
125             public void bridgeChanged(AndroidDebugBridge bridge) {
126                 director.acquireBridge(bridge);
127             }
128         });
129 
130         // get the current ADB if any
131         director.acquireBridge(AndroidDebugBridge.getBridge());
132 
133         // populate the UI with current devices (if any) in a thread
134         new Thread() {
135             @Override
136             public void run() {
137                 director.populateDeviceSelectionModel();
138             }
139         }.start();
140     }
141 
142     /*
143      * (non-Javadoc)
144      * @see
145      * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
146      * )
147      */
148     @Override
stop(BundleContext context)149     public void stop(BundleContext context) throws Exception {
150         sPlugin = null;
151         super.stop(context);
152 
153         mRedColor.dispose();
154 
155         HierarchyViewerDirector director = HierarchyViewerDirector.getDirector();
156         director.stopListenForDevices();
157         director.stopDebugBridge();
158         director.terminate();
159     }
160 
161     /**
162      * Returns the shared instance
163      *
164      * @return the shared instance
165      */
getPlugin()166     public static HierarchyViewerPlugin getPlugin() {
167         return sPlugin;
168     }
169 
170     /**
171      * Prints a message, associated with a project to the specified stream
172      *
173      * @param stream The stream to write to
174      * @param tag The tag associated to the message. Can be null
175      * @param message The message to print.
176      */
printToStream(MessageConsoleStream stream, String tag, String message)177     private static synchronized void printToStream(MessageConsoleStream stream, String tag,
178             String message) {
179         String dateTag = getMessageTag(tag);
180 
181         stream.print(dateTag);
182         stream.println(message);
183     }
184 
185     /**
186      * Creates a string containing the current date/time, and the tag
187      *
188      * @param tag The tag associated to the message. Can be null
189      * @return The dateTag
190      */
getMessageTag(String tag)191     private static String getMessageTag(String tag) {
192         Calendar c = Calendar.getInstance();
193 
194         if (tag == null) {
195             return String.format("[%1$tF %1$tT]", c); //$NON-NLS-1$
196         }
197 
198         return String.format("[%1$tF %1$tT - %2$s]", c, tag); //$NON-NLS-1$
199     }
200 }
201