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

Commit 998eaa05 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Enforce all the SliceBackgroundWorkers being singletons at syntax level"

parents 4e8e8ca8 a68f8154
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -61,3 +61,8 @@
-keepclasseswithmembers class * implements com.android.settings.slices.CustomSliceable {
    public <init>(android.content.Context);
}

# Keep classes that extends SliceBackgroundWorker, which are used by reflection.
-keepclasseswithmembers class * extends com.android.settings.slices.SliceBackgroundWorker {
    public <init>(android.content.Context, android.net.Uri);
}
+4 −3
Original line number Diff line number Diff line
@@ -91,11 +91,12 @@ public interface CustomSliceable {

    /**
     * Settings Slices which can represent component lists that are updatable by the
     * {@link SliceBackgroundWorker} returned here.
     * {@link SliceBackgroundWorker} class returned here.
     *
     * @return a {@link SliceBackgroundWorker} for fetching the list of results in the background.
     * @return a {@link SliceBackgroundWorker} class for fetching the list of results in the
     * background.
     */
    default SliceBackgroundWorker getBackgroundWorker() {
    default Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
        return null;
    }

+13 −23
Original line number Diff line number Diff line
@@ -52,7 +52,6 @@ import com.android.settings.wifi.calling.WifiCallingSliceHelper;
import com.android.settingslib.SliceBroadcastRelay;
import com.android.settingslib.utils.ThreadUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -134,8 +133,7 @@ public class SettingsSliceProvider extends SliceProvider {

    final Set<Uri> mRegisteredUris = new ArraySet<>();

    final Map<Uri, SliceBackgroundWorker> mWorkerMap = new ArrayMap<>();
    final Set<SliceBackgroundWorker> mLiveWorkers = new ArraySet<>();
    final Map<Uri, SliceBackgroundWorker> mPinnedWorkers = new ArrayMap<>();

    public SettingsSliceProvider() {
        super(READ_SEARCH_INDEXABLES);
@@ -365,46 +363,38 @@ public class SettingsSliceProvider extends SliceProvider {
    }

    private void startBackgroundWorker(CustomSliceable sliceable) {
        final SliceBackgroundWorker worker = sliceable.getBackgroundWorker();
        if (worker == null) {
        final Class workerClass = sliceable.getBackgroundWorkerClass();
        if (workerClass == null) {
            return;
        }

        final Uri uri = sliceable.getUri();
        if (mWorkerMap.containsKey(uri)) {
        if (mPinnedWorkers.containsKey(uri)) {
            return;
        }

        Log.d(TAG, "Starting background worker for: " + uri);
        mWorkerMap.put(uri, worker);
        if (!mLiveWorkers.contains(worker)) {
            mLiveWorkers.add(worker);
        }
        final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(
                getContext(), sliceable);
        mPinnedWorkers.put(uri, worker);
        worker.onSlicePinned();
    }

    private void stopBackgroundWorker(Uri uri) {
        final SliceBackgroundWorker worker = mWorkerMap.get(uri);
        final SliceBackgroundWorker worker = mPinnedWorkers.get(uri);
        if (worker != null) {
            Log.d(TAG, "Stopping background worker for: " + uri);
            worker.onSliceUnpinned();
            mWorkerMap.remove(uri);
            mPinnedWorkers.remove(uri);
        }
    }

    @Override
    public void shutdown() {
        for (SliceBackgroundWorker worker : mLiveWorkers) {
        ThreadUtils.postOnMainThread(() -> {
                try {
                    worker.close();
                } catch (IOException e) {
                    Log.w(TAG, "Exception when shutting down worker", e);
                }
            SliceBackgroundWorker.shutdown();
        });
    }
        mLiveWorkers.clear();
    }

    private List<Uri> buildUrisFromKeys(List<String> keys, String authority) {
        final List<Uri> descendants = new ArrayList<>();
+58 −7
Original line number Diff line number Diff line
@@ -17,35 +17,86 @@
package com.android.settings.slices;

import android.annotation.MainThread;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * The Slice background worker is used to make Settings Slices be able to work with data that is
 * changing continuously, e.g. available Wi-Fi networks.
 *
 * The background worker will be started at {@link SettingsSliceProvider#onSlicePinned(Uri)}, and be
 * stopped at {@link SettingsSliceProvider#onSliceUnpinned(Uri)}.
 * The background worker will be started at {@link SettingsSliceProvider#onSlicePinned(Uri)}, be
 * stopped at {@link SettingsSliceProvider#onSliceUnpinned(Uri)}, and be closed at {@link
 * SettingsSliceProvider#shutdown()}.
 *
 * {@link SliceBackgroundWorker} caches the results, uses the cache to compare if there is any data
 * changed, and then notifies the Slice {@link Uri} to update.
 *
 * It also stores all instances of all workers to ensure each worker is a Singleton.
 */
public abstract class SliceBackgroundWorker<E> implements Closeable {

    private final ContentResolver mContentResolver;
    private static final String TAG = "SliceBackgroundWorker";

    private static final Map<Uri, SliceBackgroundWorker> LIVE_WORKERS = new ArrayMap<>();

    private final Context mContext;
    private final Uri mUri;

    private List<E> mCachedResults;

    protected SliceBackgroundWorker(ContentResolver cr, Uri uri) {
        mContentResolver = cr;
    protected SliceBackgroundWorker(Context context, Uri uri) {
        mContext = context;
        mUri = uri;
    }

    /**
     * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
     * CustomSliceable}
     */
    public static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
        final Uri uri = sliceable.getUri();
        final Class<? extends SliceBackgroundWorker> workerClass =
                sliceable.getBackgroundWorkerClass();
        SliceBackgroundWorker worker = LIVE_WORKERS.get(uri);
        if (worker == null) {
            worker = createInstance(context, uri, workerClass);
            LIVE_WORKERS.put(uri, worker);
        }
        return worker;
    }

    private static SliceBackgroundWorker createInstance(Context context, Uri uri,
            Class<? extends SliceBackgroundWorker> clazz) {
        Log.d(TAG, "create instance: " + clazz);
        try {
            return clazz.getConstructor(Context.class, Uri.class).newInstance(context, uri);
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
                InvocationTargetException e) {
            throw new IllegalStateException(
                    "Invalid slice background worker: " + clazz, e);
        }
    }

    static void shutdown() {
        for (SliceBackgroundWorker worker : LIVE_WORKERS.values()) {
            try {
                worker.close();
            } catch (IOException e) {
                Log.w(TAG, "Shutting down worker failed", e);
            }
        }
        LIVE_WORKERS.clear();
    }

    /**
     * Called when the Slice is pinned. This is the place to register callbacks or initialize scan
     * tasks.
@@ -83,7 +134,7 @@ public abstract class SliceBackgroundWorker<E> implements Closeable {

        if (needNotify) {
            mCachedResults = results;
            mContentResolver.notifyChange(mUri, null);
            mContext.getContentResolver().notifyChange(mUri, null);
        }
    }
}
+8 −18
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ public class WifiSlice implements CustomSliceable {
            return listBuilder.build();
        }

        List<AccessPoint> results = getBackgroundWorker().getResults();
        List<AccessPoint> results = SliceBackgroundWorker.getInstance(mContext, this).getResults();
        if (results == null) {
            results = new ArrayList<>();
        }
@@ -264,36 +264,27 @@ public class WifiSlice implements CustomSliceable {
    }

    @Override
    public SliceBackgroundWorker getBackgroundWorker() {
        return WifiScanWorker.getInstance(mContext, WIFI_URI);
    public Class getBackgroundWorkerClass() {
        return WifiScanWorker.class;
    }

    private static class WifiScanWorker extends SliceBackgroundWorker<AccessPoint>
    public static class WifiScanWorker extends SliceBackgroundWorker<AccessPoint>
            implements WifiTracker.WifiListener {

        // TODO: enforce all the SliceBackgroundWorkers being singletons at syntax level
        private static WifiScanWorker mWifiScanWorker;

        private final Context mContext;

        private WifiTracker mWifiTracker;

        private WifiScanWorker(Context context, Uri uri) {
            super(context.getContentResolver(), uri);
        public WifiScanWorker(Context context, Uri uri) {
            super(context, uri);
            mContext = context;
        }

        public static WifiScanWorker getInstance(Context context, Uri uri) {
            if (mWifiScanWorker == null) {
                mWifiScanWorker = new WifiScanWorker(context, uri);
            }
            return mWifiScanWorker;
        }

        @Override
        protected void onSlicePinned() {
            if (mWifiTracker == null) {
                mWifiTracker = new WifiTracker(mContext, this, true, true);
                mWifiTracker = new WifiTracker(mContext, this /* wifiListener */,
                        true /* includeSaved */, true /* includeScans */);
            }
            mWifiTracker.onStart();
            onAccessPointsChanged();
@@ -307,7 +298,6 @@ public class WifiSlice implements CustomSliceable {
        @Override
        public void close() {
            mWifiTracker.onDestroy();
            mWifiScanWorker = null;
        }

        @Override
Loading