Skip to content

Commit

Permalink
Add flysight tool
Browse files Browse the repository at this point in the history
  • Loading branch information
platypii committed Feb 16, 2025
1 parent 9647125 commit c116aee
Show file tree
Hide file tree
Showing 20 changed files with 509 additions and 38 deletions.
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@
<activity
android:name=".views.tracks.TrackRemoteActivity"
android:label="@string/app_name"/>
<activity
android:name=".views.FlysightActivity"
android:label="@string/action_flysight"/>
<activity
android:name=".views.SettingsActivity"
android:label="@string/title_activity_settings"/>
Expand Down
180 changes: 180 additions & 0 deletions app/src/main/java/com/platypii/baseline/views/FlysightActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package com.platypii.baseline.views;

import com.platypii.baseline.Permissions;
import com.platypii.baseline.R;
import com.platypii.baseline.Services;
import com.platypii.baseline.bluetooth.BluetoothState;
import com.platypii.baseline.databinding.ActivityFlysightBinding;
import com.platypii.baseline.events.BluetoothEvent;
import com.platypii.baseline.measurements.MLocation;
import com.platypii.baseline.util.Convert;
import com.platypii.baseline.util.Numbers;
import com.platypii.baseline.util.PubSub.Subscriber;

import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Locale;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class FlysightActivity extends BaseActivity implements Subscriber<MLocation> {

private ActivityFlysightBinding binding;

// Periodic UI updates
private final Handler handler = new Handler();
private final int updateInterval = 100; // in milliseconds
@Nullable
private Runnable updateRunnable;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityFlysightBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
}

@Override
protected void onResume() {
super.onResume();

// Start GPS updates
Services.location.locationUpdates.subscribeMain(this);
updateGPS();

// Start event updates
EventBus.getDefault().register(this);

// Start BLE scanning
if (Services.bluetooth.ble.bluetoothState == BluetoothState.BT_STOPPED) {
Services.bluetooth.ble.start(this);
}

// Periodic UI updates
updateRunnable = new Runnable() {
public void run() {
update();
handler.postDelayed(this, updateInterval);
}
};
handler.post(updateRunnable);
update();
}

@Override
protected void onPause() {
super.onPause();
handler.removeCallbacks(updateRunnable);
updateRunnable = null;
EventBus.getDefault().unregister(this);
Services.location.locationUpdates.unsubscribeMain(this);
}

private void updateGPS() {
final MLocation loc = Services.location.lastLoc;
// TODO: Only from flysight
if (loc != null && Services.bluetooth.preferences.preferenceEnabled) {
if (Numbers.isReal(loc.latitude) && Numbers.isReal(loc.latitude)) {
String ll = String.format(Locale.getDefault(), "%.6f, %.6f", loc.latitude, loc.longitude);
if (Numbers.isReal(loc.altitude_gps)) {
ll += ", " + Convert.distance(loc.altitude_gps, 2, true);
}
if (Numbers.isReal(loc.groundSpeed())) {
ll += ", " + Convert.speed(loc.groundSpeed(), 2, true);
}
binding.flysightGpsLabel.setText(ll);
} else {
binding.flysightGpsLabel.setText("");
}
} else {
binding.flysightGpsLabel.setText("");
}
}

