How to startActivityAndCollapse(PendingIntent) from quick settings on locked screen of Android 14?

4 min read 01-09-2024
How to startActivityAndCollapse(PendingIntent) from quick settings on locked screen of Android 14?


Launching Activities from Quick Settings on Locked Screen in Android 14: A Deep Dive

Starting an activity directly from a quick settings tile while the screen is locked has become a bit trickier in Android 14 due to the deprecation of startActivityAndCollapse(Intent) and the introduction of PendingIntent. This article explores the challenges and provides a comprehensive guide on how to achieve this functionality using PendingIntent in Android 14.

Understanding the Problem

The core issue lies in the security considerations Android 14 implements. While the older startActivityAndCollapse(Intent) approach allowed direct activity launch on a locked device, the new PendingIntent system prioritizes security by requiring the device to be unlocked before executing the activity.

The Solution: Leverage WorkManager and Foreground Service

The recommended approach involves utilizing WorkManager and a ForegroundService to achieve the desired behavior.

Step 1: Implement WorkManager

WorkManager is a robust Android framework for handling background tasks. It allows us to schedule a work request that will execute a specific task, even when the app is in the background.

Example:

import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

public class MyTileService extends TileService {
    @Override
    public void onClick() {
        // Create a WorkRequest to launch the desired activity
        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(LaunchActivityWorker.class)
                .build();

        // Enqueue the work request
        WorkManager.getInstance(this).enqueue(workRequest);
        startActivityAndCollapse();
    }
}

// Define the worker class to launch the activity
public class LaunchActivityWorker extends Worker {
    @NonNull
    @Override
    public Result doWork() {
        // Create the intent to launch the desired activity
        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        // Start the activity
        startActivity(intent);
        return Result.success();
    }
}

Step 2: Create a Foreground Service

A ForegroundService is a service that runs in the foreground, providing a way to display a notification that informs the user about the ongoing service. This is essential for security reasons, as Android 14 requires a foreground service to be able to launch an activity on a locked screen.

Example:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;

public class MyForegroundService extends Service {
    private static final String CHANNEL_ID = "foreground_service_channel";

    @Override
    public void onCreate() {
        super.onCreate();

        // Create notification channel for Android 8+
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }

        // Create a notification
        Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .setContentTitle("Service is Running")
                .setContentText("This service is active.")
                .setSmallIcon(R.drawable.your_icon)
                .build();

        // Start the foreground service
        startForeground(1, notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Handle any logic required for your service
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        stopForeground(true);
        super.onDestroy();
    }
}

Step 3: Integrate into your TileService

You can now integrate WorkManager and ForegroundService into your TileService to launch the activity from the quick settings tile while the screen is locked:

public class MyTileService extends TileService {
    private static final String FOREGROUND_SERVICE_ACTION = "com.yourpackage.foregroundservice";

    @Override
    public void onClick() {
        // Create and enqueue WorkRequest
        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(LaunchActivityWorker.class)
                .build();
        WorkManager.getInstance(this).enqueue(workRequest);

        // Start the foreground service
        Intent serviceIntent = new Intent(this, MyForegroundService.class);
        startService(serviceIntent);

        // Collapse the tile
        startActivityAndCollapse();
    }
}

Step 4: Ensure Activity Permissions

Remember to set the necessary permissions for your activity in the manifest file to allow it to be displayed even when the device is locked:

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:theme="@style/AppTheme"
    android:launchMode="singleTask" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <meta-data
        android:name="android.app.shortcuts"
        android:resource="@xml/shortcuts" />
</activity>

Explanation

This approach utilizes WorkManager to schedule the activity launch as a background task, allowing it to be executed even when the device is locked. The ForegroundService is started simultaneously, providing the necessary security context for the activity to be displayed on the locked screen.

Additional Considerations:

  • Security: It's important to be mindful of security implications. Ensure the activity and associated data are handled securely, especially on a locked device.
  • Notifications: The ForegroundService will display a notification to the user, informing them about the service's activity. Consider crafting a user-friendly notification that doesn't feel intrusive.
  • Optimization: Carefully optimize your WorkManager implementation to ensure efficient resource usage.

By combining WorkManager, ForegroundService, and proper activity permissions, you can successfully launch an activity from quick settings on a locked screen in Android 14, ensuring both functionality and security. Remember to always prioritize security and user experience when designing and implementing such features.