Skip to content

Commit

Permalink
Merge pull request #214 from sanyatuning/master
Browse files Browse the repository at this point in the history
Handle multiple servers in the app
  • Loading branch information
thias15 authored Sep 20, 2021
2 parents ac40bc3 + 3ca061b commit 0160f31
Show file tree
Hide file tree
Showing 31 changed files with 629 additions and 410 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ composer.lock
/phpunit.xml
.DS_Store
Thumbs.db
wandb/

# IDE's
.idea/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,38 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ImageProxy;
import androidx.navigation.Navigation;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.openbot.R;
import org.openbot.common.CameraFragment;
import org.openbot.databinding.FragmentAutopilotBinding;
import org.openbot.env.BorderedText;
import org.openbot.env.Control;
import org.openbot.env.ImageUtils;
import org.openbot.server.ServerCommunication;
import org.openbot.server.ServerListener;
import org.openbot.tflite.Autopilot;
import org.openbot.tflite.Model;
import org.openbot.tflite.Network;
import org.openbot.tracking.MultiBoxTracker;
import org.openbot.utils.Constants;
import org.openbot.utils.Enums;
import org.openbot.utils.FileUtils;
import org.openbot.utils.PermissionUtils;
import timber.log.Timber;

public class AutopilotFragment extends CameraFragment implements ServerListener {
public class AutopilotFragment extends CameraFragment {

// options for drop down in object nav?
private FragmentAutopilotBinding binding;
private Handler handler;
private HandlerThread handlerThread;
private ServerCommunication serverCommunication;

private long lastProcessingTimeMs;
private boolean computingNetwork = false;
Expand All @@ -71,8 +64,6 @@ public class AutopilotFragment extends CameraFragment implements ServerListener
private Network.Device device = Network.Device.CPU;
private int numThreads = -1;

private ArrayAdapter<String> modelAdapter;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -98,41 +89,12 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
binding.cameraToggle.setOnClickListener(v -> toggleCamera());

List<String> models =
masterList.stream()
.filter(f -> f.type.equals(Model.TYPE.AUTOPILOT) && f.pathType != Model.PATH_TYPE.URL)
.map(f -> FileUtils.nameWithoutExtension(f.name))
.collect(Collectors.toList());
modelAdapter = new ArrayAdapter<>(requireContext(), R.layout.spinner_item, models);

modelAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
binding.modelSpinner.setAdapter(modelAdapter);
if (!preferencesManager.getAutopilotModel().isEmpty())
binding.modelSpinner.setSelection(
Math.max(
0,
modelAdapter.getPosition(
FileUtils.nameWithoutExtension(preferencesManager.getAutopilotModel()))));
getModelNames(
f -> f.type.equals(Model.TYPE.AUTOPILOT) && f.pathType != Model.PATH_TYPE.URL);
initModelSpinner(binding.modelSpinner, models, preferencesManager.getAutopilotModel());
initServerSpinner(binding.serverSpinner);

setAnalyserResolution(Enums.Preview.HD.getValue());
binding.modelSpinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selected = parent.getItemAtPosition(position).toString();
try {
masterList.stream()
.filter(f -> f.name.contains(selected))
.findFirst()
.ifPresent(value -> setModel(value));

} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
binding.deviceSpinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
Expand Down Expand Up @@ -296,8 +258,6 @@ private void recreateNetwork(Model model, Network.Device device, int numThreads)

@Override
public synchronized void onResume() {
serverCommunication = new ServerCommunication(requireContext(), this);
serverCommunication.start();
handlerThread = new HandlerThread("inference");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
Expand All @@ -314,7 +274,6 @@ public synchronized void onPause() {
} catch (final InterruptedException e) {
e.printStackTrace();
}
serverCommunication.stop();
super.onPause();
}

Expand Down Expand Up @@ -452,51 +411,11 @@ public void onConnectionEstablished(String ipAddress) {
requireActivity().runOnUiThread(() -> binding.ipAddress.setText(ipAddress));
}

@Override
public void onAddModel(String model) {
Model item =
new Model(
masterList.size() + 1,
Model.CLASS.AUTOPILOT_F,
Model.TYPE.AUTOPILOT,
model,
Model.PATH_TYPE.FILE,
requireActivity().getFilesDir() + File.separator + model,
"256x96");

if (modelAdapter != null && modelAdapter.getPosition(model) == -1) {
modelAdapter.add(model);
masterList.add(item);
FileUtils.updateModelConfig(requireActivity(), masterList);
} else {
if (model.equals(binding.modelSpinner.getSelectedItem())) {
setModel(item);
}
}
Toast.makeText(
requireContext().getApplicationContext(),
"AutopilotModel added: " + model,
Toast.LENGTH_SHORT)
.show();
}

@Override
public void onRemoveModel(String model) {
if (modelAdapter != null && modelAdapter.getPosition(model) != -1) {
modelAdapter.remove(model);
}
Toast.makeText(
requireContext().getApplicationContext(),
"AutopilotModel removed: " + model,
Toast.LENGTH_SHORT)
.show();
}

protected Model getModel() {
return model;
}

private void setModel(Model model) {
protected void setModel(Model model) {
if (this.model != model) {
Timber.d("Updating model: %s", model);
this.model = model;
Expand Down
154 changes: 153 additions & 1 deletion android/app/src/main/java/org/openbot/common/ControlsFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import org.openbot.R;
import org.openbot.env.AudioPlayer;
Expand All @@ -24,6 +33,8 @@
import org.openbot.env.SharedPreferencesManager;
import org.openbot.env.Vehicle;
import org.openbot.main.MainViewModel;
import org.openbot.server.ServerCommunication;
import org.openbot.server.ServerListener;
import org.openbot.tflite.Model;
import org.openbot.utils.ConnectionUtils;
import org.openbot.utils.Constants;
Expand All @@ -33,7 +44,9 @@
import org.openbot.utils.PermissionUtils;
import timber.log.Timber;

public abstract class ControlsFragment extends Fragment {
public abstract class ControlsFragment extends Fragment implements ServerListener {
private static final String NO_SERVER = "No server";

protected MainViewModel mViewModel;
protected Vehicle vehicle;
protected Animation startAnimation;
Expand All @@ -46,6 +59,13 @@ public abstract class ControlsFragment extends Fragment {
protected final String voice = "matthew";
protected List<Model> masterList;

protected ServerCommunication serverCommunication;

private ArrayAdapter<String> modelAdapter;
private ArrayAdapter<String> serverAdapter;
private Spinner modelSpinner;
private Spinner serverSpinner;

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Expand All @@ -58,6 +78,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
preferencesManager = new SharedPreferencesManager(requireContext());
audioPlayer = new AudioPlayer(requireContext());
masterList = FileUtils.loadConfigJSONFromAsset(requireActivity());
serverCommunication = new ServerCommunication(requireContext(), this);

requireActivity()
.getSupportFragmentManager()
Expand Down Expand Up @@ -239,8 +260,17 @@ private void toggleIndicatorEvent(int value) {
}
});

@NotNull
protected List<String> getModelNames(Predicate<Model> filter) {
return masterList.stream()
.filter(filter)
.map(f -> FileUtils.nameWithoutExtension(f.name))
.collect(Collectors.toList());
}

@Override
public void onResume() {
serverCommunication.start();
super.onResume();
}

Expand All @@ -255,6 +285,7 @@ public void onDestroy() {
@Override
public synchronized void onPause() {
Timber.d("onPause");
serverCommunication.stop();
vehicle.setControl(0, 0);
super.onPause();
}
Expand All @@ -265,6 +296,127 @@ public void onStop() {
super.onStop();
}

protected void initModelSpinner(Spinner spinner, List<String> models, String selected) {
modelAdapter = new ArrayAdapter<>(requireContext(), R.layout.spinner_item, models);
modelAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
modelSpinner = spinner;
modelSpinner.setAdapter(modelAdapter);
if (!selected.isEmpty())
modelSpinner.setSelection(
Math.max(0, modelAdapter.getPosition(FileUtils.nameWithoutExtension(selected))));
modelSpinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selected = parent.getItemAtPosition(position).toString();
try {
masterList.stream()
.filter(f -> f.name.contains(selected))
.findFirst()
.ifPresent(value -> setModel(value));

} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}

protected void initServerSpinner(Spinner spinner) {
serverAdapter = new ArrayAdapter<>(requireContext(), R.layout.spinner_item);
serverAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
serverSpinner = spinner;
serverSpinner.setAdapter(serverAdapter);
serverSpinner.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selected = parent.getItemAtPosition(position).toString();
if (selected.equals(NO_SERVER)) {
serverCommunication.disconnect();
if (serverAdapter.getPosition(preferencesManager.getServer()) > -1) {
preferencesManager.setServer(selected);
}
} else {
serverCommunication.connect(selected);
preferencesManager.setServer(selected);
}
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
serverCommunication.disconnect();
}
});
onServerListChange(serverCommunication.getServers());
}

@Override
public void onServerListChange(Set<String> servers) {
if (serverAdapter == null) {
return;
}
requireActivity()
.runOnUiThread(
() -> {
serverAdapter.clear();
serverAdapter.add(NO_SERVER);
serverAdapter.addAll(servers);
if (!preferencesManager.getServer().isEmpty()) {
serverSpinner.setSelection(
Math.max(0, serverAdapter.getPosition(preferencesManager.getServer())));
}
});
}

@Override
public void onAddModel(String model) {
Model item =
new Model(
masterList.size() + 1,
Model.CLASS.AUTOPILOT_F,
Model.TYPE.AUTOPILOT,
model,
Model.PATH_TYPE.FILE,
requireActivity().getFilesDir() + File.separator + model,
"256x96");

if (modelAdapter != null && modelAdapter.getPosition(model) == -1) {
modelAdapter.add(model);
masterList.add(item);
FileUtils.updateModelConfig(requireActivity(), masterList);
} else {
if (model.equals(modelSpinner.getSelectedItem())) {
setModel(item);
}
}
Toast.makeText(
requireContext().getApplicationContext(),
"AutopilotModel added: " + model,
Toast.LENGTH_SHORT)
.show();
}

@Override
public void onRemoveModel(String model) {
if (modelAdapter != null && modelAdapter.getPosition(model) != -1) {
modelAdapter.remove(model);
}
Toast.makeText(
requireContext().getApplicationContext(),
"AutopilotModel removed: " + model,
Toast.LENGTH_SHORT)
.show();
}

@Override
public void onConnectionEstablished(String ipAddress) {}

protected void setModel(Model model) {}

protected abstract void processControllerKeyData(String command);

protected abstract void processUSBData(String data);
Expand Down
Loading

0 comments on commit 0160f31

Please sign in to comment.