Android BroadcastReceiver and starting an intent - android

public class SessionManager extends BroadcastReceiver{
Date timeOff;
Date timeOn;
#Override
public void onReceive(Context context, Intent intent) {
if( "android.intent.action.SCREEN_OFF".equals(intent.getAction())) {
Log.i("MobileViaNetReceiver", "Screen off - start time to end session");
timeOff = Calendar.getInstance().getTime();
}
if( "android.intent.action.ACTION_SHUTDOWN".equals(intent.getAction())) {
// DO WHATEVER YOU NEED TO DO HERE
Log.i("MobileViaNetReceiver", "Shut down - log off user");
DbAdapter_User db = new DbAdapter_User(context);
db.open();
db.handleLogout();
db.close();
}
if( "android.intent.action.SCREEN_ON".equals(intent.getAction())) {
timeOn = Calendar.getInstance().getTime();
long diffInMs = timeOn.getTime()-timeOff.getTime();
// convert it to Minutes
long diffInMins = TimeUnit.MILLISECONDS.toMinutes(diffInMs);
if ((int) (diffInMins) > 15) {
//log out user
Log.i("MobileViaNetReceiver", "User inactive for 15 minutes - logout user");
DbAdapter_User db = new DbAdapter_User(context);
db.open(); // ******* HERE *************
db.handleLogout();
db.close();
} else {
Log.i("MobileViaNetReceiver", "User still active");
}
}
}
When the screen is turned ON I am checking if the user has turned scrren off for more than 15 mins, if yes, logout him. And go to LonIn screen.
I want to start an intent when I call that handleLogout() (marked * HERE **)
Can I do that when class extends BroadcastReceiver ? If no, what else can I do ?

You need to remember intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Blessings and happiness to the Google engineer who wrote the followint error message "E/AndroidRuntime( 2339): java.lang.RuntimeException: Unable to start receiver android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?"
public class AgeingAutoStartBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context,MyMainClass.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
);
}
}
Thanks to everyone who writes helpful messages here

Yes, you can do that. You just use the context that was passed into your onRecieve function when you're creating your Intent. Once you have the Intent, make this call:
Context.startActivity(yourIntent);

You certainly can. Try
Intent yourIntent = new Intent(context, YourActivity.class);
startActivity(yourIntent);
If you want to do it in your handleLogout method, pass in the Context.
private method handleLogout(Context context) {
...
}

Related

Broadcast Receiver from service Listener

I created a Broadcast Receiver (BR) in a service that will react to incoming SMS with specific number and body. I only need it to receive for a few seconds/minutes after user action, that's why I didn't registered it in manifest or activity (user may close it). BR has two parts, automatic (which works fine) and manual which should launch MainActivity and start a Dialog. I know that Dialog can't be started from BR and thats why I created a Listener, but my problem is that it is always null after service starts. It has value in onCreate of my MainActivity, but when service starts it changes to null, and I understand why (serivce re-initalize the Listener listener). I even tryed to put initialised listener value to SharedPrefs and restore it after, but when I try to store it with json it only stores null again. So how do I make my listener != null??? These are the relevant parts of my code:
MainActivity
onCreate {
SMSService smsReceiver = new SMSService();
smsReceiver.setListener(new SMSService.Listener() { //here listener from service is != null
#Override
public void onTextReceived(String s) {
dialogS(s); // totaly different dialog
}
});
...
mDialogBuilder = new AlertDialog.Builder(this);
...
.setPositiveButton(new OnClick...
Intent servisIntent = new Intent(MainActivity.this, SMSService.class);
startService(servisIntent);
...
}
SMSService
private Listener listener; // and here it get null which is the problem
public int onStartCommand(Intent intent, int flags, int startId) {
...
SMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
context.startActivity(i);
if (listener != null) {
listener.onTextReceived("4333");
}
}
void setListener(Listener listener) {
this.listener = listener; }
interface Listener {
void onTextReceived(String text);
}
Btw I also tried to put smsReceiver.setListener block of code in my Dialog .setPossitive onClickListener after calling startService hoping it would initiate after service but nothing
Installing a listener mechanism with setter method in service is bad practice. You can use ResultReceiver to receive callback results from service. It is Parcelable, so it can be passed in an intent before service started

Put onReceive on wait until the started activity finishes

In the onReceive(), I want to create a new Intent and start a new Activity. After the activity finishes, I want to get back to the same line from where I left for the activity. I know that I cannot use BroadcastReceiver class for achieving this. How can this be achieved? Below is the onReceive() code:
final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
abortBroadcast();
String passkey="hey";
Intent passkeyIntent = new Intent(context.getApplicationContext(),TestActivity.class);
passkeyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
passkeyIntent.putExtra("passkey",passkey);
context.startActivity(passkeyIntent);
Log.d("after returning...",passkey);
}
else
{
Log.d("Unexpected pairingtype:" , type+"");
}
}
}
};
Any idea that can achieve this would be appreciated.
You can use startActivityFor result instead of startActivity to start an activity..make it perform some task and return the result to previous activity
Look at this: How to manage `startActivityForResult` on Android?

