Merge "Unregister the Receiver when the service is destroyed"
diff --git a/rcs/presencepolling/Android.mk b/rcs/presencepolling/Android.mk
index e73bb60..a536825 100644
--- a/rcs/presencepolling/Android.mk
+++ b/rcs/presencepolling/Android.mk
@@ -39,5 +39,8 @@
 LOCAL_CERTIFICATE := platform
 #LOCAL_MODULE_TAGS := optional
 
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
 include $(BUILD_PACKAGE)
 
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/rcs/presencepolling/proguard.flags b/rcs/presencepolling/proguard.flags
new file mode 100644
index 0000000..c707f76
--- /dev/null
+++ b/rcs/presencepolling/proguard.flags
@@ -0,0 +1,10 @@
+# Keep classes and methods that have the guava @VisibleForTesting annotation
+-keep @**.VisibleForTesting class *
+-keepclassmembers class * {
+@**.VisibleForTesting *;
+}
+-keep @**.NeededForTesting class *
+-keepclassmembers class * {
+@**.NeededForTesting *;
+}
+-verbose
\ No newline at end of file
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java b/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
index 256f6af..365e5f6 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
@@ -40,6 +40,7 @@
 import android.os.SystemProperties;
 
 import com.android.ims.internal.Logger;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * Manages the CapabilityPolling class. Starts capability polling when a SIM card is inserted that
@@ -51,7 +52,8 @@
 
     private CapabilityPolling mCapabilityPolling = null;
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    // not final for testing
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
 
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -92,6 +94,8 @@
             mCapabilityPolling = null;
         }
 
+        unregisterReceiver(mReceiver);
+
         super.onDestroy();
     }
 
@@ -107,6 +111,11 @@
         return null;
     }
 
+    @VisibleForTesting
+    public void setBroadcastReceiver(BroadcastReceiver r) {
+        mReceiver = r;
+    }
+
     private void registerBroadcastReceiver() {
         IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         registerReceiver(mReceiver, filter);
diff --git a/rcs/presencepolling/tests/Android.mk b/rcs/presencepolling/tests/Android.mk
new file mode 100644
index 0000000..3cecc58
--- /dev/null
+++ b/rcs/presencepolling/tests/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2017 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := mockito-target \
+                        android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        android-support-test \
+        mockito-target-minus-junit4 \
+        legacy-android-test
+
+LOCAL_PACKAGE_NAME := PresencePollingTests
+LOCAL_INSTRUMENTATION_FOR := PresencePolling
+LOCAL_CERTIFICATE := platform
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
+
diff --git a/rcs/presencepolling/tests/AndroidManifest.xml b/rcs/presencepolling/tests/AndroidManifest.xml
new file mode 100644
index 0000000..e7f005e
--- /dev/null
+++ b/rcs/presencepolling/tests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.service.ims.presence.tests">
+
+    <application android:label="@string/app_name">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+        To run all tests:
+            adb shell am instrument -w com.android.service.ims.presence.tests/android.support.test.runner.AndroidJUnitRunner
+
+        To run a single class test:
+            adb shell am instrument -e class com.android.phone.unit.FooUnitTest -w com.android.service.ims.presence.tests/android.support.test.runner.AndroidJUnitRunner
+
+    -->
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.service.ims.presence"
+        android:label="PresencePolling Tests" />
+</manifest>
\ No newline at end of file
diff --git a/rcs/presencepolling/tests/AndroidTest.xml b/rcs/presencepolling/tests/AndroidTest.xml
new file mode 100644
index 0000000..b073892
--- /dev/null
+++ b/rcs/presencepolling/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+<configuration description="Run PresencePolling application tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="PresencePollingTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="PresencePollingTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.service.ims.presence.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/rcs/presencepolling/tests/res/values/donottranslate_strings.xml b/rcs/presencepolling/tests/res/values/donottranslate_strings.xml
new file mode 100644
index 0000000..3e515bf
--- /dev/null
+++ b/rcs/presencepolling/tests/res/values/donottranslate_strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<resources>
+    <!-- Application label -->
+    <string name="app_name">PresencePollingTests</string>
+</resources>
diff --git a/rcs/presencepolling/tests/src/com/android/service/ims/presence/PollingServiceTests.java b/rcs/presencepolling/tests/src/com/android/service/ims/presence/PollingServiceTests.java
new file mode 100644
index 0000000..44b1ea7
--- /dev/null
+++ b/rcs/presencepolling/tests/src/com/android/service/ims/presence/PollingServiceTests.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 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.service.ims.presence;
+
+import android.content.BroadcastReceiver;
+import android.content.IntentFilter;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.CarrierConfigManager;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Unit Tests for PollingService.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PollingServiceTests extends PresencePollingTestBase {
+
+    @Mock BroadcastReceiver mReceiver;
+
+    private PollingService mService;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mService = new PollingService();
+        mService.attach(mTestContext,null, null, null, mApp, null);
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        mService = null;
+    }
+
+    @SmallTest
+    @Test
+    public void testRegisterCarrierConfigReceiver() throws Exception {
+        mService.setBroadcastReceiver(mReceiver);
+        mService.onCreate();
+        ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+        verify(mTestContext).registerReceiver(eq(mReceiver), captor.capture());
+        IntentFilter f = captor.getValue();
+        assertEquals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED, f.getAction(0));
+    }
+
+    @SmallTest
+    @Test
+    public void testUnregisterCarrierConfigReceiver() throws Exception {
+        mService.setBroadcastReceiver(mReceiver);
+        mService.onDestroy();
+        verify(mTestContext).unregisterReceiver(eq(mReceiver));
+    }
+}
diff --git a/rcs/presencepolling/tests/src/com/android/service/ims/presence/PresencePollingTestBase.java b/rcs/presencepolling/tests/src/com/android/service/ims/presence/PresencePollingTestBase.java
new file mode 100644
index 0000000..c7c3e4f
--- /dev/null
+++ b/rcs/presencepolling/tests/src/com/android/service/ims/presence/PresencePollingTestBase.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 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.service.ims.presence;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Mockito.when;
+
+/**
+ * Base Class for PresencePolling Unit Tests
+ */
+
+public class PresencePollingTestBase {
+
+    protected @Mock Context mTestContext;
+    protected @Mock Application mApp;
+    private ApplicationInfo mAppInfo = new ApplicationInfo();
+
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mTestContext.getApplicationInfo()).thenReturn(mAppInfo);
+        mAppInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+        // Set up the looper if it does not exist on the test thread.
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+    }
+
+    public void tearDown() throws Exception {
+    }
+
+    protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
+        waitForHandlerActionDelayed(h, timeoutMillis, 0 /*delayMs*/);
+    }
+
+    protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) {
+        final CountDownLatch lock = new CountDownLatch(1);
+        h.postDelayed(lock::countDown, delayMs);
+        while (lock.getCount() > 0) {
+            try {
+                lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+        }
+    }
+}