I have a android compose application and broadcast not working with alarm.
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<receiver android:name=".broadcast.EventAlarmBroadcastReceiver"
android:exported="false"
android:process=":remote"
android:enabled="true">
<intent-filter>
<action android:name="com.zxy.control_time.app.REMIND_ACTION"/>
</intent-filter>
</receiver>
kotlin code , setExact function is not working
val intent = Intent(context,EventAlarmBroadcastReceiver::class.java)
intent.`package` = BuildConfig.APPLICATION_ID
val pendingIntent = PendingIntent.getService(
context,
EventAlarmBroadcastReceiver.REMIND_INTENT_ID_BASIC_NUMBER + this.id,
intent,
0
)
// alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + 5 * 1000,pendingIntent) not working
// context.sendBroadcast(intent) working fine
Related
I have an app that is supposed to intercept incoming calls, compare phone number with list created by the user and make silent mode if the caller is in this list, so I need my app to work always even if it was not launched by user. I tried a Service which is starting in my App class, I also call startForeground method within onStartCommand section and return START_STICKY. However, swiping away my app in app manager completely kills it without any allusion on recreating or background work, all functions that were working on app being launched or in "hide" state are not working anymore (until I tap on service notification, it opens the app again). What am I missing? I need my app to remain functional even if it is not launched so app could always compare incoming calls and decide to switch to "Do not disturb" mode.
Here is the my Service class code:
class BackgroundWorkService : Service() {
private val NOTIF_ID = 1
private val NOTIF_CHANNEL_ID = "CHANNEL_ID"
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
initChannel(this)
startServiceForeground()
return START_STICKY
}
private fun initChannel(context: Context) {
if (Build.VERSION.SDK_INT < 26) { return }
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
NOTIF_CHANNEL_ID,
"Channel for service",
NotificationManager.IMPORTANCE_DEFAULT
)
channel.description = "Channel description"
notificationManager.createNotificationChannel(channel)
}
private fun startServiceForeground() {
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
startForeground(
NOTIF_ID, NotificationCompat.Builder(
this,
NOTIF_CHANNEL_ID
)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(getString(R.string.app_name))
.setContentText("Service is running background")
.setContentIntent(pendingIntent)
.build()
)
}
Here is where I'm starting the service:
class App : Application() {
override fun onCreate() {
super.onCreate()
startService(Intent(this, BackgroundWorkService::class.java))
}
}
EDIT:
Manifest is also updated:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.donotbotherme">
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".app.App"
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.DoNotBotherMe">
<service
android:name=".app.BackgroundWorkService"
android:enabled="true"
android:exported="true" />
<activity android:name=".view.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
I have found a solution for this case after some more searches and conversations. The main fact I missed is that Android does not permit any app to work in background, instead you can create BroadcastReceiver, register it in Manifest and determine its intent-filter, then simply place the code you want to be executed in onReceive method of your BroadcastReceiver class. When the intent-filter is triggered your app will launch, execute the code and then kill itself.
Summarizing, to make you app to do some of its functions even while closed, you need to:
Create your BroadcastReceiver class (simply inherit your class from BroadcastReceiver);
Register it in your Manifest (here is my example):
<receiver android:name=".viewmodel.CallListener"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Place the code you want to execute in onReceive body in your BroadcastReceiver class.
Hope this solution will help somebody.
I can't get my BroadcastReciever() to work for DATE_CHANGED, but works just fine for TIMEZONE_CHANGED.
class DateChangeReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("my broadcast","works")
if (intent.action == Intent.ACTION_DATE_CHANGED ||
intent.action == Intent.ACTION_TIMEZONE_CHANGED) {
var netUtils = NetUtils(context)
netUtils.mainStack()
}
}
}
Here is my Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<application
android:allowBackup="true"
android:icon="#drawable/castle"
android:roundIcon="#drawable/castle"
android:label="#string/app_name"
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" />
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<receiver android:name=".DateChangeReceiver">
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED"/>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/>
</intent-filter>
</receiver>
</application>
</manifest>
Here is my function in my main activity:
fun keepAlive() {
//KEEP RUNNING IN BACKGROUND TO UPDATE WALLPAPER AT CHANGE OF DAY
val component = ComponentName(this#MainActivity, DateChangeReceiver::class.java)
packageManager.setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP)
Log.d("KEEPALIVE FUN","works")
}
keepAlive()
I get nothing in logcat when I change my date manually or if I set the time to 11:59 and wait a minute.
A couple of errors I do have in logcat that show up before I added the Reciever are:
2019-03-05 11:48:01.884 29176-29202/com.test E/libc: Access denied finding property "vendor.debug.egl.profiler"
2019-03-05 11:48:07.616 29176-29234/com.test E/libc: Access denied finding property "ro.vendor.graphics.memory"
2019-03-05 11:48:07.665 29176-29234/com.test E/libc: Access denied finding property "vendor.gralloc.enable_ahardware_buffer"
Is it possible these are effecting my BroadcastReciever? I've tested this on 3 devices so far.
Solved the issue by switching to the AlarmManager. Here's the code if anyone's curious:
val calendar: Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, 3)
}
This method worked better for me as it keeps all devices with my app updating at the same time apposed to start of new day.
val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val broadcastIntent = Intent(this, DateChangeReceiver::class.java)
val pIntent = PendingIntent.getBroadcast(this,0,broadcastIntent,0)
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pIntent
I registered broacastreceiver for date change implicitly..this worked for me.
registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_DATE_CHANGED));
According to this question, there could be a bug. It is obsolete now, but you can try to submit new issue.
Also this question may help you.
They using
ACTION_TIME_TICK
ACTION_TIMEZONE_CHANGED
ACTION_TIME_CHANGED
private final BroadcastReceiver m_timeChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_TIME_CHANGED) ||
action.equals(Intent.ACTION_TIMEZONE_CHANGED))
{
doWorkSon();
}
}
};
I'm new on android development and I still don't understand Intent very well. Here i'm using Firebase to create notifications, I add an Intent to my notification, but when my app is in foreground and I click on the notification nothing happens (when the app is killed or in background it work well).
The strange thing is at a moment it was working, when I clicked on the notification the function "onNewIntent" of my "MainActivity" class was called, but now nothing happen anymore, and I think I changed nothing on the code.
Here is how I create my intent :
Notifications notifs = new Notifications(this);
String title = remoteMessage.getData().get("title");
String body = remoteMessage.getData().get("body");
String url = remoteMessage.getData().get("url");
Intent intentNotif = new Intent(this, MainActivity.class);
intentNotif.setAction(Intent.ACTION_MAIN);
intentNotif.addCategory(Intent.CATEGORY_LAUNCHER);
intentNotif.putExtra("url", url);
intentNotif.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
//intentNotif.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
notifs.showNotif(title, body, true, intentNotif);
Here is how I add the intent to the notification :
this.builderGeneric.setContentIntent(PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
I also tried to create an intent with a custom action but it's not working, I tryed different intent flags, but I feel like i'm trying random things without knowing what I do, so that's why I'm asking for your help.
EDIT :
Here is how I create the notification if it's usefull :
Notifications(Context context) {
this.context = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.notifManager = context.getSystemService(NotificationManager.class);
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
channel.setDescription(CHANNEL_DESCRIPTION);
channel.enableLights(false);
channel.enableVibration(false);
channel.setSound(null, null);
if (this.notifManager != null) {
this.notifManager.createNotificationChannel(channel);
}
} else {
this.notifManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
this.builderGeneric = new Notification.Builder(context)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher_round);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.builderGeneric.setChannelId(this.CHANNEL_ID);
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
this.builderGeneric.setSmallIcon(R.mipmap.ic_launcher_foreground);
}
}
public void showNotif(String title, String text, boolean cancelable, Intent intent) {
this.builderGeneric.setContentTitle(title)
.setContentText(text)
.setOngoing(!cancelable)
.setContentIntent(PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
Notification notifGeneric = this.builderGeneric.build();
this.notifManager.notify(1, notifGeneric);
}
EDIT 2 : Here is my manifest :
<application
android:allowBackup="true"
android:fullBackupContent="#xml/backup_descriptor"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:launchMode="standard"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
<receiver
android:name=".NetworkChangeReceiver"
android:label="NetworkChangeReceiver">
<intent-filter
android:name=".NetworkIntentFilter"
android:label="NetworkIntentFilter">
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
<service android:name=".MyFirebaseService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
OK, First try to remove
intentNotif.setAction(Intent.ACTION_MAIN);
intentNotif.addCategory(Intent.CATEGORY_LAUNCHER);
Next, adding android:launchMode="singleTask" (also removing android:launchMode="standard") inside your activity tag in AndroidManifest.xml.
Then try again, please aware that with the launchMode is singleTask and if you click on your notification while your MainActivity is opened -> onNewIntent will be triggered (because Android will not create one more instance of this Activity) otherwise onCreate will be called.
And if it works, I would like to recommend you to read more about LaundMode here
I want to be able to start a BroadcastReceiver when a Google Fit session starts or ends on a phone. I have the manifest set up for the receivers:
<receiver android:name=".YogaSessionStartedBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.fitness.session_start" />
<data android:mimeType="vnd.google.fitness.activity_type/yoga" />
</intent-filter>
</receiver>
<receiver android:name=".YogaSessionEndedBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.fitness.session_end" />
<data android:mimeType="vnd.google.fitness.activity_type/yoga" />
</intent-filter>
</receiver>
And I'm starting a session with activity type YOGA in my app:
mSession = new Session.Builder()
.setName(SESSION_NAME)
.setIdentifier(getString(R.string.app_name) + " " + System.currentTimeMillis())
.setDescription("Yoga Session Description")
.setStartTime(Calendar.getInstance().getTimeInMillis(), TimeUnit.MILLISECONDS)
.setActivity(FitnessActivities.YOGA)
.build();
PendingResult<Status> pendingResult =
Fitness.SessionsApi.startSession(mGoogleApiClient, mSession);
However onReceive is never called in my BroadcastReceivers. Any suggestions?
Have you Register for Session ?
registerForSessions (GoogleApiClient client, PendingIntent intent)
Something like this:
Intent intent = new Intent(mContext,YogaSessionEndedBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, alarmIntent, 0);
Fitness.SessionsApi.registerForSessions(mClient,pendingIntent);
Which mClient is your GoogleApiClient,And mContext is your Activity Context.
I have one class called StopAlarmReceiver and another BootHandler.
The BootHandler resets the alarm after reboot, which was set before the boot. My problem is that the BootHandler sets the alarm but not getting fired.
Entries in Manifest file.
<receiver
android:name="com.sign.android.myscheduler.app.StopAlarmReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
<receiver
android:name="com.sign.android.myscheduler.app.BootHandler"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Code in BootHandler.
AlarmManager mgr= (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, StopAlarmReceiver.class);
PendingIntent pi = PendingIntent.getService(context, 1, i, 0);
long time = sharedPreferences.getLong("Old_time", 0);
Log.e(TAG, "New time: " +new Date(SystemClock.elapsedRealtime() + time));
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + time, 5000, pi);
manifest
just write two receivers 1 for alarm and 1 for handle the boot
<receiver
android:name="packagename.AlarmReceiver"
>
</receiver>
<!-- Will not be called unless the application explicitly enables it -->
<receiver android:name="com.avion.contact_app.DeviceBootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
add following permissions
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
In DeviceBootReceiver class check the intent action first
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences prefs = context.getSharedPreferences(
"DefaultReminder", context.MODE_PRIVATE);
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
//do whatever you want after reboot or fire alarm again
}
}