1/*
2 * Copyright (C) 2011 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
17package com.android.providers.contacts;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.provider.CallLog.Calls;
22import android.telephony.PhoneNumberUtils;
23import android.text.TextUtils;
24
25import com.android.i18n.phonenumbers.NumberParseException;
26import com.android.i18n.phonenumbers.PhoneNumberUtil;
27import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
28import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
29
30import com.google.android.collect.Sets;
31
32import java.util.Locale;
33import java.util.Set;
34
35/**
36 * Default implementation of {@link CallLogInsertionHelper}.
37 * <p>
38 * It added the country ISO abbreviation and the geocoded location.
39 * It checks for legacy unknown numbers and updates number presentation.
40 * <p>
41 * It uses {@link PhoneNumberOfflineGeocoder} to compute the geocoded location of a phone number.
42 */
43/*package*/ class DefaultCallLogInsertionHelper implements CallLogInsertionHelper {
44    private static DefaultCallLogInsertionHelper sInstance;
45
46    private static final Set<String> LEGACY_UNKNOWN_NUMBERS = Sets.newHashSet("-1", "-2", "-3");
47
48    private final CountryMonitor mCountryMonitor;
49    private PhoneNumberUtil mPhoneNumberUtil;
50    private PhoneNumberOfflineGeocoder mPhoneNumberOfflineGeocoder;
51    private final Locale mLocale;
52
53    public static synchronized DefaultCallLogInsertionHelper getInstance(Context context) {
54        if (sInstance == null) {
55            sInstance = new DefaultCallLogInsertionHelper(context);
56        }
57        return sInstance;
58    }
59
60    private DefaultCallLogInsertionHelper(Context context) {
61        mCountryMonitor = new CountryMonitor(context);
62        mLocale = context.getResources().getConfiguration().locale;
63    }
64
65    @Override
66    public void addComputedValues(ContentValues values) {
67        // Insert the current country code, so we know the country the number belongs to.
68        String countryIso = getCurrentCountryIso();
69        values.put(Calls.COUNTRY_ISO, countryIso);
70        // Insert the geocoded location, so that we do not need to compute it on the fly.
71        values.put(Calls.GEOCODED_LOCATION,
72                getGeocodedLocationFor(values.getAsString(Calls.NUMBER), countryIso));
73
74        final String number = values.getAsString(Calls.NUMBER);
75        if (LEGACY_UNKNOWN_NUMBERS.contains(number)) {
76            values.put(Calls.NUMBER_PRESENTATION, Calls.PRESENTATION_UNKNOWN);
77            values.put(Calls.NUMBER, "");
78        }
79
80        // Check for a normalized number; if not present attempt to determine one now.
81        if (!values.containsKey(Calls.CACHED_NORMALIZED_NUMBER) &&
82                !TextUtils.isEmpty(number)) {
83            String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
84            if (!TextUtils.isEmpty(normalizedNumber)) {
85                values.put(Calls.CACHED_NORMALIZED_NUMBER, normalizedNumber);
86            }
87        }
88    }
89
90    private String getCurrentCountryIso() {
91        return mCountryMonitor.getCountryIso();
92    }
93
94    private synchronized PhoneNumberUtil getPhoneNumberUtil() {
95        if (mPhoneNumberUtil == null) {
96            mPhoneNumberUtil = PhoneNumberUtil.getInstance();
97        }
98        return mPhoneNumberUtil;
99    }
100
101    private PhoneNumber parsePhoneNumber(String number, String countryIso) {
102        try {
103            return getPhoneNumberUtil().parse(number, countryIso);
104        } catch (NumberParseException e) {
105            return null;
106        }
107    }
108
109    private synchronized PhoneNumberOfflineGeocoder getPhoneNumberOfflineGeocoder() {
110        if (mPhoneNumberOfflineGeocoder == null) {
111            mPhoneNumberOfflineGeocoder = PhoneNumberOfflineGeocoder.getInstance();
112        }
113        return mPhoneNumberOfflineGeocoder;
114    }
115
116    @Override
117    public String getGeocodedLocationFor(String number, String countryIso) {
118        PhoneNumber structuredPhoneNumber = parsePhoneNumber(number, countryIso);
119        if (structuredPhoneNumber != null) {
120            return getPhoneNumberOfflineGeocoder().getDescriptionForNumber(
121                    structuredPhoneNumber, mLocale);
122        } else {
123            return null;
124        }
125    }
126}
127