Commit 1843bdd6 authored by Evan W. Patton's avatar Evan W. Patton

Merge branch 'master' into ucr

Change-Id: I6e67e5d15ce2d1999e971386bf9536fa99009219
parents 33f4061f cc56b0a8
......@@ -584,6 +584,10 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
@Description("Message providing details about starting the wireless connection.")
String AICompanionMenuItem();
@DefaultMessage("Chromebook")
@Description("Menu item for initiating a connection to the companion running on a Chromebook.")
String chromebookMenuItem();
@DefaultMessage("Emulator")
@Description("Message providing details about starting the emulator connection.")
String emulatorMenuItem();
......
......@@ -83,6 +83,7 @@ public class TopToolbar extends Composite {
private static final String WIDGET_NAME_BUILD_YAIL = "Yail";
private static final String WIDGET_NAME_CONNECT_TO = "ConnectTo";
private static final String WIDGET_NAME_WIRELESS_BUTTON = "Wireless";
private static final String WIDGET_NAME_CHROMEBOOK = "Chromebook";
private static final String WIDGET_NAME_EMULATOR_BUTTON = "Emulator";
private static final String WIDGET_NAME_USB_BUTTON = "Usb";
private static final String WIDGET_NAME_RESET_BUTTON = "Reset";
......@@ -116,6 +117,8 @@ public class TopToolbar extends Composite {
private static final String WINDOW_OPEN_FEATURES = "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes";
private static final String WINDOW_OPEN_LOCATION = "_ai2";
private static final boolean iamChromebook = isChromeBook();
private DropDownButton fileDropDown;
private DropDownButton connectDropDown;
private DropDownButton buildDropDown;
......@@ -251,18 +254,25 @@ public class TopToolbar extends Composite {
List<DropDownItem> connectItems = Lists.newArrayList();
connectItems.add(new DropDownItem(WIDGET_NAME_WIRELESS_BUTTON,
MESSAGES.AICompanionMenuItem(), new WirelessAction()));
connectItems.add(new DropDownItem(WIDGET_NAME_EMULATOR_BUTTON,
MESSAGES.emulatorMenuItem(), new EmulatorAction()));
connectItems.add(new DropDownItem(WIDGET_NAME_USB_BUTTON, MESSAGES.usbMenuItem(),
new UsbAction()));
if (iamChromebook) {
connectItems.add(new DropDownItem(WIDGET_NAME_CHROMEBOOK,
MESSAGES.chromebookMenuItem(), new ChromebookAction()));
} else {
connectItems.add(new DropDownItem(WIDGET_NAME_EMULATOR_BUTTON,
MESSAGES.emulatorMenuItem(), new EmulatorAction()));
connectItems.add(new DropDownItem(WIDGET_NAME_USB_BUTTON, MESSAGES.usbMenuItem(),
new UsbAction()));
}
connectItems.add(null);
connectItems.add(new DropDownItem(WIDGET_NAME_REFRESHCOMPANION_BUTTON, MESSAGES.refreshCompanionMenuItem(),
new RefreshCompanionAction()));
connectItems.add(null);
connectItems.add(new DropDownItem(WIDGET_NAME_RESET_BUTTON, MESSAGES.resetConnectionsMenuItem(),
new ResetAction()));
connectItems.add(new DropDownItem(WIDGET_NAME_HARDRESET_BUTTON, MESSAGES.hardResetConnectionsMenuItem(),
new HardResetAction()));
if (!iamChromebook) {
connectItems.add(new DropDownItem(WIDGET_NAME_HARDRESET_BUTTON, MESSAGES.hardResetConnectionsMenuItem(),
new HardResetAction()));
}
refreshMenu(connectDropDown, connectItems);
}
......@@ -448,8 +458,17 @@ public class TopToolbar extends Composite {
@Override
public void execute() {
if (Ode.getInstance().okToConnect()) {
startRepl(true, false, false); // false means we are
// *not* the emulator
startRepl(true, false, false, false); // false means we are
// *not* the emulator
}
}
}
private class ChromebookAction implements Command {
@Override
public void execute() {
if (Ode.getInstance().okToConnect()) {
startRepl(true, true, false, false);
}
}
}
......@@ -458,8 +477,8 @@ public class TopToolbar extends Composite {
@Override
public void execute() {
if (Ode.getInstance().okToConnect()) {
startRepl(true, true, false); // true means we are the
// emulator
startRepl(true, false, true, false); // true means we are the
// emulator
}
}
}
......@@ -468,7 +487,7 @@ public class TopToolbar extends Composite {
@Override
public void execute() {
if (Ode.getInstance().okToConnect()) {
startRepl(true, false, true);
startRepl(true, false, false, true);
}
}
}
......@@ -477,7 +496,7 @@ public class TopToolbar extends Composite {
@Override
public void execute() {
if (Ode.getInstance().okToConnect()) {
startRepl(false, false, false); // We are really stopping the repl here
startRepl(false, false, false, false); // We are really stopping the repl here
}
}
}
......@@ -972,13 +991,21 @@ public class TopToolbar extends Composite {
private void updateConnectToDropDownButton(boolean isEmulatorRunning, boolean isCompanionRunning, boolean isUsbRunning){
if (!isEmulatorRunning && !isCompanionRunning && !isUsbRunning) {
connectDropDown.setItemEnabled(MESSAGES.AICompanionMenuItem(), true);
connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), true);
connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), true);
if (iamChromebook) {
connectDropDown.setItemEnabled(MESSAGES.chromebookMenuItem(), true);
} else {
connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), true);
connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), true);
}
connectDropDown.setItemEnabled(MESSAGES.refreshCompanionMenuItem(), false);
} else {
connectDropDown.setItemEnabled(MESSAGES.AICompanionMenuItem(), false);
connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), false);
connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), false);
if (iamChromebook) {
connectDropDown.setItemEnabled(MESSAGES.chromebookMenuItem(), false);
} else {
connectDropDown.setItemEnabled(MESSAGES.emulatorMenuItem(), false);
connectDropDown.setItemEnabled(MESSAGES.usbMenuItem(), false);
}
connectDropDown.setItemEnabled(MESSAGES.refreshCompanionMenuItem(), true);
}
}
......@@ -994,16 +1021,16 @@ public class TopToolbar extends Composite {
/**
* startRepl -- Start/Stop the connection to the companion.
* If both forEmulator and forUsb are false, then we are connecting
* via Wireless.
*
* @param start -- true to start the repl, false to stop it.
* @param forChromebook -- true if we are connecting to a chromebook.
* @param forEmulator -- true if we are connecting to the emulator.
* @param forUsb -- true if this is a USB connection.
*
* If both forEmulator and forUsb are false, then we are connecting
* via Wireless.
*/
private void startRepl(boolean start, boolean forEmulator, boolean forUsb) {
private void startRepl(boolean start, boolean forChromebook, boolean forEmulator, boolean forUsb) {
DesignToolbar.DesignProject currentProject = Ode.getInstance().getDesignToolbar().getCurrentProject();
if (currentProject == null) {
OdeLog.wlog("DesignToolbar.currentProject is null. "
......@@ -1011,7 +1038,7 @@ public class TopToolbar extends Composite {
return;
}
DesignToolbar.Screen screen = currentProject.screens.get(currentProject.currentScreen);
screen.blocksEditor.startRepl(!start, forEmulator, forUsb);
screen.blocksEditor.startRepl(!start, forChromebook, forEmulator, forUsb);
if (start) {
if (forEmulator) { // We are starting the emulator...
updateConnectToDropDownButton(true, false, false);
......@@ -1170,4 +1197,12 @@ public class TopToolbar extends Composite {
}
}
private static native boolean isChromeBook() /*-{
if (/\bCrOS\b/.test(navigator.userAgent)) {
return true;
} else {
return false;
}
}-*/;
}
......@@ -144,7 +144,7 @@ public abstract class FileEditor extends Composite {
* but the YaBlocksEditor overrides this version with one that start the
* Repl going.
*/
public void startRepl(boolean alreadyRunning, boolean forEmulator, boolean forUsb) {
public void startRepl(boolean alreadyRunning, boolean forChromebook, boolean forEmulator, boolean forUsb) {
}
/**
......
......@@ -280,9 +280,9 @@ public class BlocklyPanel extends HTMLPanel {
}
}
public void startRepl(boolean alreadyRunning, boolean forEmulator, boolean forUsb) { // Start the Repl
public void startRepl(boolean alreadyRunning, boolean forChromebook, boolean forEmulator, boolean forUsb) { // Start the Repl
makeActive();
doStartRepl(alreadyRunning, forEmulator, forUsb);
doStartRepl(alreadyRunning, forChromebook, forEmulator, forUsb);
}
public void hardReset() {
......@@ -834,8 +834,8 @@ public class BlocklyPanel extends HTMLPanel {
}
}-*/;
public native void doStartRepl(boolean alreadyRunning, boolean forEmulator, boolean forUsb) /*-{
Blockly.ReplMgr.startRepl(alreadyRunning, forEmulator, forUsb);
public native void doStartRepl(boolean alreadyRunning, boolean forChromebook, boolean forEmulator, boolean forUsb) /*-{
Blockly.ReplMgr.startRepl(alreadyRunning, forChromebook, forEmulator, forUsb);
}-*/;
public native void doHardReset() /*-{
......
......@@ -637,8 +637,8 @@ public final class YaBlocksEditor extends FileEditor
* Start up the Repl (call into the Blockly.ReplMgr via the BlocklyPanel.
*/
@Override
public void startRepl(boolean alreadyRunning, boolean forEmulator, boolean forUsb) {
blocksArea.startRepl(alreadyRunning, forEmulator, forUsb);
public void startRepl(boolean alreadyRunning, boolean forChromebook, boolean forEmulator, boolean forUsb) {
blocksArea.startRepl(alreadyRunning, forChromebook, forEmulator, forUsb);
}
/*
......
......@@ -390,7 +390,8 @@ Blockly.Yail.getPropertySettersLines = function(componentJson, componentName, co
var code = [];
var type = componentDb.getType(componentJson['$Type']);
function shouldSendProperty(prop, info) {
return (prop.charAt(0) !== '$' && prop !== 'Uuid' && prop !== 'TutorialURL') ||
return (prop.charAt(0) !== '$' && prop !== 'Uuid' &&
prop !== 'TutorialURL' && prop !== 'BlocksToolkit') ||
(info && info['alwaysSend']);
}
// Gather all of the properties together
......
......@@ -485,7 +485,9 @@ Blockly.ReplMgr.putYail = (function() {
// Ready to actually exchange data
webrtcrunning = true;
top.webrtcdata = webrtcdata; // For debugging
rs.dialog.hide(); // Take down QR Code dialog
if (rs.dialog) {
rs.dialog.hide(); // Take down QR Code dialog
}
RefreshAssets(function() {
Blockly.ReplMgr.loadExtensions();
});
......@@ -1348,7 +1350,7 @@ Blockly.ReplMgr.quoteUnicode = function(input) {
return sb.join("");
};
Blockly.ReplMgr.startRepl = function(already, emulator, usb) {
Blockly.ReplMgr.startRepl = function(already, chromebook, emulator, usb) {
var rs = top.ReplState;
var me = this;
rs.didversioncheck = false; // Re-check
......@@ -1376,20 +1378,29 @@ Blockly.ReplMgr.startRepl = function(already, emulator, usb) {
rs = top.ReplState;
rs.state = this.rsState.RENDEZVOUS; // We are now rendezvousing
rs.replcode = this.genCode();
if (chromebook) {
window.open("intent://comp/" + rs.replcode + "#Intent;scheme=aicompanion;package=" +
top.ACCEPTABLE_COMPANION_PACKAGE +
";end");
}
rs.rendezvouscode = this.sha1(rs.replcode);
rs.seq_count = 1; // used for the creating the hmac mac
rs.count = 0;
rs.dialog = new Blockly.Util.Dialog(Blockly.Msg.REPL_CONNECT_TO_COMPANION, this.makeDialogMessage(rs.replcode), Blockly.Msg.REPL_CANCEL, false, null, 1, function() {
rs.dialog.hide();
rs.state = Blockly.ReplMgr.rsState.IDLE; // We're punting
rs.connection = null;
me.putYail.reset(true); // Shutdown any polling
top.BlocklyPanel_indicateDisconnect();
});
if (!chromebook) {
rs.dialog = new Blockly.Util.Dialog(Blockly.Msg.REPL_CONNECT_TO_COMPANION, this.makeDialogMessage(rs.replcode), Blockly.Msg.REPL_CANCEL, false, null, 1, function() {
rs.dialog.hide();
rs.state = Blockly.ReplMgr.rsState.IDLE; // We're punting
rs.connection = null;
me.putYail.reset(true); // Shutdown any polling
top.BlocklyPanel_indicateDisconnect();
});
}
this.getFromRendezvous();
} else {
if (top.ReplState.state == this.rsState.RENDEZVOUS) {
top.ReplState.dialog.hide();
if (top.ReplState.dialog) { // It might not be showing if we are on a Chromebook
top.ReplState.dialog.hide();
}
}
try {
top.webrtcdata.send("#DONE#"); // This should kill the companion
......@@ -1434,7 +1445,9 @@ Blockly.ReplMgr.getFromRendezvous = function() {
setTimeout(poller, 2000);
return;
}
rs.dialog.hide(); // Take down the QRCode dialog
if (rs.dialog) { // Dialog won't be present when we connect via chromebook
rs.dialog.hide(); // Take down the QRCode dialog
}
// Keep the user informed about the connection
top.ConnectProgressBar_start();
top.ConnectProgressBar_setProgress(10, Blockly.Msg.DIALOG_FOUND_COMPANION);
......@@ -1601,7 +1614,9 @@ Blockly.ReplMgr.rendPoll = function() {
top.ReplState.count = top.ReplState.count + 1;
if (top.ReplState.count > 40) {
top.ReplState.state = this.rsState.IDLE;
top.ReplState.dialog.hide(); // Punt the dialog
if (top.ReplState.dialog) {
top.ReplState.dialog.hide(); // Punt the dialog
}
dialog = new Blockly.Util.Dialog(Blockly.Msg.REPL_CONNECTION_FAILURE1, Blockly.Msg.REPL_TRY_AGAIN1, Blockly.Msg.REPL_OK, false, null, 0, function() {
dialog.hide();
});
......
......@@ -1067,6 +1067,14 @@ public final class Compiler {
out.write(" <category android:name=\"android.intent.category.LAUNCHER\" />\n");
}
out.write(" </intent-filter>\n");
if (isForCompanion) {
out.write("<intent-filter>\n");
out.write("<action android:name=\"android.intent.action.VIEW\" />\n");
out.write("<category android:name=\"android.intent.category.DEFAULT\" />\n");
out.write("<category android:name=\"android.intent.category.BROWSABLE\" />\n");
out.write("<data android:scheme=\"aicompanion\" android:host=\"comp\" />\n");
out.write("</intent-filter>\n");
}
if (simpleCompTypes.contains("com.google.appinventor.components.runtime.NearField") &&
!isForCompanion && isMain) {
......
......@@ -29,6 +29,7 @@ import com.google.appinventor.components.common.ComponentConstants;
import com.google.appinventor.components.runtime.util.AppInvHTTPD;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.OnInitializeListener;
import com.google.appinventor.components.runtime.util.RetValManager;
import com.google.appinventor.components.runtime.util.WebRTCNativeMgr;
......@@ -124,13 +125,14 @@ public class ReplForm extends Form {
Log.d(LOG_TAG, "onCreate");
loadedExternalDexs = new ArrayList<String>();
Intent intent = getIntent();
processExtras(intent, false);
processExtrasAndData(intent, false);
themeHelper.setActionBarAnimation(false);
}
@Override
void onCreateFinish() {
super.onCreateFinish();
Log.d(LOG_TAG, "onCreateFinish() Called in Repl");
if (!isEmulator() && AppInventorFeatures.doCompanionSplashScreen())
{ // Only show REPL splash if not in emulator and enabled
......@@ -138,6 +140,53 @@ public class ReplForm extends Form {
webviewIntent.setClassName(activeForm.$context(), SPLASH_ACTIVITY_CLASS);
activeForm.$context().startActivity(webviewIntent);
}
Intent intent = getIntent();
Log.d(LOG_TAG, "Intent = " + intent);
final String data = intent.getDataString();
if (data != null) {
Log.d(LOG_TAG, "Got data = " + data);
} else {
Log.d(LOG_TAG, "Did not receive any data");
}
/////////////////////////////////////////////////////////////////////////
// Chromebook Support: //
// //
// The code below parses the data provided in the intent to get the //
// code to use to talk to the rendezvous server. It appears to need to //
// run on the UI thread (I'm not sure what thread we are on here in //
// onCreateFinish(). I'm not sure why we need the delay, but it //
// doesn't work if we do not include the delay. I'm continuing to look //
// into why that is and the delay may be removed in a future //
// revision. (jis). //
// //
// Also: the rendezvous server location is hardcoded in this version. //
// a future version will let you customize the location of the //
// rendezvous server. //
/////////////////////////////////////////////////////////////////////////
if (data != null && (data.startsWith("aicompanion"))) {
registerForOnInitialize(new OnInitializeListener() {
@Override
public void onInitialize() {
String code = data.substring(data.indexOf("//comp/") + 7);
PhoneStatus status = new PhoneStatus(ReplForm.this);
status.WebRTC(true);
code = status.setHmacSeedReturnCode(code, "rendezvous.appinventor.mit.edu");
String ipAddress = PhoneStatus.GetWifiIpAddress();
int api = status.SdkLevel();
String version = status.GetVersionName();
String aid = status.InstallationId();
Log.d(LOG_TAG, "InstallationId = " + aid);
Web web = new Web(ReplForm.this);
web.Url("http://rendezvous.appinventor.mit.edu/rendezvous/");
web.PostText("ipaddr=" + ipAddress + "&port=9987&webrtc=true" +
"&version=" + version + "&api=" + api + "&aid=" +
aid + "&installer=" + status.GetInstaller() + "&r2=true&key=" + code);
status.startWebRTC("rendezvous.appinventor.mit.edu", "OK");
}
});
}
}
@Override
......@@ -243,7 +292,7 @@ public class ReplForm extends Form {
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(LOG_TAG, "onNewIntent Called");
processExtras(intent, true);
processExtrasAndData(intent, true);
}
void HandleReturnValues() {
......@@ -255,7 +304,7 @@ public class ReplForm extends Form {
}
}
protected void processExtras(Intent intent, boolean restart) {
private void processExtrasAndData(Intent intent, boolean restart) {
Bundle extras = intent.getExtras();
if (extras != null) {
Log.d(LOG_TAG, "extras: " + extras);
......@@ -264,8 +313,13 @@ public class ReplForm extends Form {
Log.d(LOG_TAG, "Extra Key: " + keys.next());
}
}
String data = intent.getDataString();
if (data != null && (data.startsWith("aicompanion"))) {
isDirect = true;
assetsLoaded = true;
}
if ((extras != null) && extras.getBoolean("rundirect")) {
Log.d(LOG_TAG, "processExtras rundirect is true and restart is " + restart);
Log.d(LOG_TAG, "processExtrasAndData rundirect is true and restart is " + restart);
isDirect = true;
assetsLoaded = true;
if (restart) {
......
......@@ -239,9 +239,10 @@ public class WebRTCNativeMgr {
/* Provide a default when the rendezvous server doesn't provide one */
rendezvousResult = "{\"rendezvous2\" : \"" + YaVersion.RENDEZVOUS_SERVER + "\"," +
"\"iceservers\" : " +
"[{ \"server\" : \"turn:turn.appinventor.mit.edu:3478\"," +
"\"username\" : \"oh\"," +
"\"password\" : \"boy\"}]}";
"[{ \"server\" : \"stun:stun.l.google.com:19302\" }," +
"{ \"server\" : \"turn:turn.appinventor.mit.edu:3478\"," +
"\"username\" : \"oh\"," +
"\"password\" : \"boy\"}]}";
}
try {
JSONObject resultJson = new JSONObject(rendezvousResult);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment