Add a test BroadCastReceiver to receive carrier Config

 - Add a timeout mechaism to wait for the intent of carrierconfigchange.
 - Add a abstract method for the condition implementation for developer.

Bug: 225092753
Test: atest passed.
Change-Id: Ica95c0d5bdb1c10ad8dca0f3670a9dade32bcfee
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java b/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java
new file mode 100644
index 0000000..ffd88fd
--- /dev/null
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TestCarrierConfigReceiver.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 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.testutils;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+
+import static com.android.testutils.TestPermissionUtil.runAsShell;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** A receiver to receive carrier config and can be awaiting the result of config change. */
+public class TestCarrierConfigReceiver extends BroadcastReceiver {
+    // CountDownLatch used to wait for this BroadcastReceiver to be notified of a CarrierConfig
+    // change. This latch will be counted down if a broadcast indicates this package has carrier
+    // configs, or if an Exception occurs in #onReceive.
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private final int mSubId;
+    private final int mTimeoutMs;
+    private final PersistableBundle mRequestedConfig;
+    private final Matcher mMatcher;
+    private final Context mContext;
+    private final CarrierConfigManager mCarrierConfigManager;
+
+    private volatile PersistableBundle mReceivedConfigs;
+    private volatile Exception mOnReceiveException;
+
+    /** A interface for doing the carrier config match between requested and received one.*/
+    public interface Matcher {
+        /**
+         * Called when a broadcast is received in order to determine whether the
+         * broadcast matches expectations.
+         *
+         *  - If this method returns true, waitForCarrierConfigChanged returns.
+         *  - If this method returns false, the broadcast will be ignored and
+         *  waitForCarrierConfigChanged will continue to wait. If this method throws an exception,
+         *  the exception will be stored and re-thrown by waitForCarrierConfigChanged.
+         */
+        boolean matchesBroadcast(PersistableBundle config) throws Exception;
+    }
+
+    public TestCarrierConfigReceiver(
+            Context context,
+            int subId,
+            int timeoutMs,
+            PersistableBundle requestedConfig,
+            Matcher matcher) {
+        mContext = context;
+        mSubId = subId;
+        mTimeoutMs = timeoutMs;
+        mRequestedConfig = requestedConfig;
+        mMatcher = matcher;
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+            // Ignores this incorrect broadcast.
+            return;
+        }
+
+        int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+                        SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        if (mSubId != subId) {
+            // Ignores this broadcast for the wrong subId.
+            return;
+        }
+        mReceivedConfigs = getCarrierConfigs(subId);
+
+        if (!CarrierConfigManager.isConfigForIdentifiedCarrier(mReceivedConfigs)) {
+            // Configs are not for an identified carrier (meaning they are defaults) - ignore
+            return;
+        }
+
+        try {
+            if (mMatcher.matchesBroadcast(mReceivedConfigs)) {
+                mLatch.countDown();
+            }
+        } catch (Exception e) {
+            // Throw an Exception - cache it and allow waitForCarrierConfigChanged() to throw it
+            mOnReceiveException = e;
+            mLatch.countDown();
+        }
+    }
+
+    private PersistableBundle getCarrierConfigs(int subId) {
+        return runAsShell(android.Manifest.permission.READ_PHONE_STATE,
+                () -> mCarrierConfigManager.getConfigForSubId(subId));
+    }
+
+    private void waitForCarrierConfigChanged() throws Exception {
+        try {
+            assertTrue("No matching carrier config broadcast received after " + mTimeoutMs
+                            + " milliseconds.", mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS));
+            // If latch is unlocked and mOnReceiveException is assigned,
+            // it shall throw the exception.
+            if (mOnReceiveException != null) {
+                throw mOnReceiveException;
+            }
+        } finally {
+            mContext.unregisterReceiver(this);
+        }
+    }
+
+    /**
+     * Override the carrier config and waiting for the carrier config change.
+     * @return A PersistentBundle with received carrier configs.
+     * @throws Exception Once timout happened, it may throw a timout exception.
+     */
+    public PersistableBundle overrideCarrierConfigForTest() throws Exception {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
+        mContext.registerReceiver(this, filter);
+        runAsShell(android.Manifest.permission.MODIFY_PHONE_STATE,
+                () -> {
+                    mCarrierConfigManager.overrideConfig(mSubId, mRequestedConfig);
+                    mCarrierConfigManager.notifyConfigChangedForSubId(mSubId);
+                });
+
+        waitForCarrierConfigChanged();
+        return mReceivedConfigs;
+    }
+}