1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.dialer.phonelookup.cnap; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.telecom.Call; 22 import android.text.TextUtils; 23 import com.android.dialer.DialerPhoneNumber; 24 import com.android.dialer.common.Assert; 25 import com.android.dialer.common.LogUtil; 26 import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; 27 import com.android.dialer.common.database.Selection; 28 import com.android.dialer.inject.ApplicationContext; 29 import com.android.dialer.phonelookup.PhoneLookup; 30 import com.android.dialer.phonelookup.PhoneLookupInfo; 31 import com.android.dialer.phonelookup.PhoneLookupInfo.CnapInfo; 32 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory; 33 import com.google.common.collect.ImmutableMap; 34 import com.google.common.collect.ImmutableSet; 35 import com.google.common.util.concurrent.Futures; 36 import com.google.common.util.concurrent.ListenableFuture; 37 import com.google.common.util.concurrent.ListeningExecutorService; 38 import com.google.protobuf.InvalidProtocolBufferException; 39 import javax.inject.Inject; 40 41 /** PhoneLookup implementation for CNAP info. */ 42 public final class CnapPhoneLookup implements PhoneLookup<CnapInfo> { 43 44 private final Context appContext; 45 private final ListeningExecutorService backgroundExecutorService; 46 47 @Inject CnapPhoneLookup( @pplicationContext Context appContext, @BackgroundExecutor ListeningExecutorService backgroundExecutorService)48 CnapPhoneLookup( 49 @ApplicationContext Context appContext, 50 @BackgroundExecutor ListeningExecutorService backgroundExecutorService) { 51 this.appContext = appContext; 52 this.backgroundExecutorService = backgroundExecutorService; 53 } 54 55 /** 56 * Override the default implementation in {@link PhoneLookup#lookup(Context, Call)} as CNAP info 57 * is in the provided {@link Call}. 58 */ 59 @Override lookup(Context appContext, Call call)60 public ListenableFuture<CnapInfo> lookup(Context appContext, Call call) { 61 String callerDisplayName = call.getDetails().getCallerDisplayName(); 62 return Futures.immediateFuture( 63 TextUtils.isEmpty(callerDisplayName) 64 ? CnapInfo.getDefaultInstance() 65 : CnapInfo.newBuilder().setName(callerDisplayName).build()); 66 } 67 68 /** 69 * CNAP info cannot be retrieved when all we have is a number. The best we can do is returning the 70 * existing info in {@link PhoneLookupHistory}. 71 */ 72 @Override lookup(DialerPhoneNumber dialerPhoneNumber)73 public ListenableFuture<CnapInfo> lookup(DialerPhoneNumber dialerPhoneNumber) { 74 return backgroundExecutorService.submit( 75 () -> { 76 Selection selection = 77 Selection.builder() 78 .and( 79 Selection.column(PhoneLookupHistory.NORMALIZED_NUMBER) 80 .is("=", dialerPhoneNumber.getNormalizedNumber())) 81 .build(); 82 83 try (Cursor cursor = 84 appContext 85 .getContentResolver() 86 .query( 87 PhoneLookupHistory.CONTENT_URI, 88 new String[] {PhoneLookupHistory.PHONE_LOOKUP_INFO}, 89 selection.getSelection(), 90 selection.getSelectionArgs(), 91 /* sortOrder = */ null)) { 92 if (cursor == null) { 93 LogUtil.e("CnapPhoneLookup.lookup", "null cursor"); 94 return CnapInfo.getDefaultInstance(); 95 } 96 97 if (!cursor.moveToFirst()) { 98 LogUtil.i("CnapPhoneLookup.lookup", "empty cursor"); 99 return CnapInfo.getDefaultInstance(); 100 } 101 102 // At ths point, we expect only one row in the cursor as 103 // PhoneLookupHistory.NORMALIZED_NUMBER is the primary key of table PhoneLookupHistory. 104 Assert.checkState(cursor.getCount() == 1); 105 106 int phoneLookupInfoColumn = 107 cursor.getColumnIndexOrThrow(PhoneLookupHistory.PHONE_LOOKUP_INFO); 108 PhoneLookupInfo phoneLookupInfo; 109 try { 110 phoneLookupInfo = PhoneLookupInfo.parseFrom(cursor.getBlob(phoneLookupInfoColumn)); 111 } catch (InvalidProtocolBufferException e) { 112 throw new IllegalStateException(e); 113 } 114 115 return phoneLookupInfo.getCnapInfo(); 116 } 117 }); 118 } 119 120 @Override isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers)121 public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) { 122 return Futures.immediateFuture(false); 123 } 124 125 @Override getMostRecentInfo( ImmutableMap<DialerPhoneNumber, CnapInfo> existingInfoMap)126 public ListenableFuture<ImmutableMap<DialerPhoneNumber, CnapInfo>> getMostRecentInfo( 127 ImmutableMap<DialerPhoneNumber, CnapInfo> existingInfoMap) { 128 return Futures.immediateFuture(existingInfoMap); 129 } 130 131 @Override setSubMessage(PhoneLookupInfo.Builder destination, CnapInfo subMessage)132 public void setSubMessage(PhoneLookupInfo.Builder destination, CnapInfo subMessage) { 133 destination.setCnapInfo(subMessage); 134 } 135 136 @Override getSubMessage(PhoneLookupInfo phoneLookupInfo)137 public CnapInfo getSubMessage(PhoneLookupInfo phoneLookupInfo) { 138 return phoneLookupInfo.getCnapInfo(); 139 } 140 141 @Override onSuccessfulBulkUpdate()142 public ListenableFuture<Void> onSuccessfulBulkUpdate() { 143 return Futures.immediateFuture(null); 144 } 145 146 @Override registerContentObservers()147 public void registerContentObservers() { 148 // No content observers for CNAP info. 149 } 150 151 @Override unregisterContentObservers()152 public void unregisterContentObservers() { 153 // No content observers for CNAP info. 154 } 155 156 @Override clearData()157 public ListenableFuture<Void> clearData() { 158 return Futures.immediateFuture(null); 159 } 160 161 @Override getLoggingName()162 public String getLoggingName() { 163 return "CnapPhoneLookup"; 164 } 165 } 166