package com.openxc.enabler;
import java.util.Timer;
import java.util.TimerTask;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.openxc.VehicleManager;
import com.openxc.interfaces.VehicleInterfaceDescriptor;
import com.openxc.interfaces.bluetooth.BluetoothException;
import com.openxc.interfaces.bluetooth.BluetoothVehicleInterface;
import com.openxc.interfaces.bluetooth.DeviceManager;
import com.openxc.remote.VehicleServiceException;
import com.openxc.remote.ViConnectionListener;
import com.openxcplatform.enabler.R;
public class StatusFragment extends Fragment {
private static String TAG = "StatusFragment";
private TextView mMessageCountView;
private TextView mViVersionView;
private TextView mViPlatformView;
private TextView mViDeviceIdView;
private View mBluetoothConnIV;
private View mUsbConnIV;
private View mNetworkConnIV;
private View mFileConnIV;
private View mNoneConnView;
private VehicleManager mVehicleManager;
private View mServiceNotRunningWarningView;
private TimerTask mUpdateMessageCountTask;
private TimerTask mUpdatePipelineStatusTask;
private Timer mTimer;
private synchronized void updateViInfo() {
if(mVehicleManager != null) {
// Must run in another thread or we get circular references to
// VehicleService -> StatusFragment -> VehicleService and the
// callback will just fail silently and be removed forever.
new Thread(new Runnable() {
public void run() {
try {
final String version = mVehicleManager.getVehicleInterfaceVersion();
final String deviceId = mVehicleManager.getVehicleInterfaceDeviceId();
final String platform = mVehicleManager.getVehicleInterfacePlatform();
getActivity().runOnUiThread(new Runnable() {
public void run() {
mViDeviceIdView.setText(deviceId);
mViVersionView.setText(version);
mViPlatformView.setText(platform);
}
});
} catch(NullPointerException e) {
// A bit of a hack, should probably use a lock - but
// this can happen if this view is being paused and it's
// not really a problem.
}
}
}).start();
}
}
private ViConnectionListener mConnectionListener = new ViConnectionListener.Stub() {
public void onConnected(final VehicleInterfaceDescriptor descriptor) {
Log.d(TAG, descriptor + " is now connected");
updateViInfo();
}
public void onDisconnected() {
if(getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "VI disconnected");
mViVersionView.setText("");
mViDeviceIdView.setText("");
mViPlatformView.setText("");
}
});
}
}
};
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
Log.i(TAG, "Bound to VehicleManager");
mVehicleManager = ((VehicleManager.VehicleBinder)service
).getService();
try {
mVehicleManager.addOnVehicleInterfaceConnectedListener(
mConnectionListener);
} catch(VehicleServiceException e) {
Log.e(TAG, "Unable to register VI connection listener", e);
}
if(getActivity() == null) {
Log.w(TAG, "Status fragment detached from activity");
}
if(mVehicleManager.isViConnected()) {
updateViInfo();
}
new Thread(new Runnable() {
public void run() {
try {
// It's possible that between starting the thread and
// this running, the manager has gone away.
if(mVehicleManager != null) {
mVehicleManager.waitUntilBound();
if(getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
mServiceNotRunningWarningView.setVisibility(View.GONE);
}
});
}
}
} catch(VehicleServiceException e) {
Log.w(TAG, "Unable to connect to VehicleService");
}
}
}).start();
mUpdateMessageCountTask = new MessageCountTask(mVehicleManager,
getActivity(), mMessageCountView);
mUpdatePipelineStatusTask = new PipelineStatusUpdateTask(
mVehicleManager, getActivity(),
mFileConnIV, mNetworkConnIV, mBluetoothConnIV, mUsbConnIV,
mNoneConnView);
mTimer = new Timer();
mTimer.schedule(mUpdateMessageCountTask, 100, 1000);
mTimer.schedule(mUpdatePipelineStatusTask, 100, 1000);
}
public synchronized void onServiceDisconnected(ComponentName className) {
Log.w(TAG, "VehicleService disconnected unexpectedly");
mVehicleManager = null;
if(getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
mServiceNotRunningWarningView.setVisibility(View.VISIBLE);
}
});
}
}
};
@Override
public void onResume() {
super.onResume();
if(getActivity() != null) {
getActivity().bindService(
new Intent(getActivity(), VehicleManager.class),
mConnection, Context.BIND_AUTO_CREATE);
}
}
@Override
public synchronized void onPause() {
super.onPause();
if(mVehicleManager != null) {
getActivity().unbindService(mConnection);
mVehicleManager = null;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.status_fragment, container, false);
mServiceNotRunningWarningView = v.findViewById(R.id.service_not_running_bar);
mMessageCountView = (TextView) v.findViewById(R.id.message_count);
mViVersionView = (TextView) v.findViewById(R.id.vi_version);
mViPlatformView = (TextView) v.findViewById(R.id.vi_device_platform);
mViDeviceIdView = (TextView) v.findViewById(R.id.vi_device_id);
mBluetoothConnIV = v.findViewById(R.id.connection_bluetooth);
mUsbConnIV = v.findViewById(R.id.connection_usb);
mFileConnIV = v.findViewById(R.id.connection_file);
mNetworkConnIV = v.findViewById(R.id.connection_network);
mNoneConnView = v.findViewById(R.id.connection_none);
v.findViewById(R.id.start_bluetooth_search_btn).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
DeviceManager deviceManager = new DeviceManager(getActivity());
deviceManager.startDiscovery();
// Re-adding the interface with a null address triggers
// automatic mode 1 time
mVehicleManager.setVehicleInterface(
BluetoothVehicleInterface.class, null);
// clears the existing explicitly set Bluetooth device.
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(
getActivity()).edit();
editor.putString(getString(R.string.bluetooth_mac_key),
getString(R.string.bluetooth_mac_automatic_option));
editor.commit();
} catch(BluetoothException e) {
Toast.makeText(getActivity(),
"Bluetooth is disabled, can't search for devices",
Toast.LENGTH_LONG).show();
} catch(VehicleServiceException e) {
Log.e(TAG, "Unable to enable Bluetooth vehicle interface", e);
}
}
});
getActivity().runOnUiThread(new Runnable() {
public void run() {
mServiceNotRunningWarningView.setVisibility(View.VISIBLE);
}
});
return v;
}
}