/**
* Updates the UI that refresh continuously, such as sample rates
*/
private void update() {
// Check phone permissions
binding.btPhoneStatus.setText("Phone OK");
binding.btPhoneStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_green, 0, 0);
if (!Services.bluetooth.preferences.preferenceEnabled) {
// Check android location permission
if (!Permissions.hasLocationPermissions(this)) {
binding.btPhoneStatus.setText("Permission required");
binding.btPhoneStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
} else if (!Permissions.isLocationServiceEnabled(this)) {
binding.btPhoneStatus.setText("Location disabled");
binding.btPhoneStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
}
} else {
// Check bluetooth permissions
if (!Permissions.hasBluetoothPermissions(this)) {
binding.btPhoneStatus.setText("Permission required");
binding.btPhoneStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
}
}
// Bluetooth status
if (Services.bluetooth.preferences.preferenceEnabled) {
// FlySight selected for GPS
binding.btGpsStatus.setText(Services.bluetooth.getStatusMessage(this));
if (Services.bluetooth.getState() == BluetoothState.BT_CONNECTED) {
binding.btGpsStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_green, 0, 0);
} else {
binding.btGpsStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
}
// Satellite signal status
final long lastFixDuration = Services.location.lastFixDuration();
if (lastFixDuration < 0) {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
binding.btSatStatus.setText("No fix");
} else if (lastFixDuration > 5000) {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
binding.btSatStatus.setText("No fix");
} else if (lastFixDuration > 1100) {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_yellow, 0, 0);
binding.btSatStatus.setText("Last fix " + lastFixDuration / 1000L + "s"); // TODO: Periodic updater for last fix
} else {
final int hz = (int)(Services.location.refreshRate() + 0.5f);
// 1 hz is not enough
if (hz >= 2) {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_green, 0, 0);
} else {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_yellow, 0, 0);
}
binding.btSatStatus.setText(String.format(Locale.getDefault(), "%d Hz", hz));
}
} else {
// FlySight not selected for GPS
binding.btGpsStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
binding.btGpsStatus.setText("FS not selected");
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_red, 0, 0);
binding.btSatStatus.setText("FS GPS off");
}
}

@Override
protected void onDestroy() {
super.onDestroy();
Services.sensors.gravity.setMaxSize(0);
Services.sensors.rotation.setMaxSize(0);
}

// Listeners
@Override
public void apply(@NonNull MLocation loc) {
updateGPS();
}

