From b13a95f088e8944b22c0d904a8e809b1de683572 Mon Sep 17 00:00:00 2001
From: My Name <thebestguy@google.com>
Date: Thu, 15 Dec 2022 07:54:28 +0000
Subject: [PATCH] Add BluetoothOppNotificationTest

Test: atest BluetoothInstrumentationTests
Bug: 237467631
Tag: #refactor
Change-Id: I8147e02d69744f589aacabee8918c9dd3f41c5b0
No-Typo-Check: IDE can't reliably detect all usages, defer typo fix to later CLs
---
 .../opp/BluetoothOppNotification.java         |  38 +--
 .../opp/BluetoothOppNotificationTest.java     | 240 ++++++++++++++++++
 2 files changed, 263 insertions(+), 15 deletions(-)
 create mode 100644 android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppNotificationTest.java

diff --git a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
index 44a9c1864b0..af138f21791 100644
--- a/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
+++ b/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
@@ -48,9 +48,12 @@ import android.os.Process;
 import android.text.format.Formatter;
 import android.util.Log;
 
+import com.android.bluetooth.BluetoothMethodProxy;
 import com.android.bluetooth.R;
 import com.android.bluetooth.Utils;
 
+import com.google.common.annotations.VisibleForTesting;
+
 import java.util.HashMap;
 
 /**
@@ -111,9 +114,11 @@ class BluetoothOppNotification {
 
     public static final int NOTIFICATION_ID_PROGRESS = -1000004;
 
-    private static final int NOTIFICATION_ID_OUTBOUND_COMPLETE = -1000005;
+    @VisibleForTesting
+    static final int NOTIFICATION_ID_OUTBOUND_COMPLETE = -1000005;
 
-    private static final int NOTIFICATION_ID_INBOUND_COMPLETE = -1000006;
+    @VisibleForTesting
+    static final int NOTIFICATION_ID_INBOUND_COMPLETE = -1000006;
 
     private boolean mUpdateCompleteNotification = true;
 
@@ -242,11 +247,11 @@ class BluetoothOppNotification {
         }
     }
 
-    private void updateActiveNotification() {
+    @VisibleForTesting
+    void updateActiveNotification() {
         // Active transfers
-        Cursor cursor =
-                mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_RUNNING, null,
-                        BluetoothShare._ID);
+        Cursor cursor = BluetoothMethodProxy.getInstance().contentResolverQuery(mContentResolver,
+                BluetoothShare.CONTENT_URI, null, WHERE_RUNNING, null, BluetoothShare._ID);
         if (cursor == null) {
             return;
         }
@@ -396,7 +401,8 @@ class BluetoothOppNotification {
         }
     }
 
-    private void updateCompletedNotification() {
+    @VisibleForTesting
+    void updateCompletedNotification() {
         long timeStamp = 0;
         int outboundSuccNumber = 0;
         int outboundFailNumber = 0;
@@ -406,9 +412,9 @@ class BluetoothOppNotification {
         int inboundFailNumber = 0;
 
         // Creating outbound notification
-        Cursor cursor =
-                mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_COMPLETED_OUTBOUND,
-                        null, BluetoothShare.TIMESTAMP + " DESC");
+        Cursor cursor = BluetoothMethodProxy.getInstance()
+                .contentResolverQuery(mContentResolver, BluetoothShare.CONTENT_URI, null,
+                        WHERE_COMPLETED_OUTBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
         if (cursor == null) {
             return;
         }
@@ -474,8 +480,9 @@ class BluetoothOppNotification {
         }
 
         // Creating inbound notification
-        cursor = mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_COMPLETED_INBOUND,
-                null, BluetoothShare.TIMESTAMP + " DESC");
+        cursor = BluetoothMethodProxy.getInstance()
+                .contentResolverQuery(mContentResolver, BluetoothShare.CONTENT_URI, null,
+                        WHERE_COMPLETED_INBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
         if (cursor == null) {
             return;
         }
@@ -539,9 +546,10 @@ class BluetoothOppNotification {
         }
     }
 
-    private void updateIncomingFileConfirmNotification() {
-        Cursor cursor =
-                mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_CONFIRM_PENDING,
+    @VisibleForTesting
+    void updateIncomingFileConfirmNotification() {
+        Cursor cursor = BluetoothMethodProxy.getInstance().contentResolverQuery(mContentResolver,
+                BluetoothShare.CONTENT_URI, null, WHERE_CONFIRM_PENDING,
                         null, BluetoothShare._ID);
 
         if (cursor == null) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppNotificationTest.java b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppNotificationTest.java
new file mode 100644
index 00000000000..4c2bc244dbf
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/opp/BluetoothOppNotificationTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 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.bluetooth.opp;
+
+import static com.android.bluetooth.opp.BluetoothOppNotification.NOTIFICATION_ID_INBOUND_COMPLETE;
+import static com.android.bluetooth.opp.BluetoothOppNotification.NOTIFICATION_ID_OUTBOUND_COMPLETE;
+import static com.android.bluetooth.opp.BluetoothOppNotification.NOTIFICATION_ID_PROGRESS;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.MatrixCursor;
+import android.graphics.drawable.Icon;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.espresso.intent.Intents;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.BluetoothMethodProxy;
+import com.android.bluetooth.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+
+@RunWith(AndroidJUnit4.class)
+public class BluetoothOppNotificationTest {
+    @Mock
+    BluetoothMethodProxy mMethodProxy;
+
+    Context mTargetContext;
+
+    BluetoothOppNotification mOppNotification;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mTargetContext = spy(new ContextWrapper(
+                ApplicationProvider.getApplicationContext()));
+        mMethodProxy = spy(BluetoothMethodProxy.getInstance());
+        BluetoothMethodProxy.setInstanceForTesting(mMethodProxy);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
+                mOppNotification = new BluetoothOppNotification(mTargetContext));
+
+        Intents.init();
+    }
+
+    @After
+    public void tearDown() {
+        BluetoothMethodProxy.setInstanceForTesting(null);
+        Intents.release();
+    }
+
+    @Test
+    public void updateActiveNotification() {
+        long timestamp = 10L;
+        int dir = BluetoothShare.DIRECTION_INBOUND;
+        int id = 0;
+        long total = 200;
+        long current = 100;
+        int status = BluetoothShare.STATUS_RUNNING;
+        int confirmation = BluetoothShare.USER_CONFIRMATION_CONFIRMED;
+        int confirmationHandoverInitiated = BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED;
+        String destination = "AA:BB:CC:DD:EE:FF";
+        NotificationManager mockNotificationManager = mock(NotificationManager.class);
+        mOppNotification.mNotificationMgr = mockNotificationManager;
+        MatrixCursor cursor = new MatrixCursor(new String[]{
+                BluetoothShare.TIMESTAMP, BluetoothShare.DIRECTION, BluetoothShare._ID,
+                BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES, BluetoothShare._DATA,
+                BluetoothShare.FILENAME_HINT, BluetoothShare.USER_CONFIRMATION,
+                BluetoothShare.DESTINATION, BluetoothShare.STATUS
+        });
+        cursor.addRow(new Object[]{
+                timestamp, dir, id, total, current, null, null, confirmation, destination, status
+        });
+        cursor.addRow(new Object[]{
+                timestamp + 10L, dir, id, total, current, null, null, confirmationHandoverInitiated,
+                destination, status
+        });
+        doReturn(cursor).when(mMethodProxy).contentResolverQuery(any(),
+                eq(BluetoothShare.CONTENT_URI), any(), any(), any(), any());
+
+        mOppNotification.updateActiveNotification();
+
+        //confirm handover case does broadcast
+        verify(mTargetContext).sendBroadcast(any(), eq(Constants.HANDOVER_STATUS_PERMISSION),
+                any());
+        // Todo: find a better way to verify the notification
+        // getContentIntent doesn't work because it requires signature permission
+        verify(mockNotificationManager).notify(eq(NOTIFICATION_ID_PROGRESS), argThat(
+                arg -> arg.getSmallIcon().sameAs(Icon.createWithResource(mTargetContext,
+                        android.R.drawable.stat_sys_download))
+        ));
+    }
+
+    @Test
+    public void updateCompletedNotification_withOutBoundShare_showsNoti() {
+        long timestamp = 10L;
+        int status = BluetoothShare.STATUS_SUCCESS;
+        int statusError = BluetoothShare.STATUS_CONNECTION_ERROR;
+        int dir = BluetoothShare.DIRECTION_OUTBOUND;
+        int id = 0;
+        long total = 200;
+        long current = 100;
+        int confirmation = BluetoothShare.USER_CONFIRMATION_CONFIRMED;
+        String destination = "AA:BB:CC:DD:EE:FF";
+        NotificationManager mockNotificationManager = mock(NotificationManager.class);
+        mOppNotification.mNotificationMgr = mockNotificationManager;
+        MatrixCursor cursor = new MatrixCursor(new String[]{
+                BluetoothShare.TIMESTAMP, BluetoothShare.DIRECTION, BluetoothShare._ID,
+                BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES, BluetoothShare._DATA,
+                BluetoothShare.FILENAME_HINT, BluetoothShare.USER_CONFIRMATION,
+                BluetoothShare.DESTINATION, BluetoothShare.STATUS
+        });
+        cursor.addRow(new Object[]{
+                timestamp, dir, id, total, current, null, null, confirmation, destination, status
+        });
+        cursor.addRow(new Object[]{
+                timestamp + 10L, dir, id, total, current, null, null, confirmation,
+                destination, statusError
+        });
+        doReturn(cursor).when(mMethodProxy).contentResolverQuery(any(),
+                eq(BluetoothShare.CONTENT_URI), any(), any(), any(), any());
+
+        mOppNotification.updateCompletedNotification();
+
+        // Todo: find a better way to verify the notification
+        // getContentIntent doesn't work because it requires signature permission
+        verify(mockNotificationManager).notify(eq(NOTIFICATION_ID_OUTBOUND_COMPLETE), argThat(
+                arg -> arg.getSmallIcon().sameAs(Icon.createWithResource(mTargetContext,
+                        android.R.drawable.stat_sys_upload_done))
+        ));
+    }
+
+    @Test
+    public void updateCompletedNotification_withInBoundShare_showsNoti() {
+        long timestamp = 10L;
+        int status = BluetoothShare.STATUS_SUCCESS;
+        int statusError = BluetoothShare.STATUS_CONNECTION_ERROR;
+        int dir = BluetoothShare.DIRECTION_INBOUND;
+        int id = 0;
+        long total = 200;
+        long current = 100;
+        int confirmation = BluetoothShare.USER_CONFIRMATION_CONFIRMED;
+        String destination = "AA:BB:CC:DD:EE:FF";
+        NotificationManager mockNotificationManager = mock(NotificationManager.class);
+        mOppNotification.mNotificationMgr = mockNotificationManager;
+        MatrixCursor cursor = new MatrixCursor(new String[]{
+                BluetoothShare.TIMESTAMP, BluetoothShare.DIRECTION, BluetoothShare._ID,
+                BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES, BluetoothShare._DATA,
+                BluetoothShare.FILENAME_HINT, BluetoothShare.USER_CONFIRMATION,
+                BluetoothShare.DESTINATION, BluetoothShare.STATUS
+        });
+        cursor.addRow(new Object[]{
+                timestamp, dir, id, total, current, null, null, confirmation, destination, status
+        });
+        cursor.addRow(new Object[]{
+                timestamp + 10L, dir, id, total, current, null, null, confirmation,
+                destination, statusError
+        });
+        doReturn(cursor).when(mMethodProxy).contentResolverQuery(any(),
+                eq(BluetoothShare.CONTENT_URI), any(), any(), any(), any());
+
+        mOppNotification.updateCompletedNotification();
+
+        // Todo: find a better way to verify the notification
+        // getContentIntent doesn't work because it requires signature permission
+        verify(mockNotificationManager).notify(eq(NOTIFICATION_ID_INBOUND_COMPLETE), argThat(
+                arg -> arg.getSmallIcon().sameAs(Icon.createWithResource(mTargetContext,
+                            android.R.drawable.stat_sys_download_done)
+        )));
+    }
+
+    @Test
+    public void updateIncomingFileConfirmationNotification() {
+        long timestamp = 10L;
+        int dir = BluetoothShare.DIRECTION_INBOUND;
+        int id = 0;
+        long total = 200;
+        long current = 100;
+        int confirmation = BluetoothShare.USER_CONFIRMATION_PENDING;
+        int status = BluetoothShare.STATUS_SUCCESS;
+        String url = "content:///abc/xyz";
+        String destination = "AA:BB:CC:DD:EE:FF";
+        String mimeType = "text/plain";
+        NotificationManager mockNotificationManager = mock(NotificationManager.class);
+        mOppNotification.mNotificationMgr = mockNotificationManager;
+        MatrixCursor cursor = new MatrixCursor(new String[]{
+                BluetoothShare.TIMESTAMP, BluetoothShare.DIRECTION, BluetoothShare._ID,
+                BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES, BluetoothShare._DATA,
+                BluetoothShare.FILENAME_HINT, BluetoothShare.USER_CONFIRMATION, BluetoothShare.URI,
+                BluetoothShare.DESTINATION, BluetoothShare.STATUS, BluetoothShare.MIMETYPE
+        });
+        cursor.addRow(new Object[]{
+                timestamp, dir, id, total, current, null, null, confirmation, url, destination,
+                status, mimeType
+        });
+        doReturn(cursor).when(mMethodProxy).contentResolverQuery(any(),
+                eq(BluetoothShare.CONTENT_URI), any(), any(), any(), any());
+
+        mOppNotification.updateIncomingFileConfirmNotification();
+
+        // Todo: find a better way to verify the notification
+        // getContentIntent doesn't work because it requires signature permission
+        verify(mockNotificationManager).notify(eq(NOTIFICATION_ID_PROGRESS), argThat(
+                arg -> arg.getSmallIcon().sameAs(Icon.createWithResource(mTargetContext,
+                    R.drawable.bt_incomming_file_notification))
+        ));
+    }
+}
-- 
GitLab