diff options
31 files changed, 530 insertions, 435 deletions
@@ -18,6 +18,7 @@ android_app { "android-common", "com.android.vcard", "guava", + "android.content.pm.flags-aconfig-java", ], // The Jacoco tool analyzes code coverage when running unit tests on the diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg new file mode 100644 index 00000000..e5f1877f --- /dev/null +++ b/PREUPLOAD.cfg @@ -0,0 +1,2 @@ +[Hook Scripts] +checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..22fe0274 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Debugging Tools +## Enable all verbose logs +Running `./logging.sh` will enable all verbose logs for the queries in the provider. +More details in the script itself. + +## Querying the database +There are 2 different ways to easily query the database, `qc` and `contatcsproviderutils.sh`. + +### QC usage +`qc` queries the deivce directly. For usage, append the query in single quotes after the command: + +e.g. +``` +qc/qc 'select * from raw_contacts' +``` + +or to get all the tables +``` +qc/qc '.tables' +``` +QC support SQLite language, but it might have some limitations working with complex nested queries. + +### contactsproviderutils.sh usage + +This script downlaods the database locally and logins into a local version. It is also possible to push any change back to the device. + +* Add tools to path + ``` + source contactsproviderutils.sh + ``` +* Pull `contacts2.db` and query: + ``` + sqlite3-pull + ``` + This will open a sql terminal with `rlwrap` which can be easily used for queries. +* Pull `contacts2.db` and query with a graphical interface: + ``` + sqlitebrowser-pull + ``` +* Push local updates to the device: + ``` + sqlite3-push + ``` + diff --git a/contactsproviderutils.sh b/contactsproviderutils.sh new file mode 100644 index 00000000..e77e08fd --- /dev/null +++ b/contactsproviderutils.sh @@ -0,0 +1,83 @@ +# Shell utility functions for contactsprovider developers. +# sudo apt-get install rlwrap to have a more fully featured sqlite CLI +# sudo apt-get install sqlitebrowser to explore the database with GUI + +CONTACTS_DB="contacts2.db" + +function contacts-pull () { + adb root && adb wait-for-device + dir=$(get-dir $1) + package=$(get-package) + + if [ -f "$dir/$CONTACTS_DB" ]; then + rm "$dir/$CONTACTS_DB" + fi + if [ -f "$dir/$CONTACTS_DB-wal" ]; then + rm "$dir/$CONTACTS_DB-wal" + fi + adb pull /data/user/0/$package/databases/$CONTACTS_DB $dir/$CONTACTS_DB + adb pull /data/user/0/$package/databases/$CONTACTS_DB-wal $dir/$CONTACTS_DB-wal +} + +function get-dir (){ + if [ -z "$1" ] + then + dir=$(pwd) + else + dir=$1 + fi + echo "$dir" +} + +function sqlite3-pull () { + dir="$(get-dir $1)" + contacts-pull $dir + rlwrap sqlite3 $dir/$CONTACTS_DB +} + +function sqlitebrowser-pull () { + dir="$(get-dir $1)" + contacts-pull $dir + sqlitebrowser $dir/$CONTACTS_DB +} + +function sqlite3-push () { + adb root && adb wait-for-device + if [ -z "$1" ] + then + dir=$(pwd) + else + dir=$1 + fi + package=$(get-package) + + adb push $dir/$CONTACTS_DB /data/user/0/$package/databases/$CONTACTS_DB + adb push $dir/$CONTACTS_DB-wal /data/user/0/$package/databases/$CONTACTS_DB-wal + + sqlite3-trigger-upgrade +} + +function sqlite3-trigger-upgrade () { + package=$(get-package) + + # Doesn't actually upgrade the db because db version is hardcoded in code + # It however triggers upgrade path + check_string="/data/user/0/$package/databases/$CONTACTS_DB \"pragma user_version\"" + version=$(adb shell sqlite3 $check_string) + echo "Old version: $version" + + version=$((version+1)) + upgrade_string="/data/user/0/$package/databases/$CONTACTS_DB \"pragma user_version=$version\"" + adb shell sqlite3 $upgrade_string + + version=$(adb shell sqlite3 $check_string) + echo "New version: $version" + + adb shell am force-stop $package +} + +function get-package() { + echo "com.android.providers.contacts" +} + +set +x # disable debugging diff --git a/logging.sh b/logging.sh new file mode 100755 index 00000000..eb341b9f --- /dev/null +++ b/logging.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -x +adb root && adb wait-for-device + +adb shell setprop log.tag.ContactsProvider VERBOSE && adb shell killall android.process.acore + +adb shell setprop log.tag.SQLiteSlowQueries VERBOSE +CONTACTS_UID=`adb shell pm list packages -U | sed -ne 's/^package:com\.android\.providers\.contacts *uid://p'` +adb shell setprop db.log.slow_query_threshold.$CONTACTS_UID 0 +adb shell setprop db.log.detailed 1 # to show more details in the "slow query" log + +# adb shell setprop log.tag.SQLiteQueryBuilder VERBOSE # Redundant if slowlog +# enabled +adb shell setprop log.tag.SQLiteConnection VERBOSE + + @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e + +user_path=data +file=contacts2.db +pass="" + +adb root && adb wait-for-device + +while getopts "theqvpu:" opt; do + case "$opt" in + t|h|e|q|v) + pass="$pass -$opt" + ;; + p) # Open profile DB instead. + file=profile.db + ;; + u) # Open for a secondary user + user_path="user/$OPTARG" + ;; + *) + exit 1 + esac +done +shift $(($OPTIND - 1)) + +$(dirname "$0")/qdb $pass /data/$user_path/com.android.providers.contacts/databases/$file "$*" @@ -0,0 +1,100 @@ +#!/bin/bash + +set -e + +html=0 +output="" +prefix="" +time="" +local=0 + +verbose=0 + +filter="cat" +pager="${QDB_PAGER:-${PAGER:-cat}}" + +# Table output mode by default +sep="〠" +output="-list -separator $sep" +filter="column -t -s $sep" + +while getopts "lcheqtv" opt; do + case "$opt" in + l) + local=1 + ;; + h) + html=1 + output="-html" + filter="cat" + pager="${HTML_VIEWER:-$pager}" + ;; + e) + prefix="EXPLAIN " + ;; + q) + prefix="EXPLAIN QUERY PLAN " + ;; + t) # Run with the time command. + time="time" + ;; + v) + verbose=1 + ;; + *) + exit 1 + esac +done +shift $(($OPTIND - 1)) + +db="$1" +shift + +if ! [[ -t 1 ]] ; then + pager="cat" +fi + +if (( $verbose )) ; then + echo "DB: $db" 1>&2 +fi + +query="$*" + +run_query() { + if (( $local )) ; then + test -f "$db" && $time sqlite3 $output -nullvalue "[NULL]" -header "$db" "$prefix$query" + else + query=$(sed -e "s!'!\'\\\'\'!g" <<<"$query") # Escape for shell + adb shell -T "(" test -f "$db" "&&" $time sqlite3 $output -nullvalue "[NULL]" -header "$db" \'"$prefix$query"\' ")" "2>&1" + fi +} + +{ + if (( $html )) ; then + cat <<EOF +<head> +<style> +body { + font:8pt monospace; +} + +table { + border: 1px solid black; + border-collapse: collapse; +} +</style> +</head> +<body> +<table border="1"> +EOF + + run_query + + cat <<EOF +</table> +<body> +EOF + else + run_query + fi +} | $filter | $pager diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index d5dbf950..bcaedf7a 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -19,7 +19,7 @@ <string name="sharedUserLabel" msgid="8024311725474286801">"Androidi tuumrakendused"</string> <string name="app_label" msgid="3389954322874982620">"Kontaktiruum"</string> <string name="provider_label" msgid="6012150850819899907">"Kontaktid"</string> - <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"Kontaktisikute uuendamiseks on vaja rohkem mälu"</string> + <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"Kontaktisikute uuendamiseks on vaja rohkem mäluruumi."</string> <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"Kontaktide salvestusruumi uuendamine"</string> <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"Puudutage täiendamise lõpetamiseks."</string> <string name="default_directory" msgid="93961630309570294">"Kontaktid"</string> diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index fd716daf..4fd36c1c 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -18,11 +18,11 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="sharedUserLabel" msgid="8024311725474286801">"एन्ड्रोइड कोर एपहरू"</string> <string name="app_label" msgid="3389954322874982620">"सम्पर्कहरू भण्डारण"</string> - <string name="provider_label" msgid="6012150850819899907">"सम्पर्कहरू"</string> + <string name="provider_label" msgid="6012150850819899907">"कन्ट्याक्टहरू"</string> <string name="upgrade_out_of_memory_notification_ticker" msgid="7638747231223520477">"सम्पर्क अद्यावधिकका लागि अझै धेरै मेमोरी चाहिन्छ।"</string> <string name="upgrade_out_of_memory_notification_title" msgid="8888171924684998531">"सम्पर्कका लागि भणडारण अद्यावधिक गर्दै"</string> <string name="upgrade_out_of_memory_notification_text" msgid="2581831842693151968">"स्तरवृद्धि पूरा गर्न ट्याप गर्नुहोस्।"</string> - <string name="default_directory" msgid="93961630309570294">"सम्पर्कहरू"</string> + <string name="default_directory" msgid="93961630309570294">"कन्ट्याक्टहरू"</string> <string name="local_invisible_directory" msgid="705244318477396120">"अन्य"</string> <string name="voicemail_from_column" msgid="435732568832121444">"बाट भ्वाइसमेल "</string> <string name="debug_dump_title" msgid="4916885724165570279">"सम्पर्क डेटाबेस प्रतिलिप गर्नुहोस्"</string> diff --git a/src/com/android/providers/contacts/ContactDirectoryManager.java b/src/com/android/providers/contacts/ContactDirectoryManager.java index 09e3ff37..5dcf788c 100644 --- a/src/com/android/providers/contacts/ContactDirectoryManager.java +++ b/src/com/android/providers/contacts/ContactDirectoryManager.java @@ -19,6 +19,8 @@ package com.android.providers.contacts; import android.annotation.NonNull; import android.content.ContentValues; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -39,6 +41,7 @@ import android.util.Log; import com.android.providers.contacts.ContactsDatabaseHelper.DbProperties; import com.android.providers.contacts.ContactsDatabaseHelper.DirectoryColumns; import com.android.providers.contacts.ContactsDatabaseHelper.Tables; + import com.google.android.collect.Lists; import com.google.android.collect.Sets; import com.google.common.annotations.VisibleForTesting; @@ -418,7 +421,8 @@ public class ContactDirectoryManager { * Scans the specified package for content directories and updates the {@link Directory} * table accordingly. */ - private List<DirectoryInfo> updateDirectoriesForPackage( + @VisibleForTesting + List<DirectoryInfo> updateDirectoriesForPackage( PackageInfo packageInfo, boolean initialScan) { if (DEBUG) { Log.d(TAG, "updateDirectoriesForPackage packageName=" + packageInfo.packageName @@ -427,6 +431,15 @@ public class ContactDirectoryManager { ArrayList<DirectoryInfo> directories = Lists.newArrayList(); + if (Flags.stayStopped() + && (packageInfo.applicationInfo != null + && ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0))) { + if (DEBUG) { + Log.d(TAG, "Package " + packageInfo.packageName + " is in stopped state"); + } + return null; + } + ProviderInfo[] providers = packageInfo.providers; if (providers != null) { for (ProviderInfo provider : providers) { diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java index 802b2488..9446462b 100644 --- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java +++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java @@ -152,9 +152,10 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { * 1400-1499 Q * 1500-1599 S * 1600-1699 T + * 1700-1799 V * </pre> */ - static final int DATABASE_VERSION = 1604; + static final int DATABASE_VERSION = 1701; private static final int MINIMUM_SUPPORTED_VERSION = 700; @VisibleForTesting @@ -882,7 +883,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { public static boolean isBasedOnStructuredName(int nameLookupType) { return nameLookupType == NameLookupType.NAME_EXACT - || nameLookupType == NameLookupType.NAME_VARIANT || nameLookupType == NameLookupType.NAME_COLLATION_KEY; } } @@ -890,13 +890,11 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { private class StructuredNameLookupBuilder extends NameLookupBuilder { // NOTE(gilad): Is in intentional that we don't use the declaration on L960? private final SQLiteStatement mNameLookupInsert; - private final CommonNicknameCache mCommonNicknameCache; public StructuredNameLookupBuilder(NameSplitter splitter, - CommonNicknameCache commonNicknameCache, SQLiteStatement nameLookupInsert) { + SQLiteStatement nameLookupInsert) { super(splitter); - this.mCommonNicknameCache = commonNicknameCache; this.mNameLookupInsert = nameLookupInsert; } @@ -909,11 +907,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { mNameLookupInsert, rawContactId, dataId, lookupType, name); } } - - @Override - protected String[] getCommonNicknameClusters(String normalizedName) { - return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); - } } private static final String TAG = "ContactsDatabaseHelper"; @@ -1518,16 +1511,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { NameLookupColumns.RAW_CONTACT_ID + ");"); - db.execSQL("CREATE TABLE " + Tables.NICKNAME_LOOKUP + " (" + - NicknameLookupColumns.NAME + " TEXT," + - NicknameLookupColumns.CLUSTER + " TEXT" + - ");"); - - db.execSQL("CREATE UNIQUE INDEX nickname_lookup_index ON " + Tables.NICKNAME_LOOKUP + " (" + - NicknameLookupColumns.NAME + ", " + - NicknameLookupColumns.CLUSTER + - ");"); - // Groups table. db.execSQL("CREATE TABLE " + Tables.GROUPS + " (" + Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + @@ -1632,8 +1615,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { createContactsIndexes(db, false /* we build stats table later */); createPresenceTables(db); - loadNicknameLookupTable(db); - // Set sequence starts. initializeAutoIncrementSequences(db); @@ -2684,6 +2665,16 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { oldVersion = 1604; } + if (isUpgradeRequired(oldVersion, newVersion, 1700)){ + upgradeToVersion1700(db); + oldVersion = 1700; + } + + if (isUpgradeRequired(oldVersion, newVersion, 1701)) { + upgradeLocaleSpecificData = true; + oldVersion = 1701; + } + // We extracted "calls" and "voicemail_status" at this point, but we can't remove them here // yet, until CallLogDatabaseHelper moves the data. @@ -2792,7 +2783,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP INDEX raw_contact_sort_key2_index"); db.execSQL("DROP INDEX IF EXISTS name_lookup_index"); - loadNicknameLookupTable(db); insertNameLookup(db); rebuildSortKeys(db); createContactsIndexes(db, rebuildSqliteStats); @@ -2871,8 +2861,8 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { */ private void insertStructuredNameLookup(SQLiteDatabase db, SQLiteStatement nameLookupInsert) { NameSplitter nameSplitter = createNameSplitter(); - NameLookupBuilder nameLookupBuilder = new StructuredNameLookupBuilder(nameSplitter, - new CommonNicknameCache(db), nameLookupInsert); + NameLookupBuilder nameLookupBuilder = new StructuredNameLookupBuilder( + nameSplitter, nameLookupInsert); final long mimeTypeId = lookupMimeTypeId(db, StructuredName.CONTENT_ITEM_TYPE); Cursor cursor = db.query(StructuredNameQuery.TABLE, StructuredNameQuery.COLUMNS, StructuredNameQuery.SELECTION, new String[] {String.valueOf(mimeTypeId)}, @@ -3535,6 +3525,22 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { mPhoneAccountHandleMigrationUtils.migrateIccIdToSubId(db); } + private void upgradeToVersion1700(SQLiteDatabase db) { + try { + /** + * Deprecate nickname database: + * Delete the name variant rows and the name variant table itself. + */ + db.execSQL("DROP TABLE " + Tables.NICKNAME_LOOKUP); + db.execSQL( + "DELETE FROM " + Tables.NAME_LOOKUP + " WHERE " + + NameLookupColumns.NAME_TYPE + " = " + NameLookupType.NAME_VARIANT); + } catch (SQLException ignore) { + Log.v(TAG, "Version 1700: Failed to delete NICKNAME_LOOKUP table and " + + "name variant rows from NAME_LOOKUP table"); + } + } + protected void migrateIccIdToSubId() { mPhoneAccountHandleMigrationUtils.migrateIccIdToSubId(getWritableDatabase()); } @@ -3771,9 +3777,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { updateIndexStats(db, Tables.GROUPS, "groups_source_id_account_id_index", "50 2 2 1 1"); - updateIndexStats(db, Tables.NICKNAME_LOOKUP, - "nickname_lookup_index", "500 2 1"); - updateIndexStats(db, Tables.STATUS_UPDATES, null, "100"); @@ -3989,16 +3992,24 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { return id; } + public long getMimeTypeIdForStructuredName(SQLiteDatabase db) { + return lookupMimeTypeId(db, StructuredName.CONTENT_ITEM_TYPE); + } + public long getMimeTypeIdForStructuredName() { - return lookupMimeTypeId(getWritableDatabase(), StructuredName.CONTENT_ITEM_TYPE); + return getMimeTypeIdForStructuredName(getWritableDatabase()); } public long getMimeTypeIdForStructuredPostal() { return lookupMimeTypeId(getWritableDatabase(), StructuredPostal.CONTENT_ITEM_TYPE); } + public long getMimeTypeIdForOrganization(SQLiteDatabase db) { + return lookupMimeTypeId(db, Organization.CONTENT_ITEM_TYPE); + } + public long getMimeTypeIdForOrganization() { - return lookupMimeTypeId(getWritableDatabase(), Organization.CONTENT_ITEM_TYPE); + return getMimeTypeIdForOrganization(getWritableDatabase()); } public long getMimeTypeIdForIm() { @@ -4584,42 +4595,6 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { return String.valueOf(mMinMatch); } - /** - * Loads common nickname mappings into the database. - */ - private void loadNicknameLookupTable(SQLiteDatabase db) { - db.execSQL("DELETE FROM " + Tables.NICKNAME_LOOKUP); - - String[] strings = mContext.getResources().getStringArray( - com.android.internal.R.array.common_nicknames); - if (strings == null || strings.length == 0) { - return; - } - - final SQLiteStatement nicknameLookupInsert = db.compileStatement("INSERT INTO " - + Tables.NICKNAME_LOOKUP + "(" + NicknameLookupColumns.NAME + "," - + NicknameLookupColumns.CLUSTER + ") VALUES (?,?)"); - - try { - for (int clusterId = 0; clusterId < strings.length; clusterId++) { - String[] names = strings[clusterId].split(","); - for (String name : names) { - String normalizedName = NameNormalizer.normalize(name); - try { - nicknameLookupInsert.bindString(1, normalizedName); - nicknameLookupInsert.bindString(2, String.valueOf(clusterId)); - nicknameLookupInsert.executeInsert(); - } catch (SQLiteException e) { - // Print the exception and keep going (this is not a fatal error). - Log.e(TAG, "Cannot insert nickname: " + name, e); - } - } - } - } finally { - nicknameLookupInsert.close(); - } - } - public static void copyStringValue( ContentValues toValues, String toKey, ContentValues fromValues, String fromKey) { @@ -4869,7 +4844,7 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { continue; } - if (mimeType == getMimeTypeIdForStructuredName()) { + if (mimeType == getMimeTypeIdForStructuredName(db)) { NameSplitter.Name name; if (bestName != null) { name = new NameSplitter.Name(); @@ -4895,7 +4870,7 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { bestDisplayNameSource = source; bestName = name; } - } else if (mimeType == getMimeTypeIdForOrganization()) { + } else if (mimeType == getMimeTypeIdForOrganization(db)) { mCharArrayBuffer.sizeCopied = 0; c.copyStringToBuffer(RawContactNameQuery.DATA1, mCharArrayBuffer); if (mCharArrayBuffer.sizeCopied != 0) { @@ -4980,12 +4955,18 @@ public class ContactsDatabaseHelper extends SQLiteOpenHelper { if (displayNameAlternative == null) { displayNameAlternative = bestPhoneticName; } - // Phonetic names disregard name order so displayNamePrimary and displayNameAlternative - // are the same. - sortKeyPrimary = sortKeyAlternative = bestPhoneticName; + /* Phonetic names disregard name order so displayNamePrimary and displayNameAlternative + are the same. + Logographic phonetic names(example Japanese), if present, will be used for ordering + of contacts in the list. Otherwise, the deduced primary name is used. + */ + sortKeyPrimary = sortKeyAlternative = sortNamePrimary; if (bestPhoneticNameStyle == PhoneticNameStyle.UNDEFINED) { bestPhoneticNameStyle = mNameSplitter.guessPhoneticNameStyle(bestPhoneticName); } + if (bestPhoneticNameStyle == PhoneticNameStyle.JAPANESE) { + sortKeyPrimary = sortKeyAlternative = bestPhoneticName; + } } else { bestPhoneticNameStyle = PhoneticNameStyle.UNDEFINED; if (displayNameStyle == FullNameStyle.UNDEFINED) { diff --git a/src/com/android/providers/contacts/ContactsPackageMonitor.java b/src/com/android/providers/contacts/ContactsPackageMonitor.java index 06565cd9..93c7df90 100644 --- a/src/com/android/providers/contacts/ContactsPackageMonitor.java +++ b/src/com/android/providers/contacts/ContactsPackageMonitor.java @@ -95,6 +95,7 @@ public class ContactsPackageMonitor { private void registerReceiver() { final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_UNSTOPPED); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java index 7b6dce38..cf49fb56 100644 --- a/src/com/android/providers/contacts/ContactsProvider2.java +++ b/src/com/android/providers/contacts/ContactsProvider2.java @@ -46,6 +46,7 @@ import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.content.SyncAdapterType; import android.content.UriMatcher; +import android.content.pm.Flags; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; @@ -175,7 +176,6 @@ import com.android.providers.contacts.aggregation.AbstractContactAggregator.Aggr import com.android.providers.contacts.aggregation.ContactAggregator; import com.android.providers.contacts.aggregation.ContactAggregator2; import com.android.providers.contacts.aggregation.ProfileAggregator; -import com.android.providers.contacts.aggregation.util.CommonNicknameCache; import com.android.providers.contacts.database.ContactsTableUtil; import com.android.providers.contacts.database.DeletedContactsTableUtil; import com.android.providers.contacts.database.MoreDatabaseUtils; @@ -187,13 +187,10 @@ import com.android.providers.contacts.util.DbQueryUtils; import com.android.providers.contacts.util.LogFields; import com.android.providers.contacts.util.LogUtils; import com.android.providers.contacts.util.NeededForTesting; -import com.android.providers.contacts.util.PhoneAccountHandleMigrationUtils; import com.android.providers.contacts.util.UserUtils; import com.android.vcard.VCardComposer; import com.android.vcard.VCardConfig; -import libcore.io.IoUtils; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -201,6 +198,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.primitives.Ints; +import libcore.io.IoUtils; + import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; @@ -1499,7 +1498,6 @@ public class ContactsProvider2 extends AbstractContactsProvider private LegacyApiSupport mLegacyApiSupport; private GlobalSearchSupport mGlobalSearchSupport; - private CommonNicknameCache mCommonNicknameCache; private SearchIndexManager mSearchIndexManager; private int mProviderStatus = STATUS_NORMAL; @@ -1677,9 +1675,9 @@ public class ContactsProvider2 extends AbstractContactsProvider public void setNewAggregatorForTest(boolean enabled) { mContactAggregator = (enabled) ? new ContactAggregator2(this, mContactsHelper, - createPhotoPriorityResolver(getContext()), mNameSplitter, mCommonNicknameCache) + createPhotoPriorityResolver(getContext()), mNameSplitter) : new ContactAggregator(this, mContactsHelper, - createPhotoPriorityResolver(getContext()), mNameSplitter, mCommonNicknameCache); + createPhotoPriorityResolver(getContext()), mNameSplitter); mContactAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true)); initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator, mContactsPhotoStore); @@ -1696,7 +1694,6 @@ public class ContactsProvider2 extends AbstractContactsProvider mNameSplitter = mContactsHelper.createNameSplitter(mCurrentLocales.getPrimaryLocale()); mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); mPostalSplitter = new PostalSplitter(mCurrentLocales.getPrimaryLocale()); - mCommonNicknameCache = new CommonNicknameCache(mContactsHelper.getReadableDatabase()); ContactLocaleUtils.setLocales(mCurrentLocales); int value = android.provider.Settings.Global.getInt(context.getContentResolver(), @@ -1708,13 +1705,13 @@ public class ContactsProvider2 extends AbstractContactsProvider : AGGREGATION_ALGORITHM_NEW_VERSION; mContactAggregator = (value == 0) ? new ContactAggregator(this, mContactsHelper, - createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache) + createPhotoPriorityResolver(context), mNameSplitter) : new ContactAggregator2(this, mContactsHelper, - createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); + createPhotoPriorityResolver(context), mNameSplitter); mContactAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true)); mProfileAggregator = new ProfileAggregator(this, mProfileHelper, - createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); + createPhotoPriorityResolver(context), mNameSplitter); mProfileAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true)); mSearchIndexManager = new SearchIndexManager(this); mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper); @@ -5941,6 +5938,22 @@ public class ContactsProvider2 extends AbstractContactsProvider return null; } + if (projection == null) { + projection = getDefaultProjection(uri); + } + + // Handle directories in stopped state + try { + if (Flags.stayStopped() + && getContext().getPackageManager() + .isPackageStopped(directoryInfo.packageName)) { + return new MatrixCursor(projection, 0); + } + } catch (NameNotFoundException e) { + Log.w(TAG, "Package name " + directoryInfo.packageName + " not found"); + } + + Builder builder = new Uri.Builder(); builder.scheme(ContentResolver.SCHEME_CONTENT); builder.authority(directoryInfo.authority); @@ -5964,9 +5977,6 @@ public class ContactsProvider2 extends AbstractContactsProvider Uri directoryUri = builder.build(); - if (projection == null) { - projection = getDefaultProjection(uri); - } int galUid = -1; try { galUid = getContext().getPackageManager().getPackageUid(directoryInfo.packageName, @@ -9836,11 +9846,6 @@ public class ContactsProvider2 extends AbstractContactsProvider String name) { mDbHelper.get().insertNameLookup(rawContactId, dataId, lookupType, name); } - - @Override - protected String[] getCommonNicknameClusters(String normalizedName) { - return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); - } } public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { diff --git a/src/com/android/providers/contacts/DefaultCallLogInsertionHelper.java b/src/com/android/providers/contacts/DefaultCallLogInsertionHelper.java index 1e232759..b1922aaf 100644 --- a/src/com/android/providers/contacts/DefaultCallLogInsertionHelper.java +++ b/src/com/android/providers/contacts/DefaultCallLogInsertionHelper.java @@ -26,6 +26,7 @@ import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder; +import com.android.internal.annotations.VisibleForTesting; import com.google.android.collect.Sets; @@ -57,11 +58,23 @@ import java.util.Set; return sInstance; } + @VisibleForTesting + public static DefaultCallLogInsertionHelper getTestInstance(Context context, + CountryMonitor countryMonitor) { + return new DefaultCallLogInsertionHelper(context, countryMonitor); + } + + private DefaultCallLogInsertionHelper(Context context) { mCountryMonitor = new CountryMonitor(context); mLocale = context.getResources().getConfiguration().locale; } + private DefaultCallLogInsertionHelper(Context context, CountryMonitor countryMonitor) { + mCountryMonitor = countryMonitor; + mLocale = context.getResources().getConfiguration().locale; + } + @Override public void addComputedValues(ContentValues values) { // Insert the current country code, so we know the country the number belongs to. diff --git a/src/com/android/providers/contacts/NameLookupBuilder.java b/src/com/android/providers/contacts/NameLookupBuilder.java index fb266da1..85da56ee 100644 --- a/src/com/android/providers/contacts/NameLookupBuilder.java +++ b/src/com/android/providers/contacts/NameLookupBuilder.java @@ -83,17 +83,6 @@ public abstract class NameLookupBuilder { String string); /** - * Returns common nickname cluster IDs for a given name. For example, it - * will return the same value for "Robert", "Bob" and "Rob". Some names belong to multiple - * clusters, e.g. Leo could be Leonard or Leopold. - * - * May return null. - * - * @param normalizedName A normalized first name, see {@link NameNormalizer#normalize}. - */ - protected abstract String[] getCommonNicknameClusters(String normalizedName); - - /** * Inserts name lookup records for the given structured name. */ public void insertNameLookup(long rawContactId, long dataId, String name, int fullNameStyle) { @@ -130,13 +119,7 @@ public abstract class NameLookupBuilder { tokenCount = MAX_NAME_TOKENS; } - // Phase I: insert all variants not involving nickname clusters - for (int i = 0; i < tokenCount; i++) { - mNicknameClusters[i] = getCommonNicknameClusters(mNames[i]); - } - insertNameVariants(rawContactId, dataId, 0, tokenCount, !tooManyTokens, true); - insertNicknamePermutations(rawContactId, dataId, 0, tokenCount); } public void appendToSearchIndex(IndexBuilder builder, String name, int fullNameStyle) { @@ -296,30 +279,6 @@ public abstract class NameLookupBuilder { } /** - * For all tokens that correspond to nickname clusters, substitutes each cluster key - * and inserts all permutations with that key. - */ - private void insertNicknamePermutations(long rawContactId, long dataId, int fromIndex, - int tokenCount) { - for (int i = fromIndex; i < tokenCount; i++) { - String[] clusters = mNicknameClusters[i]; - if (clusters != null) { - String token = mNames[i]; - for (int j = 0; j < clusters.length; j++) { - mNames[i] = clusters[j]; - - // Insert all permutations with this nickname cluster - insertNameVariants(rawContactId, dataId, 0, tokenCount, false, false); - - // Repeat recursively for other nickname clusters - insertNicknamePermutations(rawContactId, dataId, i + 1, tokenCount); - } - mNames[i] = token; - } - } - } - - /** * Insert more name indexes according to locale specifies for those locales * for which we have alternative shorthand name methods (eg, Pinyin for * Chinese, Romaji for Japanese). diff --git a/src/com/android/providers/contacts/aggregation/AbstractContactAggregator.java b/src/com/android/providers/contacts/aggregation/AbstractContactAggregator.java index 82e35f13..502a946b 100644 --- a/src/com/android/providers/contacts/aggregation/AbstractContactAggregator.java +++ b/src/com/android/providers/contacts/aggregation/AbstractContactAggregator.java @@ -93,7 +93,6 @@ public abstract class AbstractContactAggregator { protected static final String STRUCTURED_NAME_BASED_LOOKUP_SQL = NameLookupColumns.NAME_TYPE + " IN (" + NameLookupType.NAME_EXACT + "," - + NameLookupType.NAME_VARIANT + "," + NameLookupType.NAME_COLLATION_KEY + ")"; @@ -146,7 +145,6 @@ public abstract class AbstractContactAggregator { protected final ContactsDatabaseHelper mDbHelper; protected PhotoPriorityResolver mPhotoPriorityResolver; protected final NameSplitter mNameSplitter; - protected final CommonNicknameCache mCommonNicknameCache; protected boolean mEnabled = true; @@ -274,13 +272,11 @@ public abstract class AbstractContactAggregator { */ public AbstractContactAggregator(ContactsProvider2 contactsProvider, ContactsDatabaseHelper contactsDatabaseHelper, - PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter, - CommonNicknameCache commonNicknameCache) { + PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter) { mContactsProvider = contactsProvider; mDbHelper = contactsDatabaseHelper; mPhotoPriorityResolver = photoPriorityResolver; mNameSplitter = nameSplitter; - mCommonNicknameCache = commonNicknameCache; SQLiteDatabase db = mDbHelper.getReadableDatabase(); @@ -1086,11 +1082,6 @@ public abstract class AbstractContactAggregator { } @Override - protected String[] getCommonNicknameClusters(String normalizedName) { - return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); - } - - @Override protected void insertNameLookup( long rawContactId, long dataId, int lookupType, String string) { mNameLookupCandidates.add(string, lookupType); diff --git a/src/com/android/providers/contacts/aggregation/ContactAggregator.java b/src/com/android/providers/contacts/aggregation/ContactAggregator.java index a1043395..b02033e4 100644 --- a/src/com/android/providers/contacts/aggregation/ContactAggregator.java +++ b/src/com/android/providers/contacts/aggregation/ContactAggregator.java @@ -66,10 +66,8 @@ public class ContactAggregator extends AbstractContactAggregator { */ public ContactAggregator(ContactsProvider2 contactsProvider, ContactsDatabaseHelper contactsDatabaseHelper, - PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter, - CommonNicknameCache commonNicknameCache) { - super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter, - commonNicknameCache); + PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter) { + super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter); } /** diff --git a/src/com/android/providers/contacts/aggregation/ContactAggregator2.java b/src/com/android/providers/contacts/aggregation/ContactAggregator2.java index 6b1424c4..cb649cad 100644 --- a/src/com/android/providers/contacts/aggregation/ContactAggregator2.java +++ b/src/com/android/providers/contacts/aggregation/ContactAggregator2.java @@ -78,10 +78,8 @@ public class ContactAggregator2 extends AbstractContactAggregator { */ public ContactAggregator2(ContactsProvider2 contactsProvider, ContactsDatabaseHelper contactsDatabaseHelper, - PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter, - CommonNicknameCache commonNicknameCache) { - super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter, - commonNicknameCache); + PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter) { + super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter); } /** diff --git a/src/com/android/providers/contacts/aggregation/ProfileAggregator.java b/src/com/android/providers/contacts/aggregation/ProfileAggregator.java index 276a05f2..12375a49 100644 --- a/src/com/android/providers/contacts/aggregation/ProfileAggregator.java +++ b/src/com/android/providers/contacts/aggregation/ProfileAggregator.java @@ -38,10 +38,8 @@ public class ProfileAggregator extends ContactAggregator { public ProfileAggregator(ContactsProvider2 contactsProvider, ContactsDatabaseHelper contactsDatabaseHelper, - PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter, - CommonNicknameCache commonNicknameCache) { - super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter, - commonNicknameCache); + PhotoPriorityResolver photoPriorityResolver, NameSplitter nameSplitter) { + super(contactsProvider, contactsDatabaseHelper, photoPriorityResolver, nameSplitter); } @Override diff --git a/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java b/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java index c5837edd..fea29904 100644 --- a/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java +++ b/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java @@ -100,8 +100,6 @@ public class ContactMatcher { static { setScoreRange(NameLookupType.NAME_EXACT, NameLookupType.NAME_EXACT, 99, 99); - setScoreRange(NameLookupType.NAME_VARIANT, - NameLookupType.NAME_VARIANT, 90, 90); setScoreRange(NameLookupType.NAME_COLLATION_KEY, NameLookupType.NAME_COLLATION_KEY, 50, 80); diff --git a/src/com/android/providers/contacts/aggregation/util/RawContactMatcher.java b/src/com/android/providers/contacts/aggregation/util/RawContactMatcher.java index b483ba83..ef5dd87b 100644 --- a/src/com/android/providers/contacts/aggregation/util/RawContactMatcher.java +++ b/src/com/android/providers/contacts/aggregation/util/RawContactMatcher.java @@ -104,8 +104,6 @@ public class RawContactMatcher { static { setScoreRange(NameLookupType.NAME_EXACT, NameLookupType.NAME_EXACT, 99, 99); - setScoreRange(NameLookupType.NAME_VARIANT, - NameLookupType.NAME_VARIANT, 90, 90); setScoreRange(NameLookupType.NAME_COLLATION_KEY, NameLookupType.NAME_COLLATION_KEY, 50, 80); diff --git a/tests/Android.bp b/tests/Android.bp index beb2d313..06d19540 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -9,6 +9,8 @@ android_test { "ContactsProviderTestUtils", "androidx.test.rules", "mockito-target-minus-junit4", + "flag-junit", + "android.content.pm.flags-aconfig-java", ], libs: [ "android.test.runner", diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java index e8920530..9f433987 100644 --- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java @@ -55,11 +55,13 @@ import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.Settings; import android.provider.ContactsContract.StatusUpdates; import android.provider.ContactsContract.StreamItems; -import android.provider.VoicemailContract; import android.telephony.SubscriptionManager; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; import android.util.Log; + +import androidx.test.platform.app.InstrumentationRegistry; + import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; import com.android.providers.contacts.ContactsDatabaseHelper.Tables; import com.android.providers.contacts.testutil.CommonDatabaseUtils; @@ -68,23 +70,23 @@ import com.android.providers.contacts.testutil.RawContactUtil; import com.android.providers.contacts.testutil.TestUtil; import com.android.providers.contacts.util.Hex; import com.android.providers.contacts.util.MockClock; + import com.google.android.collect.Sets; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - /** * A common superclass for {@link ContactsProvider2}-related tests. */ @@ -103,6 +105,7 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { static final String WRITE_VOICEMAIL_PERMISSION = "com.android.voicemail.permission.WRITE_VOICEMAIL"; + protected Context mContext; protected static final String PACKAGE = "ContactsProvider2Test"; public static final String READ_ONLY_ACCOUNT_TYPE = SynchronousContactsProvider2.READ_ONLY_ACCOUNT_TYPE; @@ -136,9 +139,11 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { @Override protected void setUp() throws Exception { super.setUp(); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + MockitoAnnotations.initMocks(this); - mTestContext = new ContextWithServiceOverrides(getContext()); + mTestContext = new ContextWithServiceOverrides(mContext); mTestContext.injectSystemService(SubscriptionManager.class, mSubscriptionManager); mActor = new ContactsActor( diff --git a/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java b/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java index 6122ff05..eed6a848 100644 --- a/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java +++ b/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java @@ -28,8 +28,8 @@ public class CallLogInsertionHelperTest extends FixedAndroidTestCase { * The default insertion helper under test. */ private CallLogInsertionHelper mInsertionHelper = - DefaultCallLogInsertionHelper.getInstance(this.getContext()); - + DefaultCallLogInsertionHelper.getTestInstance( + this.getTestContext(), new MockCountryMonitor(this.getTestContext())); /** * Tests cases where valid, normalizable phone numbers are provided. */ @@ -66,7 +66,6 @@ public class CallLogInsertionHelperTest extends FixedAndroidTestCase { ContentValues values = new ContentValues(); values.put(Calls.NUMBER, number); mInsertionHelper.addComputedValues(values); - assertEquals(expectedNormalized, values.getAsString(Calls.CACHED_NORMALIZED_NUMBER)); } } diff --git a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java index a4165ce5..e2434960 100644 --- a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java +++ b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java @@ -16,9 +16,12 @@ package com.android.providers.contacts; +import static android.content.pm.Flags.FLAG_STAY_STOPPED; + import android.accounts.Account; import android.content.ContentValues; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -27,21 +30,29 @@ import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.os.Bundle; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.ContactsContract; import android.provider.ContactsContract.AggregationExceptions; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.RawContacts; import android.test.mock.MockContentProvider; -import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; import com.google.android.collect.Lists; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.util.Arrays; import java.util.Set; @@ -52,8 +63,11 @@ import java.util.Set; -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner * */ -@MediumTest +@RunWith(AndroidJUnit4.class) public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private static final String TAG = "ContactDirectoryManagerTest"; private ContactsMockPackageManager mPackageManager; @@ -114,8 +128,10 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { } } + @Before @Override public void setUp() throws Exception { + super.setUp(); mProvider = (ContactsProvider2) getProvider(); @@ -129,9 +145,10 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { protected String getContextPackageName() { // In this test, we need to use the real package name, because that'll be recorded in the // directory table, and if it's wrong, the tests would get confused. - return getContext().getPackageName(); + return mContext.getPackageName(); } + @Test public void testIsDirectoryProvider() { ProviderInfo provider = new ProviderInfo(); @@ -158,6 +175,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { assertTrue(ContactDirectoryManager.isDirectoryProvider(provider)); } + @Test public void testScanAllProviders() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -209,13 +227,13 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); assertTrue(cursor.moveToPosition(3)); - assertDirectoryRow(cursor, getContext().getPackageName(), + assertDirectoryRow(cursor, mContext.getPackageName(), "com.android.contacts", null, null, null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); assertTrue(cursor.moveToPosition(4)); - assertDirectoryRow(cursor, getContext().getPackageName(), + assertDirectoryRow(cursor, mContext.getPackageName(), "com.android.contacts", null, null, null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); @@ -223,6 +241,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testScanAllProviders_scanCondition() throws Exception { testScanAllProviders(); @@ -254,6 +273,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { } + @Test public void testPackageInstalled() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -305,6 +325,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testPackageUninstalled() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -351,6 +372,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testPackageReplaced() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -409,6 +431,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { * Tests if the manager works correctly when the package name for a directory is changed * (on system update). */ + @Test public void testPackageRenamed() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -472,6 +495,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testAccountRemoval() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -513,6 +537,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testNotifyDirectoryChange() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -547,6 +572,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testForwardingToDirectoryProvider() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -587,6 +613,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testProjectionPopulated() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -625,8 +652,9 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { * Test {@link ContactDirectoryManager#getDirectoryProviderPackages} with the actual * package manager, and see if it returns the google sync package. */ + @Test public void testGetDirectoryProviderPackages() { - final PackageManager pm = getContext().getPackageManager(); + final PackageManager pm = mContext.getPackageManager(); final String googleSync = "com.google.android.gms"; // Skip if the package is not installed. @@ -650,6 +678,55 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { dirProviderPackages.contains(googleSync)); } + @Test + public void testUpdateDirectoriesForUnstoppedPackage() throws Exception { + mPackageManager.setInstalledPackages( + Lists.newArrayList(createProviderPackage("test.package1", "authority1"))); + + MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority1"); + MatrixCursor response1 = provider1.createResponseCursor(); + addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, + Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + PackageInfo packageInfo = mPackageManager.getPackageInfo("test.package1", + PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageInfo.packageName; + packageInfo.applicationInfo = applicationInfo; + // Package is not in stopped state + packageInfo.applicationInfo.flags = 0; + + assertEquals(mDirectoryManager.updateDirectoriesForPackage(packageInfo, true).size(), 1); + } + + @Test + @RequiresFlagsEnabled(FLAG_STAY_STOPPED) + public void testUpdateDirectoriesForStoppedPackage() throws Exception { + mPackageManager.setInstalledPackages( + Lists.newArrayList(createProviderPackage("test.package1", "authority1"))); + + MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority1"); + MatrixCursor response1 = provider1.createResponseCursor(); + addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, + Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + PackageInfo packageInfo = mPackageManager.getPackageInfo("test.package1", + PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageInfo.packageName; + packageInfo.applicationInfo = applicationInfo; + // Put the package in stopped state: set associated app flags to true + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; + + assertNull(mDirectoryManager.updateDirectoriesForPackage(packageInfo, true)); + } + protected PackageInfo createProviderPackage(String packageName, String authority) { return createPackage(packageName, authority, true); } diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java index 0548f980..bd88e5a8 100644 --- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java +++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java @@ -491,11 +491,6 @@ public class ContactsDatabaseHelperUpgradeTest extends BaseDatabaseHelperUpgrade new TableColumn(NameLookupColumns.NAME_TYPE, INTEGER, true, null), }; - private static final TableColumn[] NICKNAME_LOOKUP_COLUMNS = new TableColumn[] { - new TableColumn(NicknameLookupColumns.NAME, TEXT, false, null), - new TableColumn(NicknameLookupColumns.CLUSTER, TEXT, false, null), - }; - private static final TableColumn[] GROUPS_COLUMNS = new TableColumn[] { new TableColumn(Groups._ID, INTEGER, false, null), new TableColumn(GroupsColumns.PACKAGE_ID, INTEGER, false, null), @@ -665,7 +660,6 @@ public class ContactsDatabaseHelperUpgradeTest extends BaseDatabaseHelperUpgrade new TableListEntry(Tables.DATA, DATA_COLUMNS), new TableListEntry(Tables.PHONE_LOOKUP, PHONE_LOOKUP_COLUMNS), new TableListEntry(Tables.NAME_LOOKUP, NAME_LOOKUP_COLUMNS), - new TableListEntry(Tables.NICKNAME_LOOKUP, NICKNAME_LOOKUP_COLUMNS), new TableListEntry(Tables.GROUPS, GROUPS_COLUMNS), new TableListEntry(Tables.AGGREGATION_EXCEPTIONS, AGGREGATION_EXCEPTIONS_COLUMNS), new TableListEntry(Tables.VISIBLE_CONTACTS, VISIBLE_CONTACTS_COLUMNS), diff --git a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java index 62f17eab..b96d6d52 100644 --- a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java +++ b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java @@ -161,4 +161,11 @@ public class ContactsMockPackageManager extends MockPackageManager { public int getPackageUid(String packageName, int flags) throws NameNotFoundException { return 123; } + + @Override + public boolean isPackageStopped(String packageName) throws NameNotFoundException { + PackageInfo packageInfo = getPackageInfo(packageName, 0); + return packageInfo.applicationInfo != null + && ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0); + } } diff --git a/tests/src/com/android/providers/contacts/MockCountryMonitor.java b/tests/src/com/android/providers/contacts/MockCountryMonitor.java new file mode 100644 index 00000000..6da71bd6 --- /dev/null +++ b/tests/src/com/android/providers/contacts/MockCountryMonitor.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 The Android Open Source 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.providers.contacts; + +import android.content.Context; + +/** + * A mock of the CountryMonitor class which always returns US + * when country ISO code is requested to ensure that the tests + * run successfully irrespective of the physical location of the + * device. + */ +public class MockCountryMonitor extends CountryMonitor { + + public MockCountryMonitor(Context context) { + super(context); + } + + @Override + public String getCountryIso() { + return "US"; + } +} diff --git a/tests/src/com/android/providers/contacts/NameLookupBuilderTest.java b/tests/src/com/android/providers/contacts/NameLookupBuilderTest.java index 1ca8b64e..f674dc9f 100644 --- a/tests/src/com/android/providers/contacts/NameLookupBuilderTest.java +++ b/tests/src/com/android/providers/contacts/NameLookupBuilderTest.java @@ -52,16 +52,6 @@ public class NameLookupBuilderTest extends TestCase { return name; } - @Override - protected String[] getCommonNicknameClusters(String normalizedName) { - if (normalizedName.equals("Bill")) { - return new String[] {"*William"}; - } else if (normalizedName.equals("Al")) { - return new String[] {"*Alex", "*Alice"}; - } - return null; - } - public String inserted() { return sb.toString(); } @@ -151,37 +141,6 @@ public class NameLookupBuilderTest extends TestCase { "(1:Biz.Foo.Bar.Baz)(2:BizFooBarBaz)", mBuilder.inserted()); } - public void testSingleNickname() { - mBuilder.insertNameLookup(0, 0, "Bill", FullNameStyle.UNDEFINED); - assertEquals("(0:Bill)(2:Bill)(1:*William)", mBuilder.inserted()); - } - - public void testSingleNameWithTwoNicknames() { - mBuilder.insertNameLookup(0, 0, "Al", FullNameStyle.UNDEFINED); - assertEquals("(0:Al)(2:Al)(1:*Alex)(1:*Alice)", mBuilder.inserted()); - } - - public void testTwoNamesOneOfWhichIsNickname() { - mBuilder.insertNameLookup(0, 0, "Foo Al", FullNameStyle.UNDEFINED); - assertEquals( - "(0:Foo.Al)(2:FooAl)" + - "(1:Al.Foo)(2:AlFoo)" + - "(1:Foo.*Alex)(1:*Alex.Foo)" + - "(1:Foo.*Alice)(1:*Alice.Foo)", mBuilder.inserted()); - } - - public void testTwoNamesBothNickname() { - mBuilder.insertNameLookup(0, 0, "Bill Al", FullNameStyle.UNDEFINED); - assertEquals( - "(0:Bill.Al)(2:BillAl)" + - "(1:Al.Bill)(2:AlBill)" + - "(1:*William.Al)(1:Al.*William)" + - "(1:*William.*Alex)(1:*Alex.*William)" + - "(1:*William.*Alice)(1:*Alice.*William)" + - "(1:Bill.*Alex)(1:*Alex.Bill)" + - "(1:Bill.*Alice)(1:*Alice.Bill)", mBuilder.inserted()); - } - public void testChineseName() { // Only run this test when Chinese collation is supported if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) { diff --git a/tests/src/com/android/providers/contacts/aggregation/ContactAggregator2Test.java b/tests/src/com/android/providers/contacts/aggregation/ContactAggregator2Test.java index b19a10fb..ff12ea05 100644 --- a/tests/src/com/android/providers/contacts/aggregation/ContactAggregator2Test.java +++ b/tests/src/com/android/providers/contacts/aggregation/ContactAggregator2Test.java @@ -429,69 +429,6 @@ public class ContactAggregator2Test extends BaseContactsProvider2Test { assertNotAggregated(rawContactId1, rawContactId2); } - public void testAggregationByCommonNicknameWithLastName() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Bill", "Gore"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "William", "Gore"); - - if (ActivityManager.isLowRamDeviceStatic()) { - // No common nickname DB on lowram devices. - assertNotAggregated(rawContactId1, rawContactId2); - } else { - assertAggregated(rawContactId1, rawContactId2, "William Gore"); - } - } - - public void testAggregationByCommonNicknameOnly() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Lawrence", null); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Larry", null); - - if (ActivityManager.isLowRamDeviceStatic()) { - // No common nickname DB on lowram devices. - assertNotAggregated(rawContactId1, rawContactId2); - } else { - assertAggregated(rawContactId1, rawContactId2, "Lawrence"); - } - } - - public void testAggregationByNicknameNoStructuredNameWithinSameAccount() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - insertNickname(rawContactId1, "Frozone"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - insertNickname(rawContactId2, "Frozone"); - - assertNotAggregated(rawContactId1, rawContactId2); - } - - public void testAggregationByNicknameNoStructuredNameWithinDifferentAccounts() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - insertNickname(rawContactId1, "Frozone"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - insertNickname(rawContactId2, "Frozone"); - - assertAggregated(rawContactId1, rawContactId2); - } - - - public void testAggregationByNicknameWithDifferentNames() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Helen", "Parr"); - insertNickname(rawContactId1, "Elastigirl"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Shawn", "Johnson"); - insertNickname(rawContactId2, "Elastigirl"); - - assertNotAggregated(rawContactId1, rawContactId2); - } - public void testNonAggregationOnOrganization() { ContentValues values = new ContentValues(); values.put(Organization.TITLE, "Monsters, Inc"); @@ -1050,54 +987,6 @@ public class ContactAggregator2Test extends BaseContactsProvider2Test { assertSuggestions(contactId1, contactId2); } - public void testAggregationSuggestionsBasedOnNickname() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker"); - insertNickname(rawContactId1, "Spider-Man"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider"); - - long contactId1 = queryContactId(rawContactId1); - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - - public void testAggregationSuggestionsBasedOnNicknameMatchingName() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent"); - insertNickname(rawContactId1, "Superman"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams"); - insertNickname(rawContactId2, "superman"); - - long contactId1 = queryContactId(rawContactId1); - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - - public void testAggregationSuggestionsBasedOnCommonNickname() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry"); - - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId1 = queryContactId(rawContactId1); - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() { // Create two contacts that would not be aggregated because of name mismatch diff --git a/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java b/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java index 37e3184c..6e65b6d6 100644 --- a/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java +++ b/tests/src/com/android/providers/contacts/aggregation/ContactAggregatorTest.java @@ -413,59 +413,6 @@ public class ContactAggregatorTest extends BaseContactsProvider2Test { assertNotAggregated(rawContactId1, rawContactId2); } - public void testAggregationByCommonNicknameWithLastName() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Bill", "Gore"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "William", "Gore"); - - - if (ActivityManager.isLowRamDeviceStatic()) { - // No common nickname DB on lowram devices. - assertNotAggregated(rawContactId1, rawContactId2); - } else { - assertAggregated(rawContactId1, rawContactId2, "William Gore"); - } - } - - public void testAggregationByCommonNicknameOnly() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Lawrence", null); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Larry", null); - - if (ActivityManager.isLowRamDeviceStatic()) { - // No common nickname DB on lowram devices. - assertNotAggregated(rawContactId1, rawContactId2); - } else { - assertAggregated(rawContactId1, rawContactId2, "Lawrence"); - } - } - - public void testAggregationByNicknameNoStructuredName() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - insertNickname(rawContactId1, "Frozone"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - insertNickname(rawContactId2, "Frozone"); - - assertAggregated(rawContactId1, rawContactId2); - } - - public void testAggregationByNicknameWithDifferentNames() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Helen", "Parr"); - insertNickname(rawContactId1, "Elastigirl"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Shawn", "Johnson"); - insertNickname(rawContactId2, "Elastigirl"); - - assertNotAggregated(rawContactId1, rawContactId2); - } - public void testNonAggregationOnOrganization() { ContentValues values = new ContentValues(); values.put(Organization.TITLE, "Monsters, Inc"); @@ -1042,54 +989,6 @@ public class ContactAggregatorTest extends BaseContactsProvider2Test { assertSuggestions(contactId1, contactId2); } - public void testAggregationSuggestionsBasedOnNickname() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker"); - insertNickname(rawContactId1, "Spider-Man"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider"); - - long contactId1 = queryContactId(rawContactId1); - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - - public void testAggregationSuggestionsBasedOnNicknameMatchingName() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent"); - insertNickname(rawContactId1, "Superman"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams"); - insertNickname(rawContactId2, "superman"); - - long contactId1 = queryContactId(rawContactId1); - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - - public void testAggregationSuggestionsBasedOnCommonNickname() { - long rawContactId1 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry"); - - long rawContactId2 = RawContactUtil.createRawContact(mResolver); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry"); - - setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, - rawContactId1, rawContactId2); - - long contactId1 = queryContactId(rawContactId1); - long contactId2 = queryContactId(rawContactId2); - assertSuggestions(contactId1, contactId2); - } - public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() { // Create two contacts that would not be aggregated because of name mismatch |