getActivity() via Android Service - android

How can I get current/running Activity from Android Service? I am working on Screen Locker and I need to getActivity() and getWindow() in order to getDecorView() to make navigation bar hidden. If anyone knows better solution, please comment. Thanks!

There is no way to get a reference to the Activity as far as I know.
A classic aproach to communicate between a Service and an Activity is by using a BroadcastReceiver.
Here is an Example:
on your Activity you can create a Inner class that extends BroadcastReceiver:
private class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.hasExtra(Constants.SOME_ACTION)) {
//DO YOUR THING
}
}
}
Don't forget to register it on onCreate:
serviceReceiver = new ServiceReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constants.SERVICE_RECEIVER);
registerReceiver(serviceReceiver, intentFilter);
and to unRegister it on onPause()
if (serviceReceiver != null)
unregisterReceiver(serviceReceiver);
Then from your Service you can send a Broadcast on an Event, something like this:
Intent intent = new Intent();
intent.setAction(Constants.SERVICE_RECEIVER);
intent.putExtra(Constants.SOME_ACTION, true);
sendBroadcast(intent);
This way your Activity can react to Events on your Service.

Related

findViewById is undefined for the type BluetoothLeService

In my public class BluetoothLeService extends Service, I have the following code:
private void updateTimeValues(BluetoothGattCharacteristic characteristic) {
TextView time = (TextView) findViewById(R.id.time);
time.setText(R.string.time);
findViewById is undefined for the type BluetoothLeService. I know that the function is declared in the Activity class but how do I implement the function without extending the Activity class.
I am a novice in Android development so please detail as possible your answer :)
Thanks!
That's correct. Service doesn't have ui. From the documentation
A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
you could use a LocalBroadcastManager to communicate with the Activity whose started the Service in order to update the UI
As you will not be able to access the textView directly from the service, you need to create a broadcast receiver in the activity.
In your service, call this onCreate
myBroadcast = LocalBroadcastManager.getInstance(this);
Now in your updateTimeValues() use myBroadcast:
Intent intent = new Intent("myNewBroadcastIntent");
intent.putExtra("newtime", "//value you want to send");
myBroadcast.sendBroadcast(intent);
Now create receiver in the onCreate of your mainActivity as follows:
myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String s = intent.getStringExtra("newtime");
//now you can set it to the textView
}
};
And register it onStart as:
LocalBroadcastManager.getInstance(this)
.registerReceiver((myReceiver),new IntentFilter("myNewBroadcastIntent"));
And unregister onStop as :
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onStop();
Hope this helps!

send action from receiver to activity?

I am using broadcast receiver in my app to detect incomming call and it works fine. But problem is I can not send action to activity. I mean.. I want do something in activity not in receiver. I read many tutorial but they all are performing action in receiver. Any idea ?
You can declare a BroadcastReceiver as inner class of the Activity. In this case you can directly call activity's methods:
public class MyActivity extends Activity {
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
activityMethod();
}
};
private final IntentFilter filter = new IntentFilter("android.intent.action.PHONE_STATE");
#Override
protected void onStart() {
super.onResume();
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onPause();
unregisterReceiver(receiver);
}
private void activityMethod() {
}
}
You can start the Activity using an Intent and put a command code in the Intent extra fields. In your Activity you can then decide the behaviour based on the command code or resort to a default behaviour if none is present.
You can start an activity from your receiver via the normal means:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, YourActivity.class);
startActivity(i);
}
Note though that the user is going to expect that the phone application starts up since they are receiving a phone call. It is very likely a bad idea to hijack the phone call by dumping your own activity on top of the stock dialer app.

Why BroadcastReceiver works even when app is in background ?