IntentService - Wakelock release issue

I have an alarm application.
Flow looks like this :
WakefulBroadcastReceiver(Acquires wakelock) --->> Intent service -->> startActivity
public class AlarmService extends IntentService {
protected void onHandleIntent(Intent intent) {
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
Basically WakefulBroadcaseReceiver starts an intent service using startWakefulService(). Inside intent service's onHandleIntent(), only work I am doing is further starting a new activity using startActivity(). That new activity is where I am using mediaPlayer in a loop, which sounds the alarm. That activity has a dismiss button, which waits for user click to stop the media player & activity finishes.
Now the problem I am facing is that after calling startactivity() inside intent service, I can not wait for TriggeredActivity to finish(no equivalent to startActivityForResult in Service) and then complete wakeful intent. Related link
startActivity(activityIntent);
WakefulBCastReceiver.completeWakefulIntent(intent); /* can't do here */
So I am not explicitly releasing wakelock here.
My question is will the wakelock be released automatically(link-to-death), when the process that is holding it is killed.
If yes, then in my particular scenario, I need not call WakefulBCastReceiver.completeWakefulIntent().
Yes, you need to use completeWakefulIntent.
You need to put your TriggeredActivity intent into EXTRAs.
#Override
public void onReceive(Context context, Intent intent) {
Intent intentService = new Intent(context, NotificationsIntentService.class);
// Inserting data inside the Intent
intentService.putExtra(NotificationsIntentService.EXTRA_NOTIF, new Intent(context, TriggeredActivity.class));
startWakefulService(context, intentService);
}
NotificationsIntentService.class
public class NotificationsIntentService extends IntentService {
private static final String TAG = "DebugNotifIntent";
public static final String EXTRA_NOTIF = "extra_notif";
public NotificationsIntentService(){
super(NotificationsIntentService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: ");
Intent extraIntent = intent.getParcelableExtra(EXTRA_NOTIF);
extraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(extraIntent);
NotificationWakefulBroadcastReceiver.completeWakefulIntent(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}
I have managed to find a solution for my problem. I am now using a Messenger for message based cross process communication between intent service & triggered activity.
I am passing a handler - alarmServiceHandler, from intent service to activity through a messenger.
Handler alarmServiceHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.arg1 == 1) {
completedTriggeredActivity = true;
}
}
};
Inside onHandleIntent(), I am passing handler through Messenger object in intent's extra data.
Messenger alarmServiceMessenger = new Messenger(alarmServiceHandler);
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.putExtra("AlarmServiceMessenger", alarmServiceMessenger);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
while(!completedTriggeredActivity){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WakefulBCastReceiver.completeWakefulIntent(intent);
In TriggeredActivity, I am retrieving messenger in Dismiss button's OnClickListener, just before calling finish() on the activity. And sending back a message to AlarmService with arg = 1, implying end of processing in triggered activity.
buttonDismiss.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Messenger alarmServiceMessenger = getIntent().getParcelableExtra("AlarmServiceMessenger");
Message alarmServiceMessage = Message.obtain();
alarmServiceMessage.arg1 = 1;
try {
alarmServiceMessenger.send(alarmServiceMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
finish();
}
After starting triggered activity, I am putting AlarmService in sleep mode till boolean variable completedTriggeredActivity has not been set to true in handleMessage(). Once true, it means triggered activity has finished & now I can proceed with releasing wake lock.
I would be glad to receive comments about my approach & any suggestions towards a better solution to my problem, than the one I have deviced.

Android - Broadcast Receiver launch a singletask Activity

I have a broadcast receiver which will launch an Activity onReceive.
When launched, this activity will perform a long task and call finish() at the end.
I do not want to trigger another launch of Activity when the previous Activity is still performing the long task. How can I launch only a singletask activity? I have set this in the manifest.
android:launchMode="singleTask"
In my onReceive method,
public void onReceive(Context context, Intent intent) {
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activity);
}
Don't seems to work.
The Activity class actually is a MediaRecorder which will record a video clip (say 10 sec). Thus I do not want to trigger another Activity while this recording is still incomplete.
You just need to have some way for your activity to communicate to your receiver to let it know whether or not it is already running. If you have that then you can make an if statement in the receiver that will keep it from launching multiples.
One option is a static boolean in your activity that indicates whether or not you are currently running. Then you can check that boolean from the receiver, and if it is true, then don't call startActivity().
your activity would need something like this:
public YourActivity extends Activity{
public static isRunning = false;
public void onStart(){
...
isRunning = true;
}
public void onStop(){
...
isRunning = false;
}
}
now in your receiver you can make a simple if statement that will check the value of isRunning:
public void onReceive(Context context, Intent intent) {
if(YourActivity.isRunning == false){
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activity);
}
}
Please add these flags.
public void onReceive(Context context, Intent intent) {
Intent activity = new Intent(context, Preview.class);
activity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP |Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
context.startActivity(activity);
}

refreshing and reloading an Activity from a Service without exiting the Activity, Android appwidget

Good day, I have an activity which i navigate to from an icon on an appwidget using pending Intents. Everything is being done in a service class. Now, the activity has a refresh button which when pressed, it sends an intent that calls the onStart() method on the service to update itself and perform some web operations. How do i go about reflecting the changes that could have occurred from the service in the activity without temporarily existing the activity.
Service to Activity:
if(intent.getExtras()!= null){
appWidgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
//if i get this action from my detailedinfo class add a boolean to it
if(intent.getAction() == refresh_action){
// boolean variable to hold condition
my_action = true;
}
Intent forecast = new Intent(this,detailedInfo.class );
forecast.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
forecast.putExtra("cityname", city);
PendingIntent forecastIntent = PendingIntent.getActivity(this, 0, forecast, 0);
/*onclick to go to detailedInfo class*/
remoteView.setOnClickPendingIntent(R.id.city_image_id, forecastIntent);
if(my_action == true){
//Log.d(TAG, "my_action is true, performing pending intent");
try {
forecastIntent.send(this, 0, forecast);
} catch (CanceledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And in the Activity class:
Intent service = new Intent(this, cityService.class);
service.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
service.setAction(refresh_action);
Uri data = Uri.withAppendedPath(Uri.parse(CityWidgetProvider.URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId));
service.setData(data);
startService(service);
I tried adding a setAction() method to the intent that calls the service and then use the same pendingIntent(even though i think is a long shot) but they seems to be ignored. Please how do i go about this and what could i have been doing wrong.? As usual any help is highly appreciated. Thank you.
I'm not 100% clear on what you're trying to do, but the easiest thing to do would be to register a BroadcastReceiver in your Activity onResume (remove it in onPause). When the service is done with whatever it needs to do, broadcast that info.
In the Activity
public static final String ACTION_STRING = "THE_BIG_ACTION";
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do whatever you want here
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(ACTION_STRING));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
In the service, when you're done, just call...
sendBroadcast(new Intent(YourActivityClass.ACTION_STRING));
If you want to include some data, just put it in the intent like you would when starting an Activity.
If your Activity is off screen when the service completes, and the user goes back to it, you'll have missed the notification. That's a different issue to resolve.

Categories

Resources