@@ -71,9 +71,6 @@ class AndroidSDK {
71
71
72
72
private static final String SDK_DOWNLOAD_URL =
73
73
"https://developer.android.com/studio/index.html#downloads" ;
74
-
75
- private static final String SDK_LICENSE_URL =
76
- "https://developer.android.com/studio/terms.html" ;
77
74
78
75
private static final String USE_ENV_SDK_TITLE = "Found an Android SDK!" ;
79
76
private static final String USE_ENV_SDK_MESSAGE =
@@ -169,6 +166,24 @@ class AndroidSDK {
169
166
"\" >these instructions</a>.<br><br>" +
170
167
"The installation files are available in this folder:</br>" ;
171
168
169
+ private static final String SDK_LICENSE_URL =
170
+ "https://developer.android.com/studio/terms.html" ;
171
+
172
+ private static final String SDK_LICENSE_TITLE = "Accept SDK license?" ;
173
+
174
+ private static final String SDK_LICENSE_MESSAGE =
175
+ "You need to accept the terms of the Android SDK license from Google in " +
176
+ "order to use the SDK. Read the license <a href=\" " + SDK_LICENSE_URL +
177
+ "\" >from here</a>." ;
178
+
179
+ private static final String NO_SDK_LICENSE_TITLE = "SDK license not accepted" ;
180
+
181
+ private static final String NO_SDK_LICENSE_MESSAGE =
182
+ "The Android SDK was installed, but will not be usable. You can accept " +
183
+ "the license at a later time by opening a terminal, changing to the " +
184
+ "SDK folder, and then running the following command:<br><br>" +
185
+ "tools/bin/sdkmanager --licenses" ;
186
+
172
187
private static final int NO_ERROR = 0 ;
173
188
private static final int SKIP_ENV_SDK = 1 ;
174
189
private static final int MISSING_SDK = 2 ;
@@ -223,8 +238,8 @@ public AndroidSDK(File folder) throws BadSDKException, IOException {
223
238
throw new BadSDKException ("There is no support library folder in " + folder );
224
239
}
225
240
226
- avdManager = findAvdManager (new File (tools , "bin" ));
227
- sdkManager = findSdkManager (new File (tools , "bin" ));
241
+ avdManager = findCliTool (new File (tools , "bin" ), "avdmanager" );
242
+ sdkManager = findCliTool (new File (tools , "bin" ), "sdkmanager" );
228
243
229
244
String path = Platform .getenv ("PATH" );
230
245
@@ -353,59 +368,45 @@ public File getZipAlignTool() {
353
368
}
354
369
355
370
356
- public void acceptLicenses () {
357
- ArrayList <String > commands = new ArrayList <String >();
358
- commands .add (sdkManager .getAbsolutePath ());
359
- commands .add ("--licenses" );
360
- ProcessBuilder pb = new ProcessBuilder (commands );
371
+ // Write to the process input, so the licenses will be accepted. In
372
+ // principle, We only need 7 'y', one for the 'yes' to the first
373
+ // 'review licenses?' question, the rest for the 6 licenses, but adding
374
+ // 10 just in case, having more does not cause any trouble.
375
+ private static final String response = "y\n y\n y\n y\n y\n y\n y\n y\n y\n y\n " ;
376
+
377
+ private void acceptLicenses () {
378
+ ProcessBuilder pb = new ProcessBuilder (sdkManager .getAbsolutePath (),
379
+ "--licenses" );
361
380
pb .redirectErrorStream (true );
362
381
try {
363
-
364
- Process prs = pb .start ();
365
- OutputStream writeTo = prs .getOutputStream ();
366
- for (int i = 0 ; i < 7 ; i ++) {
367
- Thread inThread = new Thread (new In (prs .getInputStream ()));
368
- inThread .start ();
369
- Thread .sleep (100 );
370
- writeTo .write ("y\n " .getBytes ());
371
- writeTo .flush ();
382
+ Process process = pb .start ();
383
+ final OutputStream os = process .getOutputStream ();
384
+ final InputStream is = process .getInputStream ();
385
+ // Read the process output, otherwise read() will block and wait for new
386
+ // data to read
387
+ new Thread (new Runnable () {
388
+ public void run () {
389
+ byte [] b = new byte [1024 ];
390
+ try {
391
+ while (is .read (b ) != -1 ) { }
392
+ is .close ();
393
+ } catch (IOException e ) {
394
+ e .printStackTrace ();
395
+ }
372
396
}
373
-
374
- writeTo .close ();
375
-
397
+ }, "AndroidSDK: reading licenses" ).start ();
398
+ Thread .sleep (1000 );
399
+ os .write (response .getBytes ());
400
+ os .flush ();
401
+ os .close ();
376
402
} catch (IOException e ) {
377
- e .printStackTrace ();
403
+ e .printStackTrace ();
378
404
} catch (InterruptedException e ) {
379
- // TODO Auto-generated catch block
380
405
e .printStackTrace ();
381
- }
406
+ }
382
407
}
383
408
384
409
385
- class In implements Runnable {
386
- private InputStream is ;
387
-
388
- public In (InputStream is ) {
389
- this .is = is ;
390
- }
391
-
392
- @ Override
393
- public void run () {
394
- byte [] b = new byte [1024 ];
395
- int size = 0 ;
396
- try {
397
- while ((size = is .read (b )) != -1 ) {
398
- System .err .println (new String (b ));
399
- }
400
- is .close ();
401
- } catch (IOException e ) {
402
- // TODO Auto-generated catch block
403
- e .printStackTrace ();
404
- }
405
-
406
- }
407
- }
408
-
409
410
static public File getHAXMInstallerFolder () {
410
411
String sdkPrefsPath = Preferences .get ("android.sdk.path" );
411
412
File sdkPath = new File (sdkPrefsPath );
@@ -425,26 +426,17 @@ static public File getGoogleDriverFolder() {
425
426
* for the SDK installation. Also figures out the name of android/android.bat
426
427
* so that it can be called explicitly.
427
428
*/
428
- private static File findAvdManager (final File tools ) throws BadSDKException {
429
- if (new File (tools , "avdmanager.bat" ).exists ()) {
430
- return new File (tools , "avdmanager.bat" );
429
+ private static File findCliTool (final File tools , String name )
430
+ throws BadSDKException {
431
+ if (new File (tools , name + ".bat" ).exists ()) {
432
+ return new File (tools , name + ".bat" );
431
433
}
432
- if (new File (tools , "avdmanager" ).exists ()) {
433
- return new File (tools , "avdmanager" );
434
+ if (new File (tools , name ).exists ()) {
435
+ return new File (tools , name );
434
436
}
435
- throw new BadSDKException ("Cannot find avdmanager in " + tools );
437
+ throw new BadSDKException ("Cannot find " + name + " in " + tools );
436
438
}
437
-
438
439
439
- private static File findSdkManager (final File tools ) throws BadSDKException {
440
- if (new File (tools , "sdkmanager.bat" ).exists ()) {
441
- return new File (tools , "sdkmanager.bat" );
442
- }
443
- if (new File (tools , "sdkmanager" ).exists ()) {
444
- return new File (tools , "sdkmanager" );
445
- }
446
- throw new BadSDKException ("Cannot find sdkdmanager in " + tools );
447
- }
448
440
449
441
/**
450
442
* Check for a set android.sdk.path preference. If the pref
@@ -470,7 +462,6 @@ public static AndroidSDK load(boolean checkEnvSDK, Frame editor) throws IOExcept
470
462
try {
471
463
final AndroidSDK androidSDK = new AndroidSDK (new File (sdkPrefsPath ));
472
464
Preferences .set ("android.sdk.path" , sdkPrefsPath );
473
- androidSDK .acceptLicenses ();
474
465
return androidSDK ;
475
466
} catch (final BadSDKException badPref ) {
476
467
Preferences .unset ("android.sdk.path" );
@@ -504,8 +495,7 @@ public static AndroidSDK load(boolean checkEnvSDK, Frame editor) throws IOExcept
504
495
// means we just installed the mode for the first time, so we show a
505
496
// welcome message with some useful info.
506
497
AndroidUtil .showMessage (SDK_EXISTS_TITLE , SDK_EXISTS_MESSAGE );
507
-
508
- androidSDK .acceptLicenses ();
498
+
509
499
return androidSDK ;
510
500
} catch (final BadSDKException badEnv ) {
511
501
Preferences .unset ("android.sdk.path" );
@@ -575,15 +565,19 @@ static public AndroidSDK download(final Frame editor, final AndroidMode androidM
575
565
if (sdk == null ) {
576
566
throw new BadSDKException ("SDK could not be downloaded" );
577
567
}
578
-
579
- String msg = SDK_INSTALL_MESSAGE ;
580
- File driver = AndroidSDK .getGoogleDriverFolder ();
581
- if (Platform .isWindows () && driver .exists ()) {
582
- msg += DRIVER_INSTALL_MESSAGE + driver .getAbsolutePath ();
583
- }
584
- AndroidUtil .showMessage (SDK_INSTALL_TITLE , msg );
585
-
586
- sdk .acceptLicenses ();
568
+
569
+ final int result = showSDKLicenseDialog (editor );
570
+ if (result == JOptionPane .YES_OPTION ) {
571
+ sdk .acceptLicenses ();
572
+ String msg = SDK_INSTALL_MESSAGE ;
573
+ File driver = AndroidSDK .getGoogleDriverFolder ();
574
+ if (Platform .isWindows () && driver .exists ()) {
575
+ msg += DRIVER_INSTALL_MESSAGE + driver .getAbsolutePath ();
576
+ }
577
+ AndroidUtil .showMessage (SDK_INSTALL_TITLE , msg );
578
+ } else {
579
+ AndroidUtil .showMessage (NO_SDK_LICENSE_TITLE , NO_SDK_LICENSE_MESSAGE );
580
+ }
587
581
588
582
return sdk ;
589
583
}
@@ -723,6 +717,43 @@ public void hyperlinkUpdate(HyperlinkEvent e) {
723
717
}
724
718
}
725
719
720
+
721
+ static public int showSDKLicenseDialog (Frame editor ) {
722
+ String title = SDK_LICENSE_TITLE ;
723
+ String msg = SDK_LICENSE_MESSAGE ;
724
+ String htmlString = "<html> " +
725
+ "<head> <style type=\" text/css\" >" +
726
+ "p { font: " + FONT_SIZE + "pt \" Lucida Grande\" ; " +
727
+ "margin: " + TEXT_MARGIN + "px; " +
728
+ "width: " + TEXT_WIDTH + "px }" +
729
+ "</style> </head>" + "<body> <p>" + msg + "</p> </body> </html>" ;
730
+ JEditorPane pane = new JEditorPane ("text/html" , htmlString );
731
+ pane .addHyperlinkListener (new HyperlinkListener () {
732
+ @ Override
733
+ public void hyperlinkUpdate (HyperlinkEvent e ) {
734
+ if (e .getEventType ().equals (HyperlinkEvent .EventType .ACTIVATED )) {
735
+ Platform .openURL (e .getURL ().toString ());
736
+ }
737
+ }
738
+ });
739
+ pane .setEditable (false );
740
+ JLabel label = new JLabel ();
741
+ pane .setBackground (label .getBackground ());
742
+
743
+ String [] options = new String [] { "Yes" , "No" };
744
+
745
+ int result = JOptionPane .showOptionDialog (null , pane , title ,
746
+ JOptionPane .DEFAULT_OPTION , JOptionPane .QUESTION_MESSAGE ,
747
+ null , options , options [0 ]);
748
+ if (result == JOptionPane .YES_OPTION ) {
749
+ return JOptionPane .YES_OPTION ;
750
+ } else if (result == JOptionPane .NO_OPTION ) {
751
+ return JOptionPane .NO_OPTION ;
752
+ } else {
753
+ return JOptionPane .CLOSED_OPTION ;
754
+ }
755
+ }
756
+
726
757
727
758
// this was banished from Base because it encourages bad practice.
728
759
// TODO figure out a better way to handle the above.
0 commit comments