diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2018-02-07 00:20:33 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-02-07 00:20:33 +0000 |
commit | 70ebcc7cd0879077dbe47b62138642bbed35811a (patch) | |
tree | cfccb3f22f642b16437b357201aac757f84be802 | |
parent | f48d6d55db995fa3700f9b61c1677dc68331c9ff (diff) | |
parent | 325a50b527debd7dfe109b21d90c5b5ccd657d40 (diff) |
Merge "Implement SpamPhoneLookup"
-rw-r--r-- | java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java | 96 |
1 files changed, 87 insertions, 9 deletions
diff --git a/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java b/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java index 0196ec5e1..9f0b5cf52 100644 --- a/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java +++ b/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java @@ -17,44 +17,115 @@ package com.android.dialer.phonelookup.spam; import android.content.Context; +import android.content.SharedPreferences; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.common.Assert; +import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; +import com.android.dialer.common.concurrent.Annotations.LightweightExecutor; import com.android.dialer.phonelookup.PhoneLookup; import com.android.dialer.phonelookup.PhoneLookupInfo; import com.android.dialer.phonelookup.PhoneLookupInfo.SpamInfo; import com.android.dialer.spam.Spam; +import com.android.dialer.spam.SpamStatus; +import com.android.dialer.storage.Unencrypted; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import java.util.Map.Entry; import javax.inject.Inject; /** PhoneLookup implementation for Spam info. */ public final class SpamPhoneLookup implements PhoneLookup<SpamInfo> { + @VisibleForTesting + static final String PREF_LAST_TIMESTAMP_PROCESSED = "spamPhoneLookupLastTimestampProcessed"; + + private final ListeningExecutorService lightweightExecutorService; + private final ListeningExecutorService backgroundExecutorService; + private final SharedPreferences sharedPreferences; private final Spam spam; + @Nullable private Long currentLastTimestampProcessed; + @Inject - SpamPhoneLookup(Spam spam) { + SpamPhoneLookup( + @BackgroundExecutor ListeningExecutorService backgroundExecutorService, + @LightweightExecutor ListeningExecutorService lightweightExecutorService, + @Unencrypted SharedPreferences sharedPreferences, + Spam spam) { + this.backgroundExecutorService = backgroundExecutorService; + this.lightweightExecutorService = lightweightExecutorService; + this.sharedPreferences = sharedPreferences; this.spam = spam; } @Override public ListenableFuture<SpamInfo> lookup(DialerPhoneNumber dialerPhoneNumber) { - // TODO(a bug): Use Spam to look up spam info. - return Futures.immediateFuture(SpamInfo.getDefaultInstance()); + return Futures.transform( + spam.batchCheckSpamStatus(ImmutableSet.of(dialerPhoneNumber)), + spamStatusMap -> + SpamInfo.newBuilder() + .setIsSpam(Assert.isNotNull(spamStatusMap.get(dialerPhoneNumber)).isSpam()) + .build(), + lightweightExecutorService); } @Override public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) { - // TODO(a bug): Use Spam to check if its underlying data have been updated. - return Futures.immediateFuture(false); + ListenableFuture<Long> lastTimestampProcessedFuture = + backgroundExecutorService.submit( + () -> sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L)); + + return Futures.transformAsync( + lastTimestampProcessedFuture, spam::dataUpdatedSince, lightweightExecutorService); } @Override public ListenableFuture<ImmutableMap<DialerPhoneNumber, SpamInfo>> getMostRecentInfo( ImmutableMap<DialerPhoneNumber, SpamInfo> existingInfoMap) { - // TODO(a bug): Use Spam to retrieve the most recent spam info. - return Futures.immediateFuture(existingInfoMap); + currentLastTimestampProcessed = null; + + ListenableFuture<ImmutableMap<DialerPhoneNumber, SpamStatus>> spamStatusMapFuture = + spam.batchCheckSpamStatus(existingInfoMap.keySet()); + + return Futures.transform( + spamStatusMapFuture, + spamStatusMap -> { + ImmutableMap.Builder<DialerPhoneNumber, SpamInfo> mostRecentSpamInfo = + new ImmutableMap.Builder<>(); + + for (Entry<DialerPhoneNumber, SpamStatus> dialerPhoneNumberAndSpamStatus : + spamStatusMap.entrySet()) { + DialerPhoneNumber dialerPhoneNumber = dialerPhoneNumberAndSpamStatus.getKey(); + SpamStatus spamStatus = dialerPhoneNumberAndSpamStatus.getValue(); + mostRecentSpamInfo.put( + dialerPhoneNumber, SpamInfo.newBuilder().setIsSpam(spamStatus.isSpam()).build()); + + Optional<Long> timestampMillis = spamStatus.getTimestampMillis(); + if (timestampMillis.isPresent()) { + currentLastTimestampProcessed = + currentLastTimestampProcessed == null + ? timestampMillis.get() + : Math.max(timestampMillis.get(), currentLastTimestampProcessed); + } + } + + // If currentLastTimestampProcessed is null, it means none of the numbers in + // existingInfoMap has spam status in the underlying data source. + // We should set currentLastTimestampProcessed to the current timestamp to avoid + // triggering the bulk update flow repeatedly. + if (currentLastTimestampProcessed == null) { + currentLastTimestampProcessed = System.currentTimeMillis(); + } + + return mostRecentSpamInfo.build(); + }, + lightweightExecutorService); } @Override @@ -69,8 +140,15 @@ public final class SpamPhoneLookup implements PhoneLookup<SpamInfo> { @Override public ListenableFuture<Void> onSuccessfulBulkUpdate() { - // TODO(a bug): Properly implement this method. - return Futures.immediateFuture(null); + return backgroundExecutorService.submit( + () -> { + sharedPreferences + .edit() + .putLong( + PREF_LAST_TIMESTAMP_PROCESSED, Assert.isNotNull(currentLastTimestampProcessed)) + .apply(); + return null; + }); } @Override |