• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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.ide.eclipse.adt.internal.project;
18 
19 import com.android.ide.eclipse.adt.AndroidConstants;
20 
21 import org.eclipse.core.resources.IFolder;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.runtime.IPath;
24 import org.eclipse.jface.dialogs.MessageDialog;
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.widgets.Display;
27 import org.eclipse.swt.widgets.FileDialog;
28 import org.eclipse.swt.widgets.Shell;
29 
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.FileNotFoundException;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.util.jar.JarEntry;
36 import java.util.zip.ZipEntry;
37 import java.util.zip.ZipInputStream;
38 import java.util.zip.ZipOutputStream;
39 
40 /**
41  * Export helper for project.
42  */
43 public final class ExportHelper {
44 
45     private static IExportCallback sCallback;
46 
47     public interface IExportCallback {
startExportWizard(IProject project)48         void startExportWizard(IProject project);
49     }
50 
setCallback(IExportCallback callback)51     public static void setCallback(IExportCallback callback) {
52         sCallback = callback;
53     }
54 
startExportWizard(IProject project)55     public static void startExportWizard(IProject project) {
56         if (sCallback != null) {
57             sCallback.startExportWizard(project);
58         }
59     }
60 
61     /**
62      * Exports an <b>unsigned</b> version of the application created by the given project.
63      * @param project the project to export
64      */
exportProject(IProject project)65     public static void exportProject(IProject project) {
66         Shell shell = Display.getCurrent().getActiveShell();
67 
68         // get the java project to get the output directory
69         IFolder outputFolder = BaseProjectHelper.getOutputFolder(project);
70         if (outputFolder != null) {
71             IPath binLocation = outputFolder.getLocation();
72 
73             // make the full path to the package
74             String fileName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
75 
76             File file = new File(binLocation.toOSString() + File.separator + fileName);
77 
78             if (file.exists() == false || file.isFile() == false) {
79                 MessageDialog.openError(Display.getCurrent().getActiveShell(),
80                         "Android IDE Plug-in",
81                         String.format("Failed to export %1$s: %2$s doesn't exist!",
82                                 project.getName(), file.getPath()));
83                 return;
84             }
85 
86             // ok now pop up the file save window
87             FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
88 
89             fileDialog.setText("Export Project");
90             fileDialog.setFileName(fileName);
91 
92             String saveLocation = fileDialog.open();
93             if (saveLocation != null) {
94                 // get the stream from the original file
95 
96                 ZipInputStream zis = null;
97                 ZipOutputStream zos = null;
98                 FileInputStream input = null;
99                 FileOutputStream output = null;
100 
101                 try {
102                     input = new FileInputStream(file);
103                     zis = new ZipInputStream(input);
104 
105                     // get an output stream into the new file
106                     File saveFile = new File(saveLocation);
107                     output = new FileOutputStream(saveFile);
108                     zos = new ZipOutputStream(output);
109                 } catch (FileNotFoundException e) {
110                     // only the input/output stream are throwing this exception.
111                     // so we only have to close zis if output is the one that threw.
112                     if (zis != null) {
113                         try {
114                             zis.close();
115                         } catch (IOException e1) {
116                             // pass
117                         }
118                     }
119 
120                     MessageDialog.openError(shell, "Android IDE Plug-in",
121                             String.format("Failed to export %1$s: %2$s doesn't exist!",
122                                     project.getName(), file.getPath()));
123                     return;
124                 }
125 
126                 try {
127                     ZipEntry entry;
128 
129                     byte[] buffer = new byte[4096];
130 
131                     while ((entry = zis.getNextEntry()) != null) {
132                         String name = entry.getName();
133 
134                         // do not take directories or anything inside the META-INF folder since
135                         // we want to strip the signature.
136                         if (entry.isDirectory() || name.startsWith("META-INF/")) { //$NON-NL1$
137                             continue;
138                         }
139 
140                         ZipEntry newEntry;
141 
142                         // Preserve the STORED method of the input entry.
143                         if (entry.getMethod() == JarEntry.STORED) {
144                             newEntry = new JarEntry(entry);
145                         } else {
146                             // Create a new entry so that the compressed len is recomputed.
147                             newEntry = new JarEntry(name);
148                         }
149 
150                         // add the entry to the jar archive
151                         zos.putNextEntry(newEntry);
152 
153                         // read the content of the entry from the input stream, and write it into the archive.
154                         int count;
155                         while ((count = zis.read(buffer)) != -1) {
156                             zos.write(buffer, 0, count);
157                         }
158 
159                         // close the entry for this file
160                         zos.closeEntry();
161                         zis.closeEntry();
162                     }
163 
164                 } catch (IOException e) {
165                     MessageDialog.openError(shell, "Android IDE Plug-in",
166                             String.format("Failed to export %1$s: %2$s",
167                                     project.getName(), e.getMessage()));
168                 } finally {
169                     try {
170                         zos.close();
171                     } catch (IOException e) {
172                         // pass
173                     }
174                     try {
175                         zis.close();
176                     } catch (IOException e) {
177                         // pass
178                     }
179                 }
180 
181                 // this is unsigned export. Let's tell the developers to run zip align
182                 MessageDialog.openWarning(shell, "Android IDE Plug-in", String.format(
183                         "An unsigned package of the application was saved at\n%1$s\n\n" +
184                         "Before publishing the application you will need to:\n" +
185                         "- Sign the application with your release key,\n" +
186                         "- run zipalign on the signed package. ZipAlign is located in <SDK>/tools/\n\n" +
187                         "Aligning applications allows Android to use application resources\n" +
188                         "more efficiently.", saveLocation));
189 
190             }
191         } else {
192             MessageDialog.openError(shell, "Android IDE Plug-in",
193                     String.format("Failed to export %1$s: Could not get project output location",
194                             project.getName()));
195         }
196     }
197 }
198