Ignore "new" voicemails that are too old for notifications

Bug: 68049435
Test: CallLogNotificationQueryHelperTest
PiperOrigin-RevId: 178016400
Change-Id: I6ddbebc9edce6830966072d42cf05eb21f26c8ac
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index f962e17..4745736 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -28,6 +28,7 @@
 import android.provider.CallLog.Calls;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.annotation.WorkerThread;
 import android.support.v4.os.UserManagerCompat;
 import android.telephony.PhoneNumberUtils;
@@ -35,7 +36,9 @@
 import com.android.dialer.app.R;
 import com.android.dialer.calllogutils.PhoneNumberDisplayUtil;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.database.Selection;
 import com.android.dialer.compat.android.provider.VoicemailCompat;
+import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.dialer.location.GeoUtil;
 import com.android.dialer.phonenumbercache.ContactInfo;
 import com.android.dialer.phonenumbercache.ContactInfoHelper;
@@ -43,11 +46,16 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /** Helper class operating on call log notifications. */
 @TargetApi(Build.VERSION_CODES.M)
 public class CallLogNotificationsQueryHelper {
 
+  @VisibleForTesting
+  static final String CONFIG_NEW_VOICEMAIL_NOTIFICATION_THRESHOLD_OFFSET =
+      "new_voicemail_notification_threshold";
+
   private final Context mContext;
   private final NewCallsQuery mNewCallsQuery;
   private final ContactInfoHelper mContactInfoHelper;
@@ -147,7 +155,12 @@
    */
   @Nullable
   public List<NewCall> getNewVoicemails() {
-    return mNewCallsQuery.query(Calls.VOICEMAIL_TYPE);
+    return mNewCallsQuery.query(
+        Calls.VOICEMAIL_TYPE,
+        System.currentTimeMillis()
+            - ConfigProviderBindings.get(mContext)
+                .getLong(
+                    CONFIG_NEW_VOICEMAIL_NOTIFICATION_THRESHOLD_OFFSET, TimeUnit.DAYS.toMillis(7)));
   }
 
   /**
@@ -220,10 +233,21 @@
   /** Allows determining the new calls for which a notification should be generated. */
   public interface NewCallsQuery {
 
+    long NO_THRESHOLD = Long.MAX_VALUE;
+
     /** Returns the new calls of a certain type for which a notification should be generated. */
     @Nullable
     List<NewCall> query(int type);
 
+    /**
+     * Returns the new calls of a certain type for which a notification should be generated.
+     *
+     * @param thresholdMillis New calls added before this timestamp will be considered old, or
+     *     {@link #NO_THRESHOLD} if threshold is not checked.
+     */
+    @Nullable
+    List<NewCall> query(int type, long thresholdMillis);
+
     /** Returns a {@link NewCall} pointed by the {@code callsUri} */
     @Nullable
     NewCall query(Uri callsUri);
@@ -317,6 +341,14 @@
     @Nullable
     @TargetApi(Build.VERSION_CODES.M)
     public List<NewCall> query(int type) {
+      return query(type, NO_THRESHOLD);
+    }
+
+    @Override
+    @Nullable
+    @TargetApi(Build.VERSION_CODES.M)
+    @SuppressWarnings("MissingPermission")
+    public List<NewCall> query(int type, long thresholdMillis) {
       if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) {
         LogUtil.w(
             "CallLogNotificationsQueryHelper.DefaultNewCallsQuery.query",
@@ -328,15 +360,27 @@
       // TYPE matches the query type.
       // IS_READ is not 1. A call might be backed up and restored, so it will be "new" to the
       //   call log, but the user has already read it on another device.
-      final String selection =
-          String.format("%s = 1 AND %s = ? AND %s IS NOT 1", Calls.NEW, Calls.TYPE, Calls.IS_READ);
-      final String[] selectionArgs = new String[] {Integer.toString(type)};
+      Selection.Builder selectionBuilder =
+          Selection.builder()
+              .and(Selection.column(Calls.NEW).is("= 1"))
+              .and(Selection.column(Calls.TYPE).is("=", type))
+              .and(Selection.column(Calls.IS_READ).is("IS NOT 1"));
+      if (thresholdMillis != NO_THRESHOLD) {
+        selectionBuilder =
+            selectionBuilder.and(
+                Selection.column(Calls.DATE)
+                    .is("IS NULL")
+                    .buildUpon()
+                    .or(Selection.column(Calls.DATE).is(">=", thresholdMillis))
+                    .build());
+      }
+      Selection selection = selectionBuilder.build();
       try (Cursor cursor =
           mContentResolver.query(
               Calls.CONTENT_URI_WITH_VOICEMAIL,
               (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? PROJECTION_O : PROJECTION,
-              selection,
-              selectionArgs,
+              selection.getSelection(),
+              selection.getSelectionArgs(),
               Calls.DEFAULT_SORT_ORDER)) {
         if (cursor == null) {
           return null;