ValidateNotificationPeople.java revision 44d81a4b86f73ecf79861bc576c90b8f8e4ba761
1f953664dc17dca23bd724bd64f89189c16c83263Chris Wren/*
2f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* Copyright (C) 2014 The Android Open Source Project
3f953664dc17dca23bd724bd64f89189c16c83263Chris Wren*
4f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* Licensed under the Apache License, Version 2.0 (the "License");
5f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* you may not use this file except in compliance with the License.
6f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* You may obtain a copy of the License at
7f953664dc17dca23bd724bd64f89189c16c83263Chris Wren*
8f953664dc17dca23bd724bd64f89189c16c83263Chris Wren*      http://www.apache.org/licenses/LICENSE-2.0
9f953664dc17dca23bd724bd64f89189c16c83263Chris Wren*
10f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* Unless required by applicable law or agreed to in writing, software
11f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* distributed under the License is distributed on an "AS IS" BASIS,
12f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* See the License for the specific language governing permissions and
14f953664dc17dca23bd724bd64f89189c16c83263Chris Wren* limitations under the License.
15f953664dc17dca23bd724bd64f89189c16c83263Chris Wren*/
16f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
17f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenpackage com.android.server.notification;
18f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
19f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.app.Notification;
20f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.content.Context;
21f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.database.Cursor;
22f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.net.Uri;
23f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.os.Bundle;
24f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.ContactsContract;
25f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.ContactsContract.Contacts;
26f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.Settings;
27f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.text.TextUtils;
28f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.util.LruCache;
29f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.util.Slog;
30f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
31f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport com.android.server.notification.NotificationManagerService.NotificationRecord;
32f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
33f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport java.util.ArrayList;
34f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport java.util.LinkedList;
35f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
36f953664dc17dca23bd724bd64f89189c16c83263Chris Wren/**
37f953664dc17dca23bd724bd64f89189c16c83263Chris Wren * This {@link NotificationSignalExtractor} attempts to validate
38f953664dc17dca23bd724bd64f89189c16c83263Chris Wren * people references. Also elevates the priority of real people.
39f953664dc17dca23bd724bd64f89189c16c83263Chris Wren */
40f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenpublic class ValidateNotificationPeople implements NotificationSignalExtractor {
41f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final String TAG = "ValidateNotificationPeople";
42f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final boolean INFO = true;
43f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final boolean DEBUG = false;
44f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
45f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final boolean ENABLE_PEOPLE_VALIDATOR = true;
46f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final String SETTING_ENABLE_PEOPLE_VALIDATOR =
47f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            "validate_notification_people_enabled";
4844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.STARRED };
49f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final int MAX_PEOPLE = 10;
50f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final int PEOPLE_CACHE_SIZE = 200;
51f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
52f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final float NONE = 0f;
53f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static final float VALID_CONTACT = 0.5f;
5444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    private static final float STARRED_CONTACT = 1f;
55f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
56f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    protected boolean mEnabled;
57f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private Context mContext;
58f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
59f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    // maps raw person handle to resolved person object
60f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private LruCache<String, LookupResult> mPeopleCache;
61f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
62f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private RankingFuture validatePeople(NotificationRecord record) {
63f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        float affinity = NONE;
64f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        Bundle extras = record.getNotification().extras;
65f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (extras == null) {
66f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return null;
67f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
68f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
69f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        final String[] people = getExtraPeople(extras);
70f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (people == null || people.length == 0) {
71f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return null;
72f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
73f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
74f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (INFO) Slog.i(TAG, "Validating: " + record.sbn.getKey());
75f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        final LinkedList<String> pendingLookups = new LinkedList<String>();
76f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
77f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            final String handle = people[personIdx];
78f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (TextUtils.isEmpty(handle)) continue;
79f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
80f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            synchronized (mPeopleCache) {
81f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                LookupResult lookupResult = mPeopleCache.get(handle);
82f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                if (lookupResult == null || lookupResult.isExpired()) {
83f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    pendingLookups.add(handle);
84f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                } else {
85f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    if (DEBUG) Slog.d(TAG, "using cached lookupResult: " + lookupResult.mId);
86f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                }
87f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                if (lookupResult != null) {
88f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    affinity = Math.max(affinity, lookupResult.getAffinity());
89f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                }
90f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
91f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
92f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
93f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        // record the best available data, so far:
94f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        record.setContactAffinity(affinity);
95f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
96f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (pendingLookups.isEmpty()) {
97f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (INFO) Slog.i(TAG, "final affinity: " + affinity);
98f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return null;
99f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
100f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
101f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + record.sbn.getKey());
102f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        return new RankingFuture(record) {
103f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            @Override
104f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            public void work() {
105f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                if (INFO) Slog.i(TAG, "Executing: validation for: " + mRecord.sbn.getKey());
106f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                float affinity = NONE;
107f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                for (final String handle: pendingLookups) {
10844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                    LookupResult lookupResult = null;
109f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    final Uri uri = Uri.parse(handle);
110f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    if ("tel".equals(uri.getScheme())) {
111f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                        if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
11244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
11344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                    } else if ("mailto".equals(uri.getScheme())) {
11444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
11544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
116f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
117f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                        if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
11844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        lookupResult = searchContacts(uri);
119f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    } else {
12044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        lookupResult = new LookupResult();  // invalid person for the cache
121f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                        Slog.w(TAG, "unsupported URI " + handle);
122f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                    }
12344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                    if (lookupResult != null) {
12444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        synchronized (mPeopleCache) {
12544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                            mPeopleCache.put(handle, lookupResult);
12644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        }
12744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                        affinity = Math.max(affinity, lookupResult.getAffinity());
12844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                    }
129f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                }
130f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                float affinityBound = mRecord.getContactAffinity();
131f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                affinity = Math.max(affinity, affinityBound);
132f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                mRecord.setContactAffinity(affinity);
133f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                if (INFO) Slog.i(TAG, "final affinity: " + affinity);
134f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
135f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        };
136f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
137f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
138f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private String[] getExtraPeople(Bundle extras) {
139f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
140f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (people != null) {
141f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
142f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
143f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
144f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE);
145f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (stringArray != null) {
146f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return (String[]) stringArray.toArray();
147f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
148f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
149f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        String string = extras.getString(Notification.EXTRA_PEOPLE);
150f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (string != null) {
151f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people = new String[1];
152f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people[0] = string;
153f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
154f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
155f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE);
156f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (charArray != null) {
157f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people = new String[1];
158f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people[0] = new String(charArray);
159f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
160f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
161f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
162f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE);
163f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (charSeq != null) {
164f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people = new String[1];
165f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people[0] = charSeq.toString();
166f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
167f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
168f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
169f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE);
170f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (charSeqArray != null) {
171f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            final int N = charSeqArray.length;
172f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people = new String[N];
173f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            for (int i = 0; i < N; i++) {
174f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                people[i] = charSeqArray[i].toString();
175f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
176f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
177f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
178f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
179f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        ArrayList<CharSequence> charSeqList =
180f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE);
181f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (charSeqList != null) {
182f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            final int N = charSeqList.size();
183f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            people = new String[N];
184f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            for (int i = 0; i < N; i++) {
185f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                people[i] = charSeqList.get(i).toString();
186f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
187f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return people;
188f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
189f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        return null;
190f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
191f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
19244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    private LookupResult resolvePhoneContact(final String number) {
19344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
19444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                Uri.encode(number));
19544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        return searchContacts(phoneUri);
19644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    }
19744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren
19844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    private LookupResult resolveEmailContact(final String email) {
19944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        Uri numberUri = Uri.withAppendedPath(
20044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
20144d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                Uri.encode(email));
20244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        return searchContacts(numberUri);
203f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
204f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
20544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren    private LookupResult searchContacts(Uri lookupUri) {
20644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        LookupResult lookupResult = new LookupResult();
207f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        Cursor c = null;
208f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        try {
20944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            c = mContext.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null);
210f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (c != null && c.getCount() > 0) {
211f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                c.moveToFirst();
21244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                lookupResult.readContact(c);
213f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
214f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        } catch(Throwable t) {
215f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
216f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        } finally {
217f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (c != null) {
218f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                c.close();
219f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
220f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
221f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        return lookupResult;
222f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
223f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
224f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    public void initialize(Context context) {
225f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (DEBUG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
226f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        mContext = context;
227f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
228f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
229f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
230f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
231f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
232f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    public RankingFuture process(NotificationManagerService.NotificationRecord record) {
233f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (!mEnabled) {
234f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (INFO) Slog.i(TAG, "disabled");
235f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return null;
236f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
237f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        if (record == null || record.getNotification() == null) {
238f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (INFO) Slog.i(TAG, "skipping empty notification");
239f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return null;
240f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
241f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        return validatePeople(record);
242f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
243f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
244f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    private static class LookupResult {
245f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000;  // 1hr
246f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        public static final int INVALID_ID = -1;
247f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
248f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        private final long mExpireMillis;
249f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        private int mId;
25044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        private boolean mStarred;
251f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
25244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        public LookupResult() {
25344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            mId = INVALID_ID;
25444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            mStarred = false;
255f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
256f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
257f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
25844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        public void readContact(Cursor cursor) {
25944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            final int idIdx = cursor.getColumnIndex(Contacts._ID);
26044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            if (idIdx >= 0) {
26144d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                mId = cursor.getInt(idIdx);
26244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                if (DEBUG) Slog.d(TAG, "contact _ID is: " + mId);
26344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            } else {
26444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                if (DEBUG) Slog.d(TAG, "invalid cursor: no _ID");
26544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            }
26644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            final int starIdx = cursor.getColumnIndex(Contacts.STARRED);
26744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            if (starIdx >= 0) {
26844d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                mStarred = cursor.getInt(starIdx) != 0;
26944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                if (DEBUG) Slog.d(TAG, "contact STARRED is: " + mStarred);
27044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            } else {
27144d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                if (DEBUG) Slog.d(TAG, "invalid cursor: no STARRED");
27244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            }
27344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        }
27444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren
275f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        public boolean isExpired() {
276f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return mExpireMillis < System.currentTimeMillis();
277f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
278f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
279f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        public boolean isInvalid() {
280f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return mId == INVALID_ID || isExpired();
281f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
282f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
283f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        public float getAffinity() {
284f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            if (isInvalid()) {
285f953664dc17dca23bd724bd64f89189c16c83263Chris Wren                return NONE;
28644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            } else if (mStarred) {
28744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                return STARRED_CONTACT;
288f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            } else {
28944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren                return VALID_CONTACT;
290f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            }
291f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
292f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
29344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        public LookupResult setStarred(boolean starred) {
29444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            mStarred = starred;
29544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren            return this;
29644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren        }
29744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren
298f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        public LookupResult setId(int id) {
299f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            mId = id;
300f953664dc17dca23bd724bd64f89189c16c83263Chris Wren            return this;
301f953664dc17dca23bd724bd64f89189c16c83263Chris Wren        }
302f953664dc17dca23bd724bd64f89189c16c83263Chris Wren    }
303f953664dc17dca23bd724bd64f89189c16c83263Chris Wren}
304f953664dc17dca23bd724bd64f89189c16c83263Chris Wren
305