Android: How can I get the current foreground activity (from a service)? Android: How can I get the current foreground activity (from a service)? android android

Android: How can I get the current foreground activity (from a service)?


Update: this no longer works with other apps' activities as of Android 5.0


Here's a good way to do it using the activity manager.You basically get the runningTasks from the activity manager. It will always return the currently active task first. From there you can get the topActivity.

Example here

There's an easy way of getting a list of running tasks from the ActivityManager service.You can request a maximum number of tasks running on the phone, and by default, the currently active task is returned first.

Once you have that you can get a ComponentName object by requesting the topActivity from your list.

Here's an example.

    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);    Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());    ComponentName componentInfo = taskInfo.get(0).topActivity;    componentInfo.getPackageName();

You will need the following permission on your manifest:

<uses-permission android:name="android.permission.GET_TASKS"/>


Warning: Google Play violation

Google has threatened to remove apps from the Play Store if they use accessibility services for non-accessibility purposes. However, this is reportedly being reconsidered.


Use an AccessibilityService

Benefits

  • Tested and working in Android 2.2 (API 8) through Android 7.1 (API 25).
  • Doesn't require polling.
  • Doesn't require the GET_TASKS permission.

Disadvantages

  • Each user must enable the service in Android's accessibility settings.
  • This isn't 100% reliable. Occasionally the events come in out-of-order.
  • The service is always running.
  • When a user tries to enable the AccessibilityService, they can't press the OK button if an app has placed an overlay on the screen. Some apps that do this are Velis Auto Brightness and Lux. This can be confusing because the user might not know why they can't press the button or how to work around it.
  • The AccessibilityService won't know the current activity until the first change of activity.

Example

Service

public class WindowChangeDetectingService extends AccessibilityService {    @Override    protected void onServiceConnected() {        super.onServiceConnected();        //Configure these here for compatibility with API 13 and below.        AccessibilityServiceInfo config = new AccessibilityServiceInfo();        config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;        config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;        if (Build.VERSION.SDK_INT >= 16)            //Just in case this helps            config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;        setServiceInfo(config);    }    @Override    public void onAccessibilityEvent(AccessibilityEvent event) {        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {            if (event.getPackageName() != null && event.getClassName() != null) {                ComponentName componentName = new ComponentName(                    event.getPackageName().toString(),                    event.getClassName().toString()                );                ActivityInfo activityInfo = tryGetActivity(componentName);                boolean isActivity = activityInfo != null;                if (isActivity)                    Log.i("CurrentActivity", componentName.flattenToShortString());            }        }    }    private ActivityInfo tryGetActivity(ComponentName componentName) {        try {            return getPackageManager().getActivityInfo(componentName, 0);        } catch (PackageManager.NameNotFoundException e) {            return null;        }    }    @Override    public void onInterrupt() {}}

AndroidManifest.xml

Merge this into your manifest:

<application>    <service        android:label="@string/accessibility_service_name"        android:name=".WindowChangeDetectingService"        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">        <intent-filter>            <action android:name="android.accessibilityservice.AccessibilityService"/>        </intent-filter>        <meta-data            android:name="android.accessibilityservice"            android:resource="@xml/accessibilityservice"/>    </service></application>

Service Info

Put this in res/xml/accessibilityservice.xml:

<?xml version="1.0" encoding="utf-8"?><!-- These options MUST be specified here in order for the events to be received on first start in Android 4.1.1 --><accessibility-service    xmlns:tools="http://schemas.android.com/tools"    android:accessibilityEventTypes="typeWindowStateChanged"    android:accessibilityFeedbackType="feedbackGeneric"    android:accessibilityFlags="flagIncludeNotImportantViews"    android:description="@string/accessibility_service_description"    xmlns:android="http://schemas.android.com/apk/res/android"    tools:ignore="UnusedAttribute"/>

Enabling the Service

Each user of the app will need to explicitly enable the AccessibilityService in order for it to be used. See this StackOverflow answer for how to do this.

Note that the user won't be able to press the OK button when trying to enable the accessibility service if an app has placed an overlay on the screen, such as Velis Auto Brightness or Lux.


Is there a native android way to get a reference to the currently running Activity from a service?

You may not own the "currently running Activity".

I have a service running on the background, and I would like to update my current Activity when an event occurs (in the service). Is there a easy way to do that (like the one I suggested above)?

  1. Send a broadcast Intent to the activity -- here is a sample project demonstrating this pattern
  2. Have the activity supply a PendingIntent (e.g., via createPendingResult()) that the service invokes
  3. Have the activity register a callback or listener object with the service via bindService(), and have the service call an event method on that callback/listener object
  4. Send an ordered broadcast Intent to the activity, with a low-priority BroadcastReceiver as backup (to raise a Notification if the activity is not on-screen) -- here is a blog post with more on this pattern