Bring back per-Account Contact-specific settings.

These are used for two purposes: a flag indicating the
default sync state for Groups to inherit, and a flag that
marks when Contacts that don't belong to any specific group
should be visible in UI.
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 3827a05..34b6337 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -49,6 +49,7 @@
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteCursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
 import android.net.Uri;
@@ -64,6 +65,7 @@
 import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.Presence;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.Settings;
 import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -145,6 +147,8 @@
 
     private static final int AGGREGATION_SUGGESTIONS = 8000;
 
+    private static final int SETTINGS = 9000;
+
     private static final int GROUPS = 10000;
     private static final int GROUPS_ID = 10001;
     private static final int GROUPS_SUMMARY = 10003;
@@ -316,6 +320,8 @@
     private static final HashMap<String, String> sGroupsSummaryProjectionMap;
     /** Contains the agg_exceptions columns */
     private static final HashMap<String, String> sAggregationExceptionsProjectionMap;
+    /** Contains the agg_exceptions columns */
+    private static final HashMap<String, String> sSettingsProjectionMap;
     /** Contains Presence columns */
     private static final HashMap<String, String> sPresenceProjectionMap;
 
@@ -388,6 +394,8 @@
         matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
                 AGGREGATION_EXCEPTION_ID);
 
+        matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);
+
         matcher.addURI(ContactsContract.AUTHORITY, "presence", PRESENCE);
         matcher.addURI(ContactsContract.AUTHORITY, "presence/#", PRESENCE_ID);
 
@@ -657,6 +665,16 @@
         columns.put(AggregationExceptions.RAW_CONTACT_ID, AggregationExceptionColumns.RAW_CONTACT_ID2);
         sAggregationExceptionsProjectionMap = columns;
 
+        // Settings projection map
+        columns = new HashMap<String, String>();
+        columns.put(Settings._ID, Settings._ID);
+        columns.put(Settings.ACCOUNT_NAME, Settings.ACCOUNT_NAME);
+        columns.put(Settings.ACCOUNT_TYPE, Settings.ACCOUNT_TYPE);
+        columns.put(Settings.UNGROUPED_VISIBLE, Settings.UNGROUPED_VISIBLE);
+        columns.put(Settings.SHOULD_SYNC_MODE, Settings.SHOULD_SYNC_MODE);
+        columns.put(Settings.SHOULD_SYNC, Settings.SHOULD_SYNC);
+        sSettingsProjectionMap = columns;
+
 
         columns = new HashMap<String, String>();
         columns.put(Presence._ID, Presence._ID);
@@ -1307,6 +1325,11 @@
                 break;
             }
 
+            case SETTINGS: {
+                id = mDb.insert(Tables.SETTINGS, null, values);
+                break;
+            }
+
             case PRESENCE: {
                 id = insertPresence(values);
                 break;
@@ -1685,8 +1708,12 @@
                 return deleteGroup(uri);
             }
 
+            case SETTINGS: {
+                return mDb.delete(Tables.SETTINGS, selection, selectionArgs);
+            }
+
             case PRESENCE: {
-                return mDb.delete(Tables.PRESENCE, null, null);
+                return mDb.delete(Tables.PRESENCE, selection, selectionArgs);
             }
 
             default:
@@ -1827,6 +1854,11 @@
                 break;
             }
 
+            case SETTINGS: {
+                count = mDb.update(Tables.SETTINGS, values, selection, selectionArgs);
+                break;
+            }
+
             default:
                 return mLegacyApiSupport.update(uri, values, selection, selectionArgs);
         }
@@ -2371,6 +2403,12 @@
                         sContactsProjectionMap, maxSuggestions);
             }
 
