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