| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.ddmuilib; |
| |
| import com.android.ddmlib.AdbCommandRejectedException; |
| import com.android.ddmlib.IDevice; |
| import com.android.ddmlib.Log; |
| import com.android.ddmlib.RawImage; |
| import com.android.ddmlib.TimeoutException; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.SWTException; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.dnd.ImageTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.PaletteData; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Dialog; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.Calendar; |
| |
| |
| /** |
| * Gather a screen shot from the device and save it to a file. |
| */ |
| public class ScreenShotDialog extends Dialog { |
| |
| private Label mBusyLabel; |
| private Label mImageLabel; |
| private Button mSave; |
| private IDevice mDevice; |
| private RawImage mRawImage; |
| private Clipboard mClipboard; |
| |
| /** Number of 90 degree rotations applied to the current image */ |
| private int mRotateCount = 0; |
| |
| /** |
| * Create with default style. |
| */ |
| public ScreenShotDialog(Shell parent) { |
| this(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); |
| mClipboard = new Clipboard(parent.getDisplay()); |
| } |
| |
| /** |
| * Create with app-defined style. |
| */ |
| public ScreenShotDialog(Shell parent, int style) { |
| super(parent, style); |
| } |
| |
| /** |
| * Prepare and display the dialog. |
| * @param device The {@link IDevice} from which to get the screenshot. |
| */ |
| public void open(IDevice device) { |
| mDevice = device; |
| |
| Shell parent = getParent(); |
| Shell shell = new Shell(parent, getStyle()); |
| shell.setText("Device Screen Capture"); |
| |
| createContents(shell); |
| shell.pack(); |
| shell.open(); |
| |
| updateDeviceImage(shell); |
| |
| Display display = parent.getDisplay(); |
| while (!shell.isDisposed()) { |
| if (!display.readAndDispatch()) |
| display.sleep(); |
| } |
| |
| } |
| |
| /* |
| * Create the screen capture dialog contents. |
| */ |
| private void createContents(final Shell shell) { |
| GridData data; |
| |
| final int colCount = 5; |
| |
| shell.setLayout(new GridLayout(colCount, true)); |
| |
| // "refresh" button |
| Button refresh = new Button(shell, SWT.PUSH); |
| refresh.setText("Refresh"); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.widthHint = 80; |
| refresh.setLayoutData(data); |
| refresh.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| updateDeviceImage(shell); |
| // RawImage only allows us to rotate the image 90 degrees at the time, |
| // so to preserve the current rotation we must call getRotated() |
| // the same number of times the user has done it manually. |
| // TODO: improve the RawImage class. |
| for (int i=0; i < mRotateCount; i++) { |
| mRawImage = mRawImage.getRotated(); |
| } |
| updateImageDisplay(shell); |
| } |
| }); |
| |
| // "rotate" button |
| Button rotate = new Button(shell, SWT.PUSH); |
| rotate.setText("Rotate"); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.widthHint = 80; |
| rotate.setLayoutData(data); |
| rotate.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (mRawImage != null) { |
| mRotateCount = (mRotateCount + 1) % 4; |
| mRawImage = mRawImage.getRotated(); |
| updateImageDisplay(shell); |
| } |
| } |
| }); |
| |
| // "save" button |
| mSave = new Button(shell, SWT.PUSH); |
| mSave.setText("Save"); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.widthHint = 80; |
| mSave.setLayoutData(data); |
| mSave.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| saveImage(shell); |
| } |
| }); |
| |
| Button copy = new Button(shell, SWT.PUSH); |
| copy.setText("Copy"); |
| copy.setToolTipText("Copy the screenshot to the clipboard"); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.widthHint = 80; |
| copy.setLayoutData(data); |
| copy.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| copy(); |
| } |
| }); |
| |
| |
| // "done" button |
| Button done = new Button(shell, SWT.PUSH); |
| done.setText("Done"); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.widthHint = 80; |
| done.setLayoutData(data); |
| done.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| shell.close(); |
| } |
| }); |
| |
| // title/"capturing" label |
| mBusyLabel = new Label(shell, SWT.NONE); |
| mBusyLabel.setText("Preparing..."); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); |
| data.horizontalSpan = colCount; |
| mBusyLabel.setLayoutData(data); |
| |
| // space for the image |
| mImageLabel = new Label(shell, SWT.BORDER); |
| data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); |
| data.horizontalSpan = colCount; |
| mImageLabel.setLayoutData(data); |
| Display display = shell.getDisplay(); |
| mImageLabel.setImage(ImageLoader.createPlaceHolderArt( |
| display, 50, 50, display.getSystemColor(SWT.COLOR_BLUE))); |
| |
| |
| shell.setDefaultButton(done); |
| } |
| |
| /** |
| * Copies the content of {@link #mImageLabel} to the clipboard. |
| */ |
| private void copy() { |
| mClipboard.setContents( |
| new Object[] { |
| mImageLabel.getImage().getImageData() |
| }, new Transfer[] { |
| ImageTransfer.getInstance() |
| }); |
| } |
| |
| /** |
| * Captures a new image from the device, and display it. |
| */ |
| private void updateDeviceImage(Shell shell) { |
| mBusyLabel.setText("Capturing..."); // no effect |
| |
| shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); |
| |
| mRawImage = getDeviceImage(); |
| |
| updateImageDisplay(shell); |
| } |
| |
| /** |
| * Updates the display with {@link #mRawImage}. |
| * @param shell |
| */ |
| private void updateImageDisplay(Shell shell) { |
| Image image; |
| if (mRawImage == null) { |
| Display display = shell.getDisplay(); |
| image = ImageLoader.createPlaceHolderArt( |
| display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE)); |
| |
| mSave.setEnabled(false); |
| mBusyLabel.setText("Screen not available"); |
| } else { |
| // convert raw data to an Image. |
| PaletteData palette = new PaletteData( |
| mRawImage.getRedMask(), |
| mRawImage.getGreenMask(), |
| mRawImage.getBlueMask()); |
| |
| ImageData imageData = new ImageData(mRawImage.width, mRawImage.height, |
| mRawImage.bpp, palette, 1, mRawImage.data); |
| image = new Image(getParent().getDisplay(), imageData); |
| |
| mSave.setEnabled(true); |
| mBusyLabel.setText("Captured image:"); |
| } |
| |
| mImageLabel.setImage(image); |
| mImageLabel.pack(); |
| shell.pack(); |
| |
| // there's no way to restore old cursor; assume it's ARROW |
| shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); |
| } |
| |
| /** |
| * Grabs an image from an ADB-connected device and returns it as a {@link RawImage}. |
| */ |
| private RawImage getDeviceImage() { |
| try { |
| return mDevice.getScreenshot(); |
| } |
| catch (IOException ioe) { |
| Log.w("ddms", "Unable to get frame buffer: " + ioe.getMessage()); |
| return null; |
| } catch (TimeoutException e) { |
| Log.w("ddms", "Unable to get frame buffer: timeout "); |
| return null; |
| } catch (AdbCommandRejectedException e) { |
| Log.w("ddms", "Unable to get frame buffer: " + e.getMessage()); |
| return null; |
| } |
| } |
| |
| /* |
| * Prompt the user to save the image to disk. |
| */ |
| private void saveImage(Shell shell) { |
| FileDialog dlg = new FileDialog(shell, SWT.SAVE); |
| |
| Calendar now = Calendar.getInstance(); |
| String fileName = String.format("device-%tF-%tH%tM%tS.png", |
| now, now, now, now); |
| |
| dlg.setText("Save image..."); |
| dlg.setFileName(fileName); |
| |
| String lastDir = DdmUiPreferences.getStore().getString("lastImageSaveDir"); |
| if (lastDir.length() == 0) { |
| lastDir = DdmUiPreferences.getStore().getString("imageSaveDir"); |
| } |
| dlg.setFilterPath(lastDir); |
| dlg.setFilterNames(new String[] { |
| "PNG Files (*.png)" |
| }); |
| dlg.setFilterExtensions(new String[] { |
| "*.png" //$NON-NLS-1$ |
| }); |
| |
| fileName = dlg.open(); |
| if (fileName != null) { |
| // FileDialog.getFilterPath() does NOT always return the current |
| // directory of the FileDialog; on the Mac it sometimes just returns |
| // the value the dialog was initialized with. It does however return |
| // the full path as its return value, so just pick the path from |
| // there. |
| if (!fileName.endsWith(".png")) { |
| fileName = fileName + ".png"; |
| } |
| |
| String saveDir = new File(fileName).getParent(); |
| if (saveDir != null) { |
| DdmUiPreferences.getStore().setValue("lastImageSaveDir", saveDir); |
| } |
| |
| Log.d("ddms", "Saving image to " + fileName); |
| ImageData imageData = mImageLabel.getImage().getImageData(); |
| |
| try { |
| org.eclipse.swt.graphics.ImageLoader loader = |
| new org.eclipse.swt.graphics.ImageLoader(); |
| |
| loader.data = new ImageData[] { imageData }; |
| loader.save(fileName, SWT.IMAGE_PNG); |
| } |
| catch (SWTException e) { |
| Log.w("ddms", "Unable to save " + fileName + ": " + e.getMessage()); |
| } |
| } |
| } |
| |
| } |
| |