So this is my problem: I made an app in which I need to send a string via Bluetooth, the String is a collection of data from a spinner.
The spinner is in the MainActivity where it populates with info from the database, and I got a simple BluetoothChat in another activity called BtActivity.
What I'm trying to do is to make the info of the spinner (that I got in a String) to be sent via Bluetooth, but since it is in another activity I have no Idea how to do it. The ideal would be, if possible, that the string is sent from the MainActivity.
MainActivity important code:
buttonSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
/*
Collector of Pills
*/
String shower = "";
ArrayList<PillVO> list = PillVO.getPills(spinner.getSelectedItem().toString());
for (PillVO p : list) {
shower += p.getModulo() + ", " + p.getHorario() + "; ";
}
/* This is the idea that I got for sending it
BtActivity bta = new BtActivity();
bta.SendMessageFromMain(shower);
*/
}
});
loadSpinnerData();
} /// on create finishes
BtActivity important code:
public void SendMessage() {
byte[] bytes = text.toString().getBytes(Charset.defaultCharset());
Log.d(TAG, "SendMessage: "+ bytes);
messages.setText(text.getText().toString());
mConnectedThread.write(bytes);
}
/* Idea
public void SendMessageFromMain(String lolo) {
byte[] bytes = lolo.toString().getBytes(Charset.defaultCharset());
Log.d(TAG, "SendMessage: "+ bytes);
messages.setText(text.getText().toString());
mConnectedThread.write(bytes);
}
*/
Simply send string to BtActivity via intent.
In your MainActivity
buttonSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
/*
Collector of Pills
*/
String shower = "";
ArrayList<PillVO> list = PillVO.getPills(spinner.getSelectedItem().toString());
for (PillVO p : list) {
shower += p.getModulo() + ", " + p.getHorario() + "; ";
}
Intent intent = new Intent(MainActivity.this, BtActivity.class);
intent.putExtra("shower", shower);
startActivity(intent);
}
});
In BtActivity you just get the string like
Bundle bundle = getIntent().getExtras();
String message = bundle.getString("shower");
mConnectedThread.write(message.getBytes());
Related
I have an app that writes to its local storage depending on user actions; said contents need to
be forwarded to another app.
My approach:
create a worker thread with a file observer pointed to local storage
start worker from the apps main activity
worker thread creates and sends intents with updated contents to separate app
I'm not sure (maybe need to open a separate question), but everything created in an activity gets destroyed when the activity is stopped, right? meaning that adding workers, file observers have the same life span as the activity they're defined in, right?
Code:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String FILE_OBSERVER_WORK_NAME = "file_observer_work";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "Creating file observer worker");
WorkManager workManager = WorkManager.getInstance(getApplication());
WorkContinuation continuation = workManager
.beginUniqueWork(FILE_OBSERVER_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(APIWorker.class));
Log.i(TAG, "Starting worker");
continuation.enqueue();
final Button button = findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i(TAG, "Button clicked!");
String stuffToWriteToFile = getStuff();
String cwd = getApplicationInfo().dataDir;
String stuffFilePath= cwd + File.separator + "stuff.json";
PrintWriter stuffFile= null;
try {
stuffFile = new PrintWriter(stuffFilePath, "UTF-8");
stuffFile.println(stuffToWriteToFile);
stuffFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
}
#Override
public void onResume(){
super.onResume();
// start worker here?
}
#Override
public void onStart() {
super.onStart();
// start worker here?
}
}
APIWorker.java:
public class APIWorker extends Worker {
public APIWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
private static final String TAG = APIWorker.class.getSimpleName();
#NonNull
#Override
public Result doWork() {
Context applicationContext = getApplicationContext();
Log.d(TAG, "Observing stuff file");
FileObserver fileObserver = new FileObserver(cwd) {
#Override
public void onEvent(int event, #Nullable String path) {
if(event == FileObserver.CREATE ||
event == FileObserver.MODIFY) {
String cwd = applicationContext.getApplicationInfo().dataDir;
String stuffFilePath = cwd + File.separator + "stuff.json";
String fileContents;
File observedFile = new File(stuffFilePath);
long length = observedFile.length();
if (length < 1 || length > Integer.MAX_VALUE) {
fileContents = "";
Log.w(TAG, "Empty file: " + observedFile);
} else {
try (FileReader in = new FileReader(observedFile)) {
char[] content = new char[(int)length];
int numRead = in.read(content);
if (numRead != length) {
Log.e(TAG, "Incomplete read of " + observedFile +
". Read chars " + numRead + " of " + length);
}
fileContents = new String(content, 0, numRead);
Log.d(TAG, "Sending intent ");
String packageName = "com.cam.differentapp";
Intent sendIntent = applicationContext.getPackageManager().
getLaunchIntentForPackage(packageName);
if (sendIntent == null) {
// Bring user to the market or let them choose an app?
sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setData(Uri.parse("market://details?id=" + packageName));
}
// sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, fileContents);
sendIntent.setType("application/json");
applicationContext.startActivity(sendIntent);
Log.d(TAG, "Intent sent ");
}
catch (Exception ex) {
Log.e(TAG, "Failed to read file " + path, ex);
fileContents = "";
}
}
}
}
};
fileObserver.startWatching();
return null;
}
}
Looking at the docs:
https://developer.android.com/guide/components/activities/background-starts
there are restrictions as to when activities can be started from the background but also exceptions, namely:
The app has a visible window, such as an activity in the foreground.
meaning (I think?) that as long as the user interacts with the app (MainActivity) the background worker should run, correct? It's stopped if the activity is paused/destroyed, right?
Usually you would use a Service if you have background processing to do that doesn't need user interaction (display or user input). If your app is in the foreground then your Service can launch other activities using startActivity().
Your architecture seems very strange to me. You are using a Worker, which has a maximum 10 minute lifetime. You are starting the Worker which then creates a FileObserver to detect creation/modification of files. It then reads the file and starts another Activity. This is a very complicated and roundabout way of doing things. I have doubts that you can get this working reliably.
Your Activity is writing the data to the file system. It could just call a method (on a background thread) after it has written the file that then forwards the data to another Activity. This would be much more straightforward and has a lot less moving parts.
I don't know exactly how the lifecycle of the Activity effects the Workers. I would assume that they are not directly linked to the Activity and therefore would not stop when the Activity is paused or destroyed.
I also notice that you are writing to a file on the main (UI) thread (in your OnClickListener). This is not OK and you should do file I/O in a background thread, because file I/O can block and you don't want to block the main (UI) thread.
Good day everyone.
I would like to make an application which replies to received SMS automatically.
For example.
Jon Doe sends me - "Hi", Application gets the message body, checks it with my database where I have a potential response:
ID | Text | Potential Answer
01 | Hi | Hello how are you?
and Application sends the Potential response.
So far what I have achieved -
App receives the Message, checks it with the database ( using Like '%') and gets the correct "Potential Answer" Column and passes it as message text body, but to send it I am using a button.
My Reciever is a sperate file class
public class MyReceiver extends BroadcastReceiver {
public static String textSmsbody="";
private static final String TAG=MyReceiver.class.getSimpleName();
public static final String pdu_type="pdus";
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onReceive(Context context, Intent intent) {
// Get the SMS message.
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
String strMessage = "";
String format = bundle.getString("format");
// Retrieve the SMS message received.
Object[] pdus = (Object[]) bundle.get(pdu_type);
if (pdus != null) {
// Check the Android version.
boolean isVersionM =
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
// Fill the msgs array.
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
// Check Android version and use appropriate createFromPdu.
if (isVersionM) {
// If Android version M or newer:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
} else {
// If Android version L or older:
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
// Build the message to show.
String a=msgs[i].getMessageBody();
textSmsbody=msgs[i].getMessageBody();
if (a.contains("?")) {
strMessage=msgs[i].getOriginatingAddress();
// strMessage += " :" + msgs[i].getMessageBody() + "\n";
}
else {
strMessage=a;
// strMessage += "SMS from" + msgs[i].getOriginatingAddress();
// strMessage += "ELSE:" + msgs[i].getMessageBody() + "\n";
}
// Log and display the SMS message.
Log.d(TAG, "onReceive: " + strMessage);
Toast.makeText(context, strMessage, Toast.LENGTH_LONG).show();
}
}
}
}
Sending method is in my MainActivity.
public void smsSendMessage(View view) {
databaseSearch();
// Set the destination phone number to the string in editText.
String destinationAddress = "2020";
// Find the sms_message view.
// Get the text of the SMS message.
String smsMessage = sendingText;
// Set the service center address if needed, otherwise null.
String scAddress = null;
// Set pending intents to broadcast
// when message sent and when delivered, or set to null.
PendingIntent sentIntent = null, deliveryIntent = null;
// Use SmsManager.
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage
(destinationAddress, scAddress, smsMessage,
sentIntent, deliveryIntent);
}
In layout I have a button which calls smsSendMessage () ;
My question is how I can make it automatically without button.
When the phone receives a message, the app shall check it with the database and send it by itself.
Please tell me if you need to see my Manifest file, or databasehelper.
Using JobService should be a suitable option in your case.
Create a JobService class like that
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class ExampleJobService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
//send a message
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
Also Declare In your Manifest
<service
android:name=".ExampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
Now in your Receiver, you can start it like that
ComponentName componentName = new ComponentName(context, ExampleJobService.class);
PersistableBundle bundle = new PersistableBundle();
bundle.putLong("lat", lat);
bundle.putLong("lon", lon);
JobInfo jobInfo = new JobInfo.Builder(0, componentName)
.setExtras(bundle)
.build();
For more details about JobServices https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html
I'm stuck in a program need some help. I have a fragment class in which I have multiple functions but I need only one function from it in the other class this class is not a fragment class. I used Intent but through that I'm not able to pass any function. the sample code is below. I need the ReadData whole function in the other class. as the value of data is changing in every second so i want it in the other screen to display
public class ModeFragment extends Fragment implements TitledFragment {
public void readData(){
if(manager.getConnectedDevices().size()<=0){
Toast.makeText(ModeFragment.this.getActivity(),"No connected devices", Toast.LENGTH_LONG).show();
return;
}
device1 = manager.getConnectedDevices().get(0);
Map<String , String> reciveData = getSpecificServiceInfo(device1 , CHARACTERISTIC_READABLE);
for (Map.Entry<String, String> e : reciveData.entrySet()){
manager.read(device1, e.getKey(), e.getValue(), new BleReadCallback() {
#Override
public void onRead(byte[] data, BleDevice device) {
Toast.makeText(ModeFragment.this.getActivity(), "Read success! data: " + new String(data), Toast.LENGTH_LONG).show();
// String str = data.toString();
// List<String> data1 = Arrays.asList(str.split(","));
Intent intent = new Intent(getActivity() , BluetoothActivity.class);
intent.putExtra("data" , data.toString());
startActivity(intent);
}
#Override
public void onFail(int failCode, String info, BleDevice device) {
// Toast.makeText(ModeFragment.this.getActivity(), "Read fail! data: " + info, Toast.LENGTH_LONG).show();
}
});
}
}
private void onclick(){
Intent intent = new Intent(ModeFragment.this.getActivity() , BluetoothActivity.class);
intent.putExtra("key" , "value of Key");
startActivity(intent);}}
Other class:
public class BluetoothActivity extends AppCompatActivity {
ModeFragment modeFragment = new ModeFragment();
modeFragment.readData();
Intent intent = getIntent();
String str = intent.getStringExtra("key");
sensor_1_value.setText(str);
Toast.makeText(BluetoothActivity.this , str , Toast.LENGTH_LONG).show();
}
but through intent I only get this specific Value.
I have an Android app that constantly receives data over Bluetooth and pushes data from MainActivity to MainActivity2 through Intent. The MainActivity has an ImageButton that allows switching to the MainActivity2.
I am using a variable Clicked which is true when the ImageButton is clicked and false when onBackpressed(). I use the the true/false condition to start the Bluetooth receiving when I click on an ImageButton. I am able to receive the Bluetooth data in MainActivity2, but onBackpressed closes the MainActivity2 returning to MainActivity. Then, as soon as a new data arrives, it automatically starts MainActivity2 again.
I want that MainActivity2 gets the data only when I click ImageButton and onBackPressed, MainActivity2 is permanently closed, but it does not happen.
MainActivity - ImgButtonFunction
public void onImgButtClick(View view){
Intent getNameScreenIntent = new Intent(MainActivity.this, MainActivity2.class);
final int result=1;
Clicked=true;
startActivityForResult(getNameScreenIntent,result);
}
MainActivity - small part of data receive handler
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
runOnUiThread(new Runnable() {
public void run() {
try {
String text = new String(txValue, "UTF-8");
/*Character[] Chararray = new Character[text.length()];
for (int i = 0; i < text.length(); i++) {
Chararray[i] = new Character(text.charAt(i));
}*/
/* Character[] Chararray = new Character[text.length()];
byte txByte=0;
for (int i = 0; i < txValue.length(); i++) {
Chararray[i] = new Character(text.charAt(i));}
*/
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
/*for (String retval: text.split("\n")) {
Chararray[i]=retval;
listAdapter.add("[" + currentDateTimeString + "] RecvX: " + retval + "km/h");
}*/
String str1 = String.valueOf(txValue[0]);
listAdapter.add("[" + currentDateTimeString + "] RecvX: " +str1 + "km/h");
messageListView.smoothScrollToPosition(listAdapter.getCount() - 1);
if (Clicked==true) {
Intent ii = new Intent(MainActivity.this, MainActivity2.class);
ii.putExtra("RxString", str1);
startActivity(ii);
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
});
}
MainActivity2 - onBackPressed handler
#Override
public void onBackPressed() {
Intent i=new Intent(this, MainActivity.class);
i.putExtra("Clicked",false);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
finish();
}
While starting activity2 please start it by startActivityByResult()
In onBackPressed() do setResult(RESULT_OK, new Intent().putExtra("clicked", false)) and call finish()
In your activity1, you can get result in
onActivityResult()
I have problem with starting a new activity in android. I have looked through many other questions here, but I didn't find an answer. Here's the problem:
Four classes:
1. WelcomeActivity;
2. MainActivity;
3. PopUpActivity;
4. Client;
At the begining starts WelcomeActivity where you you type all needed credentials to connect to the server, after you clicked the button, string is sent to server. Server send validation string if everything is OK. If OK is received, then MainActivity is started. Users types different things in MainActivity, the presses another button, which send another string to the server. Server processes it (string) and send back a response, also a string. And here's the problem. When server send that last string to client I want to start PopUpActivity, where will be displayed this aprticualr string in TextView.
My code:
Client part (last else if):
public void run() throws Exception {
Socket client = new Socket(ip, port);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
out.println(welcomeActivity.getCredentials());
while (true) {
final String line = in.readLine();
if (line.equals("#GO#")) {
System.out.println("#GO#");
mainActivityIntent = new Intent(welcomeActivity,
MainActivity.class);
welcomeActivity.startActivity(mainActivityIntent);
} else if (line.equals("#CLOSE#")) {
client.close();
break;
} else if (line.startsWith("#RESULTS")) {
Intent i = new Intent(MainActivity.getContext(), PopUpActivity.class);
i.putExtra(line, line);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.getContext().startActivity(i);
}
}
}
WelcomeActivity:
public void onClick(View v) {
ip = ipText.getText().toString();
port = Integer.parseInt(portText.getText().toString());
login = loginText.getText().toString();
password = passwordText.getText().toString();
credentials = login + "#" + password + "#" + brand + "#" + device + "#"
+ hardware + "#" + manufacturer + "#" + product;
client = new Client(ip, port, this);
new Handler().start();
}
private class Handler extends Thread {
public void run() {
try {
client.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
PopUpActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pop_up);
closeButton = (Button) findViewById(R.id.closeButton);
testOutcome = (TextView) findViewById(R.id.textArea);
closeButton.setOnClickListener(this);
//
Bundle extras = getIntent().getExtras();
if (extras == null) {
return;
}
String value = extras.getString(Intent.EXTRA_TEXT);
if (value != null) {
testOutcome.setText(value);
}
}
PopUpActivity is started, but text is not displayed.
Before that I tried to use Context in MainActivity:
final static Context context;
....
public void onCreate() {
context = getBaseContext();
// or context = getApplicationContext();
....
}
...
public static Context getContext() {
return context;
}
And from clint tried to call:
MainActivity.getContext().getTextView().setText(line);
At the begining I tied to call a AlertDialog, but it also was bad, NullPointerException
The problem is with your intent calling, so you may write
i.putExtra("line",line); in your MainActivity
and you can retrieve it by
Intent intent = getIntent(); intent.getStringExtra("line"); in your PopUp Activity.