I have a problem regarding about re-scheduling the tasks (with alarm) I tried to set the task on exact time and date in the future then I closed the emulator then re-open it after that waiting to popup the layout and when the time and date is on due I got error which says unable to open the (app/activity) on the screen, also in the logcat I can't see the errors (which probably the app is closed), So I'm not sure where exactly I did something wrong.
Here is the code I used for the service
public class ChibiReminderService extends WakefulIntentService {
Date date;
private long milliseconds = 0;
public ChibiReminderService() {
super("ChibiReminderService");`
}
#Override
protected void onHandleIntent(Intent intent) {
DatabaseSched db = DatabaseSched.getInstance(this); //get access to the instance of DatabaseSched
sched_lists alarm = new sched_lists();
List<DatabaseSource> tasks = db.getListSched(); //Get a list of all the tasks there
for (DatabaseSource task : tasks) {
// Cancel existing alarm
alarm.cancelAlarm(this, task.getId());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm a");
try {
date = format.parse(task.getDueDateTime());
milliseconds = date.getTime();
} catch (Exception e) {
e.printStackTrace();
}
//regular alarms
if(milliseconds >= System.currentTimeMillis()){
alarm.setAlarm(this, task.getId());
}
}
super.onHandleIntent(intent);
}
}
The OnBootReceiver
public class OnBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
WakefulIntentService.acquireStaticLock(context); //acquire a partial WakeLock
context.startService(new Intent(context, ChibiReminderService.class)); //start ChibiReminderService
}
}
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.majimechibireminder2"
android:versionCode="1"
android:versionName="1.0" android:installLocation="preferExternal">
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" android:persistent="true">
<receiver android:name=".OnBootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver"></receiver>
<service android:name=".ChibiReminderService" >
</service>
Here
You need to explicitly call close on your database connection which is missing, so add it either at the end of getListSched function
List<DatabaseSource> getListSched(){
..
..// your code
yourSQLiteDatabaseObject.close();
}
or
if your yourSQLiteDatabaseObject instance is public then you can do this before looping
List<DatabaseSource> tasks = db.getListSched();
db.yourSQLiteDatabaseObject.close();
for (DatabaseSource task : tasks) {
Note: yourSQLiteDatabaseObject will be a object of SQLiteDatabase inside your DatabaseSched class or you need to look for the chain if it's not in DatabaseSched class;
Related
I am still new to Android development, but I’m creating an app that sendings an HTTP request when it receives a broadcast (from a barcode scan). I have tried to implement some other solutions that I read on here but haven't quite figured it out yet. It would be great if someone could help me get going in the right direction.
Essentially, the end goal is for the app to keep running in the background forever so that even if the app is not open and a barcode is scanned and sent to the app via broadcast signal, the HTTP request is still sent.
This is what I have so far:
MainActivity.java
public class MainActivity extends Activity implements CompoundButton.OnCheckedChangeListener {
public static final String BARCODE_BROADCAST = "...";
private final BarcodeReceiver barcodeReceiver = new BarcodeReceiver();
private TextView mTextView;
private String scannedBarcode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.barcode);
}
#Override
public void onResume() {
super.onResume();
registerBarcodeScanner();
}
#Override
public void onPause() {
super.onPause();
unregisterBarcodeScanner();
// this code needs to keep the app running
Intent restartService = new Intent("RestartService");
this.startService(restartService);
sendBroadcast(restartService);
}
public void onDestroy() {
super.onDestroy();
// this code needs to keep the app running
Intent restartService = new Intent("RestartService");
this.startService(restartService);
sendBroadcast(restartService);
}
private void registerBarcodeScanner() {
registerReceiver(barcodeReceiver, new IntentFilter(BARCODE_BROADCAST));
}
private void unregisterBarcodeScanner() {
unregisterReceiver(barcodeReceiver);
}
private void displayBarcode() {
if (scannedBarcode == null) return;
String text = getString(R.string.barcode_scanned, scannedBarcode);
mTextView.setText(text);
/* SEND HTTP REQUEST */
}
private class BarcodeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BARCODE_BROADCAST)) {
String barcode = intent.getStringExtra("Barcode");
if (barcode != null) {
scannedBarcode = barcode;
displayBarcode();
}
}
}
}
}
RestartService.java
public class RestartService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MainActivity.class));
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="..."
android:versionCode="1">
<uses-sdk android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
tools:replace="android:label">
<activity
android:name="...MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="...RestartService"
android:enabled="true"
android:exported="true"
android:label="RestartServiceWhenStopped"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="RestartService" />
</intent-filter>
</receiver>
</application>
</manifest>
I'm trying to listen incoming call in a background service. But its not working, in debug, OnReceive() is not triggered. I've searched in all topic without any help.
I though that the background service was the problem, then i moved the code in the MainActivity class but it still not working.
Android Gradle Version : 4.1.2
Gradle Version : 6.6
API : 30
Manifest :
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.StatusChecker">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/Theme.StatusChecker.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ServiceChecker"
android:enabled="true"
android:exported="true" />
</application>
<uses-feature android:name="android.hardware.telephony">
</uses-feature>
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
MainActivity (OnCreate) :
...
// Create reciever object
IncomingCallReceiver the_receiver = new IncomingCallReceiver();
// Set When broadcast event will fire.
IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
// Register new broadcast receiver
this.registerReceiver(the_receiver, filter);
...
IncomingCallReceiver.java :
public class IncomingCallReceiver extends BroadcastReceiver {
private Context mContext;
private Intent mIntent;
#Override
public void onReceive(Context context, Intent intent) {
try {
// TELEPHONY MANAGER class object to register one listner
TelephonyManager tmgr = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
//Create Listner
PhoneStateListener PhoneListener = new PhoneStateListener();
// Register listener for LISTEN_CALL_STATE
tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch (Exception e) {
}
}
private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
String callState = "UNKNOWN";
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(mContext,"Hey call event",
Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(mContext,"Hey call event",
Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Toast.makeText(mContext,"Hey call event",
Toast.LENGTH_SHORT).show();
break;
}
super.onCallStateChanged(state, incomingNumber);
}
};
}
Thank you for help and sorry for my English mistakes.
EDIT :
Solution found...
You just need to add the permission request in your code.
String[] PERMISSIONS = {
android.Manifest.permission.READ_PHONE_STATE,
android.Manifest.permission.READ_SMS,
android.Manifest.permission.READ_PHONE_NUMBERS,
android.Manifest.permission.READ_CALL_LOG
};
ActivityCompat.requestPermissions(MainActivity.this,
PERMISSIONS,
PERMISSION_ALL);
I am making a code for making phone calls. Everything successful except that I am unable to get the system time when TelephonyManager.CALL_STATE_OFFHOOK state from the onCallStateChanged(int state, String incomingNumber).
Similarly, I want to get the system time when TelephonyManager.CALL_STATE_IDLE state is arrived. Once I get both the values in the Mainactivity I can get the difference and based its value I can start some other activity.
For example, if the time difference between TelephonyManager.CALL_STATE_IDLE state and TelephonyManager.CALL_STATE_IDLE state is less than 30 second, then I can assume that the call is not attended and I can start another call(or to another number). I am able to do all these inside the onCallStateChanged Method of PhoneStateListener class. But unable to pass this values to Mainactivity either by variables or Methods etc. This is the code for invoking call and it is working fine
Intent myIntentCall = new Intent(Intent.ACTION_CALL, Uri.parse("tel:0123456789"));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions();
}
else
{
startActivity(myIntentCall);
}
private void requestPermissions () {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);
}
From the below piece of code, I expect the updated value of _seconds to the Mainactivity class by accessing PhoneReceiver._seconds statement. But always it remain 0. But I get the correct value for _seconds in the PhoneReceiver class. The code is given below
public class PhoneReceiver extends PhoneStateListener {
Context context;
static boolean _callStarted = false;
long _callStartTime;
long _callEndTime;
long _callDuration;
long _minutes;
static long _seconds;
public PhoneReceiver(Context context) {
this.context = context;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if ((state == TelephonyManager.CALL_STATE_OFFHOOK) && !_callStarted) {
_callStarted = !_callStarted;
_callStartTime = new Date().getTime();
Toast.makeText(context, "Stage 1: " + "Off Hook -> Boolean: "+_callStarted, Toast.LENGTH_LONG).show();
}
if ((state == TelephonyManager.CALL_STATE_IDLE) && _callStarted)
{
_callEndTime = new Date().getTime();
_callDuration = _callEndTime - _callStartTime;
_minutes = (_callDuration / 1000) / 60;
_seconds = (_callDuration / 1000) % 60;
Toast.makeText(context, "Stage 2: " + "IDLE State->Boolean: "+_callStarted, Toast.LENGTH_LONG).show();
}
}
}
Android Manifest.xml is given below
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.callerApppackage.callerapp">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- put this here so that even if the app is not running,
your app can be woken up if there is a change in phone
state -->
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action
android:name=
"android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
PhonestateReciver Class is given below
public class PhoneStateReceiver extends BroadcastReceiver {
TelephonyManager manager;
PhoneReceiver myPhoneStateListener;
static boolean alreadyListening = false;
#Override
public void onReceive(Context context, Intent intent) {
myPhoneStateListener = new PhoneReceiver(context);
manager = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
//---do not add the listener more than once---
if (!alreadyListening) {
manager.listen(myPhoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
alreadyListening = true;
}
}
}
I hope I made it clear Thanking you all in advance for earlier reply.
Receiver works on all android versions from 4.2 upto 8.0. Even if app is removed from Recent Apps But if removed from Recent Apps in Android Oreo, it then never triggers receiver again.
my manifest.xml :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
My receiver.java :
public class Receiver extends BroadcastReceiver
{
public String PhoneNumber = "UNKNOWN";
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("RECEIVER :","CAPTURED THE EVENT.....");
try
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
}
}
I want to know if i am doing any mistake in code? Android Developers Documentation asking to register receiver runtime using context. Then i searched for registering it in runtime on stackoverflow but looks no proper thread accepted as answer. How can make receiver to to be ready again, even if removed from recents of Android Oreo?
Thanking you in advance.
I have deleted unrelated posts. I am posting final answer as it may help others. #WIZARD help was thankful.
PHONE_STATE is implicit and will not be triggered on android Oreo or higher. So just place permissions in manifest like :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true">
</service>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true">
</service>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
Register implicit receivers from foreground service :
public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private boolean running;
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","HERE HERE");
try
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null)
{
PhoneNumber = "UNKNOWN";
}
else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("INCOMING ","Incoming number : "+PhoneNumber);
}
if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("OUTGOING ","Outgoing number : "+PhoneNumber);
}
if(!PhoneNumber.contentEquals("UNKNOWN"))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
}
}
};
public WatchMan() { }
#Override
public void onCreate()
{
super.onCreate();
mBuilder = new NotificationCompat.Builder(this, null);
IntentFilter filterstate = new IntentFilter();
filterstate.addAction("android.intent.action.NEW_OUTGOING_CALL");
filterstate.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, filterstate);
Log.d("RECEIVER : ", "\nCreated....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("Insta Promo Is Up..")
.setTicker("Insta Promo Is Up..")
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
}
running = true;
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RECEIVER : ", "\nOnStartCommand....");
new Thread(new Runnable()
{
public void run()
{
while(running)
{
try
{
Log.d("RECEIVER : ", "\nALIVE..");
Thread.sleep(10000);
}
catch (InterruptedException e)
{
Log.d("RECEIVER : ", "\nThread : InterruptedException in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
}
catch (Exception e)
{
Log.d("RECEIVER : ", "\nThread : Exception Error in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
}
}
}
}).start();
return START_STICKY;
}
#Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
running = true;
Log.d("RECEIVER : ", "\nDestroyed....");
Log.d("RECEIVER : ", "\nWill be created again....");
}
#Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onTaskRemoved(Intent rootIntent)
{
super.onTaskRemoved(rootIntent);
Log.d("SERVICE : ", "\nTask Removed....");
}
}
There are some intent actions like NEW_OUTGOING_CALL AND BOOT_COMPLETED which are excluded and can be implemented in receiver and placed in manifest like :
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("INSTA_BOOT : ", "\nBOOT_COMPLETE_EVENT_OF_INSTA....");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
}
As i wanted to re-register or say want to restart foreground service on REBOOT OR BOOT-COMPLETE
CatchNumbers.java is a simple service which performs operation when receiver triggers perticular actions.
It works good on every restart and as android:excludeFromRecents="true" is not needed anymore as even if user removes it from recents on Oreo it will restart the service as it is STICKY. Hope it helps someone like me..!!
Based on the documentation for restrictions on implicit broadcast in Android 8, you cannot use implicit receivers in your manifest (although there are some exceptions, but phone state receiver is not among those exceptions)
You have to use foreground service and register your receiver in your foreground service instead of manifest
remove phone state receiver from manifest
register receiver in onCreate of Service:
#Override
public void onCreate() {
super.onCreate();
phoneStateReceiver = new PhoneStateReceiver();
registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
}
unregister in onDestroy:
#Override
public void onDestroy() {
unregisterReceiver(phoneStateReceiver);
super.onDestroy();
}
add a static method to your service to start service:
// start service even if your app is in stopped condition in android 8+
static void requestStart(#NonNull final Context context, #NonNull final String action){
final Context appContext = context.getApplicationContext();
Intent intent = new Intent(appContext, AppService.class);
intent.setAction(action);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// this is required to start the service if there is
// no foreground process in your app and your app is
// stopped in android 8 or above
appContext.startForegroundService(intent);
} else {
appContext.startService(intent);
}
}
start foreground in your onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(ACTION_START.equals(intent.getAction()))
startForeground(ID, notification);
else if(ACTION_STOP.equals(intent.getAction()))
stopForeground(true);
return START_STICKY;
}
I wanted to make this service a never ending service, even if the app is killed by the user. That service starts with the app - when it is background, the service still runs-, but when I clear the background tasks on phone, it is also killed. I wanted that final part to be different, wanted this service to keep running on the device... Is that possible? Thanks for the help
public class BackgroundService extends Service {
public static Runnable runnable = null;
public Context context = this;
public Handler handler = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
final PackageManager manager = getPackageManager();
//Packages instalados no dispositivo
List<ApplicationInfo> packages = manager.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo info : packages) {
Log.i("Info", "Installed package:" + info.packageName);
}
for (int i = 0; i < packages.size(); i++) {
if(packages.get(i).sourceDir.startsWith("/data/app/")){
//Non System Apps
Log.i("Info", "Installed package /NON SYSTEM/:" + packages.get(i).packageName);
}else{
//system Apps
Log.i("Info", "Installed package !/SYSTEM/!:" + packages.get(i).packageName);
}}
handler = new Handler();
runnable = new Runnable() {
public void run() {
final ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
String currentApp ="";
// The first in the list of RunningTasks is always the foreground task.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager) getSystemService(USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
time - 1000 * 1000, time);
if (appList != null && appList.size() > 0) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
for (UsageStats usageStats : appList) {
mySortedMap.put(usageStats.getLastTimeUsed(),
usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
currentApp = mySortedMap.get(
mySortedMap.lastKey()).getPackageName();
}
}
} else {
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
currentApp = foregroundTaskInfo.topActivity.getPackageName();
}
boolean ApiLigaIsRunning = false;
if (currentApp.contains("maps")) {
ApiLigaIsRunning = true;
Log.i("CHOOSEN APP IS RUNNING ","YES!!!!!!!!!!! " + currentApp);
Handler handler2 = new Handler();
final String finalCurrentApp = currentApp;
handler2.postDelayed(new Runnable() {
public void run() {
Intent openMe = new Intent(getApplicationContext(), LoginActivity.class);
openMe.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openMe);
am.killBackgroundProcesses(finalCurrentApp);
}
}, 200);
}
Toast.makeText(context, "Service is running", Toast.LENGTH_LONG).show();
List<ActivityManager.RunningAppProcessInfo> appProcesses = am.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
if (ApiLigaIsRunning == true)
Log.i("Foreground App ", appProcess.processName);
else
Log.i("Not Working! ", appProcess.processName);
}
handler.postDelayed(runnable,200);
}
}
};
handler.postDelayed(runnable, 200);
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
}
Here is my Manifest file :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="***************">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"/>
<uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="#mipmap/icon"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".LoginActivity"
android:theme="#style/AppTheme.Dark">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".BackgroundService"
android:exported="true"
android:enabled="true"
/>
</application>
Never Ending Background Service is not possible but you can Limit Close Service
cause this will Take More Battery which Not Allowed
1- Use Forground Service
this will make service to be run with Notification Like Music App
2- Use START_STICKY
this will make your service start when it Killed
It was possible with a Broadcoast Receiver. But since Oreo (API 26) you can only perform that with a Job Scheduler.
In most cases, apps can work around these limitations by using
JobScheduler jobs. This approach lets an app arrange to perform work
when the app isn't actively running, but still gives the system the
leeway to schedule these jobs in a way that doesn't affect the user
experience. Android 8.0 offers several improvements to JobScheduler
that make it easier to replace services and broadcast receivers with
scheduled jobs.
See more at : https://developer.android.com/about/versions/oreo/background