• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.screenshot;
18 
19 import com.android.ddmlib.AndroidDebugBridge;
20 import com.android.ddmlib.IDevice;
21 import com.android.ddmlib.Log;
22 import com.android.ddmlib.RawImage;
23 import com.android.ddmlib.TimeoutException;
24 import com.android.ddmlib.Log.ILogOutput;
25 import com.android.ddmlib.Log.LogLevel;
26 
27 import java.awt.image.BufferedImage;
28 import java.io.File;
29 import java.io.IOException;
30 
31 import javax.imageio.ImageIO;
32 
33 /**
34  * Connects to a device using ddmlib and dumps its event log as long as the device is connected.
35  */
36 public class Screenshot {
37 
main(String[] args)38     public static void main(String[] args) {
39         boolean device = false;
40         boolean emulator = false;
41         String serial = null;
42         String filepath = null;
43         boolean landscape = false;
44 
45         if (args.length == 0) {
46             printUsageAndQuit();
47         }
48 
49         // parse command line parameters.
50         int index = 0;
51         do {
52             String argument = args[index++];
53 
54             if ("-d".equals(argument)) {
55                 if (emulator || serial != null) {
56                     printAndExit("-d conflicts with -e and -s", false /* terminate */);
57                 }
58                 device = true;
59             } else if ("-e".equals(argument)) {
60                 if (device || serial != null) {
61                     printAndExit("-e conflicts with -d and -s", false /* terminate */);
62                 }
63                 emulator = true;
64             } else if ("-s".equals(argument)) {
65                 // quick check on the next argument.
66                 if (index == args.length) {
67                     printAndExit("Missing serial number after -s", false /* terminate */);
68                 }
69 
70                 if (device || emulator) {
71                     printAndExit("-s conflicts with -d and -e", false /* terminate */);
72                 }
73 
74                 serial = args[index++];
75             } else if ("-l".equals(argument)) {
76                 landscape = true;
77             } else {
78                 // get the filepath and break.
79                 filepath = argument;
80 
81                 // should not be any other device.
82                 if (index < args.length) {
83                     printAndExit("Too many arguments!", false /* terminate */);
84                 }
85             }
86         } while (index < args.length);
87 
88         /*
89          * If no command-line switches and no serial number was passed on the
90          * command-line, try to read a serial number from the shell environment.
91          */
92         if (!device && !emulator && serial == null) {
93             String envSerial = System.getenv("ANDROID_SERIAL");
94             if (envSerial != null) {
95                 serial = envSerial;
96             }
97         }
98 
99         if (filepath == null) {
100             printUsageAndQuit();
101         }
102 
103         Log.setLogOutput(new ILogOutput() {
104             public void printAndPromptLog(LogLevel logLevel, String tag, String message) {
105                 System.err.println(logLevel.getStringValue() + ":" + tag + ":" + message);
106             }
107 
108             public void printLog(LogLevel logLevel, String tag, String message) {
109                 System.err.println(logLevel.getStringValue() + ":" + tag + ":" + message);
110             }
111         });
112 
113         // init the lib
114         // [try to] ensure ADB is running
115         String adbLocation = System.getProperty("com.android.screenshot.bindir"); //$NON-NLS-1$
116         if (adbLocation != null && adbLocation.length() != 0) {
117             adbLocation += File.separator + "adb"; //$NON-NLS-1$
118         } else {
119             adbLocation = "adb"; //$NON-NLS-1$
120         }
121 
122         AndroidDebugBridge.init(false /* debugger support */);
123 
124         try {
125             AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(
126                     adbLocation, true /* forceNewBridge */);
127 
128             // we can't just ask for the device list right away, as the internal thread getting
129             // them from ADB may not be done getting the first list.
130             // Since we don't really want getDevices() to be blocking, we wait here manually.
131             int count = 0;
132             while (bridge.hasInitialDeviceList() == false) {
133                 try {
134                     Thread.sleep(100);
135                     count++;
136                 } catch (InterruptedException e) {
137                     // pass
138                 }
139 
140                 // let's not wait > 10 sec.
141                 if (count > 100) {
142                     System.err.println("Timeout getting device list!");
143                     return;
144                 }
145             }
146 
147             // now get the devices
148             IDevice[] devices = bridge.getDevices();
149 
150             if (devices.length == 0) {
151                 printAndExit("No devices found!", true /* terminate */);
152             }
153 
154             IDevice target = null;
155 
156             if (emulator || device) {
157                 for (IDevice d : devices) {
158                     // this test works because emulator and device can't both be true at the same
159                     // time.
160                     if (d.isEmulator() == emulator) {
161                         // if we already found a valid target, we print an error and return.
162                         if (target != null) {
163                             if (emulator) {
164                                 printAndExit("Error: more than one emulator launched!",
165                                         true /* terminate */);
166                             } else {
167                                 printAndExit("Error: more than one device connected!",true /* terminate */);
168                             }
169                         }
170                         target = d;
171                     }
172                 }
173             } else if (serial != null) {
174                 for (IDevice d : devices) {
175                     if (serial.equals(d.getSerialNumber())) {
176                         target = d;
177                         break;
178                     }
179                 }
180             } else {
181                 if (devices.length > 1) {
182                     printAndExit("Error: more than one emulator or device available!",
183                             true /* terminate */);
184                 }
185                 target = devices[0];
186             }
187 
188             if (target != null) {
189                 try {
190                     System.out.println("Taking screenshot from: " + target.getSerialNumber());
191                     getDeviceImage(target, filepath, landscape);
192                     System.out.println("Success.");
193                 } catch (IOException e) {
194                     e.printStackTrace();
195                 }
196             } else {
197                 printAndExit("Could not find matching device/emulator.", true /* terminate */);
198             }
199         } finally {
200             AndroidDebugBridge.terminate();
201         }
202     }
203 
204     /*
205      * Grab an image from an ADB-connected device.
206      */
getDeviceImage(IDevice device, String filepath, boolean landscape)207     private static void getDeviceImage(IDevice device, String filepath, boolean landscape)
208             throws IOException {
209         RawImage rawImage;
210 
211         try {
212             rawImage = device.getScreenshot();
213         } catch (TimeoutException e) {
214             printAndExit("Unable to get frame buffer: timeout", true /* terminate */);
215             return;
216         } catch (Exception ioe) {
217             printAndExit("Unable to get frame buffer: " + ioe.getMessage(), true /* terminate */);
218             return;
219         }
220 
221         // device/adb not available?
222         if (rawImage == null)
223             return;
224 
225         if (landscape) {
226             rawImage = rawImage.getRotated();
227         }
228 
229         // convert raw data to an Image
230         BufferedImage image = new BufferedImage(rawImage.width, rawImage.height,
231                 BufferedImage.TYPE_INT_ARGB);
232 
233         int index = 0;
234         int IndexInc = rawImage.bpp >> 3;
235         for (int y = 0 ; y < rawImage.height ; y++) {
236             for (int x = 0 ; x < rawImage.width ; x++) {
237                 int value = rawImage.getARGB(index);
238                 index += IndexInc;
239                 image.setRGB(x, y, value);
240             }
241         }
242 
243         if (!ImageIO.write(image, "png", new File(filepath))) {
244             throw new IOException("Failed to find png writer");
245         }
246     }
247 
printUsageAndQuit()248     private static void printUsageAndQuit() {
249         // 80 cols marker:  01234567890123456789012345678901234567890123456789012345678901234567890123456789
250         System.out.println("Usage: screenshot2 [-d | -e | -s SERIAL] [-l] OUT_FILE");
251         System.out.println("");
252         System.out.println("    -d      Uses the first device found.");
253         System.out.println("    -e      Uses the first emulator found.");
254         System.out.println("    -s      Targets the device by serial number.");
255         System.out.println("");
256         System.out.println("    -l      Rotate images for landscape mode.");
257         System.out.println("");
258 
259         System.exit(1);
260     }
261 
printAndExit(String message, boolean terminate)262     private static void printAndExit(String message, boolean terminate) {
263         System.out.println(message);
264         if (terminate) {
265             AndroidDebugBridge.terminate();
266         }
267         System.exit(1);
268     }
269 }
270