I make an android application with eclipse without activity just one class and the code inside it is this
public class PersistService extends Service {
private static final int INTERVAL = 3000; // poll every 3 secs
private static final string YOUR_APP_PACKAGE_NAME = "YOUR_APP_PACKAGE_NAME";
private static boolean stopTask;
private PowerManager.WakeLock mWakeLock;
#Override
public void onCreate() {
super.onCreate();
stopTask = false;
// Optional: Screen Always On Mode!
// Screen will never switch off this way
mWakeLock = null;
if (settings.pmode_scrn_on){
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "a_tag");
mWakeLock.acquire();
}
// Start your (polling) task
TimerTask task = new TimerTask() {
#Override
public void run() {
// If you wish to stop the task/polling
if (stopTask){
this.cancel();
}
// The first in the list of RunningTasks is always the foreground task.
RunningTaskInfo foregroundTaskInfo = activityManager.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
// Check foreground app: If it is not in the foreground... bring it!
if (!foregroundTaskPackageName.equals(YOUR_APP_PACKAGE_NAME)){
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(YOUR_APP_PACKAGE_NAME);
startActivity(LaunchIntent);
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, INTERVAL);
}
#Override
public void onDestroy(){
stopTask = true;
if (mWakeLock != null)
mWakeLock.release();
super.onDestroy();
}
}
and i register my service in this way `register your service:
<service android:name="YOURPACAKGE.PersistService"
android:enabled="true"/>`
I have some error "red line appear under".
line number 1 -> service "cannot be resolved to a type"
line number 7 -> power manager "cannot be resolved to a type"
line number 10 -> onCreat() "The method onCreate() of typePersistService must override or implement a supertype method"
line number 11 -> super "Service cannot be resolved to a type"
line number 12 -> TimerTask "cannot be resolved to a type"
line number 28 -> activityManager "cannot be resolved"
line number 43 -> onDestroy() "The method onDestroy() of type PersistService must override or implement a supertype method"
You need add imports to this class
import android.app.*;
import android.content.*;
import android.os.*;
import java.util.*;
public class PersistService extends Service {
//Class Content
}
Note: I do not use eclipse but I think it is missing some plugin or something like that to import automatically. Eclipse users please correct me if I am wrong.
You can check this below code, you didn't import any class that is the problem, And I don't understand your solution, Why you should open your package when your application open..? We can use ActivityLifecycle too to identiy our app is opening or not.
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by muthukrishnan on 10/06/17.
*/
public class PersistService extends Service {
private static final int INTERVAL = 3000; // poll every 3 secs
private static final String YOUR_APP_PACKAGE_NAME = "YOUR_APP_PACKAGE_NAME";
private static boolean stopTask;
private PowerManager.WakeLock mWakeLock;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
stopTask = false;
// Optional: Screen Always On Mode!
// Screen will never switch off this way
mWakeLock = null;
// NOTE : #Muthu I am not sure what is this variable called settings
if (settings.pmode_scrn_on){
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "a_tag");
mWakeLock.acquire();
}
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// Start your (polling) task
TimerTask task = new TimerTask() {
#Override
public void run() {
// If you wish to stop the task/polling
if (stopTask){
this.cancel();
}
// The first in the list of RunningTasks is always the foreground task.
ActivityManager.RunningTaskInfo foregroundTaskInfo = activityManager.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
// Check foreground app: If it is not in the foreground... bring it!
if (!foregroundTaskPackageName.equals(YOUR_APP_PACKAGE_NAME)){
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(YOUR_APP_PACKAGE_NAME);
startActivity(LaunchIntent);
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, INTERVAL);
}
#Override
public void onDestroy(){
stopTask = true;
if (mWakeLock != null)
mWakeLock.release();
super.onDestroy();
}
}
Related
I want to have a foreground service and I wrote the codes.
But the problem is that the app works well on API 26 and below but not in API 28.
The problem in API 28 is that it works as a background service and if you close the app, service closes too.
Here is my code:
MyService:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast;
public class MyService extends Service {
private Context context = null;
private static final int NOTIFICATION_ID = 1;
private static final String CHANNEL_ID = "ChargeScreenService";
private Looper serviceLooper;
private ServiceHandler serviceHandler;
private BatteryBroadCast batteryBroadCast;
private NotificationManager notificationManager;
private Notification notification;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
batteryBroadCast = new BatteryBroadCast(MyService.this);
batteryBroadCast.chargingChanges();
}
});
thread.start();
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
//stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work doesn't disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Hi")
.setContentText("Hello")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.setTicker("HI")
.setOngoing(true)
.build();
notificationManager.notify(NOTIFICATION_ID, notification);
} else {
notification = new Notification.Builder(this)
.setContentTitle("Hi")
.setContentText("Hello")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.setTicker("HI")
.setOngoing(true)
.build();
}
startForeground(1, notification);
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
serviceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "ChargeScreenService";
String description = "Service";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
MainActivity:
...
startService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
...
Finally, I added the permission in AndroidManifest file.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
And defined my service too.
<service
android:name=".MyService"
android:enabled="true" />
Testing devices:
Samsung galaxy J7 pro (Model number: SM-J730F) (real device)
Virtual device: Genymotion Android 6
If your app targets API level 26 or higher, the system imposes restrictions on running background services when the app itself isn't in the foreground. In most cases like this, your app should use a scheduled job instead.
I'm trying to create a timer that would launch in the background once onDestroy() is triggered, and once the timer reaches 6 hours, SharedPreferences will be used to make a change in the app.
I was wondering... what would be the correct way to setup CountDownTimer or anything similar it for onDestroy().
I will answer anything if needed. Thank you.
After about a week, a working answer came up. This answer includes what's related to how to make the service run. In this scenario, I'm building a CountDownTimer service.
AndroidManifest.xml
<service android:name=".TimeService"/>
MainActivity.java
import android.content.Intent;
import android.support.v4.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
Intent i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
i = new Intent(this, TimeService.class);
stopService(i); //To stop the service the next time the app is launched.
}
#Override
protected void onDestroy() {
launchService(); //Launches the service once when app shuts down.
super.onDestroy();
}
public void launchService() { //How to launch the service, depending the phone's API.
if(Build.VERSION.SDK_INT >= 26) {
startForegroundService(new Intent(this, TimeService.class));
}
else{
Intent i;
i = new Intent(this, TimeService.class);
ContextCompat.startForegroundService(this, i);
}
}
}
TimeService.java
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.support.annotation.Nullable;
public class TimeService extends Service {
CountDownTimer cdt = null;
private SharedPreferences pref;
//Things you want SharedPreferences to change.
Intent i;
#Override
public void onCreate() {
i = new Intent(this, TimeService.class);
startService(i);
pref = this.getSharedPreferences("myAppPref", MODE_PRIVATE);
cdt = new CountDownTimer(3600000, 1000) { //One hour timer with one second interval.
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
//Whatever you need SharedPreferences to change here.
}
};
cdt.start();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I've been able to successfully create an app (thanks davidgyoung!) that monitors beacons in the background and then subsequently opens the app in the background.
Now I would like my app to first prompt with a notification in the status bar saying something like "I've detected a beacon! Would you like to open out app?". Then the user would click on the notification to open the app or dismiss it and ignore the notification.
I've searched on stack overflow for something like but haven't had much success in finding something relevant to beacons. I did find this page that talks about adding StatusBar notifications but I'm not having much success.
Particularly its in my BeaconReferenceApplication.java and MonitoringActivity.java file. I think I put the code in the correct place (after didEnterRegion) but I have unresolved classes for areas like notificationButton, setLatestEventInfo, etc. Can someone help? Thanks in advance!
BeaconReferenceApplication.java:
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.RegionBootstrap;
import org.altbeacon.beacon.startup.BootstrapNotifier;
public class BeaconReferenceApplication extends Application implements BootstrapNotifier {
private static final String TAG = "BeaconReferenceApp";
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedBeaconsSinceBoot = false;
private MonitoringActivity monitoringActivity = null;
public void onCreate() {
super.onCreate();
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
// By default the AndroidBeaconLibrary will only find AltBeacons. If you wish to make it
// find a different type of beacon, you must specify the byte layout for that beacon's
// advertisement with a line like below. The example shows how to find a beacon with the
// same byte layout as AltBeacon but with a beaconTypeCode of 0xaabb. To find the proper
// layout expression for other beacon types, do a web search for "setBeaconLayout"
// including the quotes.
//
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
Log.d(TAG, "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
Region region = new Region("backgroundRegion", Identifier.parse("2F234454F4911BA9FFA6"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
// simply constructing this class and holding a reference to it in your custom Application
// class will automatically cause the BeaconLibrary to save battery whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
// If you wish to test beacon detection in the Android Emulator, you can use code like this:
// BeaconManager.setBeaconSimulator(new TimedBeaconSimulator() );
// ((TimedBeaconSimulator) BeaconManager.getBeaconSimulator()).createTimedSimulatedBeacons();
}
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever a Beacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedBeaconsSinceBoot) {
Log.d(TAG, "sending notification to StatusBar");
#SuppressWarnings("deprecation")
private void Notify(String notificationTitle, String notificationMessage) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
#SuppressWarnings("deprecation")
Notification notification = new Notification(R.mipmap.ic_launcher,
"New Message", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MonitoringActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(MonitoringActivity.this, notificationTitle,
notificationMessage, pendingIntent);
notificationManager.notify(9999, notification);
}
}
} else {
if (monitoringActivity != null) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an beacon, we launch the
// MainActivity
Intent intent = new Intent(this, MonitoringActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedBeaconsSinceBoot = true;
}
}
}
#Override
public void didExitRegion(Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I no longer see a beacon.");
}
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I have just switched from seeing/not seeing beacons: " + state);
}
}
private void sendNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Beacon Reference Application")
.setContentText("An beacon is nearby.")
.setSmallIcon(R.mipmap.ic_launcher);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(new Intent(this, MonitoringActivity.class));
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
public void setMonitoringActivity(MonitoringActivity activity) {
this.monitoringActivity = activity;
}
}
MonitoringActivity.java:
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import org.altbeacon.beacon.BeaconManager;
public class MonitoringActivity extends Activity {
protected static final String TAG = "MonitoringActivity";
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
private WebView mWebView;
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitoring);
// code for button notification
Button notificationButton = (Button) findViewById(R.id.notificationButton);
notificationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Notify("Title: Meeting with Business",
"Msg:Pittsburg 10:00 AM EST ");
}
});
// code for button notification
mWebView = (WebView) findViewById(R.id.activity_main_webview);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.loadUrl("http://communionchapelefca.org/edy-home");
mWebView.setWebViewClient(new MyAppWebViewClient());
verifyBluetooth();
Log.d(TAG, "Application just launched");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#TargetApi(23)
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
}
private class HelloWebViewClient extends WebViewClient{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String url)
{
webView.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
progressBar.setVisibility(view.GONE);
}
}
#Override
public void onBackPressed() {
if(mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void onRangingClicked(View view) {
Intent myIntent = new Intent(this, RangingActivity.class);
this.startActivity(myIntent);
}
#Override
public void onResume() {
super.onResume();
((BeaconReferenceApplication) this.getApplicationContext()).setMonitoringActivity(this);
}
#Override
public void onPause() {
super.onPause();
((BeaconReferenceApplication) this.getApplicationContext()).setMonitoringActivity(null);
}
private void verifyBluetooth() {
try {
if (!BeaconManager.getInstanceForApplication(this).checkAvailability()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth not enabled");
builder.setMessage("Please enable bluetooth in settings and restart this application.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
catch (RuntimeException e) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not available");
builder.setMessage("Sorry, this device does not support Bluetooth LE.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
}
So I was able to fix my problem by using the example from the Android Developers website for Notifications. I used their sample code, adapted it to my use, and then even further used .bigText to make my notification look great. Credit goes to them and daviggyoung for getting my app working. Thanks!
I also didnt need to edit my MonitoringActivity.java like I posted earlier.
final BeaconReferenceApplication.java:
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.RegionBootstrap;
import org.altbeacon.beacon.startup.BootstrapNotifier;
public class BeaconReferenceApplication extends Application implements BootstrapNotifier {
private static final String TAG = "BeaconReferenceApp";
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedBeaconsSinceBoot = false;
private MonitoringActivity monitoringActivity = null;
public void onCreate() {
super.onCreate();
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
// By default the AndroidBeaconLibrary will only find AltBeacons. If you wish to make it
// find a different type of beacon, you must specify the byte layout for that beacon's
// advertisement with a line like below. The example shows how to find a beacon with the
// same byte layout as AltBeacon but with a beaconTypeCode of 0xaabb. To find the proper
// layout expression for other beacon types, do a web search for "setBeaconLayout"
// including the quotes.
//
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
Log.d(TAG, "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
Region region = new Region("backgroundRegion", Identifier.parse("2F234454F4911BA9FFA6"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
// simply constructing this class and holding a reference to it in your custom Application
// class will automatically cause the BeaconLibrary to save battery whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
// If you wish to test beacon detection in the Android Emulator, you can use code like this:
// BeaconManager.setBeaconSimulator(new TimedBeaconSimulator() );
// ((TimedBeaconSimulator) BeaconManager.getBeaconSimulator()).createTimedSimulatedBeacons();
}
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever a Beacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedBeaconsSinceBoot) {
Log.d(TAG, "sending notification to StatusBar");
//begin code for notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Message from Communion Chapel")
.setContentText("Welcome! Thanks for coming!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("We noticed that you're here today, click here to open the app and get today's Sermon Notes and Bulletin."))
.setAutoCancel(true);
;
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MonitoringActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MonitoringActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(123, mBuilder.build());
}
}
#Override
public void didExitRegion(Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I no longer see a beacon.");
}
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
if (monitoringActivity != null) {
Log.d(TAG,"I have just switched from seeing/not seeing beacons: " + state);
}
}
private void sendNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Beacon Reference Application")
.setContentText("A beacon is nearby.")
.setSmallIcon(R.drawable.app_icon);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(new Intent(this, MonitoringActivity.class));
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
public void setMonitoringActivity(MonitoringActivity activity) {
this.monitoringActivity = activity;
}
}
So I have a service that contains a Timer. The service is meant to run even when the app in the background and is supposed to pull the user to the app when the timer executes the method(from another activity). The service is triggered on and off by a toggle button. Currently my R.id reference to my spinner keeps throwing a NullPointerException that i don't know how to fix. Can someone please help me out?
The Method the Timer is running:
public String TemperatureCatch()
{
/*this line throws the error */ Spinner reeferchoice = (Spinner)findViewById(R.id.optionselecti);
String reeferChoicei = reeferchoice.getSelectedItem().toString();
if (reeferChoicei.equals("Yes")) {
final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 500);
tg.startTone(ToneGenerator.TONE_CDMA_ABBR_ALERT);
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Temperature");
alert.setMessage("Input Temperature in F° (-20 to 65) ");
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_PHONE);
alert.setView(input);
alert.setPositiveButton("Check-In", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
temperaturei = input.getText().toString();
Toast.makeText(getBaseContext(), "Updated", Toast.LENGTH_SHORT).show();
Updater(temperaturei);
}
});
alert.show();
} else if (reeferChoicei.equals("No")) {
temperaturei = "DRY";
Updater(temperaturei);
}
return temperaturei;
}
My service code:
import android.app.IntentService;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import java.util.Timer;
import java.util.TimerTask;
public class MyService extends Service {
Locator locator;
Timer myTimer;
#Override
public void onCreate() {
locator = new Locator();
myTimer = new Timer();
}
private class MyTimerTask extends TimerTask
{
#Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
locator.TemperatureCatch();
}
}, 1000);
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyTimerTask myTimerTask = new MyTimerTask();
myTimer.scheduleAtFixedRate(myTimerTask, 0, 15000);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
myTimer.cancel();
}
}
the button:
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (isChecked)
{
startService(new Intent(this, MyService.class));
Toast.makeText(this,"Check-In will be done every 15 seconds",Toast.LENGTH_SHORT).show();
}
else
{
stopService(new Intent(this, MyService.class));
Toast.makeText(this,"Manual Check-In enabled",Toast.LENGTH_SHORT).show();
}
}
the stack trace:
Process: com.example.adrian.trucktracker, PID: 9617
java.lang.NullPointerException
at android.app.Activity.findViewById(Activity.java:1952)
at com.example.adrian.trucktracker.Locator.TemperatureCatch(Locator.java:192)
at com.example.adrian.trucktracker.MyService$MyTimerTask$1.run(MyService.java:32)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5872)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:852)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:668)
at dalvik.system.NativeStart.main(Native Method)
You should not create a instance of Activity class.
locator = new Locator(); // do not do this
This results in NullPointerException when you initialize views.
Can i Create the object of a activity in other class?
Also what you are doing seems to be a design issue.
As previous comments already pointed out, service wont have any UI, so you cannot make findViewById method call.
If you want your service to change the UI, bind to this service from your activity and using callbacks/delegates, you can notify the activity to change the UI from the service.
Activity objects are not supposed to be initialized by calling its constructor. By doing so, your overriden method onCreate() never get called, so the views are not initialized and findViewById will fail.
You should instead start the activity in the service instead of calling its contructor, something like this:
Intent t = new Intent (this, Locator.class);
t.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(t);
You can have a static getter in Locator class to get the instance of the Activity, so that you can use it in the Service.
I'm trying to create a service for the first time that runs a method from the activity every 15 seconds once a toggle button is checked when app is the background of a phone and so far the tutorials havent been helpful; this is my code so far. Forgive me if I look stupid here, its my first time using a service.
Service Code
package com.example.adrian.trucktracker;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import java.util.Timer;
import java.util.TimerTask;
public class AutoUpdateService extends Service {
Locator locator = new Locator();
Timer myTimer = new Timer();
private class MyTimerTask extends TimerTask
{
#Override
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
locator.TemperatureCatch();
}
}, 1000 );
}
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
MyTimerTask myTimerTask = new MyTimerTask();
myTimer.scheduleAtFixedRate(myTimerTask, 0, 15000);
}
#Override
public void onDestroy() {
super.onDestroy();
myTimer.cancel();
stopSelf();
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
My toggle button code
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked)
{
startService(new Intent(this,AutoUpdateService.class));
}
else
{
stopService(new Intent(this,AutoUpdateService.class));
}
You got it right to use Service. Do not use Timer, since it is extra thread you do not need. What you can do is to use AlarmManager to schedule your service intent to be launched every 15 seconds (interval). This will trigger interval time your service by calling onStartCommand in your service where you can do whatever you need by reading (if need) intent from parameters of onStartCommand.