blob: 647ca5b8dd85cdddcd6e453c1fec86a925d42a91 [file] [log] [blame]
/*
* Copyright (C) 2014 Xiao-Long Chen <chillermillerlong@hotmail.com>
* Copyright (C) 2023 The LineageOS 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.dialer.lookup;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.logging.ContactLookupResult;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.incallui.bindings.PhoneNumberService;
import java.io.IOException;
public class ReverseLookupService implements PhoneNumberService, Handler.Callback {
private final HandlerThread backgroundThread;
private final Handler backgroundHandler;
private final Handler handler;
private final Context context;
private final TelephonyManager telephonyManager;
private static final int MSG_LOOKUP = 1;
private static final int MSG_NOTIFY_NUMBER = 2;
public ReverseLookupService(Context context) {
this.context = context;
telephonyManager = context.getSystemService(TelephonyManager.class);
// TODO: stop after a while?
backgroundThread = new HandlerThread("ReverseLookup");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper(), this);
handler = new Handler(Looper.getMainLooper(), this);
}
@Override
public void getPhoneNumberInfo(String phoneNumber, NumberLookupListener numberListener) {
if (!LookupSettings.isReverseLookupEnabled(context)) {
LookupCache.deleteCachedContacts(context);
return;
}
String countryIso = telephonyManager.getSimCountryIso().toUpperCase();
String normalizedNumber = phoneNumber != null
? PhoneNumberUtils.formatNumberToE164(phoneNumber, countryIso) : null;
// Can't do reverse lookup without a number
if (normalizedNumber == null) {
return;
}
LookupRequest request = new LookupRequest();
request.normalizedNumber = normalizedNumber;
request.formattedNumber = PhoneNumberUtils.formatNumber(phoneNumber,
request.normalizedNumber, GeoUtil.getCurrentCountryIso(context));
request.numberListener = numberListener;
backgroundHandler.obtainMessage(MSG_LOOKUP, request).sendToTarget();
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOOKUP: {
// background thread
LookupRequest request = (LookupRequest) msg.obj;
request.contactInfo = doLookup(request);
if (request.contactInfo != null) {
handler.obtainMessage(MSG_NOTIFY_NUMBER, request).sendToTarget();
}
break;
}
case MSG_NOTIFY_NUMBER: {
// main thread
LookupRequest request = (LookupRequest) msg.obj;
if (request.numberListener != null) {
LookupNumberInfo info = new LookupNumberInfo(request.contactInfo);
request.numberListener.onPhoneNumberInfoComplete(info);
}
break;
}
}
return true;
}
private ContactInfo doLookup(LookupRequest request) {
final String number = request.normalizedNumber;
if (LookupCache.hasCachedContact(context, number)) {
ContactInfo info = LookupCache.getCachedContact(context, number);
if (!ContactInfo.EMPTY.equals(info)) {
return info;
} else if (info != null) {
// If we have an empty cached contact, remove it and redo lookup
LookupCache.deleteCachedContact(context, number);
}
}
try {
ReverseLookup inst = ReverseLookup.getInstance(context);
ContactInfo info = inst.lookupNumber(context, number, request.formattedNumber);
if (info != null && !info.equals(ContactInfo.EMPTY)) {
LookupCache.cacheContact(context, info);
return info;
}
} catch (IOException e) {
// ignored
}
return null;
}
private Bitmap fetchImage(LookupRequest request, Uri uri) {
if (!LookupCache.hasCachedImage(context, request.normalizedNumber)) {
Bitmap bmp = ReverseLookup.getInstance(context).lookupImage(context, uri);
if (bmp != null) {
LookupCache.cacheImage(context, request.normalizedNumber, bmp);
}
}
return LookupCache.getCachedImage(context, request.normalizedNumber);
}
private static class LookupRequest {
String normalizedNumber;
String formattedNumber;
NumberLookupListener numberListener;
ContactInfo contactInfo;
}
private static class LookupNumberInfo implements PhoneNumberInfo {
private final ContactInfo info;
private LookupNumberInfo(ContactInfo info) {
this.info = info;
}
@Override
public String getDisplayName() {
return info.name;
}
@Override
public String getNumber() {
return info.number;
}
@Override
public int getPhoneType() {
return info.type;
}
@Override
public String getPhoneLabel() {
return info.label;
}
@Override
public String getNormalizedNumber() {
return info.normalizedNumber;
}
@Override
public String getImageUrl() {
return info.photoUri != null ? info.photoUri.toString() : null;
}
@Override
public boolean isBusiness() {
// FIXME
return false;
}
@Override
public String getLookupKey() {
return info.lookupKey;
}
@Override
public ContactLookupResult.Type getLookupSource() {
return ContactLookupResult.Type.REMOTE;
}
}
}