1818import java .awt .event .ActionListener ;
1919import java .beans .PropertyChangeEvent ;
2020import java .beans .PropertyChangeListener ;
21+ import java .io .File ;
22+ import java .io .FileOutputStream ;
2123import java .io .IOException ;
24+ import java .io .InputStream ;
2225import java .net .URL ;
26+ import java .net .URLConnection ;
2327
2428public class SDKDownloader extends JFrame implements PropertyChangeListener {
2529
26- private static final String URL_SDK_TOOLS_WINDOWS = "http://dl.google.com/android/android-sdk_r23-windows.zip" ;
27- private static final String URL_SDK_TOOLS_MACOS = "http://dl.google.com/android/android-sdk_r23-macosx.zip" ;
28- private static final String URL_SDK_TOOLS_LINUX = "http://dl.google.com/android/android-sdk_r23-linux.tgz" ;
29-
3030 private static final String URL_REPOSITORY = "https://dl-ssl.google.com/android/repository/repository-10.xml" ;
3131 private static final String URL_REPOSITORY_FOLDER = "http://dl-ssl.google.com/android/repository/" ;
3232
3333 private static final String PLATFORM_API_LEVEL = "10" ;
3434
35+ public static final String PROPERTY_CHANGE_EVENT_TOTAL = "total" ;
36+ private static final String PROPERTY_CHANGE_EVENT_DOWNLOADED = "downloaded" ;
37+
38+ JProgressBar progressBar ;
39+ JLabel downloadedTextArea ;
40+
41+ private int totalSize = 0 ;
42+
3543 class SDKUrlHolder {
36- public String platformToolsUrl , buildToolsUrl , platformUrl ;
44+ public String platformToolsUrl , buildToolsUrl , platformUrl , toolsUrl ;
45+ public String platformToolsFilename , buildToolsFilename , platformFilename , toolsFilename ;
46+ public int totalSize = 0 ;
3747 }
3848
3949 class SDKDownloadTask extends SwingWorker {
4050
51+ private int downloadedSize = 0 , totalSize = 0 ;
52+ private int BUFFER_SIZE = 4096 ;
53+
4154 @ Override
4255 protected Object doInBackground () throws Exception {
4356 String hostOs = getOsString ();
57+ File modeFolder = new File (Base .getSketchbookModesFolder () + "/AndroidMode" );
58+
59+ // creating sdk root folder
60+ File sdkFolder = new File (modeFolder , "sdk" );
61+ if (!sdkFolder .exists ()) sdkFolder .mkdir ();
62+
63+ // creating temp folder for downloaded zip packages
64+ File tempFolder = new File (modeFolder , "temp" );
65+ if (!tempFolder .exists ()) tempFolder .mkdir ();
66+
67+ // creating sdk folders
68+ File toolsFolder = new File (sdkFolder , "tools" ); toolsFolder .mkdir ();
69+ File platformToolsFolder = new File (sdkFolder , "platform-tools" ); platformToolsFolder .mkdir ();
70+ File buildToolsFolder = new File (sdkFolder , "build-tools" ); buildToolsFolder .mkdir ();
71+ File platformsFoolder = new File (sdkFolder , "platforms" ); platformsFoolder .mkdir ();
72+ File platformFolder = new File (platformsFoolder , "android-10" ); platformFolder .mkdir ();
73+
4474 try {
4575 SDKUrlHolder downloadUrls = getDownloadUrls (URL_REPOSITORY , hostOs );
76+ firePropertyChange (PROPERTY_CHANGE_EVENT_TOTAL , 0 , downloadUrls .totalSize );
77+ totalSize = downloadUrls .totalSize ;
78+
79+ // tools
80+ File downloadedTools = new File (tempFolder , downloadUrls .toolsFilename );
81+ downloadFile (downloadUrls .toolsUrl , downloadedTools );
82+
83+ // platform-tools
84+ File downloadedPlatformTools = new File (tempFolder , downloadUrls .platformToolsFilename );
85+ downloadFile (downloadUrls .platformToolsUrl , downloadedPlatformTools );
86+
87+ // build-tools
88+ File downloadedBuildTools = new File (tempFolder , downloadUrls .buildToolsFilename );
89+ downloadFile (downloadUrls .buildToolsUrl , downloadedBuildTools );
90+
91+ // platform
92+ File downloadedPlatform = new File (tempFolder , downloadUrls .platformFilename );
93+ downloadFile (downloadUrls .platformUrl , downloadedPlatform );
4694 } catch (ParserConfigurationException e ) {
47- // TODO Handle exceptions here somehow (ie show error message)
95+ // TODO Handle exceptions here somehow (ie show error message) and handle at least mkdir() results (above)
4896 e .printStackTrace ();
4997 } catch (IOException e ) {
5098 e .printStackTrace ();
@@ -59,6 +107,27 @@ protected void done() {
59107 super .done ();
60108 }
61109
110+ private void downloadFile (String urlString , File saveTo ) throws IOException {
111+ URL url = new URL (urlString );
112+ URLConnection conn = url .openConnection ();
113+
114+ InputStream inputStream = conn .getInputStream ();
115+ FileOutputStream outputStream = new FileOutputStream (saveTo );
116+
117+ byte [] b = new byte [BUFFER_SIZE ];
118+ int count ;
119+ while ((count = inputStream .read (b )) >= 0 ) {
120+ outputStream .write (b , 0 , count );
121+ downloadedSize += count ;
122+
123+ firePropertyChange (PROPERTY_CHANGE_EVENT_DOWNLOADED , 0 , downloadedSize );
124+ }
125+ outputStream .flush (); outputStream .close (); inputStream .close ();
126+
127+ inputStream .close ();
128+ outputStream .close ();
129+ }
130+
62131 private String getOsString () {
63132 if (Base .isWindows ()) {
64133 return "windows" ;
@@ -84,6 +153,8 @@ private SDKUrlHolder getDownloadUrls(String repositoryUrl, String requiredHostOs
84153 Node archiveListItem = ((Element ) platform ).getElementsByTagName ("sdk:archives" ).item (0 );
85154 Node archiveItem = ((Element ) archiveListItem ).getElementsByTagName ("sdk:archive" ).item (0 );
86155 urlHolder .platformUrl = ((Element ) archiveItem ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ();
156+ urlHolder .platformFilename = urlHolder .platformUrl .split ("/" )[urlHolder .platformUrl .split ("/" ).length -1 ];
157+ urlHolder .totalSize += Integer .parseInt (((Element ) archiveItem ).getElementsByTagName ("sdk:size" ).item (0 ).getTextContent ());
87158 }
88159 }
89160
@@ -95,9 +166,9 @@ private SDKUrlHolder getDownloadUrls(String repositoryUrl, String requiredHostOs
95166 Node archive = archiveList .item (i );
96167 String hostOs = ((Element ) archive ).getElementsByTagName ("sdk:host-os" ).item (0 ).getTextContent ();
97168 if (hostOs .equals (requiredHostOs )) {
98- String platformToolsUrl = (((Element ) archive ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ());
99- if (! platformToolsUrl . startsWith ( "http" )) platformToolsUrl = URL_REPOSITORY_FOLDER + platformToolsUrl ;
100- urlHolder .platformToolsUrl = platformToolsUrl ;
169+ urlHolder . platformToolsFilename = (((Element ) archive ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ());
170+ urlHolder . platformToolsUrl = URL_REPOSITORY_FOLDER + urlHolder . platformToolsFilename ;
171+ urlHolder .totalSize += Integer . parseInt ((( Element ) archive ). getElementsByTagName ( "sdk:size" ). item ( 0 ). getTextContent ()) ;
101172 break ;
102173 }
103174 }
@@ -110,9 +181,24 @@ private SDKUrlHolder getDownloadUrls(String repositoryUrl, String requiredHostOs
110181 Node archive = archiveList .item (i );
111182 String hostOs = ((Element ) archive ).getElementsByTagName ("sdk:host-os" ).item (0 ).getTextContent ();
112183 if (hostOs .equals (requiredHostOs )) {
113- String buildToolsUrl = (((Element ) archive ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ());
114- if (!buildToolsUrl .startsWith ("http" )) buildToolsUrl = URL_REPOSITORY_FOLDER + buildToolsUrl ;
115- urlHolder .buildToolsUrl = buildToolsUrl ;
184+ urlHolder .buildToolsFilename = (((Element ) archive ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ());
185+ urlHolder .buildToolsUrl = URL_REPOSITORY_FOLDER + urlHolder .buildToolsFilename ;
186+ urlHolder .totalSize += Integer .parseInt (((Element ) archive ).getElementsByTagName ("sdk:size" ).item (0 ).getTextContent ());
187+ break ;
188+ }
189+ }
190+
191+ // tools
192+ Node toolsItem = doc .getElementsByTagName ("sdk:tool" ).item (0 );
193+ archiveListItem = ((Element ) toolsItem ).getElementsByTagName ("sdk:archives" ).item (0 );
194+ archiveList = ((Element ) archiveListItem ).getElementsByTagName ("sdk:archive" );
195+ for (int i = 0 ; i < archiveList .getLength (); i ++) {
196+ Node archive = archiveList .item (i );
197+ String hostOs = ((Element ) archive ).getElementsByTagName ("sdk:host-os" ).item (0 ).getTextContent ();
198+ if (hostOs .equals (requiredHostOs )) {
199+ urlHolder .toolsFilename = (((Element ) archive ).getElementsByTagName ("sdk:url" ).item (0 ).getTextContent ());
200+ urlHolder .toolsUrl = URL_REPOSITORY_FOLDER + urlHolder .toolsFilename ;
201+ urlHolder .totalSize += Integer .parseInt (((Element ) archive ).getElementsByTagName ("sdk:size" ).item (0 ).getTextContent ());
116202 break ;
117203 }
118204 }
@@ -123,7 +209,24 @@ private SDKUrlHolder getDownloadUrls(String repositoryUrl, String requiredHostOs
123209
124210 @ Override
125211 public void propertyChange (PropertyChangeEvent evt ) {
212+ if (evt .getPropertyName ().equals (PROPERTY_CHANGE_EVENT_TOTAL )) {
213+ progressBar .setIndeterminate (false );
214+ totalSize = (Integer ) evt .getNewValue ();
215+ progressBar .setMaximum (totalSize );
216+ } else if (evt .getPropertyName ().equals (PROPERTY_CHANGE_EVENT_DOWNLOADED )) {
217+ downloadedTextArea .setText (humanReadableByteCount ((Integer ) evt .getNewValue (), true )
218+ + " / " + humanReadableByteCount (totalSize , true ));
219+ progressBar .setValue ((Integer ) evt .getNewValue ());
220+ }
221+ }
126222
223+ // http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
224+ public static String humanReadableByteCount (long bytes , boolean si ) {
225+ int unit = si ? 1000 : 1024 ;
226+ if (bytes < unit ) return bytes + " B" ;
227+ int exp = (int ) (Math .log (bytes ) / Math .log (unit ));
228+ String pre = (si ? "kMGTPE" : "KMGTPE" ).charAt (exp -1 ) + (si ? "" : "i" );
229+ return String .format ("%.1f %sB" , bytes / Math .pow (unit , exp ), pre );
127230 }
128231
129232 public SDKDownloader () {
@@ -152,12 +255,17 @@ private void createLayout() {
152255 textarea .setAlignmentX (LEFT_ALIGNMENT );
153256 pain .add (textarea );
154257
155- JProgressBar progressBar = new JProgressBar (0 , 100 );
258+ progressBar = new JProgressBar (0 , 100 );
156259 progressBar .setValue (0 );
157260 progressBar .setStringPainted (true );
158261 progressBar .setIndeterminate (true );
262+ progressBar .setBorder (new EmptyBorder (10 , 10 , 10 , 10 ) );
159263 pain .add (progressBar );
160264
265+ downloadedTextArea = new JLabel ("" );
266+ downloadedTextArea .setAlignmentX (LEFT_ALIGNMENT );
267+ pain .add (downloadedTextArea );
268+
161269 // buttons
162270 JPanel buttons = new JPanel ();
163271// buttons.setPreferredSize(new Dimension(400, 35));
@@ -176,7 +284,7 @@ private void createLayout() {
176284// Box buttons = Box.createHorizontalBox();
177285 buttons .setAlignmentX (LEFT_ALIGNMENT );
178286 JButton cancelButton = new JButton ("Cancel download" );
179- Dimension dim = new Dimension (Preferences .BUTTON_WIDTH ,
287+ Dimension dim = new Dimension (Preferences .BUTTON_WIDTH * 2 ,
180288 cancelButton .getPreferredSize ().height );
181289
182290 cancelButton .setPreferredSize (dim );
0 commit comments