I have tried using plugins available:
flutter_android
This includes:
Sensor
SensorEvent
SensorEventListener
SensorManager
usb_serial
So i need to talk to usb devices however the plugin usb_serial
does not meet my needs since i need to use more than the package provides.
Basically i either need to create my own plugin or i need to find a way to expose the native android.hardware.usb to flutter.
Need help i don't know what is best or how to do either.
This was a long time ago but will try to help as best as possible
Since I was not able to find anything that met my needs I needed to create my own plugin using these
import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
My MainActivity look like this
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.CountDownTimer;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private static final String TAG = "D2XX";
private static final String CHANNEL = "bridge";
private static final String EVENT_CHANNEL = "event";
private static final String INPUT_EVENT_CHANNEL = "input";
private D2xxManager m_deviceManager = null;
private FT_Device m_connectedDevice;
private CONTROLLER_ENUMS m_CONTROLLER_STATUS = CONTROLLER_ENUMS.Closed;
private int m_iDeviceCount = 0;
private List<D2xxManager.FtDeviceInfoListNode> mDeviceInfoListNode;
private CountDownTimer m_updateTimer;
private final String m_initialBitMask = "00111100";
private boolean m_input1State = false;
private boolean m_input2State = false;
private boolean m_output1State = false;
private boolean m_output2State = false;
private static boolean bRegisterBroadcast = true;
private long timeLeftInMilliseconds;
private boolean m_MountedState = false;
boolean isRunning = false;
private enum CONTROLLER_ENUMS {
OK,
Opened,
Closed,
Failed,
}
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler((call, result) -> {
String strCallName = call.method.toUpperCase();
switch (strCallName) {
case "INITIALIZE": {
m_CONTROLLER_STATUS = CONTROLLER_ENUMS.OK;
boolean bConnected = Initialise();
result.success(bConnected);
}
break;
case "GETDEVICE": {
JSONObject retVal = GetDeviceList();
if (retVal != null) {
result.success(retVal.toString());
}
}
break;
case "CONNECTDEVICE": {
try {
String strSerialNumber = call.argument("SerialNumber");
if (m_connectedDevice == null) {
boolean bConnected = ConnectToDevice(strSerialNumber);
result.success(bConnected);
} else {
result.success(true);
}
} catch (Exception e) {
Log.e(TAG, "CONNECT TO DEVICE ANDROID EXC: ", e);
}
}
break;
case "SETOUTPUT": {
int output = (int) call.argument("outputNumber");
boolean state = (boolean) call.argument("state");
SetOutputs(output, state);
}
break;
case "GETINPUT": {
JSONObject retVal = CheckDeviceInputs();
if (retVal != null) {
result.success(retVal.toString());
}
}
break;
default:
break;
}
});
new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), EVENT_CHANNEL).setStreamHandler(
new EventChannel.StreamHandler() {
private BroadcastReceiver usbStateChangeReceiver;
#Override
public void onListen(Object arguments, EventChannel.EventSink events) {
usbStateChangeReceiver = createUSBStateChangeReceiver(events);
IntentFilter filter = new IntentFilter();
filter.addAction("android.hardware.usb.action.USB_DEVICE_ATTACHED");
filter.addAction("android.hardware.usb.action.USB_DEVICE_DETACHED");
registerReceiver(
usbStateChangeReceiver, filter);
}
#Override
public void onCancel(Object arguments) {
unregisterReceiver(usbStateChangeReceiver);
usbStateChangeReceiver = null;
}
}
);
new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), INPUT_EVENT_CHANNEL).setStreamHandler(
new EventChannel.StreamHandler() {
#Override
public void onListen(Object arguments, EventChannel.EventSink events) {
timeLeftInMilliseconds = 30000;
//timer is started when device is connected so tha android knows when to tell flutter button has
//been pressed
m_updateTimer = new CountDownTimer(timeLeftInMilliseconds, 100) {
public void onTick(long millisUntilFinished) {
isRunning = true;
JSONObject retVal = CheckDeviceInputs();
if (retVal != null) {
events.success(retVal.toString());
} else {
events.success(null);
}
}
public void onFinish() {
isRunning = false;
m_updateTimer.start();
}
}.start();
}
#Override
public void onCancel(Object arguments) {
//when event channel is closed we stop the timer then remove the method
if (m_updateTimer != null) {
isRunning = false;
m_updateTimer.cancel();
}
Log.w(TAG, "cancelling listener");
}
}
);
}
private BroadcastReceiver createUSBStateChangeReceiver(EventChannel.EventSink events) {
return new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//watches if the usb has been plugged in or not
String action = intent.getAction();
if ("android.hardware.usb.action.USB_DEVICE_DETACHED".equals(action)) {
Log.i(TAG, "Detached: ");
Toast.makeText(context, "Device detached",
Toast.LENGTH_LONG).show();
//if device usb plugs out cancel timer
m_connectedDevice = null;
events.success(false);
} else if ("android.hardware.usb.action.USB_DEVICE_ATTACHED".equals(action)) {
Log.i(TAG, "Attached:");
Toast.makeText(context, "Device attached",
Toast.LENGTH_LONG).show();
if (m_updateTimer != null) {
Log.e(TAG, "START THE TIMER: ");
m_updateTimer.start();
}
events.success(true);
}
}
};
}
// INITIALISE
private boolean Initialise() {
try {
m_deviceManager = D2xxManager.getInstance(this);
return m_deviceManager != null;
} catch (D2xxManager.D2xxException exc) {
Log.e(TAG, "Initialise: Failed to get instance");
return false;
}
}
// GET ALL CONNECTED DEVICES
private JSONObject GetDeviceList() {
// first check if the list is empty, then create the list based on what is plugged in
// for now only the first device will be connect
try {
m_iDeviceCount = m_deviceManager.createDeviceInfoList(this);
if (m_iDeviceCount == 0)
return null;
D2xxManager.FtDeviceInfoListNode firstItem = m_deviceManager.getDeviceInfoListDetail(0);
JSONObject returnData = new JSONObject();
try {
//create connected device info object to send to flutter
returnData.put("ID", firstItem.id);
returnData.put("Description", firstItem.description);
returnData.put("BCDDevice", firstItem.bcdDevice);
returnData.put("LineStatus", firstItem.lineStatus);
returnData.put("ModemStatus", firstItem.modemStatus);
returnData.put("Type", firstItem.type);
returnData.put("SerialNumber", firstItem.serialNumber);
return returnData;
} catch (JSONException e) {
e.printStackTrace();
Log.e(TAG, "GetDeviceList: Failed" + e);
return null;
}
} catch (Exception exc) {
Log.e(TAG, "GetDeviceList: Failed" + exc);
return null;
}
}
// CONNECT THE DEVICE
private boolean ConnectToDevice(String strSerialNumber) {
try {
m_connectedDevice = m_deviceManager.openBySerialNumber(this, strSerialNumber);
//m_initialBitMask
if (m_connectedDevice != null && m_connectedDevice.isOpen()) {
//printing the device details
Log.i(TAG, "ConnectToDevice: IsOpen : ");
Log.i(TAG, "ConnectToDevice: IsOpen : " + m_connectedDevice.getDeviceInfo().serialNumber);
Log.i(TAG, "ConnectToDevice: description : " + m_connectedDevice.getDeviceInfo().description);
Log.i(TAG, "ConnectToDevice: serialNumber : " + m_connectedDevice.getDeviceInfo().serialNumber);
Log.i(TAG, "ConnectToDevice: bcdDevice : " + String.valueOf(m_connectedDevice.getDeviceInfo().bcdDevice));
//setting bit mode
m_connectedDevice.setBitMode(Byte.parseByte(m_initialBitMask, 2), D2xxManager.FT_BITMODE_CBUS_BITBANG);
return true;
} else {
m_CONTROLLER_STATUS = CONTROLLER_ENUMS.Closed;
return false;
}
} catch (Exception exc) {
m_CONTROLLER_STATUS = CONTROLLER_ENUMS.Failed;
Log.e(TAG, "ConnectToDevice: Failed" + exc);
Log.i(TAG, "ConnectToDevice: IsNotOpen");
return false;
}
}
// SET OUTPUTS TO DEVICE
private void SetOutputs(int outputNumber, boolean bState) {
//if device is connected you can use this to activate relays
if (m_connectedDevice != null && m_connectedDevice.isOpen()) {
byte lByteMask = m_connectedDevice.getBitMode();
switch (outputNumber) {
//relay 1
case 1: {
if (bState) {
lByteMask |= 1;
} else {
lByteMask &= 0xFE;
}
}
break;
//relay 2
case 2: {
if (bState) {
lByteMask |= 2;
} else {
lByteMask &= 0xFD;
}
}
break;
}
//fire with new values
m_connectedDevice.setBitMode(lByteMask, D2xxManager.FT_BITMODE_CBUS_BITBANG);
}
}
// READ INTERRUPTS - Timer based
private JSONObject CheckDeviceInputs() {
JSONObject returnData = new JSONObject();
try {
if (m_connectedDevice != null && m_connectedDevice.isOpen()) {
byte inputBytes = m_connectedDevice.getBitMode();
boolean input1 = (inputBytes & 0x04) != 0x04;
boolean input2 = (inputBytes & 0x08) != 0x08;
if (input1) {
m_input1State = true;
}
if (input2) {
m_input2State = true;
}
//if input is true global will be set above then below if the local is
//not true anymore it will activate and deactivate the relays
if (!input1 && m_input1State) {
SetOutputs(2, true);
try {
//delay so relay light is seen
Thread.sleep(200);
SetOutputs(2, false);
} catch (InterruptedException ex) {
Log.e(TAG, "Set time out: ", ex);
}
m_input1State = false;
}
if (!input2 && m_input2State) {
SetOutputs(1, true);
try {
//delay so relay light is seen
Thread.sleep(200);
SetOutputs(1, false);
} catch (InterruptedException ex) {
Log.e(TAG, "Set time out: ", ex);
}
m_input2State = false;
}
returnData.put("Input1State", input1);
returnData.put("Input2State", input2);
return returnData;
} else {
return null;
}
} catch (JSONException e) {
e.printStackTrace();
Log.e(TAG, "Failed to get DeviceStatus: Failed" + e);
return null;
}
}
}
On my flutter side I create a banner that listens to the I/O
import 'dart:convert';
import 'package:covidqa/Controllers/DeviceController.dart';
import 'package:covidqa/Models/IRelayDevice.dart';
import 'package:covidqa/Models/Inputs.dart';
import 'package:covidqa/StateHandler/globals.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:provider/provider.dart';
class BannerView extends StatefulWidget {
final Function(Inputs) returningInputs;
final Function(bool) connected;
BannerView(this.returningInputs, this.connected);
#override
BannerViewState createState() {
return BannerViewState();
}
}
class BannerViewState extends State<BannerView> {
DeviceController deviceController = new DeviceController();
EventChannel eventChannel = const EventChannel('event');
EventChannel inputEventChannel = const EventChannel('input');
bool init;
IRelayDevice device;
Inputs inputs;
String error;
bool hasDevice = false;
Globals globals;
bool connected = false;
bool inputState1 = false;
bool inputState2 = false;
bool outputState1 = false;
bool outputState2 = false;
_init() {
deviceController.init().then((value) {
if (value == true) {
getDevice();
}
});
}
Future<void> getDevice() async {
if (!mounted) {
return;
}
deviceController.getDevice().then((data) => setState(() {
device = data;
connectDevice();
}));
}
Future connectDevice() async {
if (!mounted) {
return;
}
if (device != null) {
deviceController.connectDevice(device).then((data) => setState(() {
widget.connected(data);
connected = data;
if (data) {
inputEventChannel
.receiveBroadcastStream()
.listen(_onInput, onError: deviceController.onError);
}
}));
} else {
getDevice();
}
}
#override
void initState() {
super.initState();
_init();
eventChannel
.receiveBroadcastStream()
.listen(_onEvent, onError: deviceController.onError);
}
void _onEvent(Object event) {
if (!mounted) {
widget.connected(false);
device = null;
connected = false;
return;
}
setState(() {
hasDevice = event;
if (!hasDevice) {
device = null;
connected = false;
widget.connected(false);
} else {
connectDevice();
}
});
}
void _onInput(Object event) {
try {
if (!mounted) {
return;
}
if (event == null) {
print("Result is null");
return;
}
Map bodyResult = jsonDecode(event);
inputs = Inputs.fromJson(bodyResult);
widget.returningInputs(inputs);
} on PlatformException catch (e) {
print("exception" + e.toString());
}
}
#override
Widget build(BuildContext context) {
globals = Provider.of<Globals>(context);
return Container(
color: connected ? Colors.green : Colors.red,
height: MediaQuery.of(context).size.height * 0.01,
);
}
}
Again this was long ago and cant remember much and the code is not the most tidy but this is the just of it good luck
Related
I am trying to create an Android activity which sends data through the serial port as a product test. I have some code for doing so, which, so far, finds no serial ports on my device which definitely has a serial port. I intend to use this activity with a loopback connector on the serial port of the device to verify both the read and write functionalities. I have tried these two programs:
import android.app.Activity;
import com.symbol.emdk.EMDKManager;
import com.symbol.emdk.EMDKManager.EMDKListener;
import com.symbol.emdk.EMDKManager.FEATURE_TYPE;
import com.symbol.emdk.EMDKResults;
import com.symbol.emdk.serialcomm.SerialComm;
import com.symbol.emdk.serialcomm.SerialCommException;
import com.symbol.emdk.serialcomm.SerialCommManager;
import com.symbol.emdk.serialcomm.SerialCommResults;
import com.symbol.emdk.serialcomm.SerialPortInfo;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;
import java.util.List;
public class SerialTry3 extends Activity implements EMDKListener{
private String TAG = SerialTry3.class.getSimpleName();
private EMDKManager emdkManager = null;
private SerialComm serialCommPort = null;
private SerialCommManager serialCommManager = null;
private EditText txtDataToSend = null;
private TextView txtStatus = null;
private Button btnRead = null;
private Button btnWrite = null;
private Spinner spinnerPorts = null;
public HashMap<String, SerialPortInfo> supportedPorts = null;
#Override #SuppressWarnings("SetTextI18n")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.serial_try);
txtDataToSend = (EditText) findViewById(R.id.txtDataToSend);
txtDataToSend.setText("Serial Communication Write Data Testing.");
spinnerPorts = (Spinner)findViewById(R.id.spinnerPorts);
btnWrite = (Button) findViewById(R.id.btnWrite);
btnRead = (Button) findViewById(R.id.btnRead);
txtStatus = (TextView) findViewById(R.id.statusView);
txtStatus.setText("");
txtStatus.requestFocus();
EMDKResults results = EMDKManager.getEMDKManager(getApplicationContext(), this);
if (results.statusCode != EMDKResults.STATUS_CODE.SUCCESS) {
new AsyncStatusUpdate().execute("EMDKManager object request failed!");
}
new AsyncUiControlUpdate().execute(false);
}
#Override
public void onOpened(EMDKManager emdkManager) {
this.emdkManager = emdkManager;
Log.d(TAG, "EMDK opened");
try{
serialCommManager = (SerialCommManager) this.emdkManager.getInstance(FEATURE_TYPE.SERIALCOMM_EX);
if(serialCommManager != null) {
populatePorts();
}
else
{
new AsyncStatusUpdate().execute(FEATURE_TYPE.SERIALCOMM_EX.toString() + " Feature not supported.");
}
}
catch(Exception e)
{
Log.d(TAG, e.getMessage());
new AsyncStatusUpdate().execute(e.getMessage());
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.splash_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onDestroy() {
super.onDestroy();
deinitSerialComm();
if (emdkManager != null) {
emdkManager.release();
emdkManager = null;
}
}
#Override
protected void onPause()
{
super.onPause();
deinitSerialComm();
serialCommManager = null;
supportedPorts = null;
// Release the serialComm manager resources
if (emdkManager != null) {
emdkManager.release(FEATURE_TYPE.SERIALCOMM_EX);
}
}
#Override
protected void onResume()
{
super.onResume();
// Acquire the serialComm manager resources
if (emdkManager != null) {
serialCommManager = (SerialCommManager) emdkManager.getInstance(FEATURE_TYPE.SERIALCOMM_EX);
if (serialCommManager != null) {
populatePorts();
if (supportedPorts != null)
initSerialComm();
}
}
}
void populatePorts()
{
try {
if(serialCommManager != null) {
List<SerialPortInfo> serialPorts = serialCommManager.getSupportedPorts();
if(serialPorts.size()>0) {
supportedPorts = new HashMap<String, SerialPortInfo> ();
String[] ports = new String[serialPorts.size()];
int count = 0;
for (SerialPortInfo info : serialPorts) {
supportedPorts.put(info.getFriendlyName(), info);
ports[count] = info.getFriendlyName();
count++;
}
spinnerPorts.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_dropdown_item, ports));
spinnerPorts.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//Disabling previous serial port before getting the new one
deinitSerialComm();
initSerialComm();
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
else
{
new AsyncStatusUpdate().execute("Failed to get available ports");
Toast.makeText(this, "Failed to get available ports, serial communication may not be supported.", Toast.LENGTH_LONG).show();
finish();
}
}
else
{
new AsyncStatusUpdate().execute("SerialCommManager is null");
}
}
catch (Exception ex)
{
Log.d(TAG, ex.getMessage());
new AsyncStatusUpdate().execute(ex.getMessage());
}
}
void initSerialComm() {
new AsyncEnableSerialComm().execute(supportedPorts.get(spinnerPorts.getSelectedItem()));
}
#Override
public void onClosed() {
if(emdkManager != null) {
emdkManager.release();
}
new AsyncStatusUpdate().execute("EMDK closed unexpectedly! Please close and restart the application.");
}
public void btnReadOnClick(View arg)
{
new AsyncReadData().execute();
}
public void btnWriteOnClick(View arg)
{
new AsyncUiControlUpdate().execute(false);
try {
String writeData = txtDataToSend.getText().toString();
int bytesWritten = serialCommPort.write(writeData.getBytes(), writeData.getBytes().length);
new AsyncStatusUpdate().execute("Bytes written: "+ bytesWritten);
} catch (SerialCommException e) {
new AsyncStatusUpdate().execute("write: "+ e.getResult().getDescription());
}
catch (Exception e) {
new AsyncStatusUpdate().execute("write: "+ e.getMessage() + "\n");
}
new AsyncUiControlUpdate().execute(true);
}
void deinitSerialComm() {
if (serialCommPort != null) {
try {
serialCommPort.disable();
serialCommPort = null;
} catch (Exception ex) {
Log.d(TAG, "deinitSerialComm disable Exception: " + ex.getMessage());
}
}
}
#SuppressWarnings("StaticFieldLeak")
private class AsyncStatusUpdate extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
return params[0];
}
#Override
protected void onPostExecute(String result) {
txtStatus.setText(result);
}
}
#SuppressWarnings("StaticFieldLeak")
private class AsyncUiControlUpdate extends AsyncTask<Boolean, Void, Boolean> {
#Override
protected Boolean doInBackground(Boolean... arg0) {
return arg0[0];
}
#Override
protected void onPostExecute(Boolean bEnable) {
btnRead.setEnabled(bEnable);
btnWrite.setEnabled(bEnable);
txtDataToSend.setEnabled(bEnable);
spinnerPorts.setEnabled(bEnable);
}
}
#SuppressWarnings("StaticFieldLeak")
private class AsyncEnableSerialComm extends AsyncTask<SerialPortInfo, Void, SerialCommResults>
{
#Override
protected SerialCommResults doInBackground(SerialPortInfo... params) {
SerialCommResults returnvar = SerialCommResults.FAILURE;
try {
serialCommPort = serialCommManager.getPort(params[0]);
} catch (Exception ex) {
ex.printStackTrace();
}
if (serialCommPort != null) {
try {
serialCommPort.enable();
returnvar = SerialCommResults.SUCCESS;
} catch (SerialCommException e) {
Log.d(TAG, e.getMessage());
e.printStackTrace();
returnvar = e.getResult();
}
}
return returnvar;
}
#Override #SuppressWarnings("SetTextI18n")
protected void onPostExecute(SerialCommResults result) {
super.onPostExecute(result);
if (result == SerialCommResults.SUCCESS) {
new AsyncStatusUpdate().execute("Serial comm channel enabled: (" + spinnerPorts.getSelectedItem().toString() + ")");
txtDataToSend.setText("Serial Communication Write Data Testing " + spinnerPorts.getSelectedItem().toString() + ".");
new AsyncUiControlUpdate().execute(true);
} else {
new AsyncStatusUpdate().execute(result.getDescription());
new AsyncUiControlUpdate().execute(false);
}
}
}
#SuppressWarnings("StaticFieldLeak")
private class AsyncReadData extends AsyncTask<Void, Void, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
new AsyncUiControlUpdate().execute(false);
new AsyncStatusUpdate().execute("Reading..");
}
#Override
protected String doInBackground(Void... params) {
String statusText = "";
try {
byte[] readBuffer = serialCommPort.read(10000); //Timeout after 10 seconds
if (readBuffer != null) {
String tempString = new String(readBuffer);
statusText = "Data Read:\n" + tempString;
} else {
statusText = "No Data Available";
}
} catch (SerialCommException e) {
statusText = "read:" + e.getResult().getDescription();
} catch (Exception e) {
statusText = "read:" + e.getMessage();
}
return statusText;
}
#Override
protected void onPostExecute(String statusText) {
super.onPostExecute(statusText);
new AsyncUiControlUpdate().execute(true);
new AsyncStatusUpdate().execute(statusText);
}
}
}
and
import android.app.Activity;
import com.symbol.emdk.EMDKManager;
import com.symbol.emdk.EMDKManager.FEATURE_TYPE;
import com.symbol.emdk.EMDKResults;
import com.symbol.emdk.serialcomm.SerialComm;
import com.symbol.emdk.serialcomm.SerialCommException;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.symbol.emdk.serialcomm.SerialCommManager;
import com.symbol.emdk.serialcomm.SerialPortInfo;
import java.util.List;
public class SerialTry extends Activity implements EMDKManager.EMDKListener {
private String TAG = SerialTry.class.getSimpleName();
private EMDKManager emdkManager = null;
private SerialComm serialComm = null;
private SerialCommManager serialCommMan = null;
private EditText editText = null;
private TextView statusView = null;
private Button readButton = null;
private Button writeButton = null;
#Override #SuppressWarnings("SetTextI18n")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.serial_try);
editText = (EditText) findViewById(R.id.editText1);
editText.setText("Serial Communication Write Data Testing.");
statusView = (TextView) findViewById(R.id.statusView);
statusView.setText("");
statusView.requestFocus();
EMDKResults results = EMDKManager.getEMDKManager(getApplicationContext(), this);
if (results.statusCode != EMDKResults.STATUS_CODE.SUCCESS) {
statusView.setText("Failed to open EMDK");
} else {
statusView.setText("Opening EMDK...");
}
//
// Get the serialComm/port object by passing a SerialPortInfo object:
addReadButtonEvents();
writeButtonEvents();
setEnabled(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.splash_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (emdkManager != null) {
emdkManager.release();
emdkManager = null;
}
}
#Override
public void onOpened(EMDKManager emdkManager) {
this.emdkManager = emdkManager;
Log.d(TAG, "EMDK opened");
try{
serialCommMan = (SerialCommManager) this.emdkManager.getInstance(EMDKManager.FEATURE_TYPE.SERIALCOMM_EX);
List<SerialPortInfo> serialPorts = serialCommMan.getSupportedPorts();
serialComm = serialCommMan.getPort(serialPorts.get(0));
System.out.println("Supported Ports::::::" + serialPorts);
Thread readThread = new Thread(new Runnable() {
#Override
public void run() {
String statusText;
if (serialComm != null) {
try{
serialComm.enable();
statusText = "Serial comm channel enabled";
setEnabled(true);
} catch(SerialCommException e){
Log.d(TAG, e.getMessage());
e.printStackTrace();
statusText = e.getMessage();
setEnabled(false);
}
} else {
statusText = FEATURE_TYPE.SERIALCOMM_EX.toString() + " Feature not supported or initilization error.";
setEnabled(false);
}
displayMessage(statusText);
}
});
readThread.start();
}
catch(Exception e)
{
Log.d(TAG, e.getMessage());
e.printStackTrace();
displayMessage(e.getMessage());
}
}
#Override
public void onClosed() {
if(emdkManager != null) {
emdkManager.release();
}
displayMessage("EMDK closed abruptly.");
}
private void addReadButtonEvents() {
readButton = (Button) findViewById(R.id.btnRead);
readButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread readThread = new Thread(new Runnable() {
#Override
public void run() {
setEnabled(false);
String statusText;
try {
byte[] readBuffer = serialComm.read(10000); //Timeout after 10 seconds
if(readBuffer != null) {
String tempString = new String(readBuffer);
statusText = "Data Read:\n" + tempString;
} else {
statusText = "No Data Available";
}
}catch (SerialCommException e) {
statusText ="read:"+ e.getResult().getDescription();
e.printStackTrace();
}
catch (Exception e) {
statusText = "read:"+ e.getMessage();
e.printStackTrace();
}
setEnabled(true);
displayMessage(statusText);
}
});
readThread.start();
}
});
}
#SuppressWarnings("SetTextI18n")
private void writeButtonEvents() {
writeButton = (Button) findViewById(R.id.btnWrite);
writeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setEnabled(false);
try {
String writeData = editText.getText().toString();
int bytesWritten = serialComm.write(writeData.getBytes(), writeData.getBytes().length);
statusView.setText("Bytes written: "+ bytesWritten);
} catch (SerialCommException e) {
statusView.setText("write: "+ e.getResult().getDescription());
}
catch (Exception e) {
statusView.setText("write: "+ e.getMessage() + "\n");
}
setEnabled(true);
}
});
}
#SuppressWarnings("SetTextI18n")
void displayMessage(String message) {
final String tempMessage = message;
runOnUiThread(new Runnable() {
public void run() {
statusView.setText(tempMessage + "\n");
}
});
}
void setEnabled(boolean enableState) {
final boolean tempState = enableState;
runOnUiThread(new Runnable() {
public void run() {
readButton.setEnabled(tempState);
writeButton.setEnabled(tempState);
editText.setEnabled(tempState);
}
});
}
}
Does the problem seem to be with my code or is there something I am not understanding about the device itself? Any help would be appreciated. Thank you for your time.
I am trying to write a app which scans for beacons,
when I login to the app, it starts scanning but after some seconds it just crashes. if I turn off my bluetooth it works fine. this is the error I get:
Process: com.noxel.apppaneladmintry2, PID: 11192
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.niloofar.showroom.BeaconsFragment.onScannerClosed()' on a null object reference
at com.example.niloofar.showroom.BeaconScannerFragment.onCancel(BeaconScannerFragment.java:56)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1260)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:921)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:716)
and this is my code,
package com.example.niloofar.showroom;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.UUID;
import no.nordicsemi.android.beacon.Beacon;
import no.nordicsemi.android.beacon.BeaconRegion;
import no.nordicsemi.android.beacon.BeaconServiceConnection;
import no.nordicsemi.android.beacon.Proximity;
import no.nordicsemi.android.beacon.ServiceProxy;
public class drawermenu extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, BeaconServiceConnection.BeaconsListener, BeaconServiceConnection.RegionListener {
public ProfileFragment profileFragment;
private static final String SCANNER_FRAGMENT = "scannerFragment";
public static final String NRF_BEACON_SERVICE_URL = "market://details?id=no.nordicsemi.android.beacon.service";
public static final String OPENED_FROM_LAUNCHER = "no.nordicsemi.android.nrfbeacon.extra.opened_from_launcher";
public static final String EXTRA_OPEN_DFU = "no.nordicsemi.android.nrfbeacon.extra.open_dfu";
public static final int BEACON_COMPANY_ID = 0x0059;
private static final int REQUEST_ENABLE_BT = 1;
private boolean mServiceConnected;
private boolean mFragmentResumed;
private DatabaseHelper mDatabaseHelper;
private BeaconAdapter mAdapter;
private BeaconScannerFragment mScannerFragment;
int minor;
public Fragment fragment=null;
public FragmentA fragmentA;
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
Toast.makeText(this, "Device dows not support Bluetooth", Toast.LENGTH_LONG);
} else {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
mDatabaseHelper = new DatabaseHelper(this);
getSupportActionBar().setElevation(0);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}catch (Exception ex) {
Log.d("ERROR", ex.getMessage());
}
}
#Override
public void onStart() {
super.onStart();
// final Cursor cursor = mDatabaseHelper.getAllRegions();
bindService();
}
#Override
public void onResume() {
super.onResume();
// startScanning();
if (mFragmentResumed)
return;
mFragmentResumed = true;
// bindService();
onAddOrEditRegion();
}
#Override
public void onPause() {
super.onPause();
// stopScanning();
if (!mFragmentResumed)
return;
mFragmentResumed = false;
unbindService();
}
private BeaconServiceConnection mServiceConnection = new BeaconServiceConnection() {
#Override
public void onServiceConnected() {
try {
mServiceConnected = true;
final BeaconScannerFragment scannerFragment = mScannerFragment;
if (scannerFragment != null) {
startRangingBeaconsInRegion(BEACON_COMPANY_ID, BeaconRegion.ANY_UUID, scannerFragment);
} else {
// final FragmentManager fm = getChildFragmentManager();
// if (fm.getBackStackEntryCount() == 0) {
// Start scan only if there is no any other fragment (Mona Lisa) open
startScanning();
// }
}
} catch (Exception ex) {
Log.d("ERROR", ex.getMessage());
}
}
#Override
public void onServiceDisconnected() {
try {
mServiceConnected = false;
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
};
public void onAddOrEditRegion() {
// if (!ensurePermission())
// return;
try {
stopScanning();
// mScannerFragment=null;
final BeaconScannerFragment fragment = mScannerFragment = new BeaconScannerFragment();
fragment.show(getSupportFragmentManager(), SCANNER_FRAGMENT);
// fragment.isHidden();
mServiceConnection.startRangingBeaconsInRegion(BEACON_COMPANY_ID, BeaconRegion.ANY_UUID, fragment);
}
catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public void startScanning() {
try {
if (mServiceConnected) {
startScanning(mServiceConnection);
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public void stopScanning() {
try {
if (mServiceConnected) {
stopScanning(mServiceConnection);
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
private void bindService() {
// if (!ensurePermission())
// return;
try {
final boolean success = ServiceProxy.bindService(this, mServiceConnection);
if (!success) {
new AlertDialog.Builder(this).setTitle(R.string.service_required_title).setMessage(R.string.service_required_message)
.setPositiveButton(R.string.service_required_store, new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog, final int which) {
final Intent playIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(MainActivity.NRF_BEACON_SERVICE_URL));
startActivity(playIntent);
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(final DialogInterface dialog) {
dialog.dismiss();
finish();
}
}).show();
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
private void unbindService() {
try {
if (mServiceConnected) {
// Unbinding service will stop all active scanning listeners
ServiceProxy.unbindService(this, mServiceConnection);
mDatabaseHelper.resetSignalStrength();
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public void startScanning(final BeaconServiceConnection serviceConnection) {
try {
final Cursor cursor = mDatabaseHelper.getAllRegions();
while (cursor.moveToNext()) {
final UUID uuid = UUID.fromString(cursor.getString(2 /* UUID */));
final int major = cursor.getInt(3 /* MAJOR */);
final int minor = cursor.getInt(4 /* MINOR */);
final int event = cursor.getInt(6 /* EVENT */);
// We must start ranging for all beacons
serviceConnection.startRangingBeaconsInRegion(BEACON_COMPANY_ID, uuid, major, minor, this);
// And additionally start monitoring only for those with these two events set
if (event == BeaconContract.EVENT_IN_RANGE || event == BeaconContract.EVENT_OUT_OF_RANGE)
serviceConnection.startMonitoringForRegion(BEACON_COMPANY_ID, uuid, major, minor, this);
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public void stopScanning(final BeaconServiceConnection serviceConnection) {
try {
if (serviceConnection != null) {
serviceConnection.stopMonitoringForRegion(this);
serviceConnection.stopRangingBeaconsInRegion(this);
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
#Override
public void onBeaconsInRegion(final Beacon[] beacons, final BeaconRegion region) {
try {
if (beacons.length > 0) {
final Cursor cursor = mDatabaseHelper.findRegion(region);
try {
if (cursor.moveToNext()) {
// Check and fire events
final int event = cursor.getInt(6 /* EVENT */);
for (final Beacon beacon : beacons) {
if (event == BeaconContract.EVENT_ON_TOUCH && Proximity.IMMEDIATE.equals(beacon.getProximity()) && Proximity.NEAR.equals(beacon.getPreviousProximity())) {
fireEvent(cursor);
break;
}
if (event == BeaconContract.EVENT_GET_NEAR && Proximity.NEAR.equals(beacon.getProximity()) && Proximity.FAR.equals(beacon.getPreviousProximity())) {
fireEvent(cursor);
break;
}
}
// Update signal strength in the database
float accuracy = 5;
for (final Beacon beacon : beacons)
if (Proximity.UNKNOWN != beacon.getProximity() && beacon.getAccuracy() < accuracy)
accuracy = beacon.getAccuracy();
accuracy = -20 * accuracy + 100;
mDatabaseHelper.updateRegionSignalStrength(cursor.getLong(0 /* _ID */), (int) accuracy);
}
} finally {
cursor.close();
}
mAdapter.swapCursor(mDatabaseHelper.getAllRegions());
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
#Override
public void onEnterRegion(final BeaconRegion region) {
try {
final Cursor cursor = mDatabaseHelper.findRegion(region);
try {
if (cursor.moveToNext()) {
final int event = cursor.getInt(6 /* EVENT */);
if (event == BeaconContract.EVENT_IN_RANGE) {
fireEvent(cursor);
}
}
} finally {
cursor.close();
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
#Override
public void onExitRegion(final BeaconRegion region) {
try {
final Cursor cursor = mDatabaseHelper.findRegion(region);
try {
if (cursor.moveToNext()) {
final int event = cursor.getInt(6 /* EVENT */);
if (event == BeaconContract.EVENT_OUT_OF_RANGE) {
fireEvent(cursor);
}
}
} finally {
cursor.close();
}
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
private void fireEvent(final Cursor cursor) {
try {
final boolean enabled = cursor.getInt(9 /* ENABLED */) == 1;
if (!enabled)
return;
final int action = cursor.getInt(7 /* ACTION */);
final String actionParam = cursor.getString(8 /* ACTION PARAM */);
switch (action) {
case BeaconContract.ACTION_MONA_LISA: {
stopScanning();
// final DialogFragment dialog = new MonalisaFragment();
// dialog.show(mParentFragment.getChildFragmentManager(), "JIRNG");
break;
}
case BeaconContract.ACTION_SILENT: {
stopScanning();
// final DialogFragment dialog = new tarh();
// dialog.show(mParentFragment.getChildFragmentManager(), "JIRING");
break;
}
case BeaconContract.ACTION_ALARM: {
stopScanning();
// final DialogFragment dialog = new rest();
// dialog.show(mParentFragment.getChildFragmentManager(), "Jiring");
break;
}
case BeaconContract.ACTION_URL: {
stopScanning();
try {
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(actionParam));
startActivity(intent);
} catch (final ActivityNotFoundException e) {
Toast.makeText(this, R.string.no_application, Toast.LENGTH_SHORT).show();
}
break;
}
case BeaconContract.ACTION_APP: {
stopScanning();
try {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setPackage(actionParam);
startActivity(intent);
} catch (final ActivityNotFoundException e) {
Toast.makeText(this, R.string.no_given_application, Toast.LENGTH_SHORT).show();
}
break;
}
case BeaconContract.ACTION_TASKER:
// switch (TaskerIntent.testStatus(getActivity())) {
// case OK:
// final TaskerIntent i = new TaskerIntent(actionParam);
final BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent recIntent) {
// if (recIntent.getBooleanExtra(TaskerIntent.EXTRA_SUCCESS_FLAG, false))
Toast.makeText(drawermenu.this, R.string.tasker_success, Toast.LENGTH_SHORT).show();
drawermenu.this.unregisterReceiver(this);
}
};
// getActivity().registerReceiver(br, i.getCompletionFilter());
// Start the task
// getActivity().sendBroadcast(i);
break;
// case NotEnabled:
// Toast.makeText(getActivity(), R.string.tasker_disabled, Toast.LENGTH_SHORT).show();
// break;
// case AccessBlocked:
// Toast.makeText(getActivity(), R.string.tasker_external_access_denided, Toast.LENGTH_SHORT).show();
// break;
// case NotInstalled:
// Toast.makeText(getActivity(), R.string.tasker_not_installed, Toast.LENGTH_SHORT).show();
// break;
default:
Toast.makeText(this, R.string.tasker_error, Toast.LENGTH_SHORT).show();
break;
}
// break;
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public void onEditRegion(final long id) {
// final Intent intent = new Intent(this, BeaconsDetailsActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
// intent.putExtra(BeaconsDetailsActivity.ID, id);
// startActivity(intent);
}
public void onScannerClosedWithResult(final Beacon beacon) {
try {
mServiceConnection.stopRangingBeaconsInRegion(mScannerFragment);
mScannerFragment.dismiss();
mScannerFragment = null;
// final Cursor cursor = mDatabaseHelper.findRegionByBeacon(beacon);
minor = beacon.getMinor();
Intent intenta = new Intent(drawermenu.this, FragmentA.class);
switch (minor) {
case 99:
// startActivity(intenta);
popUp();
break;
case 246:
// startActivity(intenta);
// Toast.makeText(MainActivity.this, "246", Toast.LENGTH_LONG).show();
popUp();
break;
case 63:
popUp();
break;
case 104:
popUp();
break;
}
}
catch (Exception ex)
{
Log.e("ERROR", ex.getMessage());
}
}
private void popUp()
{
new Handler().post(new Runnable() {
#Override
public void run() {
/* Create an Intent that will start the Menu-Activity. */
Intent mainIntent = new Intent(drawermenu.this,FragmentA.class);
// mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
mainIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
drawermenu.this.startActivity(mainIntent);
// Splash.this.finish();
}
});
}
public void onScannerClosed() {
try {
mServiceConnection.stopRangingBeaconsInRegion(mScannerFragment);
mScannerFragment = null;
startScanning();
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
public DatabaseHelper getDatabaseHelper() {
return mDatabaseHelper;
}
private boolean ensureBleExists() {
try {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show();
return false;
}
return true;
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
return false;
}
}
private boolean isBleEnabled() {
try {
final BluetoothManager bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
final BluetoothAdapter ba = bm.getAdapter();
return ba != null && ba.isEnabled();
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
return false;
}
}
private void enableBle() {
try {
final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} catch (Exception ex) {
Log.e("ERROR", ex.getMessage());
}
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (id == R.id.nav_home) {
// Handle the camera action
fragment = new ProfileFragment();
} else if (id == R.id.nav_points) {
fragment = new PointFragment();
} else if (id == R.id.nav_coupons) {
fragment = new CouponFragment();
} else if (id == R.id.nav_about) {
fragment = new AboutFragment();
}
fragmentTransaction.replace(R.id.appbar, fragment,fragment.getClass().getSimpleName());
fragmentTransaction.commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
and this is the code which error is referring to:
package com.example.niloofar.showroom;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import no.nordicsemi.android.beacon.Beacon;
import no.nordicsemi.android.beacon.BeaconRegion;
import no.nordicsemi.android.beacon.BeaconServiceConnection;
import no.nordicsemi.android.beacon.Proximity;
/**
* Created by niloofar on 11/9/2016.
*/
public class BeaconScannerFragment extends DialogFragment implements BeaconServiceConnection.BeaconsListener {
// public class BeaconScannerFragment extends DialogFragment implements BeaconServiceConnection.BeaconsListener {
private boolean mCompleted;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCompleted = false;
}
#Override
public void onBeaconsInRegion(final Beacon[] beacons, final BeaconRegion region) {
if (!mCompleted) {
for (final Beacon beacon : beacons)
if (Proximity.IMMEDIATE == beacon.getProximity()) {
mCompleted = true;
final BeaconsFragment parentFragment = (BeaconsFragment) getParentFragment();
parentFragment.onScannerClosedWithResult(beacon);
dismiss();
break;
}
}
}
#NonNull
#Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
return new AlertDialog.Builder(getContext())
.setView(R.layout.fragment_scan).create();
}
#Override
public void onCancel(final DialogInterface dialog) {
super.onCancel(dialog);
final BeaconsFragment targetFragment = (BeaconsFragment) getParentFragment();
targetFragment.onScannerClosed();
}}
does anyone know how my problem will be solved?
This is the place where your problem occurs:
final BeaconsFragment parentFragment = (BeaconsFragment) getParentFragment();
parentFragment.onScannerClosedWithResult(beacon);
You initialize parentFragment, but the NullPointerException is thrown when you try to call onScannerClosedWithResult. This means that parentFragment is null. To solve this, you have three options. The first option is to use try-catch where you handle the NullPointerException. The second option is to make sure that getParentFragment will never return null. The third option is to fail gracefully when null is returned:
final BeaconsFragment parentFragment = (BeaconsFragment) getParentFragment();
if (parentFragment == null) {
parentFragment.onScannerClosedWithResult(beacon);
}
Hey guys ive been working on a project to create a type of wifi hot spot manager, so that it records the connected devices with mac address, ip address and other information. However i can't seem to work out as to why when i press get Clients from screen it doesn't gather any data of whos connected. I have compiled the file to an APK to test on my phone seeing as wifi functionality does not work on the emulator in android studio.
Credit for the code goes to:
1) Android 2.3 wifi hotspot API
2) https://www.whitebyte.info/android/android-wifi-hotspot-manager-class
package com.example.gavin.wifiattendance;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.nfc.Tag;
import android.os.AsyncTask;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.logging.LogRecord;
import android.os.Handler;
/**
* Created by Gavins on 05/03/2015.
*/
public class AccessPoint extends Activity {
private static int constant = 0;
private Context context;
private static int WIFI_STATE_UNKNOWN = -1;
private static int WIFI_STATE_DISABLING = 0;
private static int WIFI_STATE_DISABLED = 1;
public static int WIFI_STATE_ENABLING = 2;
public static int WIFI_STATE_ENABLED = 3;
private static int WIFI_STATE_FAILED = 4;
final static String[] WIFI_STATE_TEXTSTATE = new String[]{
"DISABLING","DISABLED","ENABLING","ENABLED","FAILED"
};
private WifiManager wifi;
private String TAG = "WifiAP";
private int stateWifi = -1;
private boolean alwaysEnabledWifi = true;
//enable or disable the wifi
public void toggleWifiAP(WifiManager wifiHandler, Context context){
if (wifi == null){
wifi = wifiHandler;
}
boolean wifiApIsOn = getWifiApState() == WIFI_STATE_ENABLED || getWifiApState()==WIFI_STATE_ENABLING;
new SetWifiApTask(!wifiApIsOn, false, context).execute();
}
private int setWifiApEnabled(boolean enabled){
Log.d(TAG, "Set wifi enabled called" + enabled);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Attend Lecture";
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
//remember wireless state
if (enabled && stateWifi == -1){
stateWifi = wifi.getWifiState();
}
//disable the wireless
if (enabled && wifi.getConnectionInfo() !=null){
Log.d(TAG, "disable wifi: calling");
wifi.setWifiEnabled(false);
int loopMax = 10;
while (loopMax > 0 && wifi.getWifiState() != WifiManager.WIFI_STATE_DISABLED){
Log.d(TAG, "Disable Wifi: Waiting, pass:" + (10-loopMax));
try{
Thread.sleep(500);
loopMax--;
}catch (Exception e){
e.printStackTrace();
}
}
Log.d(TAG, "Disabling wifi is done, pass: " + (10-loopMax));
}
//enable and disable wifi AP
int state = WIFI_STATE_UNKNOWN;
try {
Log.d(TAG, (enabled?"enabling":"Disabling")+"wifi ap: calling");
wifi.setWifiEnabled(false);
Method method1 = wifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method1.invoke(wifi, config, enabled);
Method method2 = wifi.getClass().getMethod("getWifiState");
state = (Integer)method2.invoke(wifi);
}catch (Exception e){
//Log.e(WIFI_SERVICE, e.getMessage());
}
//Use thread while processing occurs
if (!enabled){
int loopMax = 10;
while (loopMax>0 && (getWifiApState()==WIFI_STATE_DISABLING || getWifiApState()==WIFI_STATE_ENABLED || getWifiApState()==WIFI_STATE_FAILED)){
Log.d(TAG, (enabled?"enabling": "disabling")+ "wifi AP: waiting, pass:" + (10-loopMax));
try {
Thread.sleep(500);
loopMax--;
}catch (Exception e){
}
}
Log.d(TAG, (enabled?"enabling":"disabling")+" Wifi ap: done, pass: " + (10-loopMax));
//enable the wifi
if (stateWifi==WifiManager.WIFI_STATE_ENABLED || stateWifi==WifiManager.WIFI_STATE_ENABLING || stateWifi==WifiManager.WIFI_STATE_UNKNOWN || alwaysEnabledWifi){
Log.d(TAG, "enable wifi: Calling");
wifi.setWifiEnabled(true);
//this way it doesnt hold things up and waits for it to get enabled
}
stateWifi = -1;
}else if (enabled){
int loopMax = 10;
while (loopMax>0 && (getWifiApState()==WIFI_STATE_ENABLING || getWifiApState()==WIFI_STATE_DISABLED || getWifiApState()==WIFI_STATE_FAILED)){
Log.d(TAG, (enabled?"Enabling": "disabling") + "wifi ap: waiting, pass: " + (10-loopMax));
try{
Thread.sleep(500);
loopMax--;
}catch (Exception e){
}
}
Log.d(TAG, (enabled?"Enabling": "disabling")+ "wifi ap: done, pass: " + (10-loopMax));
}
return state;
}
//Get the wifi AP state
public int getWifiApState(){
int state = WIFI_STATE_UNKNOWN;
try {
Method method2 = wifi.getClass().getMethod("getWifiApState");
state = (Integer) method2.invoke(wifi);
}catch (Exception e){
}
if (state>=10){
constant=10;
}
WIFI_STATE_DISABLING = 0+constant;
WIFI_STATE_DISABLED = 1+constant;
WIFI_STATE_ENABLING = 2+constant;
WIFI_STATE_ENABLED = 3+constant;
WIFI_STATE_FAILED = 4+constant;
Log.d(TAG, "getWifiApState " + (state==-1?"UNKNOWN":WIFI_STATE_TEXTSTATE[state-constant]));
return state;
}
class SetWifiApTask extends AsyncTask<Void, Void, Void>{
boolean mMode;
boolean mFinish;
ProgressDialog pDialog;
public SetWifiApTask(boolean mode, boolean finish, Context context){
mMode = mode;
mFinish = finish;
pDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute(){
super.onPreExecute();
pDialog.setTitle("Turning on Access Point " + (mMode?"On":"Off" + "..."));
pDialog.setMessage("Please wait a moment...");
pDialog.show();
}
#Override
protected void onPostExecute(Void aVoid){
super.onPostExecute(aVoid);
try {
pDialog.dismiss();
MainActivity.updateStatusDisplay();
}catch (IllegalArgumentException e){
};
if (mFinish){
finish();
}
}
#Override
protected Void doInBackground(Void... params) {
setWifiApEnabled(mMode);
return null;
}
}
//get the list connected to the wifi hotspot
public void getClientList(boolean onlyReachable, FinishScanListener finishListener){
getClientList(onlyReachable, 300, finishListener);
}
public void getClientList(final boolean onlyReachable, final int reachableTimeout, final FinishScanListener finishListener){
Runnable runnable = new Runnable() {
#Override
public void run() {
BufferedReader br = null;
final ArrayList<ClientScanResult> result = new ArrayList<>();
try {
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null){
String[] splitted = line.split(" +");
if ((splitted !=null) && (splitted.length >=4)){
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")){
boolean isReachable = InetAddress.getByName(splitted[0]).isReachable(reachableTimeout);
if (!onlyReachable || isReachable){
result.add(new ClientScanResult(splitted[0], splitted[3], splitted[5], isReachable));
}
}
}
}
}catch (Exception e){
Log.e(this.getClass().toString(), e.toString());
}finally {
try {
br.close();
}catch (IOException e){
Log.e(this.getClass().toString(), e.getMessage());
}
}
//Get handler that will be used to post to main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
finishListener.onFinishScan(result);
}
};
mainHandler.post(myRunnable);
}
};
Thread myThread = new Thread(runnable);
myThread.start();
}
}
and here is the main activity file:
package com.example.gavin.wifiattendance;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.example.gavin.wifiattendance.AccessPoint;
import java.util.ArrayList;
public class MainActivity extends ActionBarActivity{
boolean wasApEnabled = false;
static AccessPoint wifiAP;
private WifiManager wifi;
static Button apButton;
static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apButton = (Button) findViewById(R.id.toggleBtn);
textView = (TextView) findViewById(R.id.wifiClients);
wifiAP = new AccessPoint();
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
scan();
apButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}
});
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD|WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
public void scan(){
wifiAP.getClientList(false, new FinishScanListener() {
#Override
public void onFinishScan(final ArrayList<ClientScanResult> clients) {
textView.setText("WifiApState:" + wifiAP.getWifiApState()+ "\n\n");
textView.append("Clients: \n");
for (ClientScanResult clientScanResult : clients){
textView.append("====================\n");
textView.append("ipAddress: " + clientScanResult.getIpAddress() + "\n");
textView.append("Device: " + clientScanResult.getDevice() + "\n");
textView.append("macAddress: " + clientScanResult.getMacAddress() + "\n");
textView.append("isReachable: " + clientScanResult.isReachable() + "\n");
}
}
});
}
#Override
public void onResume() {
super.onResume();
if (wasApEnabled) {
if (wifiAP.getWifiApState() != wifiAP.WIFI_STATE_ENABLED && wifiAP.getWifiApState() != wifiAP.WIFI_STATE_ENABLING) {
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}
}
updateStatusDisplay();
}
#Override
public void onPause() {
super.onPause();
boolean wifiApIsOn = wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLED || wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLING;
if (wifiApIsOn){
wasApEnabled = true;
wifiAP.toggleWifiAP(wifi, MainActivity.this);
}else {
wasApEnabled = false;
}
updateStatusDisplay();
}
public static void updateStatusDisplay(){
if (wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLED || wifiAP.getWifiApState()==wifiAP.WIFI_STATE_ENABLING){
apButton.setText("Turn Off");
}else {
apButton.setText("Turn on");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0,0,0, "Get Clients");
return super.onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()){
case 0:
scan();
break;
}
return super.onMenuItemSelected(featureId, item);
}
}
Edit: commented out the main looper made it work but after taking out the comments, the application now crashes on launch
http://gyazo.com/fa068fd1fce3f27f43185c0cd12568c1
Only a small portion of my users are getting this error and I can't for the life of me figure it out. I use GooglePlayServicesUtil.isGooglePlayServicesAvailable(downloadService) to test whether or not Play Services is available, and it always returns SUCCESS. I setup the channel to connect to the Chromecast, and everything works fine up until the point where I try to use RemoteMediaPlayer.load. The result is always SIGN_IN_REQUIRED for some users, with resolution: null. The status.toString() is Failed to load: Status{statusCode=SIGN_IN_REQUIRED, resolution=null}. I'm really not sure what I am supposed to with this or how to get rid of the error for my few users who are getting this.
I don't know what portion is related, so I am just posting my entire controller class:
public class ChromeCastController extends RemoteController {
private static final String TAG = ChromeCastController.class.getSimpleName();
private CastDevice castDevice;
private GoogleApiClient apiClient;
private ConnectionCallbacks connectionCallbacks;
private ConnectionFailedListener connectionFailedListener;
private Cast.Listener castClientListener;
private boolean applicationStarted = false;
private boolean waitingForReconnect = false;
private boolean error = false;
private boolean ignoreNextPaused = false;
private String sessionId;
private FileProxy proxy;
private String rootLocation;
private RemoteMediaPlayer mediaPlayer;
private double gain = 0.5;
public ChromeCastController(DownloadService downloadService, CastDevice castDevice) {
this.downloadService = downloadService;
this.castDevice = castDevice;
SharedPreferences prefs = Util.getPreferences(downloadService);
rootLocation = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
}
#Override
public void create(boolean playing, int seconds) {
downloadService.setPlayerState(PlayerState.PREPARING);
connectionCallbacks = new ConnectionCallbacks(playing, seconds);
connectionFailedListener = new ConnectionFailedListener();
castClientListener = new Cast.Listener() {
#Override
public void onApplicationStatusChanged() {
if (apiClient != null && apiClient.isConnected()) {
Log.i(TAG, "onApplicationStatusChanged: " + Cast.CastApi.getApplicationStatus(apiClient));
}
}
#Override
public void onVolumeChanged() {
if (apiClient != null && applicationStarted) {
try {
gain = Cast.CastApi.getVolume(apiClient);
} catch(Exception e) {
Log.w(TAG, "Failed to get volume");
}
}
}
#Override
public void onApplicationDisconnected(int errorCode) {
shutdownInternal();
}
};
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(castDevice, castClientListener);
apiClient = new GoogleApiClient.Builder(downloadService)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(connectionCallbacks)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
apiClient.connect();
}
#Override
public void start() {
if(error) {
error = false;
Log.w(TAG, "Attempting to restart song");
startSong(downloadService.getCurrentPlaying(), true, 0);
return;
}
try {
mediaPlayer.play(apiClient);
} catch(Exception e) {
Log.e(TAG, "Failed to start");
}
}
#Override
public void stop() {
try {
mediaPlayer.pause(apiClient);
} catch(Exception e) {
Log.e(TAG, "Failed to pause");
}
}
#Override
public void shutdown() {
try {
if(mediaPlayer != null && !error) {
mediaPlayer.stop(apiClient);
}
} catch(Exception e) {
Log.e(TAG, "Failed to stop mediaPlayer", e);
}
try {
if(apiClient != null) {
Cast.CastApi.stopApplication(apiClient);
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace());
mediaPlayer = null;
applicationStarted = false;
}
} catch(Exception e) {
Log.e(TAG, "Failed to shutdown application", e);
}
if(apiClient != null && apiClient.isConnected()) {
apiClient.disconnect();
}
apiClient = null;
if(proxy != null) {
proxy.stop();
proxy = null;
}
}
private void shutdownInternal() {
// This will call this.shutdown() indirectly
downloadService.setRemoteEnabled(RemoteControlState.LOCAL, null);
}
#Override
public void updatePlaylist() {
if(downloadService.getCurrentPlaying() == null) {
startSong(null, false, 0);
}
}
#Override
public void changePosition(int seconds) {
try {
mediaPlayer.seek(apiClient, seconds * 1000L);
} catch(Exception e) {
Log.e(TAG, "FAiled to seek to " + seconds);
}
}
#Override
public void changeTrack(int index, DownloadFile song) {
startSong(song, true, 0);
}
#Override
public void setVolume(boolean up) {
double delta = up ? 0.1 : -0.1;
gain += delta;
gain = Math.max(gain, 0.0);
gain = Math.min(gain, 1.0);
getVolumeToast().setVolume((float) gain);
try {
Cast.CastApi.setVolume(apiClient, gain);
} catch(Exception e) {
Log.e(TAG, "Failed to the volume");
}
}
#Override
public int getRemotePosition() {
if(mediaPlayer != null) {
return (int) (mediaPlayer.getApproximateStreamPosition() / 1000L);
} else {
return 0;
}
}
#Override
public int getRemoteDuration() {
if(mediaPlayer != null) {
return (int) (mediaPlayer.getStreamDuration() / 1000L);
} else {
return 0;
}
}
void startSong(DownloadFile currentPlaying, boolean autoStart, int position) {
if(currentPlaying == null) {
try {
if (mediaPlayer != null && !error) {
mediaPlayer.stop(apiClient);
}
} catch(Exception e) {
// Just means it didn't need to be stopped
}
downloadService.setPlayerState(PlayerState.IDLE);
return;
}
downloadService.setPlayerState(PlayerState.PREPARING);
MusicDirectory.Entry song = currentPlaying.getSong();
try {
MusicService musicService = MusicServiceFactory.getMusicService(downloadService);
String url;
// Offline, use file proxy
if(Util.isOffline(downloadService) || song.getId().indexOf(rootLocation) != -1) {
if(proxy == null) {
proxy = new FileProxy(downloadService);
proxy.start();
}
url = proxy.getPublicAddress(song.getId());
} else {
if(proxy != null) {
proxy.stop();
proxy = null;
}
if(song.isVideo()) {
url = musicService.getHlsUrl(song.getId(), currentPlaying.getBitRate(), downloadService);
} else {
url = musicService.getMusicUrl(downloadService, song, currentPlaying.getBitRate());
}
url = fixURLs(url);
}
// Setup song/video information
MediaMetadata meta = new MediaMetadata(song.isVideo() ? MediaMetadata.MEDIA_TYPE_MOVIE : MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
meta.putString(MediaMetadata.KEY_TITLE, song.getTitle());
if(song.getTrack() != null) {
meta.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrack());
}
if(!song.isVideo()) {
meta.putString(MediaMetadata.KEY_ARTIST, song.getArtist());
meta.putString(MediaMetadata.KEY_ALBUM_ARTIST, song.getArtist());
meta.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbum());
String coverArt = "";
if(proxy == null) {
coverArt = musicService.getCoverArtUrl(downloadService, song);
coverArt = fixURLs(coverArt);
meta.addImage(new WebImage(Uri.parse(coverArt)));
} else {
File coverArtFile = FileUtil.getAlbumArtFile(downloadService, song);
if(coverArtFile != null && coverArtFile.exists()) {
coverArt = proxy.getPublicAddress(coverArtFile.getPath());
meta.addImage(new WebImage(Uri.parse(coverArt)));
}
}
}
String contentType;
if(song.isVideo()) {
contentType = "application/x-mpegURL";
}
else if(song.getTranscodedContentType() != null) {
contentType = song.getTranscodedContentType();
} else if(song.getContentType() != null) {
contentType = song.getContentType();
} else {
contentType = "audio/mpeg";
}
// Load it into a MediaInfo wrapper
MediaInfo mediaInfo = new MediaInfo.Builder(url)
.setContentType(contentType)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setMetadata(meta)
.build();
if(autoStart) {
ignoreNextPaused = true;
}
mediaPlayer.load(apiClient, mediaInfo, autoStart, position * 1000L).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(RemoteMediaPlayer.MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
// Handled in other handler
} else if(result.getStatus().getStatusCode() != ConnectionResult.SIGN_IN_REQUIRED) {
Log.e(TAG, "Failed to load: " + result.getStatus().toString());
failedLoad();
}
}
});
} catch (IllegalStateException e) {
Log.e(TAG, "Problem occurred with media during loading", e);
failedLoad();
} catch (Exception e) {
Log.e(TAG, "Problem opening media during loading", e);
failedLoad();
}
}
private String fixURLs(String url) {
// Only change to internal when using https
if(url.indexOf("https") != -1) {
SharedPreferences prefs = Util.getPreferences(downloadService);
int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
String externalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
String internalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance, null);
url = url.replace(internalUrl, externalUrl);
}
// Use separate profile for Chromecast so users can do ogg on phone, mp3 for CC
return url.replace(Constants.REST_CLIENT_ID, Constants.CHROMECAST_CLIENT_ID);
}
private void failedLoad() {
Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load));
downloadService.setPlayerState(PlayerState.STOPPED);
error = true;
}
private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
private boolean isPlaying;
private int position;
private ResultCallback<Cast.ApplicationConnectionResult> resultCallback;
ConnectionCallbacks(boolean isPlaying, int position) {
this.isPlaying = isPlaying;
this.position = position;
resultCallback = new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
sessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
applicationStarted = true;
setupChannel();
} else {
shutdownInternal();
}
}
};
}
#Override
public void onConnected(Bundle connectionHint) {
if (waitingForReconnect) {
Log.i(TAG, "Reconnecting");
reconnectApplication();
} else {
launchApplication();
}
}
#Override
public void onConnectionSuspended(int cause) {
Log.w(TAG, "Connection suspended");
isPlaying = downloadService.getPlayerState() == PlayerState.STARTED;
position = getRemotePosition();
waitingForReconnect = true;
}
void launchApplication() {
try {
Cast.CastApi.launchApplication(apiClient, CastCompat.APPLICATION_ID, false).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to launch application", e);
}
}
void reconnectApplication() {
try {
Cast.CastApi.joinApplication(apiClient, CastCompat.APPLICATION_ID, sessionId).setResultCallback(resultCallback);
} catch (Exception e) {
Log.e(TAG, "Failed to reconnect application", e);
}
}
void setupChannel() {
if(!waitingForReconnect) {
mediaPlayer = new RemoteMediaPlayer();
mediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener() {
#Override
public void onStatusUpdated() {
MediaStatus mediaStatus = mediaPlayer.getMediaStatus();
if (mediaStatus == null) {
return;
}
switch (mediaStatus.getPlayerState()) {
case MediaStatus.PLAYER_STATE_PLAYING:
if (ignoreNextPaused) {
ignoreNextPaused = false;
}
downloadService.setPlayerState(PlayerState.STARTED);
break;
case MediaStatus.PLAYER_STATE_PAUSED:
if (!ignoreNextPaused) {
downloadService.setPlayerState(PlayerState.PAUSED);
}
break;
case MediaStatus.PLAYER_STATE_BUFFERING:
downloadService.setPlayerState(PlayerState.PREPARING);
break;
case MediaStatus.PLAYER_STATE_IDLE:
if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) {
downloadService.setPlayerState(PlayerState.COMPLETED);
downloadService.onSongCompleted();
} else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_INTERRUPTED) {
if (downloadService.getPlayerState() != PlayerState.PREPARING) {
downloadService.setPlayerState(PlayerState.PREPARING);
}
} else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_ERROR) {
Log.e(TAG, "Idle due to unknown error");
downloadService.setPlayerState(PlayerState.COMPLETED);
downloadService.next();
} else {
Log.w(TAG, "Idle reason: " + mediaStatus.getIdleReason());
downloadService.setPlayerState(PlayerState.IDLE);
}
break;
}
}
});
}
try {
Cast.CastApi.setMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace(), mediaPlayer);
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
if(!waitingForReconnect) {
DownloadFile currentPlaying = downloadService.getCurrentPlaying();
startSong(currentPlaying, isPlaying, position);
}
if(waitingForReconnect) {
waitingForReconnect = false;
}
}
}
private class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
#Override
public void onConnectionFailed(ConnectionResult result) {
shutdownInternal();
}
}
}
Edit for logs:
03-28 19:04:49.757 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: Chromecast Home Screen
03-28 19:04:52.280 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: null
03-28 19:04:54.162 6305-6305/github.daneren2005.dsub I/ChromeCastController﹕ onApplicationStatusChanged: Ready To Cast
03-28 19:05:05.194 6305-6305/github.daneren2005.dsub E/ChromeCastController﹕ Failed to load: Status{statusCode=SIGN_IN_REQUIRED, resolution=null}
It is strange that you are getting such status code at that time. What comes to mind is that the user may have not logged into his/her gmail account or something along those lines. Do you have the log file for us to take a look at to see if we can get more from the context? Also, to be sure, such user sees the application launched on the TV and only when it comes to loading a media that error is thrown?
The issue is due to using a Self Signed Certificate. I didn't realize the issue on my old phone because I had changed hosts and bought a normal certificate after switching phones. It would be nice if the SDK would through a useful error though. The one thrown makes you think that it is a problem with connecting to the Play Services SDK, and not a problem with the actual URL being used.
I am looking for and example of casting an image to chromecast in android. Oddly enough it doesn't seem like this is covered in the googlecast sample repositories. Does anyone have a simple implementation of this? I basically would like to click on an image in my app's photo gallery on my android device and have it cast to the screen.
One side question is, does the image need to be at a url? or is it possible to stream the image to the device? I appreciate the help in advance.
I've solved this without the CastCompanionLibrary, but based on google's CastHelloText-android sample. Basically what I did was:
encode an image into a base64 string and send it as a message to a custom receiver
modify the sample's receiver to receive a base64 string and set it as the image source.
upload and register my receiver and have the application use the generated application id
This is the code for the receiver:
<!DOCTYPE html>
<html>
<head>
<style>
img#androidImage {
height:auto;
width:100%;
}
</style>
<title>Cast Hello Text</title>
</head>
<body>
<img id="androidImage" src="" />
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<script type="text/javascript">
window.onload = function() {
cast.receiver.logger.setLevelValue(0);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
console.log('Starting Receiver Manager');
// handler for the 'ready' event
castReceiverManager.onReady = function(event) {
console.log('Received Ready event: ' + JSON.stringify(event.data));
window.castReceiverManager.setApplicationState("Application status is ready...");
};
// handler for 'senderconnected' event
castReceiverManager.onSenderConnected = function(event) {
console.log('Received Sender Connected event: ' + event.data);
console.log(window.castReceiverManager.getSender(event.data).userAgent);
};
// handler for 'senderdisconnected' event
castReceiverManager.onSenderDisconnected = function(event) {
console.log('Received Sender Disconnected event: ' + event.data);
if (window.castReceiverManager.getSenders().length == 0) {
window.close();
}
};
// handler for 'systemvolumechanged' event
castReceiverManager.onSystemVolumeChanged = function(event) {
console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
event.data['muted']);
};
// create a CastMessageBus to handle messages for a custom namespace
window.messageBus =
window.castReceiverManager.getCastMessageBus(
'urn:x-cast:com.google.cast.sample.helloworld');
// handler for the CastMessageBus message event
window.messageBus.onMessage = function(event) {
console.log('Message recieved');
var obj = JSON.parse(event.data)
console.log('Message type: ' + obj.type);
if (obj.type == "text") {
console.log('Skipping message: ' + obj.data);
}
if (obj.type == "image") {
var source = 'data:image/png;base64,'.concat(obj.data)
displayImage(source);
}
// inform all senders on the CastMessageBus of the incoming message event
// sender message listener will be invoked
window.messageBus.send(event.senderId, event.data);
}
// initialize the CastReceiverManager with an application status message
window.castReceiverManager.start({statusText: "Application is starting"});
console.log('Receiver Manager started');
};
function displayImage(source) {
console.log('received image');
document.getElementById("androidImage").src=source;
window.castReceiverManager.setApplicationState('image source changed');
};
</script>
</body>
</html>
Below is the modified MainActivity.java code. Don't forget to modify the app_id in string.xml once your receiver application is registered.
2 notes:
The sent messages are wrapped in a JSON object so I can filter out
the text messages.
The ENCODED_IMAGE_STRING variable isn't defined in this
example, you'll have to find an image and convert it to a base64 string yourself.
MainActivity.java:
package com.example.casthelloworld;
import java.io.IOException;
import java.util.ArrayList;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.MediaRouteActionProvider;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.support.v7.media.MediaRouter.RouteInfo;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.cast.Cast.ApplicationConnectionResult;
import com.google.android.gms.cast.Cast.MessageReceivedCallback;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.CastMediaControlIntent;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
/**
* Main activity to send messages to the receiver.
*/
public class MainActivity extends ActionBarActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int REQUEST_CODE = 1;
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private MediaRouter.Callback mMediaRouterCallback;
private CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private Cast.Listener mCastListener;
private ConnectionCallbacks mConnectionCallbacks;
private ConnectionFailedListener mConnectionFailedListener;
private HelloWorldChannel mHelloWorldChannel;
private boolean mApplicationStarted;
private boolean mWaitingForReconnect;
private String mSessionId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(
android.R.color.transparent));
// When the user clicks on the button, use Android voice recognition to
// get text
Button voiceButton = (Button) findViewById(R.id.voiceButton);
voiceButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startVoiceRecognitionActivity();
}
});
// When the user clicks on the button, use Android voice recognition to
// get text
Button yarrButton = (Button) findViewById(R.id.tmpButton);
yarrButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
castImage();
}
});
// Configure Cast device discovery
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(
CastMediaControlIntent.categoryForCast(getResources()
.getString(R.string.app_id))).build();
mMediaRouterCallback = new MyMediaRouterCallback();
}
private void castImage()
{
Log.d(TAG, "castImage()");
String image_string = createJsonMessage(MessageType.image, ENCODED_IMAGE_STRING);
sendMessage(image_string);
}
/**
* Android voice recognition
*/
private void startVoiceRecognitionActivity() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.message_to_cast));
startActivityForResult(intent, REQUEST_CODE);
}
/*
* Handle the voice recognition response
*
* #see android.support.v4.app.FragmentActivity#onActivityResult(int, int,
* android.content.Intent)
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
ArrayList<String> matches = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (matches.size() > 0) {
Log.d(TAG, matches.get(0));
String message = createJsonMessage(MessageType.text, matches.get(0));
sendMessage(message);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onResume() {
super.onResume();
// Start media router discovery
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onPause() {
if (isFinishing()) {
// End media router discovery
mMediaRouter.removeCallback(mMediaRouterCallback);
}
super.onPause();
}
#Override
public void onDestroy() {
teardown();
super.onDestroy();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat
.getActionProvider(mediaRouteMenuItem);
// Set the MediaRouteActionProvider selector for device discovery.
mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);
return true;
}
/**
* Callback for MediaRouter events
*/
private class MyMediaRouterCallback extends MediaRouter.Callback {
#Override
public void onRouteSelected(MediaRouter router, RouteInfo info) {
Log.d(TAG, "onRouteSelected");
// Handle the user route selection.
mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
launchReceiver();
}
#Override
public void onRouteUnselected(MediaRouter router, RouteInfo info) {
Log.d(TAG, "onRouteUnselected: info=" + info);
teardown();
mSelectedDevice = null;
}
}
/**
* Start the receiver app
*/
private void launchReceiver() {
try {
mCastListener = new Cast.Listener() {
#Override
public void onApplicationDisconnected(int errorCode) {
Log.d(TAG, "application has stopped");
teardown();
}
};
// Connect to Google Play services
mConnectionCallbacks = new ConnectionCallbacks();
mConnectionFailedListener = new ConnectionFailedListener();
Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions
.builder(mSelectedDevice, mCastListener);
mApiClient = new GoogleApiClient.Builder(this)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
mApiClient.connect();
} catch (Exception e) {
Log.e(TAG, "Failed launchReceiver", e);
}
}
/**
* Google Play services callbacks
*/
private class ConnectionCallbacks implements
GoogleApiClient.ConnectionCallbacks {
#Override
public void onConnected(Bundle connectionHint) {
Log.d(TAG, "onConnected");
if (mApiClient == null) {
// We got disconnected while this runnable was pending
// execution.
return;
}
try {
if (mWaitingForReconnect) {
mWaitingForReconnect = false;
// Check if the receiver app is still running
if ((connectionHint != null)
&& connectionHint
.getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING)) {
Log.d(TAG, "App is no longer running");
teardown();
} else {
// Re-create the custom message channel
try {
Cast.CastApi.setMessageReceivedCallbacks(
mApiClient,
mHelloWorldChannel.getNamespace(),
mHelloWorldChannel);
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
}
} else {
// Launch the receiver app
Cast.CastApi
.launchApplication(mApiClient,
getString(R.string.app_id), false)
.setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(
ApplicationConnectionResult result) {
Status status = result.getStatus();
Log.d(TAG,
"ApplicationConnectionResultCallback.onResult: statusCode "
+ status.getStatusCode());
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result
.getApplicationMetadata();
mSessionId = result
.getSessionId();
String applicationStatus = result
.getApplicationStatus();
boolean wasLaunched = result
.getWasLaunched();
Log.d(TAG,
"application name: "
+ applicationMetadata
.getName()
+ ", status: "
+ applicationStatus
+ ", sessionId: "
+ mSessionId
+ ", wasLaunched: "
+ wasLaunched);
mApplicationStarted = true;
// Create the custom message
// channel
mHelloWorldChannel = new HelloWorldChannel();
try {
Cast.CastApi
.setMessageReceivedCallbacks(
mApiClient,
mHelloWorldChannel
.getNamespace(),
mHelloWorldChannel);
} catch (IOException e) {
Log.e(TAG,
"Exception while creating channel",
e);
}
// set the initial instructions
// on the receiver
String message = createJsonMessage(MessageType.text, getString(R.string.instructions));
sendMessage(message);
} else {
Log.e(TAG,
"application could not launch");
teardown();
}
}
});
}
} catch (Exception e) {
Log.e(TAG, "Failed to launch application", e);
}
}
#Override
public void onConnectionSuspended(int cause) {
Log.d(TAG, "onConnectionSuspended");
mWaitingForReconnect = true;
}
}
/**
* Google Play services callbacks
*/
private class ConnectionFailedListener implements
GoogleApiClient.OnConnectionFailedListener {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.e(TAG, "onConnectionFailed ");
teardown();
}
}
/**
* Tear down the connection to the receiver
*/
private void teardown() {
Log.d(TAG, "teardown");
if (mApiClient != null) {
if (mApplicationStarted) {
if (mApiClient.isConnected() || mApiClient.isConnecting()) {
try {
Cast.CastApi.stopApplication(mApiClient, mSessionId);
if (mHelloWorldChannel != null) {
Cast.CastApi.removeMessageReceivedCallbacks(
mApiClient,
mHelloWorldChannel.getNamespace());
mHelloWorldChannel = null;
}
} catch (IOException e) {
Log.e(TAG, "Exception while removing channel", e);
}
mApiClient.disconnect();
}
mApplicationStarted = false;
}
mApiClient = null;
}
mSelectedDevice = null;
mWaitingForReconnect = false;
mSessionId = null;
}
/**
* Send a text message to the receiver
*
* #param message
*/
private void sendMessage(String message) {
if (mApiClient != null && mHelloWorldChannel != null) {
try {
Cast.CastApi.sendMessage(mApiClient,
mHelloWorldChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result) {
if (!result.isSuccess()) {
Log.e(TAG, "Sending message failed");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Exception while sending message", e);
}
} else {
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT)
.show();
}
}
/**
* Custom message channel
*/
class HelloWorldChannel implements MessageReceivedCallback {
/**
* #return custom namespace
*/
public String getNamespace() {
return getString(R.string.namespace);
}
/*
* Receive message from the receiver app
*/
#Override
public void onMessageReceived(CastDevice castDevice, String namespace,
String message) {
Log.d(TAG, "onMessageReceived: " + message);
}
}
enum MessageType {
text,
image,
}
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
private static String createJsonMessage(MessageType type, String message)
{
return String.format("{\"type\":\"%s\", \"data\":\"%s\"}", type.toString(), message);
}
}
Since on Chromecast your application is running inside a web browser, you need to have an <img/> tag show the image. The src attribute of that tag should point to the image that you want to see and it has to be a url, so if your image is residing on your phone's local storage, you need to start a small web server in your mobile application to serve that image and communicate with the receiver what url it should point at (which would be the url at which your server is serving that image). these are all doable and you can use the CastCompanionLibrary, if you want, to communicate with your custom receiver; simply use the DataCastManager class instead of VideoCastManager.
May be my answer will be helpful for other developers, because I also did'nt found good solution and done it by myself.
For showing image via Google Cast on your device screen from your app you can create and start simply web server from your app which will process http requests with selected image name or id in URL.
Example:
public class MyWebServer {
private Activity activity;
private static ServerSocket httpServerSocket;
private static boolean isWebServerSunning;
public static final String drawableDelimiter = "pic-"
public MyWebServer(Activity activity) {
this.activity = activity;
}
public void stopWebServer() {
isWebServerSunning = false;
try {
if (httpServerSocket != null) {
httpServerSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void startWebServer() {
isWebServerSunning = true;
Thread webServerThread = new Thread(() -> {
Socket socket;
HttpResponseThread httpResponseThread;
try {
httpServerSocket = new ServerSocket(5050);
while (isWebServerSunning) {
socket = httpServerSocket.accept();
httpResponseThread = new HttpResponseThread(socket);
httpResponseThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
});
webServerThread.start();
}
private class HttpResponseThread extends Thread {
Socket clientSocket;
HttpResponseThread(Socket socket) {
this.clientSocket = socket;
}
#Override
public void run() {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
OutputStream outputStream = clientSocket.getOutputStream();
) {
String input = bufferedReader.readLine();
if (input != null && !input.isEmpty() && input.contains("/") && input.contains(" ")) {
if (input.contains(drawableDelimiter)) {
String imageId = input.substring(input.indexOf("/") + 1, input.lastIndexOf(" ")).trim().split(drawableDelimiter)[1];
Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), Integer.parseInt(imageId));
if (bitmap != null) {
ByteArrayOutputStream bitmapBytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bitmapBytes);
outputStream.write("HTTP/1.0 200 OK\r\n".getBytes());
outputStream.write("Server: Apache/0.8.4\r\n".getBytes());
outputStream.write(("Content-Length: " + bitmapBytes.toByteArray().length + "\r\n").getBytes());
outputStream.write("\r\n".getBytes());
outputStream.write(bitmapBytes.toByteArray());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
And just start or stop your web server at when Google Cast will be useable or stopped.
MyWebServer myWebServer = new MyWebServer(this); // pass your activity here
myWebServer.startWebServer();
myWebServer.stopWebServer();