- Details
- Written by: Stanko Milosev
- Category: Android
- Hits: 895
val component = ComponentName(this, MyBroadcastReceiver::class.java) getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);Disable:
val component = ComponentName(this, MyBroadcastReceiver::class.java) getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED , PackageManager.DONT_KILL_APP);
- Details
- Written by: Stanko Milosev
- Category: Android
- Hits: 1159
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />and android:process=":MyService". My Manifest looks like:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.milosev.myapplication"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <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.MyApplication"> <receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true" /> <service android:name=".MyService" android:enabled="true" android:exported="true" android:process=":MyService" /> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>In Gradle I added:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"So my gradle looks like:
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } android { compileSdk 32 defaultConfig { applicationId "com.milosev.myapplication" minSdk 21 targetSdk 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1" }MyBroadcastReceiver.kt looks like:
package com.milosev.myapplication import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build import androidx.annotation.RequiresApi import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.milosev.getgpslocation.MyService class MyBroadcastReceiver : BroadcastReceiver() { @RequiresApi(Build.VERSION_CODES.O) override fun onReceive(context: Context, intent: Intent) { when (intent?.action) { "MyAction" -> { val myIntent = Intent(context, MainActivity::class.java).setAction("MyAction") LocalBroadcastManager.getInstance(context).sendBroadcast(myIntent) } "Restart" -> { val intent = Intent(context, MyService::class.java) intent.action = "startForeground" context.startForegroundService(intent) } } } }MyService.kt looks like:
package com.milosev.getgpslocation import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.Service import android.content.Context import android.content.Intent import android.graphics.Color import android.os.Build import android.os.CountDownTimer import android.os.IBinder import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import kotlinx.coroutines.* class MyService : Service(),CoroutineScope by MainScope() { private var job: Job? = null override fun onBind(intent: Intent): IBinder { TODO("Return the communication channel to the service.") } @RequiresApi(Build.VERSION_CODES.O) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { when (intent?.action) { "startForeground" -> { val channelId = createNotificationChannel("my_service", "My Background Service") val notificationBuilder = NotificationCompat.Builder(this, channelId) val notification = notificationBuilder.setOngoing(true) .setContentTitle("test") .setContentText("test") .setSmallIcon(R.mipmap.ic_launcher) .setPriority(1) .setCategory(Notification.CATEGORY_SERVICE) .build() startForeground(101, notification) val context = this job = launch { while(true) { val myIntent = Intent(context, MyBroadcastReceiver::class.java).setAction("MyAction") sendBroadcast(myIntent); delay(1_000) } } } } if (intent?.action.equals("stopForeground")) { job?.cancel() stopForeground(true) stopSelfResult(startId) } return START_STICKY; } @RequiresApi(Build.VERSION_CODES.O) private fun createNotificationChannel(channelId: String, channelName: String): String { val chan = NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_LOW ) chan.lightColor = Color.RED chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager service.createNotificationChannel(chan) return channelId } override fun onDestroy() { super.onDestroy() val myIntent = Intent(this, MyBroadcastReceiver::class.java).setAction("Restart") sendBroadcast(myIntent); } override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) val myIntent = Intent(this, MyBroadcastReceiver::class.java).setAction("Restart") sendBroadcast(myIntent); } }POI:
override fun onDestroy() { super.onDestroy() val myIntent = Intent(this, MyBroadcastReceiver::class.java).setAction("Restart") sendBroadcast(myIntent); } override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) val myIntent = Intent(this, MyBroadcastReceiver::class.java).setAction("Restart") sendBroadcast(myIntent); }In main activity:
@RequiresApi(Build.VERSION_CODES.O) override fun onResume() { super.onResume() LocalBroadcastManager.getInstance(this) .registerReceiver(broadCastReceiver, IntentFilter("MyAction")) val intent = Intent(this, MyService::class.java) intent.action = "startForeground" startForegroundService(intent) }Notice that there is a problem with onResume because it will start the service immediately. Edit: 2022-06-05: Unfortunately after latest update of Huawei my app is again getting killed. Here you can find informations about this issuse.
- Details
- Written by: Stanko Milosev
- Category: Android
- Hits: 853
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.milosev.sendbroadcastfromanotherprocess"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <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.SendBroadcastFromAnotherProcess"> <receiver android:name=".MyReceiver" android:enabled="true" android:exported="true" /> <service android:name=".MyService" android:enabled="true" android:exported="true" android:process=":MyService" /> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>In gradle I have added coroutines:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"My gradle looks like:
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } android { compileSdk 32 defaultConfig { applicationId "com.milosev.sendbroadcastfromanotherprocess" minSdk 21 targetSdk 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1" }MyService.kt: *2023-04-04 UPDATE: * To debug MyService you will have to attach to this process with debugger.
package com.milosev.sendbroadcastfromanotherprocess import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.Service import android.content.Context import android.content.Intent import android.graphics.Color import android.os.Build import android.os.IBinder import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import kotlinx.coroutines.* class MyService : Service(), CoroutineScope by MainScope() { private var job: Job? = null override fun onBind(intent: Intent): IBinder { TODO("Return the communication channel to the service.") } @RequiresApi(Build.VERSION_CODES.O) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { when (intent?.action) { "startForeground" -> { val channelId = createNotificationChannel("my_service", "My Background Service") val notificationBuilder = NotificationCompat.Builder(this, channelId) val notification = notificationBuilder.setOngoing(true) .setContentTitle("test") .setContentText("test") .setSmallIcon(R.mipmap.ic_launcher) .setPriority(1) .setCategory(Notification.CATEGORY_SERVICE) .build() startForeground(101, notification) val context = this job = launch { while(true) { val myIntent = Intent(context, MyReceiver::class.java).setAction("MyAction") myIntent.putExtra("message", "test") sendBroadcast(myIntent); delay(1_000) } } } } if (intent?.action.equals("stopForeground")) { job?.cancel() stopForeground(true) stopSelfResult(startId) } return START_STICKY; } @RequiresApi(Build.VERSION_CODES.O) private fun createNotificationChannel(channelId: String, channelName: String): String { val chan = NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_NONE ) chan.lightColor = Color.RED chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager service.createNotificationChannel(chan) return channelId } }MyReceiver.kt:
package com.milosev.sendbroadcastfromanotherprocess import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import androidx.localbroadcastmanager.content.LocalBroadcastManager class MyReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val myIntent = Intent(context, MainActivity::class.java).setAction("MyAction") myIntent.putExtra("message", "test") LocalBroadcastManager.getInstance(context).sendBroadcast(myIntent) } }MainActivity.kt:
package com.milosev.sendbroadcastfromanotherprocess import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.TextView import androidx.annotation.RequiresApi import androidx.localbroadcastmanager.content.LocalBroadcastManager class MainActivity : AppCompatActivity() { val myReceiver: BroadcastReceiver = MyReceiver() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val filter = IntentFilter("MyAction") registerReceiver(myReceiver, filter) var textView = findViewById(R.id.myText) as TextView val broadCastReceiver = object : BroadcastReceiver() { override fun onReceive(contxt: Context?, intent: Intent?) { when (intent?.action) { "MyAction" -> { textView = findViewById(R.id.myText) as TextView textView.text = intent.getStringExtra("message") } } } } LocalBroadcastManager.getInstance(this) .registerReceiver(broadCastReceiver, IntentFilter("MyAction")) } @RequiresApi(Build.VERSION_CODES.O) fun onClick(view: View) { val intent = Intent(this, MyService::class.java) intent.action = "startForeground" startForegroundService(intent) } }activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/myText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button" tools:layout_editor_absoluteX="106dp" tools:layout_editor_absoluteY="110dp" /> </androidx.constraintlayout.widget.ConstraintLayout>Example download from here.
- Details
- Written by: Stanko Milosev
- Category: Android
- Hits: 829
<?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="com.example.broadcasts"> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Broadcasts" tools:targetApi="31"> <service android:name=".MyService" android:enabled="true" android:exported="true" android:process=":MyService"/> <receiver android:name=".MyReceiver" android:enabled="true" android:exported="true" /> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.AIRPLANE_MODE" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>