Skip to content

Commit c572d2b

Browse files
committed
ask to accept SDK license after download
1 parent ff1e185 commit c572d2b

File tree

1 file changed

+108
-77
lines changed

1 file changed

+108
-77
lines changed

src/processing/mode/android/AndroidSDK.java

Lines changed: 108 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ class AndroidSDK {
7171

7272
private static final String SDK_DOWNLOAD_URL =
7373
"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";
7774

7875
private static final String USE_ENV_SDK_TITLE = "Found an Android SDK!";
7976
private static final String USE_ENV_SDK_MESSAGE =
@@ -169,6 +166,24 @@ class AndroidSDK {
169166
"\">these instructions</a>.<br><br>" +
170167
"The installation files are available in this folder:</br>";
171168

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+
172187
private static final int NO_ERROR = 0;
173188
private static final int SKIP_ENV_SDK = 1;
174189
private static final int MISSING_SDK = 2;
@@ -223,8 +238,8 @@ public AndroidSDK(File folder) throws BadSDKException, IOException {
223238
throw new BadSDKException("There is no support library folder in " + folder);
224239
}
225240

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");
228243

229244
String path = Platform.getenv("PATH");
230245

@@ -353,59 +368,45 @@ public File getZipAlignTool() {
353368
}
354369

355370

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\ny\ny\ny\ny\ny\ny\ny\ny\ny\n";
376+
377+
private void acceptLicenses() {
378+
ProcessBuilder pb = new ProcessBuilder(sdkManager.getAbsolutePath(),
379+
"--licenses");
361380
pb.redirectErrorStream(true);
362381
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+
}
372396
}
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();
376402
} catch (IOException e) {
377-
e.printStackTrace();
403+
e.printStackTrace();
378404
} catch (InterruptedException e) {
379-
// TODO Auto-generated catch block
380405
e.printStackTrace();
381-
}
406+
}
382407
}
383408

384409

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-
409410
static public File getHAXMInstallerFolder() {
410411
String sdkPrefsPath = Preferences.get("android.sdk.path");
411412
File sdkPath = new File(sdkPrefsPath);
@@ -425,26 +426,17 @@ static public File getGoogleDriverFolder() {
425426
* for the SDK installation. Also figures out the name of android/android.bat
426427
* so that it can be called explicitly.
427428
*/
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");
431433
}
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);
434436
}
435-
throw new BadSDKException("Cannot find avdmanager in " + tools);
437+
throw new BadSDKException("Cannot find " + name + " in " + tools);
436438
}
437-
438439

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-
}
448440

449441
/**
450442
* 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
470462
try {
471463
final AndroidSDK androidSDK = new AndroidSDK(new File(sdkPrefsPath));
472464
Preferences.set("android.sdk.path", sdkPrefsPath);
473-
androidSDK.acceptLicenses();
474465
return androidSDK;
475466
} catch (final BadSDKException badPref) {
476467
Preferences.unset("android.sdk.path");
@@ -504,8 +495,7 @@ public static AndroidSDK load(boolean checkEnvSDK, Frame editor) throws IOExcept
504495
// means we just installed the mode for the first time, so we show a
505496
// welcome message with some useful info.
506497
AndroidUtil.showMessage(SDK_EXISTS_TITLE, SDK_EXISTS_MESSAGE);
507-
508-
androidSDK.acceptLicenses();
498+
509499
return androidSDK;
510500
} catch (final BadSDKException badEnv) {
511501
Preferences.unset("android.sdk.path");
@@ -575,15 +565,19 @@ static public AndroidSDK download(final Frame editor, final AndroidMode androidM
575565
if (sdk == null) {
576566
throw new BadSDKException("SDK could not be downloaded");
577567
}
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+
}
587581

588582
return sdk;
589583
}
@@ -723,6 +717,43 @@ public void hyperlinkUpdate(HyperlinkEvent e) {
723717
}
724718
}
725719

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+
726757

727758
// this was banished from Base because it encourages bad practice.
728759
// TODO figure out a better way to handle the above.

0 commit comments

Comments
 (0)