pehaada
pehaada

Reputation: 513

How do I make may Android TV App relaunch after a crash

I'm building a corporate app for android TV that I need to have always in the foreground. Every now and then the app will crash along with the service that will relaunch it. Is there a best practice to ensure the app is always running. What I can't figure out is how to launch after a force stop. The app can be side loaded so we don't have to worry about App Store approval.

The problem is when I use a service worker it will also die since it is attached to the original process https://developer.android.com/reference/android/app/Service

Same issue with the https://developer.android.com/topic/libraries/architecture/workmanager

Any ideas on an approach to basically check if the app is running and if it isn't start it up ? Is there any other event that I can hook into to launch the app ?

Upvotes: 1

Views: 529

Answers (2)

Constantin
Constantin

Reputation: 915

You can try to use the BroadcastReceiver to handle this, which will be invoked when your app is closed. In your manifest, add this:

<receiver android:name="com.your.package.name.YourReceiver">;
    <intent-filter>;
        <action android:name="android.intent.action.USER_PRESENT" />;
    </intent-filter>;
</receiver>;

And then, in YourReceiver.java

public class YourReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context mContext, Intent intent) {
        // when app is closed, the method will be invoked
        // do something here to launch your app
    }
}

Upvotes: 0

Amirhosein
Amirhosein

Reputation: 4446

If a crash happens the app will rerun itself:

 class AppExceptionHandler(private val context: Context, private val myActivityClass: Class<*>) :
    Thread.UncaughtExceptionHandler {
    override fun uncaughtException(thread: Thread, exception: Throwable) {
        Logger.d(exception.javaClass.simpleName)
            exception.printStackTrace()
            val intent = Intent(context, myActivityClass)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)

            context.startActivity(intent)
            //restarting the Activity
            Process.killProcess(Process.myPid())
            System.exit(0)
    }
}

and call from your main activity:

  Thread.setDefaultUncaughtExceptionHandler(
        AppExceptionHandler(
            applicationContext,
            MainActivity::class.java
        )
    )

In this way, I don't think you need to know whether the app is now in the foreground and running but you can get the top running package name in a running service. Also making your app a default launcher could be a workaround.

   fun topPackageNameObservable(): Observable<String?>? {
        return Observable.fromCallable {
            var topPackageName = ""
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    val mUsageStatsManager =
                        getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
                    val stats =
                        mUsageStatsManager.queryUsageStats(
                            UsageStatsManager.INTERVAL_DAILY,
                            System.currentTimeMillis() - TimeUnit.DAYS.toMillis(
                                1
                            ),
                            System.currentTimeMillis() + TimeUnit.DAYS.toMillis(
                                1
                            )
                        )
                    if (stats != null) {
                        val mySortedMap: SortedMap<Long, UsageStats> =
                            TreeMap()
                        for (usageStats in stats) {
                            mySortedMap[usageStats.lastTimeUsed] = usageStats
                        }
                        if (!mySortedMap.isEmpty()) {
                            topPackageName = mySortedMap[mySortedMap.lastKey()]!!.packageName
                        }
                    } else {
                        topPackageName = activityManager.getRunningAppProcesses().get(0).processName
                    }
                } else {
                    topPackageName =
                        activityManager.getRunningTasks(1).get(0).topActivity.getPackageName()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            topPackageName
        }
    }

Try using PackageManager and getLaunchIntentForPackage()

Upvotes: 3

Related Questions