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.ClientData.IHprofDumpHandler; 20 import com.android.ddmlib.ClientData.IMethodProfilingHandler; 21 import com.android.ddmlib.SyncException; 22 import com.android.ddmlib.SyncService; 23 import com.android.ddmlib.SyncService.ISyncProgressMonitor; 24 import com.android.ddmlib.TimeoutException; 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 @Override 82 public void run(ISyncProgressMonitor monitor) throws SyncException, IOException, 83 TimeoutException { 84 sync.pullFile(remoteFilePath, localFilePath, monitor); 85 } 86 87 @Override 88 public void close() { 89 sync.close(); 90 } 91 }, 92 String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); 93 } 94 } 95 96 /** 97 * Prompts the user for a save location and copies a temp file into it. 98 * <p/>This <strong>must</strong> be called from the UI Thread. 99 * @param localFileName The default local name 100 * @param tempFilePath The name of the temp file to copy. 101 * @param title The title of the File Save dialog. 102 * @return true if success, false on error or cancel. 103 */ 104 protected boolean promptAndSave(String localFileName, byte[] data, String title) { 105 FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); 106 107 fileDialog.setText(title); 108 fileDialog.setFileName(localFileName); 109 110 String localFilePath = fileDialog.open(); 111 if (localFilePath != null) { 112 try { 113 saveFile(data, new File(localFilePath)); 114 return true; 115 } catch (IOException e) { 116 String errorMsg = e.getMessage(); 117 displayErrorInUiThread( 118 "Failed to save file '%1$s'%2$s", 119 localFilePath, 120 errorMsg != null ? ":\n" + errorMsg : "."); 121 } 122 } 123 124 return false; 125 } 126 127 /** 128 * Display an error message. 129 * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the 130 * UI Thread. This is safe to be called from a non-UI Thread. 131 * @param format the string to display 132 * @param args the string arguments 133 */ 134 protected void displayErrorInUiThread(final String format, final Object... args) { 135 mParentShell.getDisplay().asyncExec(new Runnable() { 136 @Override 137 public void run() { 138 MessageDialog.openError(mParentShell, getDialogTitle(), 139 String.format(format, args)); 140 } 141 }); 142 } 143 144 /** 145 * Display an error message. 146 * This must be called from the UI Thread. 147 * @param format the string to display 148 * @param args the string arguments 149 */ 150 protected void displayErrorFromUiThread(final String format, final Object... args) { 151 MessageDialog.openError(mParentShell, getDialogTitle(), 152 String.format(format, args)); 153 } 154 155 /** 156 * Saves a given data into a temp file and returns its corresponding {@link File} object. 157 * @param data the data to save 158 * @return the File into which the data was written or null if it failed. 159 * @throws IOException 160 */ 161 protected File saveTempFile(byte[] data, String extension) throws IOException { 162 File f = File.createTempFile("ddms", extension); 163 saveFile(data, f); 164 return f; 165 } 166 167 /** 168 * Saves some data into a given File. 169 * @param data the data to save 170 * @param output the file into the data is saved. 171 * @throws IOException 172 */ 173 protected void saveFile(byte[] data, File output) throws IOException { 174 FileOutputStream fos = null; 175 try { 176 fos = new FileOutputStream(output); 177 fos.write(data); 178 } finally { 179 if (fos != null) { 180 fos.close(); 181 } 182 } 183 } 184 } 185