+            case SETTINGS: {
+                qb.setTables(Tables.SETTINGS);
+                qb.setProjectionMap(sSettingsProjectionMap);
+                break;
+            }
+
             case PRESENCE: {
                 qb.setTables(Tables.PRESENCE);
                 qb.setProjectionMap(sPresenceProjectionMap);
@@ -2832,6 +2870,7 @@
                 return mOpenHelper.getDataMimeType(dataId);
             case AGGREGATION_EXCEPTIONS: return AggregationExceptions.CONTENT_TYPE;
             case AGGREGATION_EXCEPTION_ID: return AggregationExceptions.CONTENT_ITEM_TYPE;
+            case SETTINGS: return Settings.CONTENT_TYPE;
             case AGGREGATION_SUGGESTIONS: return Contacts.CONTENT_TYPE;
             case SEARCH_SUGGESTIONS:
                 return SearchManager.SUGGEST_MIME_TYPE;
diff --git a/src/com/android/providers/contacts/OpenHelper.java b/src/com/android/providers/contacts/OpenHelper.java
index 73b51ca..f5b3c9f 100644
--- a/src/com/android/providers/contacts/OpenHelper.java
+++ b/src/com/android/providers/contacts/OpenHelper.java
@@ -40,6 +40,7 @@
 import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.Presence;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.Settings;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -59,7 +60,7 @@
 /* package */ class OpenHelper extends SQLiteOpenHelper {
     private static final String TAG = "OpenHelper";
 
-    private static final int DATABASE_VERSION = 68;
+    private static final int DATABASE_VERSION = 70;
     private static final String DATABASE_NAME = "contacts2.db";
     private static final String DATABASE_PRESENCE = "presence_db";
 
@@ -75,6 +76,7 @@
         public static final String PHONE_LOOKUP = "phone_lookup";
         public static final String NAME_LOOKUP = "name_lookup";
         public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions";
+        public static final String SETTINGS = "settings";
         public static final String DATA = "data";
         public static final String GROUPS = "groups";
         public static final String PRESENCE = "presence";
@@ -731,8 +733,8 @@
                 Groups.NOTES + " TEXT," +
                 Groups.SYSTEM_ID + " TEXT," +
                 Groups.DELETED + " INTEGER NOT NULL DEFAULT 0," +
-                Groups.GROUP_VISIBLE + " INTEGER," +
-                Groups.SHOULD_SYNC + " INTEGER NOT NULL DEFAULT 1," +
+                Groups.GROUP_VISIBLE + " INTEGER NOT NULL DEFAULT 0," +
+                Groups.SHOULD_SYNC + " INTEGER NOT NULL," +
                 Groups.SYNC1 + " TEXT, " +
                 Groups.SYNC2 + " TEXT, " +
                 Groups.SYNC3 + " TEXT, " +
@@ -769,6 +771,17 @@
                 AggregationExceptionColumns.RAW_CONTACT_ID1 +
         ");");
 
+        // Settings uses SYNC_MODE_UNSUPPORTED as default unless specified.
+        db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.SETTINGS + " (" +
+                Settings.ACCOUNT_NAME + " STRING NOT NULL," +
+                Settings.ACCOUNT_TYPE + " STRING NOT NULL," +
+                Settings.UNGROUPED_VISIBLE + " INTEGER NOT NULL DEFAULT 0," +
+                Settings.SHOULD_SYNC_MODE + " INTEGER NOT NULL DEFAULT 0, " +
+                Settings.SHOULD_SYNC + " INTEGER NOT NULL DEFAULT 1, " +
+                "PRIMARY KEY (" + Settings.ACCOUNT_NAME + ", " +
+                Settings.ACCOUNT_TYPE + ") ON CONFLICT REPLACE" +
+        ");");
+
         // The table for recent calls is here so we can do table joins
         // on people, phones, and calls all in one place.
         db.execSQL("CREATE TABLE " + Tables.CALLS + " (" +
@@ -1022,6 +1035,7 @@
         db.execSQL("DROP TABLE IF EXISTS " + Tables.GROUPS + ";");
         db.execSQL("DROP TABLE IF EXISTS " + Tables.ACTIVITIES + ";");
         db.execSQL("DROP TABLE IF EXISTS " + Tables.CALLS + ";");
+        db.execSQL("DROP TABLE IF EXISTS " + Tables.SETTINGS + ";");
 
         db.execSQL("DROP VIEW IF EXISTS " + Tables.CONTACT_ENTITIES + ";");
         db.execSQL("DROP VIEW IF EXISTS " + Views.CONTACTS_ALL + ";");
@@ -1061,6 +1075,7 @@
         db.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + ";");
         db.execSQL("DELETE FROM " + Tables.GROUPS + ";");
         db.execSQL("DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS + ";");
+        db.execSQL("DELETE FROM " + Tables.SETTINGS + ";");
         db.execSQL("DELETE FROM " + Tables.ACTIVITIES + ";");
         db.execSQL("DELETE FROM " + Tables.CALLS + ";");