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.SyncService; 20 import com.android.ddmlib.ClientData.IHprofDumpHandler; 21 import com.android.ddmlib.ClientData.IMethodProfilingHandler; 22 import com.android.ddmlib.SyncService.SyncResult; 23 import com.android.ddmuilib.SyncProgressMonitor; 24 25 import org.eclipse.core.runtime.IProgressMonitor; 26 import org.eclipse.jface.dialogs.MessageDialog; 27 import org.eclipse.jface.dialogs.ProgressMonitorDialog; 28 import org.eclipse.jface.operation.IRunnableWithProgress; 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 BaseFileHandler(Shell parentShell)49 public BaseFileHandler(Shell parentShell) { 50 mParentShell = parentShell; 51 } 52 getDialogTitle()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 */ promptAndPull(SyncService sync, String localFileName, String remoteFilePath, String title)67 protected SyncResult promptAndPull(SyncService sync, 68 String localFileName, String remoteFilePath, String title) 69 throws InvocationTargetException, InterruptedException { 70 FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); 71 72 fileDialog.setText(title); 73 fileDialog.setFileName(localFileName); 74 75 String localFilePath = fileDialog.open(); 76 if (localFilePath != null) { 77 return pull(sync, localFilePath, remoteFilePath); 78 } 79 80 return null; 81 } 82 83 /** 84 * Prompts the user for a save location and copies a temp file into it. 85 * <p/>This <strong>must</strong> be called from the UI Thread. 86 * @param localFileName The default local name 87 * @param tempFilePath The name of the temp file to copy. 88 * @param title The title of the File Save dialog. 89 * @return true if success, false on error or cancel. 90 */ promptAndSave(String localFileName, byte[] data, String title)91 protected boolean promptAndSave(String localFileName, byte[] data, String title) { 92 FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); 93 94 fileDialog.setText(title); 95 fileDialog.setFileName(localFileName); 96 97 String localFilePath = fileDialog.open(); 98 if (localFilePath != null) { 99 try { 100 saveFile(data, new File(localFilePath)); 101 return true; 102 } catch (IOException e) { 103 String errorMsg = e.getMessage(); 104 displayErrorInUiThread( 105 "Failed to save file '%1$s'%2$s", 106 localFilePath, 107 errorMsg != null ? ":\n" + errorMsg : "."); 108 } 109 } 110 111 return false; 112 } 113 114 /** 115 * Pulls a file off of a device. This displays a {@link ProgressMonitorDialog} and therefore 116 * must be run from the UI Thread. 117 * @param sync the {@link SyncService} to use to pull the file. 118 * @param localFilePath the path of the local file to create 119 * @param remoteFilePath the path of the remote file to pull 120 * @return the result of the sync as an instance of {@link SyncResult} 121 * @throws InvocationTargetException 122 * @throws InterruptedException 123 */ pull(final SyncService sync, final String localFilePath, final String remoteFilePath)124 protected SyncResult pull(final SyncService sync, final String localFilePath, 125 final String remoteFilePath) 126 throws InvocationTargetException, InterruptedException { 127 final SyncResult[] res = new SyncResult[1]; 128 new ProgressMonitorDialog(mParentShell).run(true, true, new IRunnableWithProgress() { 129 public void run(IProgressMonitor monitor) { 130 try { 131 res[0] = sync.pullFile(remoteFilePath, localFilePath, 132 new SyncProgressMonitor(monitor, String.format( 133 "Pulling %1$s from the device", remoteFilePath))); 134 } finally { 135 sync.close(); 136 } 137 } 138 }); 139 140 return res[0]; 141 } 142 143 /** 144 * Display an error message. 145 * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the 146 * UI Thread. This is safe to be called from a non-UI Thread. 147 * @param format the string to display 148 * @param args the string arguments 149 */ displayErrorInUiThread(final String format, final Object... args)150 protected void displayErrorInUiThread(final String format, final Object... args) { 151 mParentShell.getDisplay().asyncExec(new Runnable() { 152 public void run() { 153 MessageDialog.openError(mParentShell, getDialogTitle(), 154 String.format(format, args)); 155 } 156 }); 157 } 158 159 /** 160 * Display an error message. 161 * This must be called from the UI Thread. 162 * @param format the string to display 163 * @param args the string arguments 164 */ displayErrorFromUiThread(final String format, final Object... args)165 protected void displayErrorFromUiThread(final String format, final Object... args) { 166 MessageDialog.openError(mParentShell, getDialogTitle(), 167 String.format(format, args)); 168 } 169 170 /** 171 * Saves a given data into a temp file and returns its corresponding {@link File} object. 172 * @param data the data to save 173 * @return the File into which the data was written or null if it failed. 174 * @throws IOException 175 */ saveTempFile(byte[] data)176 protected File saveTempFile(byte[] data) throws IOException { 177 File f = File.createTempFile("ddms", null); 178 saveFile(data, f); 179 return f; 180 } 181 182 /** 183 * Saves some data into a given File. 184 * @param data the data to save 185 * @param output the file into the data is saved. 186 * @throws IOException 187 */ saveFile(byte[] data, File output)188 protected void saveFile(byte[] data, File output) throws IOException { 189 FileOutputStream fos = null; 190 try { 191 fos = new FileOutputStream(output); 192 fos.write(data); 193 } finally { 194 if (fos != null) { 195 fos.close(); 196 } 197 } 198 } 199 } 200