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

Commit c1d8bffb authored by Soonil Nagarkar's avatar Soonil Nagarkar Committed by Android (Google) Code Review
Browse files

Merge "Give ServiceWatcher a proper lifecycle"

parents 5bba6f62 b71eaf58
Loading
Loading
Loading
Loading
+80 −52
Original line number Diff line number Diff line
@@ -185,9 +185,49 @@ public class ServiceWatcher implements ServiceConnection {
    private final Handler mHandler;
    private final Intent mIntent;

    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
        @Override
        public boolean onPackageChanged(String packageName, int uid, String[] components) {
            return true;
        }

        @Override
        public void onSomePackagesChanged() {
            onBestServiceChanged(false);
        }
    };
    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }
            int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
            if (userId == UserHandle.USER_NULL) {
                return;
            }

            switch (action) {
                case Intent.ACTION_USER_SWITCHED:
                    onUserSwitched(userId);
                    break;
                case Intent.ACTION_USER_UNLOCKED:
                    onUserUnlocked(userId);
                    break;
                default:
                    break;
            }

        }
    };

    @Nullable private final OnBindRunner mOnBind;
    @Nullable private final Runnable mOnUnbind;

    // write from caller thread only, read anywhere
    private volatile boolean mRegistered;

    // read/write from handler thread only
    private int mCurrentUserId;

@@ -225,79 +265,67 @@ public class ServiceWatcher implements ServiceConnection {
    }

    /**
     * Register this class, which will start the process of determining the best matching service
     * and maintaining a binding to it. Will return false and fail if there are no possible matching
     * services at the time this functions is called.
     * Returns true if there is at least one component that could satisfy the ServiceWatcher's
     * constraints.
     */
    public boolean register() {
        if (mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
    public boolean checkServiceResolves() {
        return !mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
                MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
                UserHandle.USER_SYSTEM).isEmpty()) {
            return false;
                UserHandle.USER_SYSTEM).isEmpty();
    }

        new PackageMonitor() {
            @Override
            public boolean onPackageChanged(String packageName, int uid, String[] components) {
                return true;
            }
    /**
     * Starts the process of determining the best matching service and maintaining a binding to it.
     */
    public void register() {
        Preconditions.checkState(!mRegistered);

            @Override
            public void onSomePackagesChanged() {
                onBestServiceChanged(false);
            }
        }.register(mContext, UserHandle.ALL, true, mHandler);
        mPackageMonitor.register(mContext, UserHandle.ALL, true, mHandler);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (action == null) {
                    return;
                }
                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                if (userId == UserHandle.USER_NULL) {
                    return;
                }
        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter, null,
                mHandler);

                switch (action) {
                    case Intent.ACTION_USER_SWITCHED:
                        onUserSwitched(userId);
                        break;
                    case Intent.ACTION_USER_UNLOCKED:
                        onUserUnlocked(userId);
                        break;
                    default:
                        break;
                }
        mCurrentUserId = ActivityManager.getCurrentUser();

        mRegistered = true;

        mHandler.post(() -> onBestServiceChanged(false));
    }
        }, UserHandle.ALL, intentFilter, null, mHandler);

        mCurrentUserId = ActivityManager.getCurrentUser();
    /**
     * Stops the process of determining the best matching service and releases any binding.
     */
    public void unregister() {
        Preconditions.checkState(mRegistered);

        mRegistered = false;

        mPackageMonitor.unregister();
        mContext.unregisterReceiver(mBroadcastReceiver);

        mHandler.post(() -> onBestServiceChanged(false));
        return true;
    }

    private void onBestServiceChanged(boolean forceRebind) {
        Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());

        ServiceInfo bestServiceInfo = ServiceInfo.NONE;

        if (mRegistered) {
            List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
                    mIntent,
                    GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
                    mCurrentUserId);

        ServiceInfo bestServiceInfo = ServiceInfo.NONE;
            for (ResolveInfo resolveInfo : resolveInfos) {
                ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
                if (serviceInfo.compareTo(bestServiceInfo) > 0) {
                    bestServiceInfo = serviceInfo;
                }
            }
        }

        if (forceRebind || !bestServiceInfo.equals(mTargetService)) {
            rebind(bestServiceInfo);
+5 −1
Original line number Diff line number Diff line
@@ -60,7 +60,11 @@ public class GeocoderProxy {
    }

    private boolean register() {
        return mServiceWatcher.register();
        boolean resolves = mServiceWatcher.checkServiceResolves();
        if (resolves) {
            mServiceWatcher.register();
        }
        return resolves;
    }

    /**
+5 −1
Original line number Diff line number Diff line
@@ -75,7 +75,11 @@ public class HardwareActivityRecognitionProxy {
    }

    private boolean register() {
        return mServiceWatcher.register();
        boolean resolves = mServiceWatcher.checkServiceResolves();
        if (resolves) {
            mServiceWatcher.register();
        }
        return resolves;
    }

    private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+5 −1
Original line number Diff line number Diff line
@@ -92,7 +92,11 @@ public class ProxyLocationProvider extends AbstractLocationProvider {
    }

    private boolean register() {
        return mServiceWatcher.register();
        boolean resolves = mServiceWatcher.checkServiceResolves();
        if (resolves) {
            mServiceWatcher.register();
        }
        return resolves;
    }

    private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+4 −4
Original line number Diff line number Diff line
@@ -75,16 +75,16 @@ public final class GeofenceProxy {
    }

    private boolean register(Context context) {
        if (mServiceWatcher.register()) {
        boolean resolves = mServiceWatcher.checkServiceResolves();
        if (resolves) {
            mServiceWatcher.register();
            context.bindServiceAsUser(
                    new Intent(context, GeofenceHardwareService.class),
                    new GeofenceProxyServiceConnection(),
                    Context.BIND_AUTO_CREATE,
                    UserHandle.SYSTEM);
            return true;
        }

        return false;
        return resolves;
    }

    private class GeofenceProxyServiceConnection implements ServiceConnection {
Loading