} catch (InterruptedException e) {
connection_lost();
}
- }
+ }
+
+ private static final int buffer_size = 1024;
+
+ private byte[] buffer = new byte[buffer_size];
+ private int buffer_len = 0;
+ private int buffer_off = 0;
public int getchar() {
- try {
- wait_connected();
- return input.read();
- } catch (IOException e) {
- connection_lost();
- } catch (java.lang.InterruptedException e) {
- connection_lost();
+ while (buffer_off == buffer_len) {
+ try {
+ wait_connected();
+ buffer_len = input.read(buffer);
+ buffer_off = 0;
+ } catch (IOException e) {
+ connection_lost();
+ return AltosLink.ERROR;
+ } catch (java.lang.InterruptedException e) {
+ connection_lost();
+ return AltosLink.ERROR;
+ }
}
- return AltosLink.ERROR;
+ return buffer[buffer_off++];
}
public void close() {
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
public class AltosDroid extends FragmentActivity {
// Debugging
- private static final String TAG = "AltosDroid";
- private static final boolean D = true;
+ static final String TAG = "AltosDroid";
+ static final boolean D = true;
// Message types received by our Handler
public static final int MSG_STATE_CHANGE = 1;
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
+ public static FragmentManager fm;
+
// Layout Views
private TextView mTitle;
ad.set_location((Location) msg.obj);
break;
case MSG_CRC_ERROR:
+ break;
case MSG_UPDATE_AGE:
if (ad.saved_state != null) {
ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000));
void set_location(Location location) {
saved_location = location;
+ Log.d(TAG, "set_location");
update_ui(saved_state);
}
+ boolean same_string(String a, String b) {
+ if (a == null) {
+ if (b == null)
+ return true;
+ return false;
+ } else {
+ if (b == null)
+ return false;
+ return a.equals(b);
+ }
+ }
+
void update_ui(AltosState state) {
+
+ Log.d(TAG, "update_ui");
if (state != null && saved_state != null) {
if (saved_state.state != state.state) {
String currentTab = mTabHost.getCurrentTabTag();
+ Log.d(TAG, "switch state");
switch (state.state) {
case AltosLib.ao_flight_boost:
if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent");
}
}
}
- saved_state = state;
AltosGreatCircle from_receiver = null;
}
if (state != null) {
- mCallsignView.setText(state.callsign);
- mSerialView.setText(String.format("%d", state.serial));
- mFlightView.setText(String.format("%d", state.flight));
- mStateView.setText(state.state_name());
- mRSSIView.setText(String.format("%d", state.rssi));
+ if (saved_state == null || !same_string(saved_state.callsign, state.callsign)) {
+ Log.d(TAG, "update callsign");
+ mCallsignView.setText(state.callsign);
+ }
+ if (saved_state == null || state.serial != saved_state.serial) {
+ Log.d(TAG, "update serial");
+ mSerialView.setText(String.format("%d", state.serial));
+ }
+ if (saved_state == null || state.flight != saved_state.flight) {
+ Log.d(TAG, "update flight");
+ mFlightView.setText(String.format("%d", state.flight));
+ }
+ if (saved_state == null || state.state != saved_state.state) {
+ Log.d(TAG, "update state");
+ mStateView.setText(state.state_name());
+ }
+ if (saved_state == null || state.rssi != saved_state.rssi) {
+ Log.d(TAG, "update rssi");
+ mRSSIView.setText(String.format("%d", state.rssi));
+ }
}
for (AltosDroidTab mTab : mTabs)
- mTab.update_ui(state, from_receiver, saved_location);
+ mTab.update_ui(state, from_receiver, saved_location, mTab == mTabsAdapter.currentItem());
if (state != null)
mAltosVoice.tell(state);
+
+ saved_state = state;
}
private void onTimerTick() {
super.onCreate(savedInstanceState);
if(D) Log.e(TAG, "+++ ON CREATE +++");
+ fm = getSupportFragmentManager();
+
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
import org.altusmetrum.altoslib_5.*;
import android.location.Location;
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.app.FragmentManager;
+import android.location.Location;
+import android.util.Log;
+
+public abstract class AltosDroidTab extends Fragment {
+ AltosState last_state;
+ AltosGreatCircle last_from_receiver;
+ Location last_receiver;
+
+ public abstract void show(AltosState state, AltosGreatCircle from_receiver, Location receiver);
+
+ public abstract String tab_name();
+
+ public void set_visible(boolean visible) {
+ FragmentTransaction ft = AltosDroid.fm.beginTransaction();
+ if (visible)
+ ft.show(this);
+ else
+ ft.hide(this);
+ ft.commit();
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) {
+ if (is_current) {
+ Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name()));
+
+ show(state, from_receiver, receiver);
+ } else {
+ Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name()));
+ last_state = state;
+ last_from_receiver = from_receiver;
+ last_receiver = receiver;
+ return;
+ }
+ }
+
+ public void onHiddenChanged(boolean hidden) {
+ if (last_state != null && isVisible()) {
+ AltosState state = last_state;
+ AltosGreatCircle from_receiver = last_from_receiver;
+ Location receiver = last_receiver;
-public interface AltosDroidTab {
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver);
+ last_state = null;
+ last_from_receiver = null;
+ last_receiver = null;
+ show(state, from_receiver, receiver);
+ }
+ }
}
}
- public void speak(String s) {
+ public synchronized void speak(String s) {
if (!tts_enabled) return;
tts.speak(s, TextToSpeech.QUEUE_ADD, null);
}
}
}
old_state = state;
- idle_thread.notice(state, spoke);
+ if (idle_thread != null)
+ idle_thread.notice(state, spoke);
}
state.state == AltosLib.ao_flight_stateless) &&
state.range >= 0)
{
- speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
- (int) (state.height() + 0.5),
- state.from_pad.bearing_words(
- AltosGreatCircle.BEARING_VOICE),
- (int) (state.from_pad.bearing + 0.5),
- (int) (state.elevation + 0.5),
- (int) (state.range + 0.5)));
+ if (state.from_pad != null) {
+ speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
+ (int) (state.height() + 0.5),
+ state.from_pad.bearing_words(
+ AltosGreatCircle.BEARING_VOICE),
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.elevation + 0.5),
+ (int) (state.range + 0.5)));
+ } else {
+ speak(String.format("Height %d, elevation %d, range %d.\n",
+ (int) (state.height() + 0.5),
+ (int) (state.elevation + 0.5),
+ (int) (state.range + 0.5)));
+ }
} else if (state.state > AltosLib.ao_flight_pad) {
if (state.height() != AltosLib.MISSING)
speak(String.format("%d meters", (int) (state.height() + 0.5)));
import android.widget.TextView;
import android.location.Location;
-public class TabAscent extends Fragment implements AltosDroidTab {
+public class TabAscent extends AltosDroidTab {
AltosDroid mAltosDroid;
private TextView mHeightView;
mAltosDroid = null;
}
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ public String tab_name() {
+ return "ascent";
+ }
+
+ public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height()));
import android.widget.TextView;
import android.location.Location;
-public class TabDescent extends Fragment implements AltosDroidTab {
+public class TabDescent extends AltosDroidTab {
AltosDroid mAltosDroid;
private TextView mSpeedView;
mAltosDroid = null;
}
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ public String tab_name() { return "descent"; }
+
+ public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
import android.widget.TextView;
import android.location.Location;
-public class TabLanded extends Fragment implements AltosDroidTab {
+public class TabLanded extends AltosDroidTab {
AltosDroid mAltosDroid;
private TextView mBearingView;
mAltosDroid = null;
}
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ public String tab_name() { return "landed"; }
+
+ public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (from_receiver != null) {
mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "W", "E"));
}
-
+
if (state != null) {
mMaxHeightView.setText(String.format("%6.0f m", state.max_height()));
mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
}
}
-
}
import android.widget.TextView;
import android.location.Location;
-public class TabMap extends Fragment implements AltosDroidTab {
+public class TabMap extends AltosDroidTab {
AltosDroid mAltosDroid;
private SupportMapFragment mMapFragment;
private Marker mRocketMarker;
private Marker mPadMarker;
+ private boolean pad_set;
private Polyline mPolyline;
private TextView mDistanceView;
}
}
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ public String tab_name() { return "map"; }
+
+ public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (from_receiver != null) {
mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
mPolyline.setVisible(true);
}
- if (state.state == AltosLib.ao_flight_pad) {
+ if (!pad_set && state.pad_lat != AltosLib.MISSING) {
+ pad_set = true;
mPadMarker.setPosition(new LatLng(state.pad_lat, state.pad_lon));
mPadMarker.setVisible(true);
}
}
}
-
}
import android.widget.TextView;
import android.location.Location;
-public class TabPad extends Fragment implements AltosDroidTab {
+public class TabPad extends AltosDroidTab {
AltosDroid mAltosDroid;
private TextView mBatteryVoltageView;
mAltosDroid = null;
}
- public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ public String tab_name() { return "pad"; }
+
+ public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
if (state != null) {
mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage));
mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabWidget;
-
-
+import android.util.Log;
/**
* This is a helper class that implements the management of tabs and all
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+ private int position;
- static final class TabInfo {
+ static class TabInfo {
private final String tag;
private final Class<?> clss;
private final Bundle args;
+ private Fragment fragment;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ Log.d(AltosDroid.TAG, String.format("TabsAdapter.getItem(%d)", position));
+ info.fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ return info.fragment;
+ }
+
+ public Fragment currentItem() {
+ TabInfo info = mTabs.get(position);
+ return info.fragment;
}
public void onTabChanged(String tabId) {
- int position = mTabHost.getCurrentTab();
+ AltosDroidTab prev_frag = (AltosDroidTab) mTabs.get(position).fragment;
+
+ position = mTabHost.getCurrentTab();
+
+ AltosDroidTab cur_frag = (AltosDroidTab) mTabs.get(position).fragment;
+
+ if (prev_frag != cur_frag) {
+ if (prev_frag != null) {
+ prev_frag.set_visible(false);
+ }
+ }
+ if (cur_frag != null) {
+ cur_frag.set_visible(true);
+ }
+ Log.d(AltosDroid.TAG, String.format("TabsAdapter.onTabChanged(%s) = %d", tabId, position));
mViewPager.setCurrentItem(position);
}