I require a service to send messages to the Cloud while receiving data from the device as a result I have the following code:
public class MessageService extends Service {
private int mAlert = 0;
private PanicReceiver mPanicReceiver;
#Override
public void onCreate() {
super.onCreate();
mPanicReceiver = new PanicReceiver();
IntentFilter panicFilter = new IntentFilter();
panicFilter.addAction(Constants.PANIC_ON_RECEIVER_ACTION);
panicFilter.addAction(Constants.PANIC_OFF_RECEIVER_ACTION);
registerReceiver(mPanicReceiver, panicFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mPanicReceiver);
super.onDestroy();
}
private class PanicReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Constants.PANIC_ON_RECEIVER_ACTION:
mAlert = 2;
break;
case Constants.PANIC_OFF_RECEIVER_ACTION:
mAlert = 0;
break;
}
}
}
}
I would like to seperate the broadcast receiver to a seperate file. How can you do that?
MessageService.class
public class MessageService extends Service {
private PanicReceiver mPanicReceiver;
#Override
public void onCreate() {
super.onCreate();
mPanicReceiver = new PanicReceiver();
IntentFilter panicFilter = new IntentFilter();
panicFilter.addAction(Constants.PANIC_ON_RECEIVER_ACTION);
panicFilter.addAction(Constants.PANIC_OFF_RECEIVER_ACTION);
registerReceiver(mPanicReceiver, panicFilter);
}
#Override
public void onDestroy() {
unregisterReceiver(mPanicReceiver);
super.onDestroy();
}
private int getAlert() {
return mPanicReceiver.getAlert();
}
}
PanicReceiver.java
private class PanicReceiver extends BroadcastReceiver {
private int mAlert = 0;
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Constants.PANIC_ON_RECEIVER_ACTION:
this.setAlert(2);
break;
case Constants.PANIC_OFF_RECEIVER_ACTION:
this.setAlert(0);
break;
}
}
public int getAlert() {
return mAlert;
}
public void setAlert(int mAlert) {
this.mAlert = mAlert;
}
}
Just move mAlert from MessageService to PanicReceiver, than you can use the IDE to assist you to refactor out the class pressing F6 with the cursor upside the class name, or with a right click:
Related
I am developing an app to monitor changes in proximity sensor value. In app there should be two separate buttons to start a service and then to start monitoring proximity sensor.
This is my service class
public class MyService extends Service{
Sensor proxSensor;
SensorManager sm;
public static MyService instance;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
instance = this;
return Service.START_STICKY;
}
public void startScan(){
sm=(SensorManager)getSystemService(SENSOR_SERVICE);
proxSensor=sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
SensorEventListener eventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Log.e("Sensor","Value "+sensorEvent.values[0]);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
sm.registerListener(eventListener, proxSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
I am starting service from my main activity
public void viewNotification(View view){
startService(new Intent(this,MyService.class));
}
public void viewNotification2(View view){
MyService.instance.startScan();
}
The Log output is printed correctly while the app is running but when I close the activity and remove it from previous apps list the output is not given. But if I call startScan() within onStartCommand it goes on running even after I close the app.
Why doesn't it keep on giving the output?
Is there any other method instead of using static MyService to achieve this?
First of all - use service binding or aidl approaches for working with your Service. (see: https://developer.android.com/guide/components/bound-services.html)
For example:
Suppose, we have service named MyService.
In this class you need write next
private final IBinder mBinder = new LocalServiceBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalServiceBinder extends Binder {
public MyService getBinder() {
return MyService.this;
}
}
Next in your Activity:
private MyService mService;
boolean isBounded;
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
MyService.LocalServiceBinder binder = (MyService.LocalServiceBinder) service;
mService = binder.getBinder();
isBounded = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
isBounded = false;
}
};
And
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, MyService.class), mServiceConnection, BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (isBounded) {
unbindService(mServiceConnection);
isBounded = false;
}
}
Now you can call your service methods like:
private void activityMethod(){
if (isBounded){
mService.someMethod();
}
}
Second, for working in foreground, call startForeground (int id, Notification notification) method.
This question already has an answer here:
Want to Access Power Button events in android [duplicate]
(1 answer)
Closed 4 years ago.
I am developing an application in which call on an number on power button click (4 times) but now issue is when user press home button 4 times it will trigged the call and I want only side power button click.
My receiver and service in manifest
<receiver
android:name=".services.SOSBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
<service
android:name=".services.SOSService"
android:enabled="true">
</service>
and my BroadcastReceiver class
public class SOSBroadcastReceiver extends BroadcastReceiver
{
private static long lastTriggerTime = 0;
private static final int ONE_MILLI = 1000;
protected static final long ONE_SEC = 1 * ONE_MILLI;
protected static final long TWO_SEC = 2 * ONE_MILLI;
protected static final long THREE_SEC = 3 * ONE_MILLI;
protected static final int TRIGGER_THRESHOLD = 3;
protected static boolean triggerInProgress = false;
protected static int triggerCounter = 0;
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().contains(Intent.ACTION_SCREEN_ON))
{
if (!triggerInProgress)
{
checkAndCreateAlert(context);
}
}
else if (intent.getAction().contains(Intent.ACTION_SCREEN_OFF))
{
if (!triggerInProgress)
{
checkAndCreateAlert(context);
}
}
}
private void checkAndCreateAlert(Context context)
{
/*---- If the gap between power button press is less than 2 seconds ----*/
if ((System.currentTimeMillis() - lastTriggerTime) <= TWO_SEC
|| (triggerCounter == 0))
{
triggerCounter++;
lastTriggerTime = System.currentTimeMillis();
}
else
{
triggerCounter = 0;
}
if (triggerCounter > TRIGGER_THRESHOLD)
{
((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
triggerInProgress = true;
Intent intent = new Intent(context, SOSActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("timer", true);
context.startActivity(intent);
triggerInProgress = false;
triggerCounter = 0;
}
}
}
My code will keep the count of power button click in terms of screen_on and screen_off event and execute the other method if power button is pressed more than 3 time in 2secs.
This is my Service class
public class SOSService extends Service
{
BroadcastReceiver mReceiver;
IntentFilter pqrs_intentFilter;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
unregisterReceiver(mReceiver);
}
#Override
public void onStart(Intent intent, int startid)
{
pqrs_intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
pqrs_intentFilter.addAction(Intent.ACTION_SCREEN_ON);
mReceiver = new SOSBroadcastReceiver();
registerReceiver(mReceiver, pqrs_intentFilter);
}
public void onStop(Intent intent)
{
unregisterReceiver(mReceiver);
}
}
public class ExampleActivity extends Activity {
#Override
protected void onCreate() {
// INITIALIZE RECEIVER
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
// YOUR CODE
}
#Override
protected void onPause() {
// WHEN THE SCREEN IS ABOUT TO TURN OFF
if (ScreenReceiver.wasScreenOn) {
// THIS IS THE CASE WHEN ONPAUSE() IS CALLED BY THE SYSTEM DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED OFF");
} else {
// THIS IS WHEN ONPAUSE() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onPause();
}
#Override
protected void onResume() {
// ONLY WHEN SCREEN TURNS ON
if (!ScreenReceiver.wasScreenOn) {
// THIS IS WHEN ONRESUME() IS CALLED DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED ON");
} else {
// THIS IS WHEN ONRESUME() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onResume();
}
}
Receiver
public class ScreenReceiver extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
Intent i = new Intent(context, UpdateService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
Service
public static class UpdateService extends Service {
#Override
public void onCreate() {
super.onCreate();
// REGISTER RECEIVER THAT HANDLES SCREEN ON AND SCREEN OFF LOGIC
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onStart(Intent intent, int startId) {
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if (!screenOn) {
// YOUR CODE
} else {
// YOUR CODE
}
}
}
Hopefully this was useful. Let me know if you have questions.
I'm trying to run a background service in React-Native. From what I've heard I need to write it in native Java and connect it to the react-native code. When I try to emit an event I get an error:
Tried to access a JS module before the React instance was fully set up. Calls to should only happen once initialize() has been called on your native module.
So I added a check to see if the Module is running:
if (reactContext.getLifecycleState() == LifecycleState.RESUMED)
But it always returns false. The lifecycle is stuck on BEFORE_CREATE. How should I emit my event.
Service:
public class TestService extends Service {
double distance = 0.0;
ReactContext reactContext;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
reactContext = new ReactContext(getApplicationContext());
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
WritableMap params = Arguments.createMap();
distance+= 0.7;
Log.d("LOG", "Trying to send distance: "+distance+" on lifecycle: "+reactContext.getLifecycleState());
params.putDouble("distance", distance);
sendEvent(reactContext, "updateDistance", params);
}
},0,1000);
return START_STICKY;
}
private void sendEvent(ReactContext reactContext, String eventName, #Nullable WritableMap params) {
if (reactContext.getLifecycleState() == LifecycleState.RESUMED) {
reactContext.getJSModule(DeviceEventManagerModule
.RCTDeviceEventEmitter.class)
.emit(eventName, params);
Log.d("LOG", "Sent distance: "+distance);
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Module:
public class ServiceModule extends ReactContextBaseJavaModule {
ReactContext reactContext;
public ServiceModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.initialize();
}
#ReactMethod
public void startTrackingService() {
Intent intent = new Intent(reactContext, TestService.class);
reactContext.startService(intent);
}
#Override
public String getName() {
return "ServiceModule";
}
}
Package:
public class ServicePackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ServiceModule(reactContext));
return modules;
}
#Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
MainApplication:
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ReactNativePushNotificationPackage(),
new ServicePackage()
);
}
I solved it :)
In the service I was creating a new context from base context which is NOT the same object. The workaround was to broadcast the data from the service and then send them do javascript.
ServiceModule:
public class ServiceModule extends ReactContextBaseJavaModule {
public static String UPDATE = "updateDistance";
public static String DISTANCE = "distance";
private IntentFilter intentFilter;
private BroadcastReceiver receiver;
public ServiceModule(ReactApplicationContext reactContext) {
super(reactContext);
initializeBroadcastReceiver();
}
#ReactMethod
public void startTrackingService() {
Intent intent = new Intent(getReactApplicationContext(), TestService.class);
getReactApplicationContext().startService(intent);
}
#ReactMethod
public void stopTrackingService() {
Intent intent = new Intent(getReactApplicationContext(), TestService.class);
getReactApplicationContext().stopService(intent);
}
private void sendEvent(ReactContext reactContext, String eventName, #Nullable WritableMap params) {
if (reactContext.hasActiveCatalystInstance()) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
private void initializeBroadcastReceiver() {
intentFilter = new IntentFilter();
intentFilter.addAction(UPDATE);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
WritableMap params = Arguments.createMap();
params.putDouble(DISTANCE, intent.getDoubleExtra(DISTANCE, 0));
sendEvent(getReactApplicationContext(), UPDATE, params);
}
};
getReactApplicationContext().registerReceiver(receiver, intentFilter);
}
#Override
public String getName() {
return "ServiceModule";
}
}
TestService:
public class TestService extends Service {
double distance = 0.0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Timer().scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ServiceModule.UPDATE);
broadcastIntent.putExtra(ServiceModule.DISTANCE, distance);
sendBroadcast(broadcastIntent);
distance+= 0.7;
}
},0,1000);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I need to execute some tasks when my application is closed.
I have made a service for do this and tried many things, but i don't have the good result.
If someone have a tutorial or some path to follow, it would be great
This is my service:
public class TrackersImporter extends Service {
private static TrackersImporter instance;
private static long refreshDelay = 1; // Minutes
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private boolean isInit = false;
public ArrayList<Tracker> trackers = new ArrayList<>();
public static TrackersImporter getInstance(){
if (instance == null)
instance = new TrackersImporter();
return instance;
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("TrackersImporter",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
Message message = mServiceHandler.obtainMessage();
message.arg1 = startId;
mServiceHandler.sendMessage(message);
} catch (Exception e) {
Log.w("TrackersImporter", e.getMessage());
}
return START_STICKY;
}
public void addTracker(Tracker tracker) {
trackers.add(tracker);
}
protected void showToast(final String msg){
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
// Object responsible for
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
addTracker(Runkeeper.getInstance(MainActivity.getActivity()));
addTracker(Strava.getInstance(MainActivity.getActivity()));
startImport(MainActivity.getActivity().getBaseContext(), MainActivity.getActivity().getAppUser(), trackers);
stopSelf(msg.arg1);
}
/**
* Perform data imports.
* Imports are performed only 1 time.
* Additional calls to this method are equivalent to no-op.
* Call init() then performImport() for each TrackerImportable
* #param user user receiving the datas
*/
public void startImport(Context context, User user, ArrayList<Tracker> trackers) {
Context ctx = MainActivity.getActivity().getApplicationContext();
LocalDateTime now = new LocalDateTime();
if (Preferences.getPref(ctx, "tracker_import_date") == "")
Preferences.setPref(ctx, "tracker_import_date", now.toString());
LocalDateTime past = LocalDateTime.parse(Preferences.getPref(ctx, "tracker_import_date"));
long duration = new Duration(past.toDateTime(), now.toDateTime()).getStandardMinutes();
if (isInit)
return;
if (duration > refreshDelay) {
Preferences.setPref(ctx, "tracker_import_date", now.toString());
for (Tracker tracker : trackers) {
if (tracker.isEnabled() && Tracker.isUserEnabled(context, tracker.getName())) {
tracker.init();
tracker.performImport(user);
}
}
}
isInit = true;
}
}
}
This is my mainActivity
public class MainActivity extends BaseActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (ConnectivityUtil.isConnected(this.getApplicationContext())) {
initGoogleFit();
initTrackers(appUser);
}
}
private void initTrackers(User user) {
Intent trackersIntentService = new Intent(this, TrackersImporter.class);
trackersIntentService.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startService(trackersIntentService);
}
#Override
protected void onResume() {
...
if (ConnectivityUtil.isConnected(this.getApplicationContext())) {
initTrackers(appUser);
}
}
}
First Create one launcher Activity which is like your Main Activity.
In Activity "onCreate" Method you need to start Service and Do Some thing if you wont in Service "onStartCommand" Method.
public class MainActivity extends Activity {
ArrayList<Integer> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(MainActivity.this,TrackersImporter.class);
}
public class TrackersImporter extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do something
Log.v(TAG ,"Service is started");
}
}
And also Register this Service at manifest.xml like this.
<service android:name=".TrackersImporter"></service>
if you like stop service
stopService(new Intent(MainActivity.this,TrackersImporter.class);
I have 2 classes which are GcmMessageHandler and Control (its an activity class, shows some graphics). When i handle the gcm message, i want to refresh control class (but if its front)
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
mes = extras.getString("title");
showToast();
Log.i("GCM", "Received : (" +messageType+") "+extras.getString("title"));
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
public void showToast(){
handler.post(new Runnable() {
public void run() {
if(mes.equals("Control")){
}else{
Toast.makeText(getApplicationContext(),mes , Toast.LENGTH_LONG).show();
}
}
});
}
}
In this part:
if(mes.equals("Control")){ }
if the control activity class is resume, i want to refresh it. How can i do this?
You can use a BroadcastReceiver in order to notify your activity about any changes. So register a BroadcastReceiver in your activity first:
public class MainActivity extends Activity {
public static String REFRESH_ACTIVITY = "com.domain.action.REFRESH_UI"
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do UI updates
}
};
#Override
public void onResume() {
super.onResume();
// do UI updates
IntentFilter filter = new IntentFilter();
filter.addAction(REFRESH_ACTIVITY);
this.registerReceiver(broadcastReceiver, filter);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(broadcastReceiver);
}
...
}
Then send the broadcast to perform the UI update from any location:
if (mes.equals("Control")) {
Intent intent = new Intent();
intent.setAction(MainActivity.REFRESH_ACTIVITY);
sendBroadcast(intent);
}
Maybe you could use an observer design pattern.
Let the GcmMessageHandler hold the Control activity as an observer and then notify it when needed.
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private Control mObserver
public GcmMessageHandler() {
super("GcmMessageHandler");
}
public void attachObserver(Control ctrl) {
mObserver = ctrl;
}
Then you just add a method to the Control class that can be called from the GcmMessageHandler class.
if(mes.equals("Control")){
mObserver.update(); // example
}else ...
It would be more slick if you first defined an observer interface:
public interface IObserver {
public abstract void update();
}
and had your Control class implement that. This way your GcmMessageHandler class could have a list of observers:
public class GcmMessageHandler extends IntentService {
String mes;
private Handler handler;
private List<IObserver> mObservers;
public GcmMessageHandler() {
super("GcmMessageHandler");
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new Handler();
mObservers = new ArrayList<IObserver>();
}
public void attachObserver(Control ctrl) {
mObservers.add(ctrl);
}
private void notify() {
for(IObserver observer : mObservers)
observer.update();
}
And of course if the Control class is the one holding the GcmMessageHandler object your just call the attach method from Control like this:
myGcmMessageHandler.attachObserver(this);