blob: b0f885ad60f8961829dd27e32f7f3401b7db64e0 [file] [log] [blame]
/*
* 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());
}
}
}
}