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; 21da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wrenimport android.content.pm.PackageManager; 2299f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wrenimport android.database.ContentObserver; 23f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.database.Cursor; 24f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.net.Uri; 2512aeda802ed91a49977a22166319ce74a3352e30Christoph Studerimport android.os.AsyncTask; 26f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.os.Bundle; 2799f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wrenimport android.os.Handler; 28da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wrenimport android.os.UserHandle; 29f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.ContactsContract; 30f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.ContactsContract.Contacts; 31f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.provider.Settings; 32f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.text.TextUtils; 33da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wrenimport android.util.ArrayMap; 3422f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynoldsimport android.util.ArraySet; 35da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wrenimport android.util.Log; 36f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.util.LruCache; 37f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport android.util.Slog; 38f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 39f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport java.util.ArrayList; 4022f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynoldsimport java.util.Arrays; 41f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenimport java.util.LinkedList; 4222f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynoldsimport java.util.List; 43da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wrenimport java.util.Map; 4422f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynoldsimport java.util.Set; 4512aeda802ed91a49977a22166319ce74a3352e30Christoph Studerimport java.util.concurrent.Semaphore; 4612aeda802ed91a49977a22166319ce74a3352e30Christoph Studerimport java.util.concurrent.TimeUnit; 47f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 4866dfcc50dff82e50cd64d14b9aeea1c795876364Chris Wrenimport android.os.SystemClock; 4966dfcc50dff82e50cd64d14b9aeea1c795876364Chris Wren 50f953664dc17dca23bd724bd64f89189c16c83263Chris Wren/** 51f953664dc17dca23bd724bd64f89189c16c83263Chris Wren * This {@link NotificationSignalExtractor} attempts to validate 52f953664dc17dca23bd724bd64f89189c16c83263Chris Wren * people references. Also elevates the priority of real people. 5392af372fc60f59c628a7169d4a506e9c834c097aChris Wren * 5492af372fc60f59c628a7169d4a506e9c834c097aChris Wren * {@hide} 55f953664dc17dca23bd724bd64f89189c16c83263Chris Wren */ 56f953664dc17dca23bd724bd64f89189c16c83263Chris Wrenpublic class ValidateNotificationPeople implements NotificationSignalExtractor { 5712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer // Using a shorter log tag since setprop has a limit of 32chars on variable name. 5812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer private static final String TAG = "ValidateNoPeople"; 591a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);; 6012aeda802ed91a49977a22166319ce74a3352e30Christoph Studer private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 61f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 62f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static final boolean ENABLE_PEOPLE_VALIDATOR = true; 63f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static final String SETTING_ENABLE_PEOPLE_VALIDATOR = 64f953664dc17dca23bd724bd64f89189c16c83263Chris Wren "validate_notification_people_enabled"; 6544d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.STARRED }; 66f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static final int MAX_PEOPLE = 10; 67f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static final int PEOPLE_CACHE_SIZE = 200; 68f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 6999f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren /** Indicates that the notification does not reference any valid contacts. */ 7099f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren static final float NONE = 0f; 7199f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren 7299f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren /** 7399f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren * Affinity will be equal to or greater than this value on notifications 7499f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren * that reference a valid contact. 7599f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren */ 7699f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren static final float VALID_CONTACT = 0.5f; 7799f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren 7899f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren /** 7999f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren * Affinity will be equal to or greater than this value on notifications 8099f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren * that reference a starred contact. 8199f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren */ 8299f963ea04d7a86219ece00c356f3f6bce33b6d6Chris Wren static final float STARRED_CONTACT = 1f; 83f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 84f953664dc17dca23bd724bd64f89189c16c83263Chris Wren protected boolean mEnabled; 85da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private Context mBaseContext; 86f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 87f953664dc17dca23bd724bd64f89189c16c83263Chris Wren // maps raw person handle to resolved person object 88f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private LruCache<String, LookupResult> mPeopleCache; 89da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private Map<Integer, Context> mUserToContextMap; 9099f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren private Handler mHandler; 9199f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren private ContentObserver mObserver; 9299f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren private int mEvictionCount; 935eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren private NotificationUsageStats mUsageStats; 94f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 955eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren public void initialize(Context context, NotificationUsageStats usageStats) { 96da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); 97da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mUserToContextMap = new ArrayMap<>(); 98da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mBaseContext = context; 995eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren mUsageStats = usageStats; 100da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE); 101da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt( 102da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1); 10399f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren if (mEnabled) { 10499f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mHandler = new Handler(); 10599f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mObserver = new ContentObserver(mHandler) { 10699f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren @Override 10799f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren public void onChange(boolean selfChange, Uri uri, int userId) { 10899f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren super.onChange(selfChange, uri, userId); 10999f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren if (DEBUG || mEvictionCount % 100 == 0) { 1101a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "mEvictionCount: " + mEvictionCount); 11199f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren } 11299f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mPeopleCache.evictAll(); 11399f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mEvictionCount++; 11499f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren } 11599f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren }; 11699f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mBaseContext.getContentResolver().registerContentObserver(Contacts.CONTENT_URI, true, 11799f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren mObserver, UserHandle.USER_ALL); 11899f4c7d0c9c9c29ced22da0a8af4d1a04b0ef186Chris Wren } 119da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 120da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 121da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren public RankingReconsideration process(NotificationRecord record) { 122da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (!mEnabled) { 1231a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "disabled"); 124da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return null; 125da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 126da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (record == null || record.getNotification() == null) { 1271a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "skipping empty notification"); 128da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return null; 129da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 130da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (record.getUserId() == UserHandle.USER_ALL) { 1311a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "skipping global notification"); 132da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return null; 133da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 134da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren Context context = getContextAsUser(record.getUser()); 135da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (context == null) { 1361a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "skipping notification that lacks a context"); 137da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return null; 138da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 139da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return validatePeople(context, record); 140da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 141da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 142da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren @Override 143da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren public void setConfig(RankingConfig config) { 144da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren // ignore: config has no relevant information yet. 145da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 146da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 14712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer /** 14812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer * @param extras extras of the notification with EXTRA_PEOPLE populated 14912aeda802ed91a49977a22166319ce74a3352e30Christoph Studer * @param timeoutMs timeout in milliseconds to wait for contacts response 15012aeda802ed91a49977a22166319ce74a3352e30Christoph Studer * @param timeoutAffinity affinity to return when the timeout specified via 15112aeda802ed91a49977a22166319ce74a3352e30Christoph Studer * <code>timeoutMs</code> is hit 15212aeda802ed91a49977a22166319ce74a3352e30Christoph Studer */ 15312aeda802ed91a49977a22166319ce74a3352e30Christoph Studer public float getContactAffinity(UserHandle userHandle, Bundle extras, int timeoutMs, 15412aeda802ed91a49977a22166319ce74a3352e30Christoph Studer float timeoutAffinity) { 1557381daa0b99ef5beb224ffd2544a156af40e78d1Chris Wren if (DEBUG) Slog.d(TAG, "checking affinity for " + userHandle); 156da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (extras == null) return NONE; 157da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren final String key = Long.toString(System.nanoTime()); 158da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren final float[] affinityOut = new float[1]; 159da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren Context context = getContextAsUser(userHandle); 160da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (context == null) { 161da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return NONE; 162da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 16322f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds final PeopleRankingReconsideration prr = 16422f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds validatePeople(context, key, extras, null, affinityOut); 165da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren float affinity = affinityOut[0]; 16612aeda802ed91a49977a22166319ce74a3352e30Christoph Studer 167da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (prr != null) { 16812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer // Perform the heavy work on a background thread so we can abort when we hit the 16912aeda802ed91a49977a22166319ce74a3352e30Christoph Studer // timeout. 17012aeda802ed91a49977a22166319ce74a3352e30Christoph Studer final Semaphore s = new Semaphore(0); 17112aeda802ed91a49977a22166319ce74a3352e30Christoph Studer AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 17212aeda802ed91a49977a22166319ce74a3352e30Christoph Studer @Override 17312aeda802ed91a49977a22166319ce74a3352e30Christoph Studer public void run() { 17412aeda802ed91a49977a22166319ce74a3352e30Christoph Studer prr.work(); 17512aeda802ed91a49977a22166319ce74a3352e30Christoph Studer s.release(); 17612aeda802ed91a49977a22166319ce74a3352e30Christoph Studer } 17712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer }); 17812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer 17912aeda802ed91a49977a22166319ce74a3352e30Christoph Studer try { 18012aeda802ed91a49977a22166319ce74a3352e30Christoph Studer if (!s.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 18112aeda802ed91a49977a22166319ce74a3352e30Christoph Studer Slog.w(TAG, "Timeout while waiting for affinity: " + key + ". " 18212aeda802ed91a49977a22166319ce74a3352e30Christoph Studer + "Returning timeoutAffinity=" + timeoutAffinity); 18312aeda802ed91a49977a22166319ce74a3352e30Christoph Studer return timeoutAffinity; 18412aeda802ed91a49977a22166319ce74a3352e30Christoph Studer } 18512aeda802ed91a49977a22166319ce74a3352e30Christoph Studer } catch (InterruptedException e) { 18612aeda802ed91a49977a22166319ce74a3352e30Christoph Studer Slog.w(TAG, "InterruptedException while waiting for affinity: " + key + ". " 18712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer + "Returning affinity=" + affinity, e); 18812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer return affinity; 18912aeda802ed91a49977a22166319ce74a3352e30Christoph Studer } 19012aeda802ed91a49977a22166319ce74a3352e30Christoph Studer 191da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren affinity = Math.max(prr.getContactAffinity(), affinity); 192da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 193da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return affinity; 194da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 195da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 196da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private Context getContextAsUser(UserHandle userHandle) { 197da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren Context context = mUserToContextMap.get(userHandle.getIdentifier()); 198da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren if (context == null) { 199da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren try { 200da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren context = mBaseContext.createPackageContextAsUser("android", 0, userHandle); 201da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mUserToContextMap.put(userHandle.getIdentifier(), context); 202da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } catch (PackageManager.NameNotFoundException e) { 203da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren Log.e(TAG, "failed to create package context for lookups", e); 204da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 205da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 206da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return context; 207da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 208da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 209da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private RankingReconsideration validatePeople(Context context, 210da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren final NotificationRecord record) { 2112b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock final String key = record.getKey(); 2122b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock final Bundle extras = record.getNotification().extras; 2132b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock final float[] affinityOut = new float[1]; 21422f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds final PeopleRankingReconsideration rr = 21522f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds validatePeople(context, key, extras, record.getPeopleOverride(), affinityOut); 2165eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren final float affinity = affinityOut[0]; 2175eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren record.setContactAffinity(affinity); 2185eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren if (rr == null) { 2195eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren mUsageStats.registerPeopleAffinity(record, affinity > NONE, affinity == STARRED_CONTACT, 2205eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren true /* cached */); 2215eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren } else { 2225eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren rr.setRecord(record); 2235eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren } 2242b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock return rr; 2252b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 2262b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 227da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras, 22822f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds List<String> peopleOverride, float[] affinityOut) { 22966dfcc50dff82e50cd64d14b9aeea1c795876364Chris Wren long start = SystemClock.elapsedRealtime(); 230f953664dc17dca23bd724bd64f89189c16c83263Chris Wren float affinity = NONE; 231f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (extras == null) { 232f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return null; 233f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 23422f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds final Set<String> people = new ArraySet<>(peopleOverride); 23522f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds final String[] notificationPeople = getExtraPeople(extras); 23622f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds if (notificationPeople != null ) { 23722f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds people.addAll(Arrays.asList(getExtraPeople(extras))); 238f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 239f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 2401a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId()); 241f953664dc17dca23bd724bd64f89189c16c83263Chris Wren final LinkedList<String> pendingLookups = new LinkedList<String>(); 24222f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds int personIdx = 0; 24322f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds for (String handle : people) { 244f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (TextUtils.isEmpty(handle)) continue; 245f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 246f953664dc17dca23bd724bd64f89189c16c83263Chris Wren synchronized (mPeopleCache) { 247da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren final String cacheKey = getCacheKey(context.getUserId(), handle); 248da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren LookupResult lookupResult = mPeopleCache.get(cacheKey); 249f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (lookupResult == null || lookupResult.isExpired()) { 250f953664dc17dca23bd724bd64f89189c16c83263Chris Wren pendingLookups.add(handle); 251f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } else { 2529ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer if (DEBUG) Slog.d(TAG, "using cached lookupResult"); 253f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 254f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (lookupResult != null) { 255f953664dc17dca23bd724bd64f89189c16c83263Chris Wren affinity = Math.max(affinity, lookupResult.getAffinity()); 256f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 257f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 25822f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds if (++personIdx == MAX_PEOPLE) { 25922f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds break; 26022f02b3e4acd7c6983f4d4d58b85069d5ec920abJulia Reynolds } 261f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 262f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 263f953664dc17dca23bd724bd64f89189c16c83263Chris Wren // record the best available data, so far: 2642b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock affinityOut[0] = affinity; 265f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 266f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (pendingLookups.isEmpty()) { 2671a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity); 268f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return null; 269f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 270f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 2712b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + key); 272da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return new PeopleRankingReconsideration(context, key, pendingLookups); 273da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren } 274da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren 275da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private String getCacheKey(int userId, String handle) { 276da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return Integer.toString(userId) + ":" + handle; 277f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 278f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 27992af372fc60f59c628a7169d4a506e9c834c097aChris Wren // VisibleForTesting 28092af372fc60f59c628a7169d4a506e9c834c097aChris Wren public static String[] getExtraPeople(Bundle extras) { 281fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren Object people = extras.get(Notification.EXTRA_PEOPLE); 282fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof String[]) { 283fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return (String[]) people; 284f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 285f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 286fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof ArrayList) { 287fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren ArrayList arrayList = (ArrayList) people; 288fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren 289fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (arrayList.isEmpty()) { 290fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return null; 291fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren } 292fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren 293fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (arrayList.get(0) instanceof String) { 294fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren ArrayList<String> stringArray = (ArrayList<String>) arrayList; 295fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return stringArray.toArray(new String[stringArray.size()]); 296fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren } 297fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren 298fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (arrayList.get(0) instanceof CharSequence) { 299fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren ArrayList<CharSequence> charSeqList = (ArrayList<CharSequence>) arrayList; 300fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren final int N = charSeqList.size(); 301fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren String[] array = new String[N]; 302fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren for (int i = 0; i < N; i++) { 303fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren array[i] = charSeqList.get(i).toString(); 304fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren } 305fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return array; 306fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren } 307fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren 308fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return null; 309f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 310f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 311fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof String) { 312fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren String[] array = new String[1]; 313fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren array[0] = (String) people; 314fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return array; 315f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 316fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren 317fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof char[]) { 318fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren String[] array = new String[1]; 319fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren array[0] = new String((char[]) people); 320fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return array; 321f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 322f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 323fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof CharSequence) { 324fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren String[] array = new String[1]; 325fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren array[0] = ((CharSequence) people).toString(); 326fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return array; 327f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 328f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 329fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren if (people instanceof CharSequence[]) { 330fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren CharSequence[] charSeqArray = (CharSequence[]) people; 331f953664dc17dca23bd724bd64f89189c16c83263Chris Wren final int N = charSeqArray.length; 332fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren String[] array = new String[N]; 333f953664dc17dca23bd724bd64f89189c16c83263Chris Wren for (int i = 0; i < N; i++) { 334fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren array[i] = charSeqArray[i].toString(); 335f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 336fb69da323b97ae4712054d37fb2f7d54cddb7dbdChris Wren return array; 337f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 338f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 339f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return null; 340f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 341f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 342da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private LookupResult resolvePhoneContact(Context context, final String number) { 34344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 34444d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren Uri.encode(number)); 345da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return searchContacts(context, phoneUri); 34644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } 34744d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren 348da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private LookupResult resolveEmailContact(Context context, final String email) { 34944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren Uri numberUri = Uri.withAppendedPath( 35044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, 35144d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren Uri.encode(email)); 352da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren return searchContacts(context, numberUri); 353f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 354f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 355da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private LookupResult searchContacts(Context context, Uri lookupUri) { 35644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren LookupResult lookupResult = new LookupResult(); 357f953664dc17dca23bd724bd64f89189c16c83263Chris Wren Cursor c = null; 358f953664dc17dca23bd724bd64f89189c16c83263Chris Wren try { 359da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null); 3609ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer if (c == null) { 3619ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer Slog.w(TAG, "Null cursor from contacts query."); 3629ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer return lookupResult; 363f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 3649ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer while (c.moveToNext()) { 3659ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer lookupResult.mergeContact(c); 3669ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer } 3679ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer } catch (Throwable t) { 368f953664dc17dca23bd724bd64f89189c16c83263Chris Wren Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t); 369f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } finally { 370f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (c != null) { 371f953664dc17dca23bd724bd64f89189c16c83263Chris Wren c.close(); 372f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 373f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 374f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return lookupResult; 375f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 376f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 377f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static class LookupResult { 378f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr 379f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 380f953664dc17dca23bd724bd64f89189c16c83263Chris Wren private final long mExpireMillis; 3819ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer private float mAffinity = NONE; 382f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 38344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren public LookupResult() { 384f953664dc17dca23bd724bd64f89189c16c83263Chris Wren mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS; 385f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 386f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 3879ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer public void mergeContact(Cursor cursor) { 3889ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer mAffinity = Math.max(mAffinity, VALID_CONTACT); 3899ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer 3909ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer // Contact ID 3919ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer int id; 39244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren final int idIdx = cursor.getColumnIndex(Contacts._ID); 39344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren if (idIdx >= 0) { 3949ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer id = cursor.getInt(idIdx); 3959ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer if (DEBUG) Slog.d(TAG, "contact _ID is: " + id); 39644d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } else { 3979ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer id = -1; 3989ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer Slog.i(TAG, "invalid cursor: no _ID"); 39944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } 4009ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer 4019ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer // Starred 40244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren final int starIdx = cursor.getColumnIndex(Contacts.STARRED); 40344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren if (starIdx >= 0) { 4049ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer boolean isStarred = cursor.getInt(starIdx) != 0; 4059ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer if (isStarred) { 4069ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer mAffinity = Math.max(mAffinity, STARRED_CONTACT); 4079ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer } 4089ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer if (DEBUG) Slog.d(TAG, "contact STARRED is: " + isStarred); 40944d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } else { 41044d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren if (DEBUG) Slog.d(TAG, "invalid cursor: no STARRED"); 41144d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } 41244d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren } 41344d81a4b86f73ecf79861bc576c90b8f8e4ba761Chris Wren 4149ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer private boolean isExpired() { 415f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return mExpireMillis < System.currentTimeMillis(); 416f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 417f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 4189ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer private boolean isInvalid() { 4199ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer return mAffinity == NONE || isExpired(); 420f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 421f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 422f953664dc17dca23bd724bd64f89189c16c83263Chris Wren public float getAffinity() { 423f953664dc17dca23bd724bd64f89189c16c83263Chris Wren if (isInvalid()) { 424f953664dc17dca23bd724bd64f89189c16c83263Chris Wren return NONE; 425f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 4269ffa50096f5ad980bdaef4d214ad1a835b9b2991Christoph Studer return mAffinity; 427f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 428f953664dc17dca23bd724bd64f89189c16c83263Chris Wren } 4292b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 4302b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock private class PeopleRankingReconsideration extends RankingReconsideration { 4312b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock private final LinkedList<String> mPendingLookups; 432da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private final Context mContext; 4332b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 4342b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock private float mContactAffinity = NONE; 4355eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren private NotificationRecord mRecord; 4362b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 437da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) { 4382b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock super(key); 439da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mContext = context; 4402b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock mPendingLookups = pendingLookups; 4412b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4422b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 4432b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock @Override 4442b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock public void work() { 44566dfcc50dff82e50cd64d14b9aeea1c795876364Chris Wren long start = SystemClock.elapsedRealtime(); 4461a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey); 44712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer long timeStartMs = System.currentTimeMillis(); 4482b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock for (final String handle: mPendingLookups) { 4492b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock LookupResult lookupResult = null; 4502b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock final Uri uri = Uri.parse(handle); 4512b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if ("tel".equals(uri.getScheme())) { 4522b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle); 453da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart()); 4542b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } else if ("mailto".equals(uri.getScheme())) { 4552b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle); 456da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart()); 4572b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) { 4582b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle); 459da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren lookupResult = searchContacts(mContext, uri); 4602b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } else { 4612b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock lookupResult = new LookupResult(); // invalid person for the cache 4622b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock Slog.w(TAG, "unsupported URI " + handle); 4632b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4642b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock if (lookupResult != null) { 4652b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock synchronized (mPeopleCache) { 466da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren final String cacheKey = getCacheKey(mContext.getUserId(), handle); 467da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8dChris Wren mPeopleCache.put(cacheKey, lookupResult); 4682b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 469f37dae7b60280279a100fb7870122f4e495c81ecChris Wren if (DEBUG) Slog.d(TAG, "lookup contactAffinity is " + lookupResult.getAffinity()); 4702b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity()); 471f37dae7b60280279a100fb7870122f4e495c81ecChris Wren } else { 472f37dae7b60280279a100fb7870122f4e495c81ecChris Wren if (DEBUG) Slog.d(TAG, "lookupResult is null"); 4732b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4742b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 47512aeda802ed91a49977a22166319ce74a3352e30Christoph Studer if (DEBUG) { 47612aeda802ed91a49977a22166319ce74a3352e30Christoph Studer Slog.d(TAG, "Validation finished in " + (System.currentTimeMillis() - timeStartMs) + 47712aeda802ed91a49977a22166319ce74a3352e30Christoph Studer "ms"); 47812aeda802ed91a49977a22166319ce74a3352e30Christoph Studer } 479723aa768f6d5b1a6696b9ac46c039d1b5be73dbfChris Wren 4805eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren if (mRecord != null) { 4815eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren mUsageStats.registerPeopleAffinity(mRecord, mContactAffinity > NONE, 4825eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren mContactAffinity == STARRED_CONTACT, false /* cached */); 4835eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren } 4842b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4852b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 4862b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock @Override 4872b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock public void applyChangesLocked(NotificationRecord operand) { 4882b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock float affinityBound = operand.getContactAffinity(); 4892b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock operand.setContactAffinity(Math.max(mContactAffinity, affinityBound)); 4901a5dad867419e76928c84f0f4fdc4feacce43bbdChris Wren if (VERBOSE) Slog.i(TAG, "final affinity: " + operand.getContactAffinity()); 4912b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4922b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock 4932b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock public float getContactAffinity() { 4942b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock return mContactAffinity; 4952b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 4965eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren 4975eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren public void setRecord(NotificationRecord record) { 4985eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren mRecord = record; 4995eab2b72afe5b20dc66c237b1cceedfc09de2d52Chris Wren } 5002b122f4c2e691f0319e4f9ea5873989792bb56a6John Spurlock } 501f953664dc17dca23bd724bd64f89189c16c83263Chris Wren} 502f953664dc17dca23bd724bd64f89189c16c83263Chris Wren 503