Add AbstractDiscoveryProvider and Controller

Test: Successfully built. Unit test will be added.
Bug: 189954300
Change-Id: Iaed9c95d3b92a7dad00035d10086bec0303f5d41
diff --git a/nearby/service/java/com/android/server/nearby/provider/AbstractDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/AbstractDiscoveryProvider.java
new file mode 100644
index 0000000..7cc859c
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/provider/AbstractDiscoveryProvider.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.provider;
+
+import static com.android.server.nearby.NearbyService.TAG;
+
+import android.content.Context;
+import android.nearby.NearbyDeviceParcelable;
+import android.nearby.ScanRequest;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Base class for all discovery providers.
+ *
+ * @hide
+ */
+public abstract class AbstractDiscoveryProvider {
+
+    protected final Context mContext;
+    protected final DiscoveryProviderController mController;
+    protected final Executor mExecutor;
+    protected Listener mListener;
+
+    /**
+     * Interface for listening to discovery providers.
+     */
+    public interface Listener {
+        /**
+         * Called when a provider has a new nearby device available. May be invoked from any thread.
+         */
+        void onNearbyDeviceDiscovered(NearbyDeviceParcelable nearbyDevice);
+    }
+
+    protected AbstractDiscoveryProvider(Context context, Executor executor) {
+        mContext = context;
+        mExecutor = executor;
+        mController = new Controller();
+    }
+
+    /**
+     * Callback invoked when the provider is started, and signals that other callback invocations
+     * can now be expected. Always implies that the provider request is set to the empty request.
+     * Always invoked on the provider executor.
+     */
+    protected void onStart() { }
+
+    /**
+     * Callback invoked when the provider is stopped, and signals that no further callback
+     * invocations will occur (until a further call to {@link #onStart()}. Always invoked on the
+     * provider executor.
+     */
+    protected void onStop() { }
+
+    /**
+     * Callback invoked to inform the provider of a new provider request which replaces any prior
+     * provider request. Always invoked on the provider executor.
+     */
+    protected void invalidateScanMode() { }
+
+    /**
+     * Retrieves the controller for this discovery provider. Should never be invoked by subclasses,
+     * as a discovery provider should not be controlling itself. Using this method from subclasses
+     * could also result in deadlock.
+     */
+    protected DiscoveryProviderController getController() {
+        return mController;
+    }
+
+    private class Controller implements DiscoveryProviderController {
+
+        private boolean mStarted = false;
+        private @ScanRequest.ScanMode int mScanMode;
+
+        @Override
+        public void setListener(@Nullable Listener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public boolean isStarted() {
+            return mStarted;
+        }
+
+        @Override
+        public void start() {
+            if (mStarted) {
+                Log.d(TAG, "Provider already started.");
+                return;
+            }
+            mStarted = true;
+            mExecutor.execute(AbstractDiscoveryProvider.this::onStart);
+        }
+
+        @Override
+        public void stop() {
+            if (!mStarted) {
+                Log.d(TAG, "Provider already stopped.");
+                return;
+            }
+            mStarted = false;
+            mExecutor.execute(AbstractDiscoveryProvider.this::onStop);
+        }
+
+        @Override
+        public void setProviderScanMode(@ScanRequest.ScanMode int scanMode) {
+            if (mScanMode == scanMode) {
+                Log.d(TAG, "Provider already in desired scan mode.");
+                return;
+            }
+            mScanMode = scanMode;
+            mExecutor.execute(AbstractDiscoveryProvider.this::invalidateScanMode);
+        }
+
+        @ScanRequest.ScanMode
+        @Override
+        public int getProviderScanMode() {
+            return mScanMode;
+        }
+    }
+}
diff --git a/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderController.java b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderController.java
new file mode 100644
index 0000000..469f623
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/provider/DiscoveryProviderController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.provider;
+
+import android.annotation.Nullable;
+import android.nearby.ScanRequest;
+
+/**
+ * Interface for controlling discovery providers.
+ */
+interface DiscoveryProviderController {
+
+    /**
+     * Sets the listener which can expect to receive all state updates from after this point.
+     * May be invoked at any time.
+     */
+    void setListener(@Nullable AbstractDiscoveryProvider.Listener listener);
+
+    /**
+     * Returns true if in the started state.
+     */
+    boolean isStarted();
+
+    /**
+     * Starts the discovery provider. Must be invoked before any other method (except
+     * {@link #setListener(AbstractDiscoveryProvider.Listener)} (Listener)}).
+     */
+    void start();
+
+    /**
+     * Stops the discovery provider. No other methods may be invoked after this method (except
+     * {@link #setListener(AbstractDiscoveryProvider.Listener)} (Listener)}), until {@link #start()} is called again.
+     */
+    void stop();
+
+    /**
+     * Sets the desired scan mode.
+     */
+    void setProviderScanMode(@ScanRequest.ScanMode int scanMode);
+
+    /** Gets the controller scan mode. */
+    @ScanRequest.ScanMode
+    int getProviderScanMode();
+}