/**
* Listen for altitude updates
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onBluetoothEvent(BluetoothEvent event) {
updateGPS();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ protected void onCreate(Bundle savedInstanceState) {
binding.nav.setOnClickListener(this::clickNav);
binding.tracks.setOnClickListener(this::clickTracks);
binding.profiles.setOnClickListener(this::clickLasers);
binding.flysight.setOnClickListener(this::clickFlysight);
binding.settings.setOnClickListener(this::clickSettings);
}

Expand Down Expand Up @@ -186,6 +187,11 @@ public void clickLasers(View v) {
startActivity(new Intent(this, LaserActivity.class));
}

public void clickFlysight(View v) {
firebaseAnalytics.logEvent("click_flysight", null);
startActivity(new Intent(this, FlysightActivity.class));
}

public void clickSettings(View v) {
firebaseAnalytics.logEvent("click_settings", null);
startActivity(new Intent(this, SettingsActivity.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ private void updateViews() {
binding.btSatStatus.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.status_yellow, 0, 0);
binding.btSatStatus.setText("Last fix " + lastFixDuration / 1000L + "s"); // TODO: Periodic updater for last fix
} else {
final int sats = Services.location.lastLoc.satellitesUsed;
int sats = -1;
if (Services.location.lastLoc != null) {
sats = Services.location.lastLoc.satellitesUsed;
}
final int hz = (int)(Services.location.refreshRate() + 0.5f);
// 1 hz is not enough
if (hz >= 2) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.platypii.baseline.views.bluetooth;

import android.os.Build;
import com.platypii.baseline.R;
import com.platypii.baseline.Services;
import com.platypii.baseline.bluetooth.BluetoothItem;
Expand All @@ -23,12 +22,9 @@ class BluetoothAdapter extends BaseAdapter {

private final LayoutInflater inflater;

private final String internalGps;

BluetoothAdapter(@NonNull Context context, @NonNull List<BluetoothItem> devices) {
this.devices = devices;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
internalGps = context.getString(R.string.internal_gps);
}

@Override
Expand All @@ -42,20 +38,18 @@ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup
final TextView addressView = convertView.findViewById(R.id.bluetooth_id);
final ImageView checkedView = convertView.findViewById(R.id.bluetooth_checked);

if (position == 0) {
// Bluetooth GPS device
final BluetoothItem device = devices.get(position);
nameView.setText(device.name);
addressView.setText(device.address);
if (device.internal) {
// Internal phone GPS
nameView.setText(internalGps);
addressView.setText(Build.MANUFACTURER + " " + Build.MODEL);
if (!Services.bluetooth.preferences.preferenceEnabled) {
checkedView.setVisibility(View.VISIBLE);
} else {
checkedView.setVisibility(View.GONE);
}
} else {
// Bluetooth GPS device
final BluetoothItem device = devices.get(position - 1);
nameView.setText(device.name);
addressView.setText(device.address);
if (device.name.contains("GPS") || device.name.startsWith("FlySight") || device.name.startsWith("Mohawk")) {
nameView.setTextColor(0xffeeeeee);
} else {
Expand All @@ -73,12 +67,12 @@ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup

@Override
public int getCount() {
return devices.size() + 1;
return devices.size();
}

@Override
public Object getItem(int position) {
return position == 0 ? null : devices.get(position - 1);
return devices.get(position);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.platypii.baseline.views.bluetooth;

import com.platypii.baseline.R;
import com.platypii.baseline.Services;
import com.platypii.baseline.bluetooth.BluetoothDeviceComparator;
import com.platypii.baseline.bluetooth.BluetoothItem;
Expand All @@ -9,6 +10,7 @@

import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
Expand All @@ -33,26 +35,37 @@ public class BluetoothDeviceListFragment extends ListFragment {
private final Set<BluetoothItem> deviceSet = new HashSet<>();
@Nullable
private BluetoothAdapter bluetoothAdapter;
private String internalGps = "Phone GPS"; // cached "Phone GPS" string from context

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// Set list adapter
final Activity activity = getActivity();
if (activity != null) {
internalGps = activity.getString(R.string.internal_gps);
bluetoothAdapter = new BluetoothAdapter(activity, devices);
setListAdapter(bluetoothAdapter);
}
return super.onCreateView(inflater, container, savedInstanceState);
}

protected Set<BluetoothItem> getDeviceList() {
final Set<BluetoothItem> devices = new HashSet<>();
for (BluetoothDevice device : Services.bluetooth.getBondedDevices()) {
devices.add(new BluetoothItem(device));
}
// Add internal phone gps
final String phoneName = Build.MANUFACTURER + " " + Build.MODEL;
deviceSet.add(new BluetoothItem(internalGps, phoneName, false, true));
return devices;
}

private void updateDeviceList() {
devices.clear();
deviceSet.clear();
try {
for (BluetoothDevice device : Services.bluetooth.getBondedDevices()) {
deviceSet.add(new BluetoothItem(device));
}
deviceSet.addAll(getDeviceList());
} catch (SecurityException e) {
Log.e(TAG, "Error getting device list", e);
}
Expand All @@ -68,15 +81,15 @@ public void onListItemClick(@NonNull ListView l, @NonNull View v, int position,
final BluetoothItem device = (BluetoothItem) l.getItemAtPosition(position);
final Activity activity = getActivity();
if (activity != null) {
if (device != null) {
if (!device.internal) {
Log.i(TAG, "Bluetooth device selected " + device.name);

if (!device.address.equals(Services.bluetooth.preferences.preferenceDeviceId)) {
// Changed bluetooth device, reset state
Services.location.locationProviderBluetooth.reset();
}

// Save device preference
// Save bluetooth device and enable bluetooth
Services.bluetooth.preferences.save(activity, true, device.address, device.name, device.ble);
// Update ui
EventBus.getDefault().post(new BluetoothEvent());
Expand All @@ -90,7 +103,7 @@ public void onListItemClick(@NonNull ListView l, @NonNull View v, int position,
Analytics.logEvent(activity, "bluetooth_selected", bundle);
} else {
Log.i(TAG, "Internal GPS selected");
// Save device preference
// Clear bluetooth device and disable bluetooth
Services.bluetooth.preferences.save(activity, false, null, null, false);
// Update ui
EventBus.getDefault().post(new BluetoothEvent());
Expand Down
Loading

0 comments on commit c116aee

Please sign in to comment.