New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tpbot/movement service #249
Conversation
and stop it on USB disconnected
Conflicts: TelepresenceBot/mobile/build.gradle TelepresenceBot/mobile/src/main/java/com/novoda/tpbot/human/HumanActivity.java
@@ -35,6 +50,68 @@ protected void onCreate(Bundle savedInstanceState) { | |||
|
|||
RecyclerView.Adapter adapter = new DirectionAdapter(LayoutInflater.from(this), Collections.<Direction>emptyList()); | |||
directions.setAdapter(adapter); | |||
|
|||
ControllerView controllerView = Views.findById(this, R.id.bot_debug_controls); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a controller view so that you can send commands straight to the Arduino?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes exactly, as I wrote in the description, this is only for debug purposes, while we don't have the network communication from the human controller
|
||
private MovementService movementService; | ||
private boolean bound; | ||
private Handler handler; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am used to have private final Handler handler = new Handler();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now these are not there anymore, moved into the CommandRepeater
creation
} | ||
}; | ||
|
||
private void startRepeatingCommand(String command) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking about encapsulating this command handling in a separate class.
You would have a CommandHandler
as a field maybe which has currentCommand
inside.
I think it is weird to see String currentCommand
inside the Activity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in ae51908, this reduced the duplication of that logic between the two activities
} | ||
} | ||
|
||
private Runnable repeatCommand = new Runnable() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in b66e064
private Runnable repeatCommand = new Runnable() { | ||
@Override | ||
public void run() { | ||
sendCommand(BotActivity.this.currentCommand); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 lines can maybe extracted into a method named sendRepeatingCommand(String)
What do you think?
android:orientation="vertical" | ||
tools:context="com.novoda.tpbot.human.HumanActivity"> | ||
|
||
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
xmlns:android="http://schemas.android.com/apk/res/android"
is this redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, they were leftovers from a previous refactor. Removed in 1f1793c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor changes needed for my eyes' sake (I'm old).
IBinder iBinder) { | ||
MovementService.Binder binder = (MovementService.Binder) iBinder; | ||
movementService = binder.getService(); | ||
bound = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename to boundToMovementService
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
@Override | ||
public void onServiceDisconnected(ComponentName arg0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arg0
? 🤢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops 👅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
public void startConnection() { | ||
|
||
if (!isSerialStarted) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would invert this to return if isSerialStarted
.
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); | ||
|
||
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList(); | ||
if (!usbDevices.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too many nested layers here 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also have a quick return above too. Always try to prefer the positive case when possible 😃
|
||
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { | ||
@Override | ||
public void onReceive(Context context, Intent intent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please break this down into smaller methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 33eb4f5
toaster.popToast("Port is not open"); | ||
} | ||
} else { | ||
Log.d("SERIAL", "Port is null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract TAG to constant?
Intent movementService = new Intent(context.getApplicationContext(), MovementService.class); | ||
if (usbConnected(intent)) { | ||
context.startService(movementService); | ||
} else if(usbDisconnected(intent)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after if
😄
@@ -32,6 +34,22 @@ | |||
android:icon="@mipmap/ic_launcher" | |||
android:label="@string/bot" /> | |||
|
|||
<receiver android:name="com.novoda.tpbot.bot.UsbReceiver"> | |||
<intent-filter> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need to be in this order? Can we group the <intent-filter>
together?
|
||
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList(); | ||
if (!usbDevices.isEmpty()) { | ||
boolean keep = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usage wasn't immediately clear when I read this, is there a better name?
} | ||
}; | ||
|
||
private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onDataReceievedListener
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. mCallback
😷
@@ -3,7 +3,7 @@ | |||
import com.novoda.notils.logger.simple.Log; | |||
import com.novoda.tpbot.Direction; | |||
|
|||
interface ControllerListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is being used by both I would move it to the more generic package. I know that it will move again in the future but it shows our intent clearly when looking at the structure of the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 2739722
@@ -15,13 +15,11 @@ | |||
public class HumanActivity extends AppCompatActivity { | |||
|
|||
private static final String LAZERS = String.valueOf(Character.toChars(0x1F4A5)); | |||
private static final long COMMAND_REPEAT_DELAY = TimeUnit.MILLISECONDS.toMillis(100); | |||
private static final long COMMAND_FADING_DELAY = TimeUnit.MILLISECONDS.toMillis(100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it is worth moving this internally to the debug view? Likely will be the same whether ever we use it at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good point
android:orientation="vertical" | ||
tools:context="com.novoda.tpbot.human.HumanActivity"> | ||
|
||
<android.support.v7.widget.RecyclerView |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking of replacing this with the DebugView
in my branch, it will make the process of building the debug version slightly faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do it once this is merged?
So that changes for a single PR are smaller
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work on this 👍 Good to see the progress. We should try to extract out some of those if statements to make the usb connection class easier to read.
usbManager.requestPermission(device, pendingIntent); | ||
break; | ||
} else { | ||
connection = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be set to null
on each iteration of the loop? I assumed this would happen if we go through all of the usbDevices
and we do not find a supporting device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🎉
@frapontillo @Mecharyry all comments addressed (including @tasomaniac ones, but he already approved 👅 ) |
private static final String SERIAL_TAG = "SERIAL"; | ||
|
||
private static final String ACTION_USB_PERMISSION = "com.novoda.tpbot.USB_PERMISSION"; | ||
private static final List<Integer> SUPPORTED_VENDOR_IDS = Arrays.asList(9025, 10755, 4292); // TODO: read from devices_filter.xml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this going to be done in a future PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job! 🎉
Problem
We need the Bot section of our Android app to communicate with the Arduino movement unit.
Solution
First of all we need to detect when a USB device is connected. This is done through a BroadcastReceiver declared in the manifest with the action
android.hardware.usb.action.USB_DEVICE_ATTACHED
.It will be triggered only by devices with one of the vendor IDs defined in
devices_filter.xml
.At the moment I only added three common vendor IDs generally associated with different versions of Arduino boards. If we will see that some other boards are not recognised, we can list the connected devices' vendor IDs from the BotActivity, and add these to the list later.
Once we detect a new matching device, the BroadcastReceiver starts an Android Service responsible of this communication.
The service (
MovementService
) does the following:In this PR I made the
BotActivity
bind with the service and added a command pad to that activity as well, so that we can control the bot also from the receiver part. This is for debug only and should be removed once we have the Human-Bot network communication done.