I want to do some work when user unlock their phone
I define a receiver in AndroidManifest.xml
<receiver
android:enabled="true"
android:name=".service.ScreenReceiver">
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
and Receiver
class ScreenReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
}
private fun checkClearSavedNote(context: Context) {
AppPref.getInstance(context).putString(AppPref.KEY_ID_CURRENT_NOTE, "")
Log.e("Quang", "clear note")
}
}
But it was not called when fired
I've tried using Service and registerBroadcastReceiver inside
and start it when application start
class MyApplication : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
instance = this
MultiDex.install(applicationContext)
try {
startService(Intent(this, NoteService::class.java))
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
}
but it work only with Android API < 8.0 because background execution limit
You can set your targetSdk < 26 to leverage implicit broadcasts. Otherwise you have to change your design according to latest list of exempted broadcasts.
Related
AppWidget.kt:
override fun onEnabled(context: Context) {
// register price and widget button update receivers
val filters = IntentFilter()
filters.addAction(BROADCAST_PRICE_UPDATED)
filters.addAction(BROADCAST_WIDGET_UPDATE_BUTTON_CLICK)
LocalBroadcastManager.getInstance(context.applicationContext).registerReceiver(br, filters)
}
override fun onDisabled(context: Context) {
// unregister price and widget button update receivers
LocalBroadcastManager.getInstance(context.applicationContext).unregisterReceiver(br)
}
private val br = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { ... }
Notes: local broadcast receiver receives all other registered broadcasts, except from piWidgetUpdateButtonClicked. Using LocalBroadcastManager is the only way I've been able to send/receive broadcasts, as apparently using global broadcast system filters out broadcasts from my app's package?
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.app_widget)
// Create an Intent to launch MainActivity when widget background touched
val piLaunchMainActiv: PendingIntent = PendingIntent.getActivity(context,0,
Intent(context.applicationContext, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.widget_background_layout, piLaunchMainActiv)
// create intent to update widget when button clicked TODO this not working
val piWidgetUpdateButtonClicked =
PendingIntent.getBroadcast(context, appWidgetId,
Intent(BROADCAST_WIDGET_UPDATE_BUTTON_CLICK), PendingIntent.FLAG_UPDATE_CURRENT
or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.widget_update_button, piWidgetUpdateButtonClicked)
Notes: *piLauchMainActiv *pending intent works fine, but piWidgetUpdateButtonClicked does nothing. I've tried using context.applicationContext, also does nothing. Also I've tried explicitly setting receiving class: Intent.setClass(context, AppWidget::class.java), nothing.
Apparently, latest Google Android releases want you to register broadcast receivers programmatically, as I've done above, rather than in the manifest, which I've tried too, but also doesn't work:
AndroidManifest.xml:
<receiver
android:name=".AppWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="org.bitanon.bitcointicker.BROADCAST_PRICE_UPDATED" />
</intent-filter>
<intent-filter>
<action android:name="org.bitanon.bitcointicker.BROADCAST_WIDGET_UPDATE_BUTTON_CLICK" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/app_widget_info" />
</receiver>
After days and days of reading through other related posts on stackoverflow, nothing has helped. I'm completely stumped, please send help!
I have the following Broadcast Receiver
class ShutdownReceiver(): BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Intent.ACTION_SHUTDOWN == intent?.action) {
HiddenFileUtility.appendLogs("ACTION_SHUTDOWN: true")
ApplicationGlobalContext.setShutDownState(true)
}
}
}
I register the ShutdownReceiver through the AndroidManifext.xml like this:
<receiver android:name=".BroadcastReceivers.ShutdownReceiver">
<intent-filter android:priority="1">
<action android:name="android.intent.action.BOOT_COMPLETED" android:priority="999"/>
</intent-filter>
</receiver>
And i never receive the ACTION_SHUTDOWN intent.
In the Android official documentation states that As of Build.VERSION_CODES#P this broadcast is only sent to receivers registered through Context.registerReceiver link here
The solution is to delete the ShutdownReceiver from the AndroidManifest.xml and register it using Context.registerReceiver like this:
val shutdownReceiver = ShutdownReceiver();
val bootIntentFilter = IntentFilter(Intent.ACTION_SHUTDOWN);
context.registerReceiver(shutdownReceiver, bootIntentFilter);
I'm testing some functions with flutter to try to find out if I'm able to handle it and right now it doesn't seem that I would be able to make it.
I've set up a app which should be able to handle incoming text from android intents. With that text I've wanted to open a specific screen of my app and load specific data into the screen.
I've tried so many different approaches that I can't even remember when it worked best and what went wrong.
Right now I have the following code.
AndroidManifest.xml
<application
android:name=".MyApplication"
android:label="My cool App"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MyFlutterActivity"
android:launchMode="standard"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<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.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
MyApplication.kt
class MyApplication : FlutterApplication(), PluginRegistrantCallback {
lateinit var flutterEngine: FlutterEngine
override fun registerWith(registry: PluginRegistry) {
FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
}
override fun onCreate() {
super.onCreate()
// Instantiate a FlutterEngine.
flutterEngine = FlutterEngine(this)
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
// Cache the FlutterEngine to be used by FlutterActivity.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine)
FlutterFirebaseMessagingService.setPluginRegistrant(this)
}
As you can see I'm also using the FlutterFirebaseMessagingService to receive notifications, which I'm right now not already sure if it is still working as it already was.
FlutterActivity.kt
class MyFlutterActivity : FlutterActivity() {
private var sharedText: String? = null
override fun provideFlutterEngine(context: Context): FlutterEngine? {
return FlutterEngineCache.getInstance().get("my_engine_id")
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
// Use the GeneratedPluginRegistrant to add every plugin that's in the pubspec.
//GeneratedPluginRegistrant.registerWith(flutterEngine)
handleShareIntent()
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "com.example.app.shared.data")
.setMethodCallHandler {call: MethodCall , result: MethodChannel.Result ->
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText)
sharedText = null
}
}
}
fun handleShareIntent() {
//val intent = getIntent()
val action = intent.action
val type = intent.type
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent)
}
}
}
fun handleSendText(intent: Intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
}
main.dart
static const platform =
const MethodChannel('com.example.app.shared.data');
static Stream<String> get sharedData {
return new Stream<String>.fromFuture(
platform.invokeMethod("getSharedText"));
}
//... inside build
StreamProvider<String>.value(
lazy: true,
value: sharedData,
),
// .. handle inside build
final String sharedData = Provider.of<String>(context);
// .. handle shared Data and open Screen..
I've tried to log every step to find out what's not working.
So I connected my android phone and tried to debug, but didn't found a step where to handle the incoming data, even if the text is successfully handled inside the "handleSendText" method of the FlutterAcitivity.kt.
What even more confused me is, that if i save a dart file / press hot reload, my breakpoint inside the sharedData getter of the main.dart is getting called and from there everything works as it should.
But why do I have to hot reload where it should start itself instead.
Am I'm missing anything or doing wrong at this point?
Any help appreciated.
I have tried every possible answer on SO but nothing has helped.
I want to reset alarms using AlarmManager on device reboot and the code to do exactly that works, but it doesn't when I put it inside the receiver.
I had tried creating a service but that didn't seem to work at all which that was probably incompetence of my part, however I just can't see why this code isn't working.
AndroidManifest:
<manifest
(...)
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
(...)
<application
(...)
<receiver
android:name = ".utils.DeviceRebootReceiver">
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
DeviceRebootReceiver:
class DeviceRebootReceiver : BroadcastReceiver() {
override fun onReceive(context : Context?, intent : Intent?) {
resetAlarms(context)
}
}
fun resetAlarms(context:Context):
fun resetAlarms(context : Context?) {
suspend fun resetAlarmsCoroutine(context : Context) {
val reminders = NotesDatabase.getInstance(context).notesDatabaseDAO.getAllActiveReminders()
reminders.forEach {
if (it.reminderTime > System.currentTimeMillis()) {
createAlarm(it.reminderTime, it.reminderMessage,null,context)
}
}
}
CoroutineScope(Dispatchers.IO).launch {
if (context != null) {
resetAlarmsCoroutine(context)
}
}
}
No need to show the createAlarm() function cause it works fine, BUT since I had seen that AlarmManager could cause problems on reboot I do instantiate it there like so:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
Maybe stupid question, but I have already spent to many hours on this.
I have my Kotlin listener:
package pl.bmideas.michal.bmnotifier
public class MyNotificationListener : NotificationListenerService() {
private var apiService :BackendApi? = null;
override fun onCreate() {
Log.i("MyNotificationListener" , "Creating NotificationListenerService service")
super.onCreate()
(.........SOMETHING ELSE..............)
}
override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "DESTROING")
(.........SOMETHING ELSE..............)
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
val sbnInfo = StatusBarNotificationExtended(sbn)
Log.i(TAG, "REMOVED")
}
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.i(TAG, "RECIVED`")
(.........SOMETHING ELSE..............)
}
companion object {
var TAG = "MyNotificationListener"
}
}
and my config looks looks this:
<service
android:enabled="true"
android:name="pl.bmideas.michal.bmnotifier.MyNotificationListener"
android:label="#string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
I'm not doing anything special in Activity.
Yes - I've checked security option and my app has access to notifications.
Yes - I've tried pointing to service by dot instead of full package
In logcat I can only see:
12-23 12:56:54.989 889-889/? V/NotificationListeners: enabling notification listener for 0:
ComponentInfo{pl.bmideas.michal.bmnotifier/pl.bmideas.michal.bmnotifier.MyNotificationListener}
I cant get instance unless i will bidn to this service in Activity wchich creates the service but still I get no info in logcat about notifications.
Can you guys help?
Holly....
after rewriting this code to pure Java it works..... but why?