Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5ea08c6 authored by Nan Wu's avatar Nan Wu
Browse files

Allow tile services to start foreground service when tile is clicked

Add the tile service app to temp allow list for 15 seconds to allow
it to start a foreground service during that short period.

Flag: NA
Bug: 329242921
Test: Manual test. CtsTileServiceTestCases, TileLifecycleManagerTest, CtsSystemUiHostTestCases
Change-Id: I26d4fb94162c88e3320d8b308c3cdec48b7e73b2
parent 72423fe1
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -427,6 +427,12 @@ public class PowerExemptionManager {
     */
    public static final int REASON_PACKAGE_UNARCHIVE = 328;

    /**
     * Tile onClick event
     * @hide
     */
    public static final int REASON_TILE_ONCLICK = 329;

    /** @hide The app requests out-out. */
    public static final int REASON_OPT_OUT_REQUESTED = 1000;

@@ -504,13 +510,15 @@ public class PowerExemptionManager {
            REASON_ROLE_EMERGENCY,
            REASON_SYSTEM_MODULE,
            REASON_CARRIER_PRIVILEGED_APP,
            REASON_OPT_OUT_REQUESTED,
            REASON_DPO_PROTECTED_APP,
            REASON_DISALLOW_APPS_CONTROL,
            REASON_ACTIVE_DEVICE_ADMIN,
            REASON_MEDIA_NOTIFICATION_TRANSFER,
            REASON_PACKAGE_INSTALLER,
            REASON_SYSTEM_EXEMPT_APP_OP,
            REASON_PACKAGE_UNARCHIVE,
            REASON_TILE_ONCLICK,
            REASON_OPT_OUT_REQUESTED,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ReasonCode {}
+5 −0
Original line number Diff line number Diff line
@@ -310,6 +310,11 @@ public class PowerWhitelistManager {
     * @hide
     */
    public static final int REASON_SHELL = PowerExemptionManager.REASON_SHELL;
    /**
     * Tile onClick event
     * @hide
     */
    public static final int REASON_TILE_ONCLICK = PowerExemptionManager.REASON_TILE_ONCLICK;

    /**
     * The list of BG-FGS-Launch and temp-allowlist reason code.
+8 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.BatteryStats;
import android.os.IDeviceIdleController;
import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.ServiceManager;
@@ -735,4 +736,11 @@ public class FrameworkServicesModule {
    static Optional<SatelliteManager> provideSatelliteManager(Context context) {
        return Optional.ofNullable(context.getSystemService(SatelliteManager.class));
    }

    @Provides
    @Singleton
    static IDeviceIdleController provideDeviceIdleController() {
        return IDeviceIdleController.Stub.asInterface(
                ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
    }
}
+43 −3
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.systemui.qs.external;

import static android.os.PowerWhitelistManager.REASON_TILE_ONCLICK;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;

import android.app.ActivityManager;
@@ -31,8 +33,10 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.service.quicksettings.IQSService;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.TileService;
@@ -89,7 +93,9 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private static final int MAX_BIND_RETRIES = 5;
    private static final long DEFAULT_BIND_RETRY_DELAY = 5 * DateUtils.SECOND_IN_MILLIS;
    private static final long LOW_MEMORY_BIND_RETRY_DELAY = 20 * DateUtils.SECOND_IN_MILLIS;

    private static final long TILE_SERVICE_ONCLICK_ALLOW_LIST_DEFAULT_DURATION_MS = 15_000;
    private static final String PROPERTY_TILE_SERVICE_ONCLICK_ALLOW_LIST_DURATION =
            "property_tile_service_onclick_allow_list_duration";
    // Shared prefs that hold tile lifecycle info.
    private static final String TILES = "tiles_prefs";

@@ -102,6 +108,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private final PackageManagerAdapter mPackageManagerAdapter;
    private final BroadcastDispatcher mBroadcastDispatcher;
    private final ActivityManager mActivityManager;
    private final IDeviceIdleController mDeviceIdleController;

    private Set<Integer> mQueuedMessages = new ArraySet<>();
    @NonNull
@@ -120,12 +127,15 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    private TileChangeListener mChangeListener;
    // Return value from bindServiceAsUser, determines whether safe to call unbind.
    private AtomicBoolean mIsBound = new AtomicBoolean(false);
    private long mTempAllowFgsLaunchDuration = TILE_SERVICE_ONCLICK_ALLOW_LIST_DEFAULT_DURATION_MS;
    private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
    private AtomicBoolean mDeviceConfigChangedListenerRegistered = new AtomicBoolean(false);

    @AssistedInject
    TileLifecycleManager(@Main Handler handler, Context context, IQSService service,
            PackageManagerAdapter packageManagerAdapter, BroadcastDispatcher broadcastDispatcher,
            @Assisted Intent intent, @Assisted UserHandle user, ActivityManager activityManager,
            @Background DelayableExecutor executor) {
            IDeviceIdleController deviceIdleController, @Background DelayableExecutor executor) {
        mContext = context;
        mHandler = handler;
        mIntent = intent;
@@ -136,6 +146,16 @@ public class TileLifecycleManager extends BroadcastReceiver implements
        mPackageManagerAdapter = packageManagerAdapter;
        mBroadcastDispatcher = broadcastDispatcher;
        mActivityManager = activityManager;
        mDeviceIdleController = deviceIdleController;
        mDeviceConfigChangedListener = properties -> {
            if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
                return;
            }
            mTempAllowFgsLaunchDuration = properties.getLong(
                    PROPERTY_TILE_SERVICE_ONCLICK_ALLOW_LIST_DURATION,
                    TILE_SERVICE_ONCLICK_ALLOW_LIST_DEFAULT_DURATION_MS);
        };

        if (mDebug) Log.d(TAG, "Creating " + mIntent + " " + mUser);
    }

@@ -211,6 +231,13 @@ public class TileLifecycleManager extends BroadcastReceiver implements
        }
        mBound.set(bind);
        if (bind) {
            if (mDeviceConfigChangedListenerRegistered.compareAndSet(false, true)) {
                DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, mExecutor,
                        mDeviceConfigChangedListener);
                mTempAllowFgsLaunchDuration = DeviceConfig.getLong(NAMESPACE_SYSTEMUI,
                        PROPERTY_TILE_SERVICE_ONCLICK_ALLOW_LIST_DURATION,
                        TILE_SERVICE_ONCLICK_ALLOW_LIST_DEFAULT_DURATION_MS);
            }
            if (mBindTryCount == MAX_BIND_RETRIES) {
                // Too many failures, give up on this tile until an update.
                startPackageListening();
@@ -363,6 +390,9 @@ public class TileLifecycleManager extends BroadcastReceiver implements
            stopPackageListening();
        }
        mChangeListener = null;
        if (mDeviceConfigChangedListener != null) {
            DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener);
        }
    }

    /**
@@ -566,7 +596,17 @@ public class TileLifecycleManager extends BroadcastReceiver implements
    @Override
    public void onClick(IBinder iBinder) {
        if (mDebug) Log.d(TAG, "onClick " + iBinder + " " + getComponent() + " " + mUser);
        if (isNullOrFailedAction(mOptionalWrapper, (wrapper) -> wrapper.onClick(iBinder))) {
        if (isNullOrFailedAction(mOptionalWrapper, (wrapper) -> {
            final String packageName = mIntent.getComponent().getPackageName();
            try {
                mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName,
                        mTempAllowFgsLaunchDuration, mUser.getIdentifier(), REASON_TILE_ONCLICK,
                        "tile onclick");
            } catch (RemoteException e) {
                Log.d(TAG, "Caught exception trying to add client package to temp allow list", e);
            }
            return wrapper.onClick(iBinder);
        })) {
            mClickBinder = iBinder;
            queueMessage(MSG_ON_CLICK);
            handleDeath();
+22 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.systemui.qs.external;

import static android.os.PowerExemptionManager.REASON_TILE_ONCLICK;
import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -52,6 +53,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IDeviceIdleController;
import android.os.UserHandle;
import android.service.quicksettings.IQSService;
import android.service.quicksettings.IQSTileService;
@@ -83,6 +85,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
            mock(BroadcastDispatcher.class);
    private final IQSTileService.Stub mMockTileService = mock(IQSTileService.Stub.class);
    private final ActivityManager mActivityManager = mock(ActivityManager.class);
    private final IDeviceIdleController mDeviceIdleController = mock(IDeviceIdleController.class);

    private ComponentName mTileServiceComponentName;
    private Intent mTileServiceIntent;
@@ -126,6 +129,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mTileServiceIntent,
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);
    }

@@ -385,6 +389,20 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
        assertTrue(mStateManager.isToggleableTile());
    }

    @Test
    public void testClickCallsDeviceIdleManager() throws Exception {
        mStateManager.onTileAdded();
        mStateManager.onStartListening();
        mStateManager.onClick(null);
        mStateManager.executeSetBindService(true);
        mExecutor.runAllReady();

        verify(mMockTileService).onClick(null);
        verify(mDeviceIdleController).addPowerSaveTempWhitelistApp(
                mTileServiceComponentName.getPackageName(), 15000,
                mUser.getIdentifier(), REASON_TILE_ONCLICK, "tile onclick");
    }

    @Test
    public void testFalseBindCallsUnbind() {
        Context falseContext = mock(Context.class);
@@ -396,6 +414,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mTileServiceIntent,
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);

        manager.executeSetBindService(true);
@@ -418,6 +437,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mTileServiceIntent,
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);

        manager.executeSetBindService(true);
@@ -440,6 +460,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mTileServiceIntent,
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);

        manager.executeSetBindService(true);
@@ -464,6 +485,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
                mTileServiceIntent,
                mUser,
                mActivityManager,
                mDeviceIdleController,
                mExecutor);

        manager.executeSetBindService(true);