|  | @@ -16,183 +16,72 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  package org.ros.android;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import com.google.common.base.Preconditions;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  import android.app.Activity;
 | 
	
		
			
				|  |  | -import android.content.ComponentName;
 | 
	
		
			
				|  |  |  import android.content.Intent;
 | 
	
		
			
				|  |  | -import android.content.ServiceConnection;
 | 
	
		
			
				|  |  | -import android.os.AsyncTask;
 | 
	
		
			
				|  |  | -import android.os.IBinder;
 | 
	
		
			
				|  |  | -import org.ros.address.InetAddressFactory;
 | 
	
		
			
				|  |  | -import org.ros.exception.RosRuntimeException;
 | 
	
		
			
				|  |  | -import org.ros.node.NodeMain;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  import org.ros.node.NodeMainExecutor;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import java.net.NetworkInterface;
 | 
	
		
			
				|  |  | -import java.net.SocketException;
 | 
	
		
			
				|  |  |  import java.net.URI;
 | 
	
		
			
				|  |  | -import java.net.URISyntaxException;
 | 
	
		
			
				|  |  | -import java.util.concurrent.ExecutionException;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * @author damonkohler@google.com (Damon Kohler)
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  public abstract class RosActivity extends Activity {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private static final int MASTER_CHOOSER_REQUEST_CODE = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  private final ServiceConnection nodeMainExecutorServiceConnection;
 | 
	
		
			
				|  |  | -  private final String notificationTicker;
 | 
	
		
			
				|  |  | -  private final String notificationTitle;
 | 
	
		
			
				|  |  | +  private final RosActivityComponent rosActivityComponent;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    protected NodeMainExecutorService nodeMainExecutorService;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private final class NodeMainExecutorServiceConnection implements ServiceConnection {
 | 
	
		
			
				|  |  | +  private class RosActivityEventsHandler implements RosActivityComponent.RosActivityEvents {
 | 
	
		
			
				|  |  |      @Override
 | 
	
		
			
				|  |  | -    public void onServiceConnected(ComponentName name, IBinder binder) {
 | 
	
		
			
				|  |  | -      nodeMainExecutorService = ((NodeMainExecutorService.LocalBinder) binder).getService();
 | 
	
		
			
				|  |  | -      nodeMainExecutorService.addListener(new NodeMainExecutorServiceListener() {
 | 
	
		
			
				|  |  | -        @Override
 | 
	
		
			
				|  |  | -        public void onShutdown(NodeMainExecutorService nodeMainExecutorService) {
 | 
	
		
			
				|  |  | -          // We may have added multiple shutdown listeners and we only want to
 | 
	
		
			
				|  |  | -          // call finish() once.
 | 
	
		
			
				|  |  | -          if (!RosActivity.this.isFinishing()) {
 | 
	
		
			
				|  |  | -            RosActivity.this.finish();
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -      if (getMasterUri() == null) {
 | 
	
		
			
				|  |  | -        startMasterChooser();
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        init();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    public void initialize(final NodeMainExecutor nodeMainExecutor) {
 | 
	
		
			
				|  |  | +      init(nodeMainExecutor);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @Override
 | 
	
		
			
				|  |  | -    public void onServiceDisconnected(ComponentName name) {
 | 
	
		
			
				|  |  | +    public void onNodeMainExecutorServiceConnected(final NodeMainExecutorService
 | 
	
		
			
				|  |  | +                                                       nodeMainExecutorService) {
 | 
	
		
			
				|  |  | +      RosActivity.this.nodeMainExecutorService = nodeMainExecutorService;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  protected RosActivity(String notificationTicker, String notificationTitle) {
 | 
	
		
			
				|  |  | -    super();
 | 
	
		
			
				|  |  | -    this.notificationTicker = notificationTicker;
 | 
	
		
			
				|  |  | -    this.notificationTitle = notificationTitle;
 | 
	
		
			
				|  |  | -    nodeMainExecutorServiceConnection = new NodeMainExecutorServiceConnection();
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    public void onNodeMainExecutorServiceDisconnected() {
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  @Override
 | 
	
		
			
				|  |  | -  protected void onStart() {
 | 
	
		
			
				|  |  | -    super.onStart();
 | 
	
		
			
				|  |  | -    bindNodeMainExecutorService();
 | 
	
		
			
				|  |  | +  public RosActivity(String notificationTicker, String notificationTitle) {
 | 
	
		
			
				|  |  | +    rosActivityComponent = new RosActivityComponent(this, notificationTicker, notificationTitle,
 | 
	
		
			
				|  |  | +        new RosActivityEventsHandler());
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private void bindNodeMainExecutorService() {
 | 
	
		
			
				|  |  | -    Intent intent = new Intent(this, NodeMainExecutorService.class);
 | 
	
		
			
				|  |  | -    intent.setAction(NodeMainExecutorService.ACTION_START);
 | 
	
		
			
				|  |  | -    intent.putExtra(NodeMainExecutorService.EXTRA_NOTIFICATION_TICKER, notificationTicker);
 | 
	
		
			
				|  |  | -    intent.putExtra(NodeMainExecutorService.EXTRA_NOTIFICATION_TITLE, notificationTitle);
 | 
	
		
			
				|  |  | -    startService(intent);
 | 
	
		
			
				|  |  | -    Preconditions.checkState(
 | 
	
		
			
				|  |  | -        bindService(intent, nodeMainExecutorServiceConnection, BIND_AUTO_CREATE),
 | 
	
		
			
				|  |  | -        "Failed to bind NodeMainExecutorService.");
 | 
	
		
			
				|  |  | +  public void startMasterChooser() {
 | 
	
		
			
				|  |  | +    rosActivityComponent.startMasterChooser();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  @Override
 | 
	
		
			
				|  |  | -  protected void onDestroy() {
 | 
	
		
			
				|  |  | -    unbindService(nodeMainExecutorServiceConnection);
 | 
	
		
			
				|  |  | -    super.onDestroy();
 | 
	
		
			
				|  |  | +  public URI getMasterUri() {
 | 
	
		
			
				|  |  | +    return rosActivityComponent.getMasterUri();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private void init() {
 | 
	
		
			
				|  |  | -    // Run init() in a new thread as a convenience since it often requires
 | 
	
		
			
				|  |  | -    // network access.
 | 
	
		
			
				|  |  | -    new AsyncTask<Void, Void, Void>() {
 | 
	
		
			
				|  |  | -      @Override
 | 
	
		
			
				|  |  | -      protected Void doInBackground(Void... params) {
 | 
	
		
			
				|  |  | -        RosActivity.this.init(nodeMainExecutorService);
 | 
	
		
			
				|  |  | -        return null;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }.execute();
 | 
	
		
			
				|  |  | +  public String getRosHostname() {
 | 
	
		
			
				|  |  | +    return rosActivityComponent.getRosHostname();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /**
 | 
	
		
			
				|  |  | -   * This method is called in a background thread once this {@link Activity} has
 | 
	
		
			
				|  |  | -   * been initialized with a master {@link URI} via the {@link MasterChooser}
 | 
	
		
			
				|  |  | -   * and a {@link NodeMainExecutorService} has started. Your {@link NodeMain}s
 | 
	
		
			
				|  |  | -   * should be started here using the provided {@link NodeMainExecutor}.
 | 
	
		
			
				|  |  | -   * 
 | 
	
		
			
				|  |  | -   * @param nodeMainExecutor
 | 
	
		
			
				|  |  | -   *          the {@link NodeMainExecutor} created for this {@link Activity}
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  |    protected abstract void init(NodeMainExecutor nodeMainExecutor);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  public void startMasterChooser() {
 | 
	
		
			
				|  |  | -    Preconditions.checkState(getMasterUri() == null);
 | 
	
		
			
				|  |  | -    // Call this method on super to avoid triggering our precondition in the
 | 
	
		
			
				|  |  | -    // overridden startActivityForResult().
 | 
	
		
			
				|  |  | -    super.startActivityForResult(new Intent(this, MasterChooser.class), 0);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  public URI getMasterUri() {
 | 
	
		
			
				|  |  | -    Preconditions.checkNotNull(nodeMainExecutorService);
 | 
	
		
			
				|  |  | -    return nodeMainExecutorService.getMasterUri();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  public String getRosHostname() {
 | 
	
		
			
				|  |  | -    Preconditions.checkNotNull(nodeMainExecutorService);
 | 
	
		
			
				|  |  | -    return nodeMainExecutorService.getRosHostname();
 | 
	
		
			
				|  |  | +  @Override
 | 
	
		
			
				|  |  | +  protected void onStart() {
 | 
	
		
			
				|  |  | +    super.onStart();
 | 
	
		
			
				|  |  | +    rosActivityComponent.onStart();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    @Override
 | 
	
		
			
				|  |  | -  public void startActivityForResult(Intent intent, int requestCode) {
 | 
	
		
			
				|  |  | -    Preconditions.checkArgument(requestCode != MASTER_CHOOSER_REQUEST_CODE);
 | 
	
		
			
				|  |  | -    super.startActivityForResult(intent, requestCode);
 | 
	
		
			
				|  |  | +  protected void onDestroy() {
 | 
	
		
			
				|  |  | +    rosActivityComponent.onDestroy();
 | 
	
		
			
				|  |  | +    super.onDestroy();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    @Override
 | 
	
		
			
				|  |  |    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
	
		
			
				|  |  | -    super.onActivityResult(requestCode, resultCode, data);
 | 
	
		
			
				|  |  | -    if (resultCode == RESULT_OK) {
 | 
	
		
			
				|  |  | -      if (requestCode == MASTER_CHOOSER_REQUEST_CODE) {
 | 
	
		
			
				|  |  | -        String host;
 | 
	
		
			
				|  |  | -        String networkInterfaceName = data.getStringExtra("ROS_MASTER_NETWORK_INTERFACE");
 | 
	
		
			
				|  |  | -        // Handles the default selection and prevents possible errors
 | 
	
		
			
				|  |  | -        if (networkInterfaceName == null || networkInterfaceName.equals("")) {
 | 
	
		
			
				|  |  | -          host = InetAddressFactory.newNonLoopback().getHostAddress();
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          try {
 | 
	
		
			
				|  |  | -            NetworkInterface networkInterface = NetworkInterface.getByName(networkInterfaceName);
 | 
	
		
			
				|  |  | -            host = InetAddressFactory.newNonLoopbackForNetworkInterface(networkInterface).getHostAddress();
 | 
	
		
			
				|  |  | -          } catch (SocketException e) {
 | 
	
		
			
				|  |  | -            throw new RosRuntimeException(e);
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        nodeMainExecutorService.setRosHostname(host);
 | 
	
		
			
				|  |  | -        if (data.getBooleanExtra("ROS_MASTER_CREATE_NEW", false)) {
 | 
	
		
			
				|  |  | -          nodeMainExecutorService.startMaster(data.getBooleanExtra("ROS_MASTER_PRIVATE", true));
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          URI uri;
 | 
	
		
			
				|  |  | -          try {
 | 
	
		
			
				|  |  | -            uri = new URI(data.getStringExtra("ROS_MASTER_URI"));
 | 
	
		
			
				|  |  | -          } catch (URISyntaxException e) {
 | 
	
		
			
				|  |  | -            throw new RosRuntimeException(e);
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          nodeMainExecutorService.setMasterUri(uri);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        // Run init() in a new thread as a convenience since it often requires network access.
 | 
	
		
			
				|  |  | -        new AsyncTask<Void, Void, Void>() {
 | 
	
		
			
				|  |  | -          @Override
 | 
	
		
			
				|  |  | -          protected Void doInBackground(Void... params) {
 | 
	
		
			
				|  |  | -            RosActivity.this.init(nodeMainExecutorService);
 | 
	
		
			
				|  |  | -            return null;
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        }.execute();
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        // Without a master URI configured, we are in an unusable state.
 | 
	
		
			
				|  |  | -        nodeMainExecutorService.forceShutdown();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    super.onActivityResult(requestCode, resultCode, data);
 | 
	
		
			
				|  |  | +    rosActivityComponent.onActivityResult(requestCode, resultCode, data);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 |