I am checking Internet connectivity in my app using BroadcastReceiver and I show an alert dialog if the connection is lost. It works fine. But my problem is that BroadcastReceiver works even if my app is in backgroung. So dialog pops up when internet connection is lost even if user is in some other app. This is totally ruining my app.
Has anyone got any idea how to restrict Broadcast receiver in the app only?
Here is my BroadcastReceiver :
public class ConnectivityChangedReceiver extends BroadcastReceiver{
#Override
public void onReceive( Context context, Intent intent )
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
} else {
try{
Intent i=new Intent(context, InternetDialogActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} catch(Exception e){
e.printStackTrace();
}
}
}
}
And the activity is:
public class InternetDialogActivity extends Activity implements OnClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.internet_dialog_box);
getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
Button retryButton = (Button) findViewById(R.id.retryInternetButton);
retryButton.setOnClickListener(this);
}
public boolean checkConnectivity(){
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo!=null && networkInfo.isConnected()) {
finish();
return true;
} else {
Intent intent = getIntent();
finish();
startActivity(intent);
return false;
}
}
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.retryInternetButton:
try{
checkConnectivity();
} catch(Exception e){
e.printStackTrace();
}
break;
}
}
}
Here is how I declared receiver and activity in manifest:
<receiver android:name="com.lisnx.service.ConnectivityChangedReceiver"
android:label="NetworkConnection">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<activity android:name="com.lisnx.activity.InternetDialogActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="#android:style/Theme.Dialog" />
I have read that we can restrict BroadcastReceiver to work within the app by not declaring it in the manifest. But I don't know how will receiver work then? Please help me. I am stuck on it badly. Thanx in advance.
A BroadcastReceiver works when the app is in the background because the event that the receiver picks up are sent globally, and each app is registered to listen in on these, regardless of whether or not it is running.
To deal with this, in your BroadcastReceiver's onReceive code, check if your app is in the foreground.
There is one--and only one that I know of--consistently effective method to do this. You need to keep track of your pause/resume actions for your application. Ensure that you check this in every activity.
There is some sample code in this answer (solution #1). In your case, you would want to check MyApplication.isActivityVisible() == true as a validation before doing anything from your BroadcastReceiver.
Have you tried to remove the Intent filter from the manifest and register/unregister it in activity? So you can try to register Intent filter in onStart() and unregister it on onStop() methods. The code goes somethink like this:
static final String ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);
unregisterReceiver(ConnectivityChangedReceiver);
You should also learn about Activity Lifecycle, if it's not familiar yet.
You should register/unregister your BroadcastReceiver in onPause() and onResume() of each activity. Then you know that the receiver is only "listening" when your app is in the foreground. You can easily do that by creating your own BaseActivity that extends Activity and overrides onPause() and onResume() and registers/unregisters your receiver. Just have all your activities extend BaseActivity and have them call through to super.onResume() and super.onPause() as usual. Here's example code:
public class BaseActivity extends Activity {
// Create an IntentFilter to listen for connectivity change events
static IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
// Create an instance of our BroadcastReceiver
static ConnectivityChangedReceiver receiver = new ConnectivityChangedReceiver();
#Override
protected void onPause() {
super.onPause();
// Stop listening for connectivity change events
unregisterReceiver(receiver);
}
#Override
protected void onResume() {
super.onResume();
// Listen for connectivity change events
registerReceiver(receiver, filter);
}
}
All your activities should extend BaseActivity and if they need to do anything special in onResume() or onPause() just make sure to call through to super.onXXXXX() like this:
public MyActivity extends BaseActivity {
#Override
protected void onResume() {
super.onResume();
// Here you do whatever you need to do in onResume() of your activity
...
}
#Override
protected void onPause() {
super.onPause();
// Here you do whatever you need to do in onPause() of your activity
...
}
}
I didn't run the code through a compiler so I apologize if there's a typo or I missed something.
I think you will have to make sure that you are not using the receiver when app is in background. For that you will have to use every activities onPause() and onResume() methods.
As far as I know, if Broadcast receiver is registered inside manifest.xml then broadcast receiver exists as long as application exists. Also, Dynamically registered receivers (that means, Register your BroadcastReceiver programmatically) are called on the UI thread. This means that your receivers blocks any UI handling and thus the onReceive() method should be as fast as possible.
However, I will try to discuss information about Broadcast Receiver. But, first should know some information. Firstly, Broadcast receiver is a standalone application component which means it will continue running even when other application component are not running. That's why we unregister broadcast receiver in onPause on the activity. Also, Developer should register this in Activity.onResume() implementation.
Secondly, Developer should not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack. I have put that information from BroadcastReceiver documentation.
Another point is that a BroadcastReceiver object is only valid for the duration of the call to onReceive(). As soon as the onReceive() method is finished, your BroadcastReceiver terminates.
Now, how to register your receiver programmatically:
public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
Here, BroadcastReceiver- receiver will be call when any broadcast intent match with filter.
And IntentFilter- Intent specifies which event your receiver should listen to.
Register:
YourConnectionListener receiver;
this.reciever = new YourConnectionListener();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(this.reciever, filter);
Sent your Broadcast Info:
Intent intent = new Intent();
intent.putExtra("Message", "Your connectivity info has Changed!!");
this.sendBroadcast(intent);
Receiver:
Now, need to receive the Broadcast. Android calls the onReceive() method on all registered broadcast receivers whenever the event occurs. Say you want to be notified whenever the connection is changed.
public class YourConnectionListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
// your Code
}
}
onReceive() has two arguments:
context: The Context object you can use to access additional information or to start services or activities.
intent: Intent used to register your receiver. This object contains additional information that you can use in your implementation.
Additionally, Developer should avoid any long-lasting tasks in your BroadcastReceiver. So, In statically and dynamically registered receivers, Developer should do minor tasks in the receiver itself.For any longer tasks you should start a service from within your receiver.
To make a Broadcast Receiver that fires only when you app is running follow the below code.
1. Create your Broadcast Receiver like this:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class InternetStatusNotifier extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Recieve notification here
}
}
2. Make an activity or fragment where you want the Broadcast Receiver to work like this:
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
public class MainActivity extends Activity {
private InternetStatusNotifier mInternetStatusNotifier;
#Override
protected void onCreate(Bundle savedInstanceState) {
mInternetStatusNotifier = new InternetStatusNotifier();
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
registerReceiver(mInternetStatusNotifier, new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE"));
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(mInternetStatusNotifier);
super.onPause();
}
Note: That is how you use broadcasts receiver in a screen specific manner. Only the screen displaying will receive broadcasts in this way. When you register broadcast using manifest file then they are even received when app is closed
That is the way broadcast receivers work in Android. If you register for a broadcast in the manifest and your app is not running, Android will start a new process to handle the broadcast. It is generally a bad idea to directly show a UI from a broadcast receiver, because this may interrupt other apps. I'm also not convinced that a universal 'connection lost' dialog is a good idea either. This should probably be handled by each activity that uses network access.
As for the original question, you need to disable your receiver when your activity goes in the background (onPause(), etc.) and enable it when you come to the foreground (onResume(), etc). Put enabled=false in your manifest and then use something like this in your code to toggle it as necessary:
public static void toggle(Context context, boolean enable) {
int flag = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
ComponentName receiver = new ComponentName(context,
ConnectivityMonitor.class);
context.getPackageManager().setComponentEnabledSetting(receiver, flag,
PackageManager.DONT_KILL_APP);
}
A simple way of finding whether the app is in foreground or not
if((mContext.getPackageName().equalsIgnoreCase(
((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
I better suggest you to check the internet setting from the application when someone opens it, here is the piece of code how i do it.
public static boolean isNetworkConnected(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
return false; // There are no active networks.
} else
return true;
}

Android: how to send object from BroadcastReceiver to running Activity

I have a class that extends BroadcastReceiver that reads new sms
public class SmsReceiver extends BroadcastReceiver
{
// reading sms
// I want to send the sms text to my main activity
}
And have another class in the same app that is my main Activity.
So when I receive new sms, I want to send its content to my main Activity that is already running and display it.
How can I do that?
I would be thankful for some code samples :)
i can suggest you two possibilities
send new broadcasts from this receiver to a new receiver which is registered inside your activity
register this receiver inside your activity and reduce the hassle
i guess option two is more suitable
this is how you may register a broadcast receiver inside your activity class:
IntentFilter filter = new IntentFilter();
public void onResume(){
filter.addAction("action_string_1");
filter.addAction("action_string_2");
registerReceiver(receiver, filter);
}
public void onPause(){
unregisterReceiver(receiver);
}
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("action_string_1")){
//do something here
}
else if(action.equals("action_string_2")){
//do somethign here
}
}
};

Android Communication between Broadcast Receiver and MainActivity (Send data to activity)

I've a simple Main Activity which has to stop till an SMS is received... How can I launch a method from the MainActivity within the BroadcastReceiver's onReceive() Method?
Is there away with Signal and Wait? Can I pass something with a pending Intent, or how can I implement this communication?
Communication from BroadcastReceiver to Activity is touchy; what if the activity is already gone?
If I were you I'd set up a new BroadcastReceiver inside the Activity, which would receive a CLOSE message:
private BroadcastReceiver closeReceiver;
// ...
closeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//EDIT: receiving parameters
String value = getIntent().getStringExtra("name");
//... do something with value
finish();
}
};
registerReceiver(closeReceiver, new IntentFilter(CLOSE_ACTION));
Then from the SMS BroadcastReceiver you can send out this action:
Intent i = new Intent(CLOSE_ACTION);
i.putExtra("name", "value"); //EDIT: this passes a parameter to the receiver
context.sendBroadcast(i);
I hope this helps?
I had the exact same problem, I tried using intent but i was unsuccessful
The easiest way to use it would be using static methods and static variables
MainActivity.java
public static void stopsms()
{
/*
some code to stop the activity
*/
}
SMSReceiver.java
at the end call this function
MainActivity.stopsms();
It works amazing if your code does not affect when you use static methods and variables. Let me know if you need any help.
The problem with registering a second receiver within the activity, however, is that it will not be persistent like registering in the manifest... thus, although, this solution may work, will only work if the activity is running in background.
it's easy, use interface like that:
1) in your broadcast receiver create an interface.
public interface ChangeListener{
public void functionWhoSendData(String type);
public void etc();
}
and instantiate that interface in your broadcast receiver, use it:
public void onReceive(....
String data=functionWhereYouReceiveYouData();
ChangeListener.functionWhoSendData(data);
}
And in your activity, make it implements your interface

Categories

Resources