OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / sdk / ddms / app / src / com / android / ddms / DeviceCommandDialog.java
diff --git a/sdk/ddms/app/src/com/android/ddms/DeviceCommandDialog.java b/sdk/ddms/app/src/com/android/ddms/DeviceCommandDialog.java
new file mode 100644 (file)
index 0000000..ce6865d
--- /dev/null
@@ -0,0 +1,435 @@
+/* //device/tools/ddms/src/com/android/ddms/DeviceCommandDialog.java
+**
+** Copyright 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.ddms;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+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.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Execute a command on an ADB-attached device and save the output.
+ *
+ * There are several ways to do this.  One is to run a single command
+ * and show the output.  Another is to have several possible commands and
+ * let the user click a button next to the one (or ones) they want.  This
+ * currently uses the simple 1:1 form.
+ */
+public class DeviceCommandDialog extends Dialog {
+
+    public static final int DEVICE_STATE = 0;
+    public static final int APP_STATE = 1;
+    public static final int RADIO_STATE = 2;
+    public static final int LOGCAT = 3;
+
+    private String mCommand;
+    private String mFileName;
+
+    private Label mStatusLabel;
+    private Button mCancelDone;
+    private Button mSave;
+    private Text mText;
+    private Font mFont = null;
+    private boolean mCancel;
+    private boolean mFinished;
+
+
+    /**
+     * Create with default style.
+     */
+    public DeviceCommandDialog(String command, String fileName, Shell parent) {
+        // don't want a close button, but it seems hard to get rid of on GTK
+        // keep it on all platforms for consistency
+        this(command, fileName, parent,
+            SWT.DIALOG_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL | SWT.RESIZE);
+    }
+
+    /**
+     * Create with app-defined style.
+     */
+    public DeviceCommandDialog(String command, String fileName, Shell parent,
+        int style)
+    {
+        super(parent, style);
+        mCommand = command;
+        mFileName = fileName;
+    }
+
+    /**
+     * Prepare and display the dialog.
+     * @param currentDevice
+     */
+    public void open(IDevice currentDevice) {
+        Shell parent = getParent();
+        Shell shell = new Shell(parent, getStyle());
+        shell.setText("Remote Command");
+
+        mFinished = false;
+        mFont = findFont(shell.getDisplay());
+        createContents(shell);
+
+        // Getting weird layout behavior under Linux when Text is added --
+        // looks like text widget has min width of 400 when FILL_HORIZONTAL
+        // is used, and layout gets tweaked to force this.  (Might be even
+        // more with the scroll bars in place -- it wigged out when the
+        // file save dialog was invoked.)
+        shell.setMinimumSize(500, 200);
+        shell.setSize(800, 600);
+        shell.open();
+
+        executeCommand(shell, currentDevice);
+
+        Display display = parent.getDisplay();
+        while (!shell.isDisposed()) {
+            if (!display.readAndDispatch())
+                display.sleep();
+        }
+
+        if (mFont != null)
+            mFont.dispose();
+    }
+
+    /*
+     * Create a text widget to show the output and some buttons to
+     * manage things.
+     */
+    private void createContents(final Shell shell) {
+        GridData data;
+
+        shell.setLayout(new GridLayout(2, true));
+
+        shell.addListener(SWT.Close, new Listener() {
+            public void handleEvent(Event event) {
+                if (!mFinished) {
+                    Log.d("ddms", "NOT closing - cancelling command");
+                    event.doit = false;
+                    mCancel = true;
+                }
+            }
+        });
+
+        mStatusLabel = new Label(shell, SWT.NONE);
+        mStatusLabel.setText("Executing '" + shortCommandString() + "'");
+        data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+        data.horizontalSpan = 2;
+        mStatusLabel.setLayoutData(data);
+
+        mText = new Text(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+        mText.setEditable(false);
+        mText.setFont(mFont);
+        data = new GridData(GridData.FILL_BOTH);
+        data.horizontalSpan = 2;
+        mText.setLayoutData(data);
+
+        // "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) {
+                saveText(shell);
+            }
+        });
+        mSave.setEnabled(false);
+
+        // "cancel/done" button
+        mCancelDone = new Button(shell, SWT.PUSH);
+        mCancelDone.setText("Cancel");
+        data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
+        data.widthHint = 80;
+        mCancelDone.setLayoutData(data);
+        mCancelDone.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                if (!mFinished)
+                    mCancel = true;
+                else
+                    shell.close();
+            }
+        });
+    }
+
+    /*
+     * Figure out what font to use.
+     *
+     * Returns "null" if we can't figure it out, which SWT understands to
+     * mean "use default system font".
+     */
+    private Font findFont(Display display) {
+        String fontStr = PrefsDialog.getStore().getString("textOutputFont");
+        if (fontStr != null) {
+            FontData fdat = new FontData(fontStr);
+            if (fdat != null)
+                return new Font(display, fdat);
+        }
+        return null;
+    }
+
+
+    /*
+     * Callback class for command execution.
+     */
+    class Gatherer extends Thread implements IShellOutputReceiver {
+        public static final int RESULT_UNKNOWN = 0;
+        public static final int RESULT_SUCCESS = 1;
+        public static final int RESULT_FAILURE = 2;
+        public static final int RESULT_CANCELLED = 3;
+
+        private Shell mShell;
+        private String mCommand;
+        private Text mText;
+        private int mResult;
+        private IDevice mDevice;
+
+        /**
+         * Constructor; pass in the text widget that will receive the output.
+         * @param device
+         */
+        public Gatherer(Shell shell, IDevice device, String command, Text text) {
+            mShell = shell;
+            mDevice = device;
+            mCommand = command;
+            mText = text;
+            mResult = RESULT_UNKNOWN;
+
+            // this is in outer class
+            mCancel = false;
+        }
+
+        /**
+         * Thread entry point.
+         */
+        @Override
+        public void run() {
+
+            if (mDevice == null) {
+                Log.w("ddms", "Cannot execute command: no device selected.");
+                mResult = RESULT_FAILURE;
+            } else {
+                try {
+                    mDevice.executeShellCommand(mCommand, this);
+                    if (mCancel)
+                        mResult = RESULT_CANCELLED;
+                    else
+                        mResult = RESULT_SUCCESS;
+                }
+                catch (IOException ioe) {
+                    Log.w("ddms", "Remote exec failed: " + ioe.getMessage());
+                    mResult = RESULT_FAILURE;
+                } catch (TimeoutException e) {
+                    Log.w("ddms", "Remote exec failed: " + e.getMessage());
+                    mResult = RESULT_FAILURE;
+                } catch (AdbCommandRejectedException e) {
+                    Log.w("ddms", "Remote exec failed: " + e.getMessage());
+                    mResult = RESULT_FAILURE;
+                } catch (ShellCommandUnresponsiveException e) {
+                    Log.w("ddms", "Remote exec failed: " + e.getMessage());
+                    mResult = RESULT_FAILURE;
+                }
+            }
+
+            mShell.getDisplay().asyncExec(new Runnable() {
+                public void run() {
+                    updateForResult(mResult);
+                }
+            });
+        }
+
+        /**
+         * Called by executeRemoteCommand().
+         */
+        public void addOutput(byte[] data, int offset, int length) {
+
+            Log.v("ddms", "received " + length + " bytes");
+            try {
+                final String text;
+                text = new String(data, offset, length, "ISO-8859-1");
+
+                // add to text widget; must do in UI thread
+                mText.getDisplay().asyncExec(new Runnable() {
+                    public void run() {
+                        mText.append(text);
+                    }
+                });
+            }
+            catch (UnsupportedEncodingException uee) {
+                uee.printStackTrace();      // not expected
+            }
+        }
+
+        public void flush() {
+            // nothing to flush.
+        }
+
+        /**
+         * Called by executeRemoteCommand().
+         */
+        public boolean isCancelled() {
+            return mCancel;
+        }
+    };
+
+    /*
+     * Execute a remote command, add the output to the text widget, and
+     * update controls.
+     *
+     * We have to run the command in a thread so that the UI continues
+     * to work.
+     */
+    private void executeCommand(Shell shell, IDevice device) {
+        Gatherer gath = new Gatherer(shell, device, commandString(), mText);
+        gath.start();
+    }
+
+    /*
+     * Update the controls after the remote operation completes.  This
+     * must be called from the UI thread.
+     */
+    private void updateForResult(int result) {
+        if (result == Gatherer.RESULT_SUCCESS) {
+            mStatusLabel.setText("Successfully executed '"
+                + shortCommandString() + "'");
+            mSave.setEnabled(true);
+        } else if (result == Gatherer.RESULT_CANCELLED) {
+            mStatusLabel.setText("Execution cancelled; partial results below");
+            mSave.setEnabled(true);     // save partial
+        } else if (result == Gatherer.RESULT_FAILURE) {
+            mStatusLabel.setText("Failed");
+        }
+        mStatusLabel.pack();
+        mCancelDone.setText("Done");
+        mFinished = true;
+    }
+
+    /*
+     * Allow the user to save the contents of the text dialog.
+     */
+    private void saveText(Shell shell) {
+        FileDialog dlg = new FileDialog(shell, SWT.SAVE);
+        String fileName;
+
+        dlg.setText("Save output...");
+        dlg.setFileName(defaultFileName());
+        dlg.setFilterPath(PrefsDialog.getStore().getString("lastTextSaveDir"));
+        dlg.setFilterNames(new String[] {
+            "Text Files (*.txt)"
+        });
+        dlg.setFilterExtensions(new String[] {
+            "*.txt"
+        });
+
+        fileName = dlg.open();
+        if (fileName != null) {
+            PrefsDialog.getStore().setValue("lastTextSaveDir",
+                                            dlg.getFilterPath());
+
+            Log.d("ddms", "Saving output to " + fileName);
+
+            /*
+             * Convert to 8-bit characters.
+             */
+            String text = mText.getText();
+            byte[] ascii;
+            try {
+                ascii = text.getBytes("ISO-8859-1");
+            }
+            catch (UnsupportedEncodingException uee) {
+                uee.printStackTrace();
+                ascii = new byte[0];
+            }
+
+            /*
+             * Output data, converting CRLF to LF.
+             */
+            try {
+                int length = ascii.length;
+
+                FileOutputStream outFile = new FileOutputStream(fileName);
+                BufferedOutputStream out = new BufferedOutputStream(outFile);
+                for (int i = 0; i < length; i++) {
+                    if (i < length-1 &&
+                        ascii[i] == 0x0d && ascii[i+1] == 0x0a)
+                    {
+                        continue;
+                    }
+                    out.write(ascii[i]);
+                }
+                out.close();        // flush buffer, close file
+            }
+            catch (IOException ioe) {
+                Log.w("ddms", "Unable to save " + fileName + ": " + ioe);
+            }
+        }
+    }
+
+
+    /*
+     * Return the shell command we're going to use.
+     */
+    private String commandString() {
+        return mCommand;
+
+    }
+
+    /*
+     * Return a default filename for the "save" command.
+     */
+    private String defaultFileName() {
+        return mFileName;
+    }
+
+    /*
+     * Like commandString(), but length-limited.
+     */
+    private String shortCommandString() {
+        String str = commandString();
+        if (str.length() > 50)
+            return str.substring(0, 50) + "...";
+        else
+            return str;
+    }
+}
+