I've made a tileService which triggers a foreground service when clicked. I have taken the battery optimisation permission from settings and set it on don't optimise. However after 3 days the tile becomes unresponsive.
public class QSIntentService
extends TileService {
String TAG = getClass().getSimpleName();
Context context;
boolean isTileActive;
#Override
public void onStartListening() {
super.onStartListening();
Log.e(TAG, "-----onStartListening Tile--");
if (isServiceRunning(getApplicationContext())) {
isTileActive = true;
updateTile();
} else {
isTileActive = false;
updateTile();
}
}
#Override
public void onClick() {
context = getApplicationContext();
Log.e(TAG, "-----onClick --- ");
Tile tile = getQsTile();
isTileActive = (tile.getState() == Tile.STATE_ACTIVE);
Intent serviceIntent = new Intent(context,
ForegroundService.class);
if (isServiceRunning(context)) {
isTileActive = false;
Utils.setBooleanFromPref(context,
context.getString(R.string.widgetStop), true);
if (ShareIBeaconInfo.INSTANCE.getForegroundService() != null) {
ForegroundService foregroundService =
ShareIBeaconInfo.INSTANCE.getForegroundService();
if (foregroundService.scanDevice != null) {
foregroundService.stopForegroundService();
}
}
context.stopService(serviceIntent);
} else {
isTileActive = true;
Utils.setBooleanFromPref(context,
context.getString(R.string.widgetStop), false);
Log.e(TAG, "service is not running");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent service = new Intent(context,
ForegroundService.class);
ContextCompat.startForegroundService(context, service);
} else {
Intent service = new Intent(context, ForegroundService.class);
context.startService(service);
}
}
updateTile();
}
private void updateTile() {
Tile tile = super.getQsTile();
int activeState = isTileActive ?
Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
tile.setState(activeState);
tile.updateTile();
}
private boolean isServiceRunning(Context context) {
try {
final ActivityManager manager;
manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager
.getRunningServices(Integer.MAX_VALUE)) {
if ("com.foregroundscan.service.ForegroundService"
.equalsIgnoreCase(service.service.getClassName())) {
return true;
}
}
} catch (NullPointerException ex) {
} catch (Exception e) {
}
return false;
}
}
My test device is OnePlus 6T running over android 9. Also is there a way to push a dialogue if the tile is unresponsive? So that I can restart the service?
I received a log when I click on a tile when it is unresponsive
2-08 16:34:56.710 1831-2154/? E/MdmLogger: Cannot get tag from tileTag
: Tile.CustomTile
I have service implemented of FirebaseMessagingService. Today I noticed unusial behavior when phone blocked. I contunie to receive message and android show me via notification but code in onMessageReceived doesn't work.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
final Context context = this;
if(remoteMessage == null){
return;
}
if(remoteMessage.getNotification() != null){
try {
final Message msg = createMessage(remoteMessage.getNotification());
Handler handler= new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
if(!isAppIsInBackgrund(context)){
Intent intent = new Intent("APP_MESSAGE_BROADCAST");
intent.putExtra("SENDER", msg.getCorrespondent().getId().toString());
intent.putExtra("MESSAGE_ID", msg.getId());
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
else {
showNotification(msg.getCorrespondent().getName(), msg.getBody());
}
}
});
} catch (Exception e) {
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
}
}
}
// isAppIsInBackgrund - method where's i check openning app.
public boolean isAppIsInBackgrund(Context context){
boolean isInBackground = true;
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH){
List<ActivityManager.RunningAppProcessInfo> runningProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo processInfo:runningProcesses){
if(processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
for (String activeProcess:processInfo.pkgList){
if(activeProcess.equals(context.getPackageName())){
isInBackground = false;
}
}
}
}
}
else {
List<ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);
ComponentName componentName = taskInfo.get(0).topActivity;
if(componentName.getPackageName().equals(context.getPackageName())){
isInBackground = false;
}
}
return isInBackground; }
i have created one TimerTask and one Service.i want to check continuously current foreground App Name. But When My App get closed after 1 or 2 minute service is Not Active.How can i run my Service continuously.
In emulator it's working fine but in Real Device service stop after sometime
BackgroundService.java
public class BackgroundService extends Service {
private Timer mTimer;
public BackgroundService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
private void startTimer() {
if (mTimer == null) {
mTimer = new Timer();
AppLockTimerTask lockTask = new AppLockTimerTask(this);
mTimer.schedule(lockTask, 0L, 1000L);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startTimer();
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
mTimer.cancel();
mTimer.purge();
mTimer = null;
super.onDestroy();
Intent bootCompleteReceiver = new Intent("com.android.background");
sendBroadcast(bootCompleteReceiver);
}
#Override
public void onTaskRemoved(Intent rootIntent) {
mTimer.cancel();
mTimer.purge();
mTimer = null;
super.onDestroy();
Intent bootCompleteReceiver = new Intent("com.android.background");
sendBroadcast(bootCompleteReceiver);
}}
AppLockTimerTask.java
public class AppLockTimerTask extends TimerTask {
private static final String TAG = "AppLockTimerTask";
private MySharedPreferences mySharedPreferences;
private DBHelper dbHelper;
private Context mContext;
public AppLockTimerTask(Context context) {
mContext = context;
dbHelper = new DBHelper(mContext);
mySharedPreferences = MySharedPreferences.getInstance(mContext);
}
#Override
public void run() {
printForegroundTask();
}
private void printForegroundTask() {
String currentApp = "NULL";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(Context.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 am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
currentApp = tasks.get(0).processName;
}
Log.e(TAG, "Current App in foreground is: " + currentApp);
getNewCurrentApp(currentApp);
}
private void getNewCurrentApp(String currentApp) {
if (!currentApp.equals("com.dharmendra.applock_timerbase")) {
String previousApp = mySharedPreferences.getData(Constant.previousOpenAppName);
if (previousApp.equals("")) {
mySharedPreferences.saveData(Constant.previousOpenAppName, currentApp);
} else {
if (previousApp.equals(currentApp)) {
Log.d(TAG, "App Not Change ==>" + currentApp);
} else {
Log.d(TAG, "App Change ==>" + currentApp);
HashMap<String, String> map = dbHelper.selectFromLI(currentApp);
if (map.size() > 0) {
if (map.get("type").equals("p")) {
Intent i = new Intent();
i.setClassName("com.dharmendra.applock_timerbase", "com.dharmendra.applock_timerbase.OpenPatternLock");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("previousApp", previousApp);
i.putExtra("currentApp", currentApp);
i.putExtra("type", "p");
mContext.startActivity(i);
} else {
Log.d(TAG, "Timmer Lock");
}
} else {
mySharedPreferences.saveData(Constant.previousOpenAppName, currentApp);
}
}
}
}
}}
You can run a long background service above Android 5.0 to Android 7 by using:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
On Android 8 onwards you must use Firebse JobDispatcher, GCMNetworkmanager etc.
Application is working with in Kitkat version. After lollipop version application is not working properly. I am thinking problem with getRunningTasks() . Could you please give me guidance ,How to overcome this problem.
public class StartupServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Log.d("Detector", "Auto Start" + AppLockerPreference.getInstance(context).isAutoStart());
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
if (AppLockerPreference.getInstance(context).isAutoStart()){
if (AppLockerPreference.getInstance(context).isServiceEnabled()){
context.startService(new Intent(context, DetectorService.class));
}else{
AppLockerPreference.getInstance(context).saveServiceEnabled(false);
}
}
return;
}else if (AppLockerPreference.getInstance(context).isServiceEnabled()){
Toast.makeText(context, "App------>6", Toast.LENGTH_SHORT).show();
context.startService(new Intent(context, DetectorService.class));
}
}
}
DetectorService
public class DetectorService extends Service {
//public static final String ACTION_DETECTOR_SERVICE = "com.gueei.detector.service";
#Override
public IBinder onBind(Intent intent) {
return null;
}
private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
}
return;
}
// Fall back on the old API.
stopForeground(true);
mNM.notify(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
}
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
stopForeground(false);
}
#Override
public void onCreate() {
//debug: log.i("Detector","Service.Oncreate");
initConstant();
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
}
#Override
public void onDestroy() {
//debug: log.i("Detector","Service.Ondestroy");
mThread.interrupt();
// Make sure our notification is gone.
stopForegroundCompat(R.string.service_running);
}
// This is the old onStart method that will be called on the pre-2.0
// platform. On 2.0 or later we override onStartCommand() so this
// method will not be called.
#Override
public void onStart(Intent intent, int startId) {
//debug: log.i("Detector","Service.Onstart");
handleCommand(intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//debug: log.i("Detector","Service.OnStartCommand");
handleCommand(intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return Service.START_STICKY;
}
private void handleCommand(Intent intent){
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_running);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.statusbar_icon, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, AppLockerActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, text,
text, contentIntent);
startForegroundCompat(R.string.service_running, notification);
startMonitorThread((ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE));
}
private void startMonitorThread(final ActivityManager am){
if (mThread!=null)
mThread.interrupt();
mThread = new MonitorlogThread(new ActivityStartingHandler(this));
mThread.start();
}
private static Thread mThread;
private static boolean constantInited = false;
private static Pattern ActivityNamePattern;
private static String logCatCommand;
private static String ClearlogCatCommand;
private void initConstant() {
//debug: log.i("Detector","Service.OninitConstant");
if (constantInited) return;
String pattern = getResources().getString(R.string.activity_name_pattern);
//debug: log.d("Detector", "pattern: " + pattern);
ActivityNamePattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
logCatCommand = getResources().getString(R.string.logcat_command);
ClearlogCatCommand = getResources().getString(R.string.logcat_clear_command);
}
MonitorlogThread
private class MonitorlogThread extends Thread{
ActivityStartingListener mListener;
public MonitorlogThread(ActivityStartingListener listener){
//debug: log.i("Detector","Monitor//debug: logThread");
mListener = listener;
}
BufferedReader br;
private Context context;
#Override
public void run() {
//debug: log.i("Detector","RUN!");
while(!this.isInterrupted() ){
try {
Thread.sleep(100);
////debug: log.i("Detector","try!");
//This is the code I use in my service to identify the current foreground application, its really easy:
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
//Toast.makeText(context, "App------>7", Toast.LENGTH_SHORT).show();
Log.d("Android", "App------>7----"+am);
//RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
Log.d("Android", "App------>8----"+foregroundTaskInfo);
//Toast.makeText(context, "App------>7"+foregroundTaskInfo, Toast.LENGTH_SHORT).show();
//Thats it, then you can easily access details of the foreground app/activity:
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mListener!=null){
//mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskAppName);
mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskActivityName);
}
} catch (InterruptedException e) {
// good practice
Thread.currentThread().interrupt();
return;
}
}
}
}
Use this code for above 5.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
UsageStatsManager usageStatsManager = (UsageStatsManager) ctx.getSystemService("usagestats");
long milliSecs = 60 * 1000;
Date date = new Date();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, date.getTime() - milliSecs, date.getTime());
if (queryUsageStats.size() > 0) {
Log.i(TAG, "UsageStats size: " + queryUsageStats.size());
}
long recentTime = 0;
String recentPkg = "";
for (int i = 0; i < queryUsageStats.size(); i++) {
UsageStats stats = queryUsageStats.get(i);
if (i == 0 && !getPackageName().equals(stats.getPackageName())) {
Log.i(TAG, "PackageName: " + stats.getPackageName() + " " + stats.getLastTimeStamp());
}
if (stats.getLastTimeStamp() > recentTime) {
String recentTime = stats.getLastTimeStamp();
String recentPkg = stats.getPackageName();
}
};
} catch (Exception e) {
e.printStackTrace();
}
}
Can you try this.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
ActivityManager.RunningAppProcessInfo runningAppProcessInfo = (ActivityManager.RunningAppProcessInfo) am.getRunningAppProcesses();
String foregroundTaskPackageName = runningAppProcessInfo.pkgList.getClass().getPackage().getName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = runningAppProcessInfo.pkgList.getClass().getName();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
} else {
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
Use RunningAppProcessInfo instead of getRunningTasks for SDK versions greater than KitKat.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
...
} else {
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
...
}
This is a Google Chat application. When I get a message from Google Chat I want to show it in the status bar as a notification when the activity is in background.
I tried setting boolean values in the onPause() method but it did not work.
public void addMessage(String chatid, String msg) {
// I want to the execute this line only when the activity is in background
notify.getCurrentActivity(getApplicationContext(), msg, fromName, chatid);
}
public void getCurrentActivity(Context context, String msg){
showNotification(context, msg, fromName, fromChatID);
}
try to do below
try{
boolean foregroud = new ForegroundCheckTask().execute(context).get();
if(foregroud)
{
//app is foreground
}
else
{
//app is not foreground }
}catch(Exception e)
{
e.toString();
}
add below async
//Foreground check
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
#Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0].getApplicationContext();
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
I find out solution myself
private int key; // Declare as global
protected void onPause
{
key=1;
super.onpause();
}
protected void onResume{
key=0;
super.onResume();
}
public void addMessage(String chatid, String msg) {
if(key==1)
{
notify.getCurrentActivity(getApplicationContext(), msg, fromName, chatid);
}
}