Android ContentResolver not reliable - java

I am currently developing an Application to consistently running a Service which gets all received Messages and pushes them to Google Sheets. My Service includes an Async Task which is created once a Message is received. Here is the AsyncTask which is inside my Service class. The SMSListener is a Broadcast Receiver class.
SmsListener
public class SmsListener extends BroadcastReceiver {
private boolean RECEIVED = false;
#Override
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
setRECEIVED(true);
Log.d("DEBUGSMSLISTENER", "SMS is received.");
}
}
public boolean isRECEIVED() {
return RECEIVED;
}
public void setRECEIVED(boolean RECEIVED) {
this.RECEIVED = RECEIVED;
}
}
AsyncTask
static class AsyncPushTask extends AsyncTask<Void, Integer, Uri> {
//Fields
private AsyncPushTask(SmsListener listener, Context context, ContactManager manager, Context application) {
smsListener = listener;
contentResolver = context.getContentResolver();
contactManager = manager;
applicationContext = application;
}
#Override
protected Uri doInBackground(Void... voids) {
Log.d(TAG, "ASYNC BACKGROUND started");
Log.d(TAG, "is received " + smsListener.isRECEIVED());
//if (isPermitted() & smsListener.isRECEIVED()) {
//if (true) {
Log.d(TAG, "is permitted and received SMS TASK");
Cursor cursor = contentResolver.query(Uri.parse("content://sms/inbox"), null, null, null, null);
if (cursor.moveToFirst()) { // must check the result to prevent exception
//Do the work to push SMS to Google Sheets
The Code works as expected but sometimes, I cannot recreate the behavior, the First SMS in the inbox isnt recognized correctly, so that the pushed message equals the one that was pushed in the last cycle.
TY for the help.

Related

EventChannel not being called every time

I am very new to flutter+dart framework. I am trying to understand how EventChannel works. I have set up EventChannel to capture the number of an incoming call.
On the android side, I have set up an BroadcastReceiver as follows.
public class CallEventHandler extends BroadcastReceiver implements EventChannel.StreamHandler {
private static final String TAG = "[SAMPLE]";
private static final int NUMBER_LEN = 10;
private EventChannel.EventSink eventSink = null;
private Activity activity = null;
public CallEventHandler(Activity activity) {
this.activity = activity;
}
#Override
public void onListen(Object arguments, EventChannel.EventSink events) {
Log.i(TAG, "[onListen] setting up events");
eventSink = events;
}
#Override
public void onCancel(Object arguments) {
Log.i(TAG, "[onCancel] cancel events");
eventSink = null;
activity = null;
}
#Override
public void onReceive(Context context, Intent intent) {
try {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
if(incomingNumber != null) {
Log.i(TAG, "[CallEventHandler] Incoming number : " + incomingNumber);
if(incomingNumber.length() > NUMBER_LEN) {
incomingNumber = incomingNumber.substring(incomingNumber.length() - NUMBER_LEN, incomingNumber.length());
Log.i(TAG, "[CallEventHandler] Incoming number after : " + incomingNumber);
if(activity != null) {
String finalIncomingNumber = incomingNumber;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if(eventSink != null) {
Log.i(TAG, "[CallEventHandler] HERESSSSS : " + finalIncomingNumber);
eventSink.success(finalIncomingNumber);
}
}
});
}
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
In the onReceive method, I am getting the incoming number and I am sending it to EventSink.
In my MainActivity I am setting up the CallEventHandler as follows:
private final String eventId = "SAMPLE_ID";
private CallEventHandler handler = new CallEventHandler(this);
#Override
public void onStart() {
super.onStart();
...
registerReceiver(handler, filter);
}
#Override
public void onStop() {
super.onStop();
unregisterReceiver(handler);
}
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), eventId)
.setStreamHandler(handler);
}
On the Flutter side, the code is as follows:
class EventHandler {
static const String TAG = "[SAMPLE]";
final String _eventId = "SAMPLE_ID";
EventChannel? _evtChannel;
Stream<String>? _evtStream;
EventHandler() {
debugPrint(TAG + " Setting up EventHandler");
_evtChannel = EventChannel(_eventId);
_evtStream = _evtChannel?.receiveBroadcastStream().distinct().map((dynamic
event) => getString(event as String));
}
void startListening(void Function(String data)? onData) {
debugPrint(TAG + " starting listening");
_evtStream?.listen((data) {
debugPrint(TAG + " In listening");
onData!(data);
});
}
}
In my UI code, I have a StatefulWidget (MySamplePage) where I am registering my callback when the call is received
void initState() {
widget.handler.startListening((incomingNumber) {
debugPrint(_tag + " data : $incomingNumber");
...
});
}
In my stateful home page build method, I initialize the handler in initState and added a route in build method
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
super.initState();
debugPrint(_tag + "initState");
_handler = EventHandler();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'/caller': (context) => MySamplePage(
handler: _handler
),
},
...
);
}
}
The issue I am facing is that, when the widget is opened I am receiving the first incoming call, as expected. But if I make another call, then that second call is not captured by the stream. If I press the back button, and reopen the Widget everything works as expected, the first incoming call is printed in the console. I know the the Android code is sending the event from the onReceive method (The `HERESSSSS' line is printed every time), but the flutter stream is not getting the values. I am not sure what I am doing wrong here. Can anyone please help?
My log is
I/flutter (11836): [SAMPLE][HomeScreen]initState
I/flutter (11836): [SAMPLE][EventHandler] Setting up EventHandler
V/AutofillManager(11836): requestHideFillUi(null): anchor = null
I/flutter (11836): [SAMPLE][EventHandler] starting listening
I/[SAMPLE] (11836): [onListen] setting up events
I/[SAMPLE] (11836): [CallEventHandler] Receiver start
I/[SAMPLE] (11836): [CallEventHandler] Receiver start
I/[SAMPLE] (11836): [CallEventHandler] Incoming number : +91XXXXXXXXXX
I/[SAMPLE] (11836): [CallEventHandler] Incoming number after : XXXXXXXXXX
I/[SAMPLE] (11836): [CallEventHandler] HERESSSSS : XXXXXXXXXX
I/flutter (11836): [SAMPLE][EventHandler] In listening
I/flutter (11836): [SAMPLE] data : XXXXXXXXXX
In the subsequent incoming calls, the last line is not printed
Thank you
Ok, I have managed to resolve it, but don't know if this is the correct approach. The issue is that MySamplePage is a StatefulWidget, And I am calling setState in its State object. That might be the reason it's unable to listen to the stream anymore. I have called startListening is the setState method and changed the code accordingly (remove the previous subscription and re-listen to the stream)
void startListening(void Function(String data)? onData) {
debugPrint(TAG + " starting listening");
if(_subscription != null) {
_subscription?.cancel();
_subscription = null;
}
_subscription ??= _evtStream?.listen((data) {
debugPrint(TAG + " In listening");
onData!(data);
});
}
Here _subscription is a variable of type StreamSubscription<String>?. Hope this answer is helpful. And I should have posted complete code earlier.

Keep Streaming service running over MediaBrowserService when Doze Mode

I am working on a Android Streaming App using MediaBrowserServiceCompat based on this great article https://medium.com/androiddevelopers/mediabrowserservicecompat-and-the-modern-media-playback-app-7959a5196d90. My app works pretty good except when phone goes to Doze Mode. I have been looking over internet and see some possible solutions to keep my service alive. One of those is running the UI and the Music Service in different Process. However since I am using the MediaBrowserService I don't know how to start the service from UI using AIDL.
This is how I connected the service with the Main Activity in the same process:
MainActivity.java
private class MediaBrowserConnection extends MediaBrowserHelper {
private MediaBrowserConnection(Context context) {
super(context, MusicService.class);
}
#Override
protected void onConnected(#NonNull MediaControllerCompat mediaController) {
mMediaController = mediaController;
}
#Override
protected void onChildrenLoaded(#NonNull String parentId,
#NonNull List<MediaBrowserCompat.MediaItem> children) {
super.onChildrenLoaded(parentId, children);
}
}
MediaBrowserHelper.java
public MediaBrowserHelper(Context context,
Class<? extends MediaBrowserServiceCompat> serviceClass) {
mContext = context;
mMediaBrowserServiceClass = serviceClass;
mMediaBrowserConnectionCallback = new MediaBrowserConnectionCallback();
mMediaControllerCallback = new MediaControllerCallback();
mMediaBrowserSubscriptionCallback = new MediaBrowserSubscriptionCallback();
}
public void onStart() {
if (mMediaBrowser == null) {
mMediaBrowser =
new MediaBrowserCompat(
mContext,
new ComponentName(mContext, mMediaBrowserServiceClass),
mMediaBrowserConnectionCallback,
null);
mMediaBrowser.connect();
}
Log.d(TAG, "onStart: Creating MediaBrowser, and connecting");
}
public void onStop() {
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
mMediaController = null;
}
if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
mMediaBrowser.disconnect();
mMediaBrowser = null;
}
resetState();
Log.d(TAG, "onStop: Releasing MediaController, Disconnecting from MediaBrowser");
}
Anyone knows how to do this or is there any other reliable solution to keep streaming alive?
Thanks

Reading Bluetooth data and putting it to MainActivity

I've been looking for this for a while and everything I've tried has not worked yet. I implemented a Bluetooth connection service class that let's me connect and send messages via Bluetooth to a HC-05 module. I'm able to see each message within the console (with a Log), however, no matter what I tried, I can't seem to put the bytes received into my main activity where I can treat it. Here is the code I have in the BluetoothConnectionService class where my Log is located:
BluetoothConnectionService:
private Handler mHandler; // handler that gets info from Bluetooth service
// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;
// ... (Add other message types here as needed.)
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
// Send the obtained bytes to the MainActivity
Handler mainActivityHandler = new Handler();
mainActivityHandler.obtainMessage(MessageConstants.MESSAGE_READ, bytes, -1, buffer);
// Send the obtained bytes to the UI activity.
/*Message readMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_READ, bytes, -1,
buffer);
readMsg.sendToTarget();*/
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
MainActivity: (in the onCreate)
btnReadGlucose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//On va envoyer quelle personne il faut lire le data
String patientName = mSpinner.getSelectedItem().toString();
int patientPosition = mSpinner.getSelectedItemPosition();
Log.d(TAG, "Le patient " + patientName + " a la position " + patientPosition + " est selectionne");
//Trouver quelle lettre envoyer
DataEnvoyer = mappingPatients(patientPosition);
RequestData = true;
//Envoi du data
envoyerCommandeBluetooth(DataEnvoyer);
//How do I call my handler ?
}
});
I'm still a newbie with Bluetooth communication handlers. I think I'm close to the answer but I really don't know how to get the message in the byte and save it to a value in my main activity.
Can anyone help ?
Thanks,
luisarcher.
METHOD 1 : If this service running on the same thread as the activity then bind the service with activity.
//IN YOUR ACTIVITY
startService(new Intent(getApplicationContext(), BluetoothService.class));
bindService(new Intent(getApplicationContext(), BluetoothService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
BluetoothService.BackgroundBinder backgroundBinder = (BluetoothService.BackgroundBinder) iBinder;
mBackgroundService = backgroundBinder.getBackgroundService();
startPinging();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBackgroundService = null;
}
};
//IN SERVICE
public class BluetoothBinder extends Binder {
public BluetoothService getBluetoothService() {
return BluetoothService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "Inside onBind");
return new BluetoothBinder();
}
Now that the service is binded you can declare a getter in service for incomingMessage so when you press the button in activity it returns you the message.
METHOD 2(VIA HANDLER):if you need an interface to communicate across processes you can create a Messenger. It handles communication on single thread.
I haven't done this but a good post about this can be found here.
METHOD 3(VIA LocalBroadCast): In your bluetooth service send a localBroadcast whenever you receive a message
//SERVICE
private void sendMessage(String incomingMessage) {
Intent intent = new Intent("UNIQUE_ACTION");
intent.putExtra("incomingMessage", incomingMessage);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
sendMessage(incomingMessage);
//ACTIVITY
#Override
public void onResume() {
super.onResume();
// This registers mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,new IntentFilter("UNIQUE_ACTION"));
}
// Handling the received Intents for the "UNIQUE_ACTION" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String incomingMessage = intent.getStringExtra()("incomingMessage");
Log.d(TAG, incomingMessage);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
Also, I would suggest looking at this link for communication between service and activity.
P.S:Have a look at this library for bluetooth communication.It does provide methods to get data from Bluetooth and I have personally tested that it works with HC-05 and also has examples.

Android Service only runs whilst debugging

Background
I am creating a service that syncs a local Realm database (stored on phone) with an online database. The database stores users and measurements.
I initialise the service by calling 'startService(new Intent(this, SyncService.class));' during the splash activity's onCreate() method, and specify in the manifest that the service should run for the length of the application.
The service has a broadcast receiver. When the receiver detects a network change from 'not connected' to 'connected', it fires a method called syncDatabases().
This method finds all measurements recorded locally after the timestamp of the last API callback, and sends them to the database. The API responds to a request by returning the object + a unique ID.
When a measurement is made whilst the device is offline, it is stored locally. When an internet connection is made, the syncDatabases() method should be called in order to update the online server with the local measurements.
My steps...
Steps when debugging the project:
With wifi I open the app and with an external device make a new measurement. This appears on both the app and in the database. I then turn wifi off and make another measurement - this appears on the device.
I attach the debugger.
I turn back on wifi and this triggers the services' receivers' onReceive() method. I step through this and it all works according to plan. I reach the syncDatabases() method, and from there I receive the callback from the API, and it then updates the Realm database with the new ID value.
The problem...
If I don't attach the debugger, nothing happens. The new measurements aren't pushed to the database, and none of my Log.e calls are printed.
Why is this happening? And is there an alternative solution / fix for this problem?
Code
Service class
public class SyncService extends Service {
private static final String TAG = "SYNCSERVICE";
private boolean mConnected = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getExtras() != null) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo != null) {
switch (netInfo.getState()) {
case CONNECTED:
if (!mConnected) {
Log.e("NETWORK", "Network " + netInfo.getTypeName() + " now connected");
syncDatabases();
mConnected = true;
}
break;
default:
mConnected = false;
break;
}
} else mConnected = false;
}
}
};
#Override
public void onCreate() {
super.onCreate();
initReceiver();
ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager.getActiveNetworkInfo() != null) {
mConnected = true;
}
android.util.Log.e(TAG, "onCreate: SyncService created");
}
#Override
public void onDestroy() {
super.onDestroy();
unInitReceiver();
android.util.Log.e(TAG, "onDestroy: SyncService destroyed");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
android.util.Log.e(TAG, "onBind: SyncService bound");
return null;
}
#Override
public boolean onUnbind(Intent intent) {
android.util.Log.e(TAG, "onUnbind: SyncService unbound");
return super.onUnbind(intent);
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
android.util.Log.e(TAG, "onRebind: SyncService rebound");
}
private void initReceiver() {
IntentFilter filters = new IntentFilter();
filters.addAction("android.net.wifi.WIFI_STATE_CHANGED");
filters.addAction("android.net.wifi.STATE_CHANGE");
registerReceiver(mReceiver, filters);
}
private void unInitReceiver() {
unregisterReceiver(mReceiver);
}
public void syncDatabases() {
RealmResults<UserDB> users = RealmDB.getInstance(getApplicationContext()).where(UserDB.class).findAll();
if (users.size() > 0) {
int userId = users.get(0).getmUserID();
Log.e("MESSAGE", PreferenceUtils.getInstance().getLastSyncDate());
Date lastSync = null;
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.getDefault());
try {
lastSync = sdf.parse(PreferenceUtils.getInstance().getLastSyncDate());
}
catch (ParseException e) {
e.printStackTrace();
try {
lastSync = BaseFragment.FORMAT.parse(PreferenceUtils.getInstance().getLastSyncDate());
}
catch (ParseException e1) {
e1.printStackTrace();
}
}
if (lastSync != null) {
Date lastSyncOffset = new Date(lastSync.getTime() + 1000);
/** Get all local results which have been made after the last sync date
 **/
RealmResults<MeasurementDB> newLocalMeasurements = RealmDB.getInstance(getApplicationContext())
.where(MeasurementDB.class).equalTo("user_ID", userId)
.greaterThan("dateCreated", lastSyncOffset)
.findAll();
/** For each measurement made after the last sync, add it to the server
 **/
for (MeasurementDB measurement : newLocalMeasurements) {
TemperatureListener mListener = new TemperatureListener(measurement);
ApiRequest.getInstance(getApplicationContext()).registerNewMeasurement(measurement.getAverage(),
measurement.getDateCreated().toString(), mListener, mListener);
}
}
}
}
/**
* Temperature listener receives the local copy of the temperature item. onResponse can then
* directly mutate the object instead of searching local db
*/
private class TemperatureListener implements Response.Listener<Measurement>, Response.ErrorListener {
private MeasurementDB measurement;
public TemperatureListener(MeasurementDB measurement) {
this.measurement = measurement;
}
#Override
public void onErrorResponse(VolleyError error) {
Log.e("OnResponse", "Failure");
}
#Override
public void onResponse(Measurement response) {
Log.e("OnResponse", "Success");
/** Update our local measurement's ID value (supplied by server)
 **/
RealmDB.getInstance(getApplicationContext()).beginTransaction();
measurement.setMeasurement_ID(response.getmMeasurementId());
RealmDB.getInstance(getApplicationContext()).commitTransaction();
/** Update the last sync date
 **/
PreferenceUtils.getInstance().setLastSyncDate(response.getmDateCreated());
}
}
}
Initialisation of Service in splash activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mTimedOut = true;
finishActivity();
}
}, DURATION);
/** Will sync application / cloud databases in background of app when network connected. **/
startService(new Intent(this, SyncService.class));
doApiWork();
}
Manifest entry
Stop with task to kill the service at the same time as the app.
Exported 'false' stops other apps from using the service.
<service
android:name=".network.SyncService"
android:stopWithTask="true"
android:enabled="true"
android:exported="false"/>
EDIT
I removed the service and left a receiver class, registered in the manifest, which triggers methods on another class when needed. However the receiver is only triggered in debug mode.

Writing to database when app is closed

I'm using gcm for chat, and I have an onMessageReceived() method that receives the messages, saves them in the database, and sends a notification to the user.
When the app is running (or paused - running in the background), this is how I store the messages in the database:
private DBHelper mDbHelper;
mDbHelper = new DBHelper(MainApplication.getAppContext());
SQLiteDatabase db = mDbHelper.getWritableDatabase();
The method getAppContext() is a static method in my main activity which returns the context.
This all works. I receive a message, save it successfully, and get a notification (when app is running, or in the background).
Problem is when the app is closed. I can't use MainApplication.getAppContext();, because there's no context when the app is closed.
Maybe I should pass the context in some other way?
UPDATE
Eventually I saved messages on server if the app was closed, and when user opens it I fetch'em from server, delete them from there, and save them on user's device. (like a queue pop operation...)
Let me know if there's a better method
see accepted answer...
OK so 1 year later I needed this again and I found the answer:
Turns out there's a static method in SQLiteOpenHelper which opens the database without context: openDatabase().
So replace this:
mDbHelper = new DBHelper(MainApplication.getContext());
db = mDbHelper.getWritableDatabase();
with this:
db = SQLiteDatabase.openDatabase("path/to/database.db", null, OPEN_READWRITE);
The static method openDatabase() doesn't need a context so we can call it even when the app is closed.
Create a class which extends Service and do your database operations in onStartCommand() method. Also start the service in onMessageReceived.
For your need you can make use of broadcast receiver.
first, create a broadcast receiver like below,
public class UpdateReceiver extends BroadcastReceiver {
protected UpdateListener listener;
public UpdateReceiver(UpdateListener listener) {
this.listener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent == null || intent.getExtras() == null) {
return;
}
if (intent.getBooleanExtra("message", false)) {
listener.onMessage(intent.getStringExtra("messageText"));
}
}
public interface UpdateListener {
public void onMessage(String message);
}
}
then make your MainActivity implement this receiver, like
public class MainActivity implements UpdateReceiver.UpdateListener
and you need to register your broadcast receiver, then you can override onMessage method in your MainActivity and you can receive your message there.
so your main activity will look like,
public class MainActivity implements UpdateReceiver.UpdateListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UpdateReceiver chatMessageReceiver = new UpdateReceiver (this);
registerReceiver(chatMessageReceiver, new IntentFilter("messagereceived"));
}
#Override
protected void onMessage( String message) {
//do your DB Operations
}
}
in your onMessageReceived method, call this broadcast receiver like,
Intent intent = new Intent();
intent.setAction("messagereceived");
intent.putExtra("message", true);
intent.putExtra("messageText", "your message")
getApplicationContext().sendBroadcast(intent);

Categories

Resources