1 /* 2 * Copyright (C) 2009 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.ddmuilib.handler; 18 19 import com.android.ddmlib.SyncException; 20 import com.android.ddmlib.SyncService; 21 import com.android.ddmlib.TimeoutException; 22 import com.android.ddmlib.ClientData.IHprofDumpHandler; 23 import com.android.ddmlib.ClientData.IMethodProfilingHandler; 24 import com.android.ddmlib.SyncService.ISyncProgressMonitor; 25 import com.android.ddmuilib.SyncProgressHelper; 26 import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; 27 28 import org.eclipse.jface.dialogs.MessageDialog; 29 import org.eclipse.swt.SWT; 30 import org.eclipse.swt.widgets.Display; 31 import org.eclipse.swt.widgets.FileDialog; 32 import org.eclipse.swt.widgets.Shell; 33 34 import java.io.File; 35 import java.io.FileOutputStream; 36 import java.io.IOException; 37 import java.lang.reflect.InvocationTargetException; 38 39 /** 40 * Base handler class for handler dealing with files located on a device. 41 * 42 * @see IHprofDumpHandler 43 * @see IMethodProfilingHandler 44 */ 45 public abstract class BaseFileHandler { 46 47 protected final Shell mParentShell; 48 49 public BaseFileHandler(Shell parentShell) { 50 mParentShell = parentShell; 51 } 52 53 protected abstract String getDialogTitle(); 54 55 /** 56 * Prompts the user for a save location and pulls the remote files into this location. 57 * <p/>This <strong>must</strong> be called from the UI Thread. 58 * @param sync the {@link SyncService} to use to pull the file from the device 59 * @param localFileName The default local name 60 * @param remoteFilePath The name of the file to pull off of the device 61 * @param title The title of the File Save dialog. 62 * @return The result of the pull as a {@link SyncResult} object, or null if the sync 63 * didn't happen (canceled by the user). 64 * @throws InvocationTargetException 65 * @throws InterruptedException 66 * @throws SyncException if an error happens during the push of the package on the device. 67 * @throws IOException 68 */ 69 protected void promptAndPull(final SyncService sync, 70 String localFileName, final String remoteFilePath, String title) 71 throws InvocationTargetException, InterruptedException, SyncException, TimeoutException, 72 IOException { 73 FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); 74 75 fileDialog.setText(title); 76 fileDialog.setFileName(localFileName); 77 78 final String localFilePath = fileDialog.open(); 79 if (localFilePath != null) { 80 SyncProgressHelper.run(new SyncRunnable() { 81 public void run(ISyncProgressMonitor monitor) throws SyncException, IOException, 82 TimeoutException { 83 sync.pullFile(remoteFilePath, localFilePath, monitor); 84 } 85 86 public void close() { 87 sync.close(); 88 } 89 }, 90 String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); 91 } 92 } 93 94 /** 95 * Prompts the user for a save location and copies a temp file into it. 96 * <p/>This <strong>must</strong> be called from the UI Thread. 97 * @param localFileName The default local name 98 * @param tempFilePath The name of the temp file to copy. 99 * @param title The title of the File Save dialog. 100 * @return true if success, false on error or cancel. 101 */ 102 protected boolean promptAndSave(String localFileName, byte[] data, String title) { 103 FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); 104 105 fileDialog.setText(title); 106 fileDialog.setFileName(localFileName); 107 108 String localFilePath = fileDialog.open(); 109 if (localFilePath != null) { 110 try { 111 saveFile(data, new File(localFilePath)); 112 return true; 113 } catch (IOException e) { 114 String errorMsg = e.getMessage(); 115 displayErrorInUiThread( 116 "Failed to save file '%1$s'%2$s", 117 localFilePath, 118 errorMsg != null ? ":\n" + errorMsg : "."); 119 } 120 } 121 122 return false; 123 } 124 125 /** 126 * Display an error message. 127 * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the 128 * UI Thread. This is safe to be called from a non-UI Thread. 129 * @param format the string to display 130 * @param args the string arguments 131 */ 132 protected void displayErrorInUiThread(final String format, final Object... args) { 133 mParentShell.getDisplay().asyncExec(new Runnable() { 134 public void run() { 135 MessageDialog.openError(mParentShell, getDialogTitle(), 136 String.format(format, args)); 137 } 138 }); 139 } 140 141 /** 142 * Display an error message. 143 * This must be called from the UI Thread. 144 * @param format the string to display 145 * @param args the string arguments 146 */ 147 protected void displayErrorFromUiThread(final String format, final Object... args) { 148 MessageDialog.openError(mParentShell, getDialogTitle(), 149 String.format(format, args)); 150 } 151 152 /** 153 * Saves a given data into a temp file and returns its corresponding {@link File} object. 154 * @param data the data to save 155 * @return the File into which the data was written or null if it failed. 156 * @throws IOException 157 */ 158 protected File saveTempFile(byte[] data, String extension) throws IOException { 159 File f = File.createTempFile("ddms", extension); 160 saveFile(data, f); 161 return f; 162 } 163 164 /** 165 * Saves some data into a given File. 166 * @param data the data to save 167 * @param output the file into the data is saved. 168 * @throws IOException 169 */ 170 protected void saveFile(byte[] data, File output) throws IOException { 171 FileOutputStream fos = null; 172 try { 173 fos = new FileOutputStream(output); 174 fos.write(data); 175 } finally { 176 if (fos != null) { 177 fos.close(); 178 } 179 } 180 } 181 } 182