Title of this question might be incorrect as I am assuming this is the problem. I am new to both Java and Android and have been struggling on this for days.
I am trying to connect to an ECU (non OBD-2) via an FTDI cable, usb-to-go and an Android device.
I have based most of this code on the examples shown on the FTDI website using their Android D2xx.jar library, example code and by reading their documentation.
The problem I am experiencing is that the TextView "dataView" is not being updated at all. In Fact the following line shows an error of : "The value of the local variable dataView is not used" - The TextView append line is not being seen due to it being in a separate thread? Or this possibly indicates to me that my implementation of a message handler could be incorrect or something similar?
In addition to this, the data from the ECU is expected in hex format , 6 bytes to be precise initially. So the second part of my question is is how to display the hex info in textView as hex in string format?
TextView dataView = (TextView) findViewById(R.id.dataView);
-----------------------------------------------------------
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (iavailable > 0) {
dataView.append(String.copyValueOf(readDataToText, 0, iavailable));
}
}
};
------------------------------------------------------------
public class readECUThread extends Thread {
Handler mHandler;
readECUThread(Handler h) {
mHandler = h;
this.setPriority(Thread.MIN_PRIORITY);
}
#Override
public void run() {
int i;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
synchronized (ftDev) {
iavailable = ftDev.getQueueStatus();
if (iavailable > 0) {
if (iavailable > readLength) {
iavailable = readLength;
}
ftDev.read(readData, iavailable);
for (i = 0; i < iavailable; i++) {
readDataToText[i] = (char) readData[i];
}
Message msg = mHandler.obtainMessage();
mHandler.sendMessage(msg);
}
}
}
}
This was a simple stupid error on my part in the 1st line of my originally posted code:
TextView dataView = (TextView) findViewById(R.id.dataView);
Should have just been :
dataView = (TextView) findViewById(R.id.dataView);
Eclipse did not pick this up as an error so it had me scratching my head for a while. I now get data to the TextView field but in very strange characters (possibly Korean as it is a Samsung phone?).
Related
I have a wearable app. The app after it finishes has data like time/date, UUID, Geo location, parameters selected displayed in front of me like a Data Report or Log in several TextViews underneath each other. Like a list. I want this data to be transferred from my wearable device to my android phone.
Now I have to ask does the WearOS app the pairs the phone with the watch enables such a thing? Like can the data be sent through it? OR what exactly can I do? I read about Sync data items with the Data Layer API in the documentation, but I'm not sure if the code snippets provided would help achieve what I want.
public class MainActivity extends Activity {
private static final String COUNT_KEY = "com.example.key.count";
private DataClient dataClient;
private int count = 0;
...
// Create a data map and put data in it
private void increaseCounter() {
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
putDataMapReq.getDataMap().putInt(COUNT_KEY, count++);
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
Task<DataItem> putDataTask = dataClient.putDataItem(putDataReq);
}
...
}
The data I display in the textviews are called through methods that I call things like: getLocation, getUUID, getDateTime, getSelections, etc... when I click a button I call them in the setOnClickListener. I want this data in the TextViews to be placed in a file or something like that and send them over to the mobile phone from the watch when they're generated.
private void getDateTime()
{
SimpleDateFormat sdf_date = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat sdf_time = new SimpleDateFormat("HH:mm:ss z");
String currentDate= sdf_date.format(new Date());
String currentTime= sdf_time.format(new Date());
textView_date_time.setText("Date: "+currentDate+"\n"+"Time: "+currentTime);
}
#SuppressLint("SetTextI18n")
private void getUUID()
{
// Retrieving the value using its keys the file name
// must be same in both saving and retrieving the data
#SuppressLint("WrongConstant") SharedPreferences sh = getSharedPreferences("UUID_File", MODE_APPEND);
// The value will be default as empty string because for
// the very first time when the app is opened, there is nothing to show
String theUUID = sh.getString(PREF_UNIQUE_ID, uniqueID);
// We can then use the data
textView_UUID.setText("UUID: "+theUUID);
}
#SuppressLint("SetTextI18n")
private void getSelections()
{
textView_data_selected.setText("Tool No.: "+c.getToolNo()+
"\nTool Size: " +c.getToolSizeStr()+
"\nFrom Mode: " +c.getCurrentModeStr()+
"\nGoto Mode: " +c.getModeStr()+
"\nMethod: " +c.getMethodStr()+
"\nBit Duration: " +c.getBitDuration()+
"\nUpper bound" +c.getUpStageValue()+
"\nLower bound: "+c.getDownStageValue());
}
The above are examples of the methods I use to get the data. then I call them here:
gps_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= 26) {
getLocation();
getDateTime();
getUUID();
getSelections();
}
else
{
//ActivityCompat.requestPermissions(get_location.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
Toast.makeText(get_location.this,"Build SDK too low",Toast.LENGTH_SHORT);
}
}
});
Now how do I take all this and send it over from my device to the the phone?
Note: The data report I want to send as a file, I want it done subtly like something done in the background. I don't know what else to do or where to look.
You have two options if you want to use the Data Layer, one is to use the MessageClient API to bundle your data up in a message and send it directly to the handheld. The easiest here would be to create an arbitrary JSONObject and serialize your data as a JSON string you can stuff into a message. For example:
try {
final JSONObject object = new JSONObject();
object.put("heart_rate", (int) event.values[0]);
object.put("timestamp", Instant.now().toString());
new MessageSender("/MessageChannel", object.toString(), getApplicationContext()).start();
} catch (JSONException e) {
Log.e(TAG, "Failed to create JSON object");
}
In my case, I do this in my onSensorChanged implementation, but you can insert this wherever you are updating your text.
MessageSender is just a threaded wrapper around the MessageClient:
import java.util.List;
class MessageSender extends Thread {
private static final String TAG = "MessageSender";
String path;
String message;
Context context;
MessageSender(String path, String message, Context context) {
this.path = path;
this.message = message;
this.context = context;
}
public void run() {
try {
Task<List<Node>> nodeListTask = Wearable.getNodeClient(context.getApplicationContext()).getConnectedNodes();
List<Node> nodes = Tasks.await(nodeListTask);
byte[] payload = message.getBytes();
for (Node node : nodes) {
String nodeId = node.getId();
Task<Integer> sendMessageTask = Wearable.getMessageClient(context).sendMessage(nodeId, this.path, payload);
try {
Tasks.await(sendMessageTask);
} catch (Exception exception) {
// TODO: Implement exception handling
Log.e(TAG, "Exception thrown");
}
}
} catch (Exception exception) {
Log.e(TAG, exception.getMessage());
}
}
}
The other option is to create a nested hierarchy of data items in the Data Layer and implement DataClient.OnDataChangedListener on both sides, such that changes that are written in on one side are automatically synchronized with the other. You can find a good walkthrough on how to do that here.
For your specific case, just packing it in a JSON object would probably be the simplest. The writing out to your preferred file format you can then implement on the handheld side without needing to involve the wear side.
please help me I am trying to get text from stack of notifications. I am getting following error.
java.lang.NoSuchFieldException: No field mActions in class
Landroid/app/Notification$BuilderRemoteViews; (declaration of
'android.app.Notification$BuilderRemoteViews' appears in
/system/framework/framework.jar)
I am using NotificationListenerService and
private List<String> getMessages(Notification notification) {
RemoteViews views = notification.bigContentView;
if (views == null) views = notification.contentView;
if (views == null) return null;
List<String> text = new ArrayList<String>();
try {
Field field = views.getClass().getDeclaredField(Constants.ACTIONS);
field.setAccessible(true);
#SuppressWarnings("unchecked")
ArrayList<Parcelable> actions = (ArrayList<Parcelable>) field.get(views);
for (Parcelable p : actions) {
Parcel parcel = Parcel.obtain();
p.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
int tag = parcel.readInt();
if (tag != 2) continue;
parcel.readInt();
String methodName = parcel.readString();
if (methodName == null) {
continue;
} else if (methodName.equals(Constants.SET_TEXT)) {
parcel.readInt();
methodName.getBytes();
String gettingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel).toString().trim();
text.add(gettingText);
} else if (methodName.equals(Constants.SET_TIME)) {
parcel.readInt();
String gettingText = new SimpleDateFormat("h:mm a").format(new Date(parcel.readLong()));
text.add(gettingText);
}
parcel.recycle();
}
} catch (Exception e) {
Log.e("NotificationClassifier", e.toString());
}
return text;
}
This is working fine in android 4,5 but's its getting crash on Android 7, Getting error like mAction field not available.
Please any one help me to solve this, I am stuck from two days.
Thank you
You are using reflection to access method names and you are not switching the code for multiple platforms. The fields/methods that you are trying to access, change over time on multiple versions of the OS, so if you really want to have the reflection, you have to study what changes they were.
Generally, reflection should really be last resort, since on Android, the base code varies from version to version, and even from manufacturer to manufacturer.
I am working on an Android app that will constantly receive data from an Arduino HC-05 and store it in a database. For now I am focusing on receiving the data properly (so just displaying it on the screen is my next step).
I have followed this guide (PDF) to setup a basic app that will receive data from the Arduino. However, it doesn't include a section about using the received data. I've tried adding two lines of code to the handleMessage function in order to display the received data on screen, but I don't see any difference in the textview (it stays "Hello World!").
I know that my Arduino is sending the data just fine, since on another app called "Serial Bluetooth Terminal" it is displayed properly. Here is the code for the Handler class:
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
byte[] writeBuf = (byte[]) msg.obj;
int begin = (int)msg.arg1;
int end = (int)msg.arg2;
switch(msg.what) {
case 1:
String writeMessage = new String(writeBuf);
writeMessage = writeMessage.substring(begin, end);
// 2 lines of code I've added here:
TextView tempTextView = (TextView) findViewById(R.id.text_view);
tempTextView.setText(writeMessage);
break;
}
}
};
Aside from the 2 lines, the code is basically the same as the final stage of the guide. And here is the code for the Arduino (which currently just sends "1 2.00 3.00" over and over):
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(0, 1); //RX|TX
int Temp= 1;
float Ph = 2;
float Ec = 3;
void setup() {
Serial.begin(9600);
BTSerial.begin(9600);
}
void loop() {
Serial.print(Temp);
Serial.print(" ");
delay(100);
Serial.print(Ph);
Serial.print(" ");
delay(100);
Serial.print(Ec);
Serial.print(" ");
delay(100);
Serial.print('\n');
if(Serial.available())
BTSerial.write(Serial.read());
}
I must be missing something here. Every example I've seen with Android's 2-way binding is based on a String in the backing data for anything user-enterable, like an EditText.
Handling anything not a String seems somewhat... inelegant. For example, if I have a double in my domain model that needs to be editable, the best binding I've come up with requires a ViewModel with surprisingly a lot of code to interface between the model and the EditText.
Am I missing something key? Should I really need 30 lines of code to interface an EditText with a double? For the sake of discussion, let's consider a currency field, represented as a double, in a two-way bound EditText:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:text="#={fragModel.startBucks}"
android:id="#+id/editText2"/>
And here's the ViewModel I've had to construct in order to give the EditText a string to bind to.
#Bindable private String startBucksString;
private double localBucks;
public String getStartBucksString() {
double domainBucks = cd.getStartBucks();
// Ignore incoming change of less than rounding error
if( Math.abs(localBucks - domainBucks) < .001 ) return startBucksString;
startBucksString = "";
if( domainBucks != 0)
startBucksString = String.format("$%.2f", domainBucks);
return startBucksString;
}
public void setStartBucksString(String inBuckstr) {
double calcBucks=0;
inBuckstr = inBuckstr.replaceAll( "[^\\d.]", "" );
try {
calcBucks = Double.parseDouble(inBuckstr);
} catch( NumberFormatException e) {
return;
}
// Neglect outgoing change of less than rounding error
if( Math.abs(localBucks - calcBucks) < .001 ) return;
startBucksString = String.format("$%.2f", calcBucks);
localBucks = calcBucks;
cd.setStartBucks(calcBucks);
notifyPropertyChanged(BR.startBucksString);
}
Here, I wrote a simple, compilable example of 2-way binding with a ViewModel. It illustrates the difficulty I had in continuously updating a float in the domain model -- in the end, I decided there's no way to do it without writing a custom TextWatcher for each domain field.
My approach is to delay notifyPropertyChanged method calling using Handles. In this way while the user is typing, the code don't run, then 2,5 seconds after the user has stopped to type last character, the notificationPropertyChanged will be called.
The visual effect is cool, and the user is free to write numbers as he wants.
See these two examples:
Use can use this compact(?) code for each field:
//
// g1FuelCostYear field
//
private double g1FuelCostYear;
#Bindable
public String getG1FuelCostYear() {
return Double.valueOf(g1FuelCostYear).toString();
}
private Handler hG1FuelCostYearDelay = null;
public void setG1FuelCostYear(String g1FuelCostYear) {
// Delayed notification hadler creation
if (hG1FuelCostYearDelay == null) {
hG1FuelCostYearDelay = new Handler() {
#Override
public void handleMessage(Message msg) {
notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear);
}
};
} else {
// For each call remove pending notifications
hG1FuelCostYearDelay.removeCallbacksAndMessages(null);
}
// Data conversion logic
try {
this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear);
}
catch (Exception ex) {
this.g1FuelCostYear = 0.0;
log(ex);
}
// New delayed field notification (other old notifications are removed before)
hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500);
}
This code instead is useful when you use currency converter or percent converter. The user can write a plain double, the code convert to currency string. If the setter is called with the currency string the code is able to convert it as double too.
//
// g1FuelCostYear field
//
private double g1FuelCostYear;
#Bindable
public String getG1FuelCostYear() {
NumberFormat nf = NumberFormat.getCurrencyInstance();
return nf.format(this.g1FuelCostYear);
//return Double.valueOf(g1FuelCostYear).toString();
}
private Handler hG1FuelCostYearDelay = null;
public void setG1FuelCostYear(String g1FuelCostYear) {
if (hG1FuelCostYearDelay == null)
{
hG1FuelCostYearDelay = new Handler() {
#Override
public void handleMessage(Message msg) {
notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear);
}
};
} else {
hG1FuelCostYearDelay.removeCallbacksAndMessages(null);
}
boolean success = false;
try {
NumberFormat nf = NumberFormat.getCurrencyInstance();
this.g1FuelCostYear = nf.parse(g1FuelCostYear).doubleValue();
success = true;
}
catch (Exception ex) {
this.g1FuelCostYear = 0.0;
log(ex);
}
if (!success) {
try {
this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear);
success = true;
} catch (Exception ex) {
this.g1FuelCostYear = 0.0;
log(ex);
}
}
updateG1FuelConsumption();
hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500);
}
My App recieves a neverending datastream from a bluetooth device.
I am reading this stream in a while(true) loop and can see the read data in my log.
The problem is, that my device is not responding anymore. Is there a (hopefully) simple way to let the application read the stream in the background?
Thanks!
Christian.
#boulder:
Sorry, I don't really understand that AsynkTask class. :(
Can you please help me with this code putting it in the background?
Thank you very much!
try {
while (true)
{
read = isBT.read(msgBuffer);
connected = true;
StringBuilder strBuffer = new StringBuilder();
for (int i = 0; i<read; i++)
{
int b = msgBuffer[i];
strBuffer.append(b);
}
Log.d(TAG,"++++++ Read "+ read + " Bytes: " + strBuffer.toString());
}
}
catch (IOException e) {
Log.d(TAG," +++ IOException ++++", e);
}
May be this will be helpful http://android-developers.blogspot.com/2009/05/painless-threading.html
Handler example:
private static final String CONTENT_TAG = "content";
// Call this from datastream thread to post data
private void postProgress(String aBufferContent) {
// Wrapping data in bundle
final Bundle bundle = new Bundle();
bundle.putString(CONTENT_TAG, aBufferContent);
// Sending message to handler
final Message message = mProgressHandler.obtainMessage();
message.setData(bundle);
mProgressHandler.sendMessage(message);
}
// This will be executed in UI thread. Do you GUI update job here
private final Handler mProgressHandler = new Handler() {
public void handleMessage(Message msg) {
final String streamContent = msg.getData().getString(CONTENT_TAG);
myTextView.setText(streamContent);
}
};