package org.droidplanner.android.fragments.actionbar;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.o3dr.android.client.Drone;
import com.o3dr.services.android.lib.drone.attribute.AttributeEvent;
import com.o3dr.services.android.lib.drone.attribute.AttributeType;
import com.o3dr.services.android.lib.drone.property.Altitude;
import com.o3dr.services.android.lib.drone.property.Battery;
import com.o3dr.services.android.lib.drone.property.Gps;
import com.o3dr.services.android.lib.drone.property.Home;
import com.o3dr.services.android.lib.drone.property.Signal;
import com.o3dr.services.android.lib.drone.property.State;
import com.o3dr.services.android.lib.gcs.returnToMe.ReturnToMeState;
import com.o3dr.services.android.lib.util.MathUtils;
import org.beyene.sius.unit.length.LengthUnit;
import org.droidplanner.android.R;
import org.droidplanner.android.dialogs.SelectionListDialog;
import org.droidplanner.android.fragments.SettingsFragment;
import org.droidplanner.android.fragments.helpers.ApiListenerFragment;
import org.droidplanner.android.utils.Utils;
import org.droidplanner.android.utils.prefs.DroidPlannerPrefs;
import java.util.Locale;
/**
* Created by Fredia Huya-Kouadio on 1/14/15.
*/
public class ActionBarTelemFragment extends ApiListenerFragment {
private final static IntentFilter eventFilter = new IntentFilter();
static {
eventFilter.addAction(AttributeEvent.BATTERY_UPDATED);
eventFilter.addAction(AttributeEvent.STATE_CONNECTED);
eventFilter.addAction(AttributeEvent.STATE_DISCONNECTED);
eventFilter.addAction(AttributeEvent.GPS_POSITION);
eventFilter.addAction(AttributeEvent.GPS_COUNT);
eventFilter.addAction(AttributeEvent.GPS_FIX);
eventFilter.addAction(AttributeEvent.SIGNAL_UPDATED);
eventFilter.addAction(AttributeEvent.STATE_VEHICLE_MODE);
eventFilter.addAction(AttributeEvent.TYPE_UPDATED);
eventFilter.addAction(AttributeEvent.ALTITUDE_UPDATED);
eventFilter.addAction(SettingsFragment.ACTION_PREF_HDOP_UPDATE);
eventFilter.addAction(SettingsFragment.ACTION_PREF_UNIT_SYSTEM_UPDATE);
eventFilter.addAction(DroidPlannerPrefs.ACTION_PREF_RETURN_TO_ME_UPDATED);
eventFilter.addAction(AttributeEvent.RETURN_TO_ME_STATE_UPDATE);
eventFilter.addAction(AttributeEvent.HOME_UPDATED);
}
private final BroadcastReceiver eventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (getActivity() == null)
return;
switch (intent.getAction()) {
case AttributeEvent.BATTERY_UPDATED:
updateBatteryTelem();
break;
case AttributeEvent.STATE_CONNECTED:
showTelemBar();
updateAllTelem();
break;
case AttributeEvent.STATE_DISCONNECTED:
hideTelemBar();
updateAllTelem();
break;
case DroidPlannerPrefs.ACTION_PREF_RETURN_TO_ME_UPDATED:
case AttributeEvent.RETURN_TO_ME_STATE_UPDATE:
case AttributeEvent.GPS_POSITION:
case AttributeEvent.HOME_UPDATED:
updateHomeTelem();
break;
case AttributeEvent.GPS_COUNT:
case AttributeEvent.GPS_FIX:
updateGpsTelem();
break;
case AttributeEvent.SIGNAL_UPDATED:
updateSignalTelem();
break;
case AttributeEvent.STATE_VEHICLE_MODE:
case AttributeEvent.TYPE_UPDATED:
updateFlightModeTelem();
break;
case SettingsFragment.ACTION_PREF_HDOP_UPDATE:
updateGpsTelem();
break;
case SettingsFragment.ACTION_PREF_UNIT_SYSTEM_UPDATE:
updateHomeTelem();
break;
case AttributeEvent.ALTITUDE_UPDATED:
updateAltitudeTelem();
break;
default:
break;
}
}
};
private DroidPlannerPrefs appPrefs;
private TextView homeTelem;
private TextView altitudeTelem;
private TextView gpsTelem;
private PopupWindow gpsPopup;
private TextView batteryTelem;
private PopupWindow batteryPopup;
private TextView signalTelem;
private PopupWindow signalPopup;
private TextView flightModeTelem;
private String emptyString;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_action_bar_telem, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
emptyString = getString(R.string.empty_content);
final Context context = getActivity().getApplicationContext();
final LayoutInflater inflater = LayoutInflater.from(context);
final int popupWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
final int popupHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
final Drawable popupBg = getResources().getDrawable(android.R.color.transparent);
homeTelem = (TextView) view.findViewById(R.id.bar_home);
homeTelem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Launch dialog to allow the user to select between rtl and rtm
final SelectionListDialog selectionDialog = SelectionListDialog.newInstance(new ReturnToHomeAdapter(context, getDrone(), appPrefs));
Utils.showDialog(selectionDialog, getChildFragmentManager(), "Return to home type", true);
}
});
altitudeTelem = (TextView) view.findViewById(R.id.bar_altitude);
gpsTelem = (TextView) view.findViewById(R.id.bar_gps);
final View gpsPopupView = inflater.inflate(R.layout.popup_info_gps, (ViewGroup) view, false);
gpsPopup = new PopupWindow(gpsPopupView, popupWidth, popupHeight, true);
gpsPopup.setBackgroundDrawable(popupBg);
gpsTelem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
gpsPopup.showAsDropDown(gpsTelem);
}
});
batteryTelem = (TextView) view.findViewById(R.id.bar_battery);
final View batteryPopupView = inflater.inflate(R.layout.popup_info_power, (ViewGroup) view, false);
batteryPopup = new PopupWindow(batteryPopupView, popupWidth, popupHeight, true);
batteryPopup.setBackgroundDrawable(popupBg);
batteryTelem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
batteryPopup.showAsDropDown(batteryTelem);
}
});
signalTelem = (TextView) view.findViewById(R.id.bar_signal);
final View signalPopupView = inflater.inflate(R.layout.popup_info_signal, (ViewGroup) view, false);
signalPopup = new PopupWindow(signalPopupView, popupWidth, popupHeight, true);
signalPopup.setBackgroundDrawable(popupBg);
signalTelem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signalPopup.showAsDropDown(signalTelem);
}
});
flightModeTelem = (TextView) view.findViewById(R.id.bar_flight_mode);
flightModeTelem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Launch dialog to allow the user to select vehicle modes
final Drone drone = getDrone();
final SelectionListDialog selectionDialog = SelectionListDialog.newInstance(new FlightModeAdapter(context, drone));
Utils.showDialog(selectionDialog, getChildFragmentManager(), "Flight modes selection", true);
}
});
appPrefs = DroidPlannerPrefs.getInstance(context);
}
private void showTelemBar() {
final View view = getView();
if (view != null)
view.setVisibility(View.VISIBLE);
}
private void hideTelemBar() {
final View view = getView();
if (view != null)
view.setVisibility(View.GONE);
}
@Override
public void onStart() {
hideTelemBar();
super.onStart();
}
@Override
public void onApiConnected() {
final Drone drone = getDrone();
if (drone.isConnected())
showTelemBar();
else
hideTelemBar();
updateAllTelem();
getBroadcastManager().registerReceiver(eventReceiver, eventFilter);
}
@Override
public void onApiDisconnected() {
getBroadcastManager().unregisterReceiver(eventReceiver);
}
private void updateAllTelem() {
updateFlightModeTelem();
updateSignalTelem();
updateGpsTelem();
updateHomeTelem();
updateBatteryTelem();
updateAltitudeTelem();
}
private void updateFlightModeTelem() {
final Drone drone = getDrone();
final boolean isDroneConnected = drone.isConnected();
final State droneState = drone.getAttribute(AttributeType.STATE);
if (isDroneConnected) {
flightModeTelem.setText(droneState.getVehicleMode().getLabel());
flightModeTelem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_navigation_light_blue_a400_18dp, 0, 0, 0);
} else {
flightModeTelem.setText(emptyString);
flightModeTelem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_navigation_grey_700_18dp, 0, 0, 0);
}
}
private void updateSignalTelem() {
final Drone drone = getDrone();
final View popupView = signalPopup.getContentView();
TextView rssiView = (TextView) popupView.findViewById(R.id.bar_signal_rssi);
TextView remRssiView = (TextView) popupView.findViewById(R.id.bar_signal_remrssi);
TextView noiseView = (TextView) popupView.findViewById(R.id.bar_signal_noise);
TextView remNoiseView = (TextView) popupView.findViewById(R.id.bar_signal_remnoise);
TextView fadeView = (TextView) popupView.findViewById(R.id.bar_signal_fade);
TextView remFadeView = (TextView) popupView.findViewById(R.id.bar_signal_remfade);
final Signal droneSignal = drone.getAttribute(AttributeType.SIGNAL);
if (!drone.isConnected() || !droneSignal.isValid()) {
signalTelem.setText(emptyString);
signalTelem.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_signal_cellular_null_grey_700_18dp,
0, 0, 0);
rssiView.setText("RSSI: " + emptyString);
remRssiView.setText("RemRSSI: " + emptyString);
noiseView.setText("Noise: " + emptyString);
remNoiseView.setText("RemNoise: " + emptyString);
fadeView.setText("Fade: " + emptyString);
remFadeView.setText("RemFade: " + emptyString);
} else {
final int signalStrength = (int) droneSignal.getSignalStrength();
final int signalIcon;
if (signalStrength >= 100)
signalIcon = R.drawable.ic_signal_cellular_4_bar_grey_700_18dp;
else if (signalStrength >= 75)
signalIcon = R.drawable.ic_signal_cellular_3_bar_grey_700_18dp;
else if (signalStrength >= 50)
signalIcon = R.drawable.ic_signal_cellular_2_bar_grey_700_18dp;
else if (signalStrength >= 25)
signalIcon = R.drawable.ic_signal_cellular_1_bar_grey_700_18dp;
else
signalIcon = R.drawable.ic_signal_cellular_0_bar_grey_700_18dp;
signalTelem.setText(String.format(Locale.ENGLISH, "%d%%", signalStrength));
signalTelem.setCompoundDrawablesWithIntrinsicBounds(signalIcon, 0, 0, 0);
rssiView.setText(String.format("RSSI %2.0f dB", droneSignal.getRssi()));
remRssiView.setText(String.format("RemRSSI %2.0f dB", droneSignal.getRemrssi()));
noiseView.setText(String.format("Noise %2.0f dB", droneSignal.getNoise()));
remNoiseView.setText(String.format("RemNoise %2.0f dB", droneSignal.getRemnoise()));
fadeView.setText(String.format("Fade %2.0f dB", droneSignal.getFadeMargin()));
remFadeView.setText(String.format("RemFade %2.0f dB", droneSignal.getRemFadeMargin()));
}
signalPopup.update();
}
private void updateGpsTelem() {
final Drone drone = getDrone();
final boolean displayHdop = appPrefs.shouldGpsHdopBeDisplayed();
final View popupView = gpsPopup.getContentView();
TextView satNoView = (TextView) popupView.findViewById(R.id.bar_gps_satno);
TextView hdopStatusView = (TextView) popupView.findViewById(R.id.bar_gps_hdop_status);
hdopStatusView.setVisibility(displayHdop ? View.GONE : View.VISIBLE);
final String update;
final int gpsIcon;
if (!drone.isConnected()) {
update = (displayHdop ? "hdop: " : "") + emptyString;
gpsIcon = R.drawable.ic_gps_off_grey_700_18dp;
satNoView.setText("S: " + emptyString);
hdopStatusView.setText("hdop: " + emptyString);
} else {
Gps droneGps = drone.getAttribute(AttributeType.GPS);
final String fixStatus = droneGps.getFixStatus();
if (displayHdop) {
update = String.format(Locale.ENGLISH, "hdop: %.1f", droneGps.getGpsEph());
} else {
update = String.format(Locale.ENGLISH, "%s", fixStatus);
}
switch (fixStatus) {
case Gps.LOCK_3D:
case Gps.LOCK_3D_DGPS:
case Gps.LOCK_3D_RTK:
gpsIcon = R.drawable.ic_gps_fixed_black_24dp;
break;
case Gps.LOCK_2D:
case Gps.NO_FIX:
default:
gpsIcon = R.drawable.ic_gps_not_fixed_grey_700_18dp;
break;
}
satNoView.setText(String.format(Locale.ENGLISH, "S: %d", droneGps.getSatellitesCount()));
if (appPrefs.shouldGpsHdopBeDisplayed()) {
hdopStatusView.setText(String.format(Locale.ENGLISH, "%s", fixStatus));
} else {
hdopStatusView.setText(String.format(Locale.ENGLISH, "hdop: %.1f", droneGps.getGpsEph()));
}
}
gpsTelem.setText(update);
gpsTelem.setCompoundDrawablesWithIntrinsicBounds(gpsIcon, 0, 0, 0);
gpsPopup.update();
}
private void updateHomeTelem() {
final Drone drone = getDrone();
String update = getString(R.string.empty_content);
int drawableResId = appPrefs.isReturnToMeEnabled()
? R.drawable.ic_person_grey_700_18dp
: R.drawable.ic_home_grey_700_18dp;
if (drone.isConnected()) {
final Gps droneGps = drone.getAttribute(AttributeType.GPS);
final Home droneHome = drone.getAttribute(AttributeType.HOME);
if (droneGps.isValid() && droneHome.isValid()) {
LengthUnit distanceToHome = getLengthUnitProvider().boxBaseValueToTarget
(MathUtils.getDistance2D(droneHome.getCoordinate(), droneGps.getPosition()));
update = String.format("%s", distanceToHome);
final ReturnToMeState returnToMe = drone.getAttribute(AttributeType.RETURN_TO_ME_STATE);
switch (returnToMe.getState()) {
case ReturnToMeState.STATE_UPDATING_HOME:
//Change the home telemetry icon
drawableResId = R.drawable.ic_person_blue_a400_18dp;
break;
case ReturnToMeState.STATE_USER_LOCATION_INACCURATE:
case ReturnToMeState.STATE_USER_LOCATION_UNAVAILABLE:
case ReturnToMeState.STATE_WAITING_FOR_VEHICLE_GPS:
case ReturnToMeState.STATE_ERROR_UPDATING_HOME:
drawableResId = R.drawable.ic_person_red_500_18dp;
update = getString(R.string.empty_content);
break;
}
}
}
homeTelem.setCompoundDrawablesWithIntrinsicBounds(drawableResId, 0, 0, 0);
homeTelem.setText(update);
}
private void updateBatteryTelem() {
final Drone drone = getDrone();
final View batteryPopupView = batteryPopup.getContentView();
final TextView dischargeView = (TextView) batteryPopupView.findViewById(R.id.bar_power_discharge);
final TextView currentView = (TextView) batteryPopupView.findViewById(R.id.bar_power_current);
final TextView remainView = (TextView) batteryPopupView.findViewById(R.id.bar_power_remain);
String update;
Battery droneBattery;
final int batteryIcon;
if (!drone.isConnected() || ((droneBattery = drone.getAttribute(AttributeType.BATTERY)) == null)) {
update = emptyString;
dischargeView.setText("D: " + emptyString);
currentView.setText("C: " + emptyString);
remainView.setText("R: " + emptyString);
batteryIcon = R.drawable.ic_battery_circle_0_24dp;
} else {
Double discharge = droneBattery.getBatteryDischarge();
String dischargeText;
if (discharge == null) {
dischargeText = "D: " + emptyString;
} else {
dischargeText = "D: " + electricChargeToString(discharge);
}
dischargeView.setText(dischargeText);
final double battRemain = droneBattery.getBatteryRemain();
remainView.setText(String.format(Locale.ENGLISH, "R: %2.0f %%", battRemain));
currentView.setText(String.format("C: %2.1f A", droneBattery.getBatteryCurrent()));
update = String.format(Locale.ENGLISH, "%2.1fV", droneBattery.getBatteryVoltage());
if (battRemain >= 100) {
batteryIcon = R.drawable.ic_battery_circle_8_24dp;
} else if (battRemain >= 87.5) {
batteryIcon = R.drawable.ic_battery_circle_7_24dp;
} else if (battRemain >= 75) {
batteryIcon = R.drawable.ic_battery_circle_6_24dp;
} else if (battRemain >= 62.5) {
batteryIcon = R.drawable.ic_battery_circle_5_24dp;
} else if (battRemain >= 50) {
batteryIcon = R.drawable.ic_battery_circle_4_24dp;
} else if (battRemain >= 37.5) {
batteryIcon = R.drawable.ic_battery_circle_3_24dp;
} else if (battRemain >= 25) {
batteryIcon = R.drawable.ic_battery_circle_2_24dp;
} else if (battRemain >= 12.5) {
batteryIcon = R.drawable.ic_battery_circle_1_24dp;
} else {
batteryIcon = R.drawable.ic_battery_circle_0_24dp;
}
}
batteryPopup.update();
batteryTelem.setText(update);
batteryTelem.setCompoundDrawablesWithIntrinsicBounds(batteryIcon, 0, 0, 0);
}
private String electricChargeToString(double chargeInmAh) {
double absCharge = Math.abs(chargeInmAh);
if (absCharge >= 1000) {
return String.format(Locale.US, "%2.1f Ah", chargeInmAh / 1000);
} else {
return String.format(Locale.ENGLISH, "%2.0f mAh", chargeInmAh);
}
}
private void updateAltitudeTelem() {
final Drone drone = getDrone();
final Altitude altitude = drone.getAttribute(AttributeType.ALTITUDE);
if (altitude != null) {
double alt = altitude.getAltitude();
LengthUnit altUnit = getLengthUnitProvider().boxBaseValueToTarget(alt);
this.altitudeTelem.setText(altUnit.toString());
}
}
}