auto import from //depot/cupcake/@135843
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
new file mode 100644
index 0000000..330a673
--- /dev/null
+++ b/packages/SettingsProvider/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user development
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := 
+
+LOCAL_PACKAGE_NAME := SettingsProvider
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
new file mode 100644
index 0000000..4abc337
--- /dev/null
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.providers.settings"
+        android:sharedUserId="android.uid.system">
+
+    <!-- Permission to write Gservices in SettingsProvider -->
+    <permission android:name="android.permission.WRITE_GSERVICES"
+        android:label="@string/permlab_writeGservices"
+        android:description="@string/permdesc_writeGservices"
+        android:protectionLevel="signature" />
+
+    <application android:allowClearUserData="false"
+                 android:label="Settings Storage"
+                 android:icon="@drawable/ic_launcher_settings">
+
+        <provider android:name="SettingsProvider" android:authorities="settings"
+                  android:process="system" android:multiprocess="false"
+                  android:writePermission="android.permission.WRITE_SETTINGS"
+                  android:initOrder="100" />
+    </application>
+</manifest>
diff --git a/packages/SettingsProvider/MODULE_LICENSE_APACHE2 b/packages/SettingsProvider/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SettingsProvider/MODULE_LICENSE_APACHE2
diff --git a/packages/SettingsProvider/NOTICE b/packages/SettingsProvider/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/SettingsProvider/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/SettingsProvider/etc/Android.mk b/packages/SettingsProvider/etc/Android.mk
new file mode 100644
index 0000000..e3f958c
--- /dev/null
+++ b/packages/SettingsProvider/etc/Android.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2008 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.
+#
+
+LOCAL_PATH := $(my-dir)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bookmarks.xml
+
+LOCAL_MODULE_TAGS := user development
+
+# This will install the file in /system/etc
+#
+LOCAL_MODULE_CLASS := ETC
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := favorites.xml
+
+LOCAL_MODULE_TAGS := user development
+
+# This will install the file in /system/etc
+#
+LOCAL_MODULE_CLASS := ETC
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
new file mode 100644
index 0000000..5fb6608
--- /dev/null
+++ b/packages/SettingsProvider/etc/bookmarks.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<bookmarks>
+    <bookmark
+        package="com.android.browser"
+        class="com.android.browser.BrowserActivity"
+        shortcut="b" />
+    <bookmark
+        package="com.android.contacts"
+        class="com.android.contacts.DialtactsContactsEntryActivity"
+        shortcut="c" />
+    <bookmark
+        package="com.android.email"
+        class="com.android.email.activity.Welcome"
+        shortcut="e" />
+    <bookmark
+        package="com.google.android.gm"
+        class="com.google.android.gm.ConversationListActivityGmail"
+        shortcut="g" />
+    <bookmark
+        package="com.android.providers.im"
+        class="com.android.providers.im.LandingPage"
+        shortcut="i" />
+    <bookmark
+        package="com.android.calendar"
+        class="com.android.calendar.LaunchActivity"
+        shortcut="l" />
+    <bookmark
+        package="com.google.android.apps.maps"
+        class="com.google.android.maps.MapsActivity"
+        shortcut="m" />
+    <bookmark
+        package="com.android.music"
+        class="com.android.music.MusicBrowserActivity"
+        shortcut="p" />
+    <bookmark
+        package="com.android.mms"
+        class="com.android.mms.ui.ConversationList"
+        shortcut="s" />
+    <bookmark
+        package="com.google.android.youtube"
+        class="com.google.android.youtube.HomePage"
+        shortcut="y" />
+</bookmarks>
\ No newline at end of file
diff --git a/packages/SettingsProvider/etc/favorites.xml b/packages/SettingsProvider/etc/favorites.xml
new file mode 100644
index 0000000..0ecf8a6
--- /dev/null
+++ b/packages/SettingsProvider/etc/favorites.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<favorites>
+    <favorite package="com.android.contacts" class="com.android.contacts.DialtactsActivity" screen="1" x="0" y="3"/>
+    <favorite package="com.android.contacts" class="com.android.contacts.DialtactsContactsEntryActivity" screen="1" x="1" y="3" />
+    <favorite package="com.android.browser" class="com.android.browser.BrowserActivity" screen="1" x="2" y="3" />
+    <favorite package="com.google.android.apps.maps" class="com.google.android.maps.MapsActivity" screen="1" x="3" y="3" />
+</favorites>
diff --git a/packages/SettingsProvider/res/drawable/ic_launcher_settings.png b/packages/SettingsProvider/res/drawable/ic_launcher_settings.png
new file mode 100755
index 0000000..16db056
--- /dev/null
+++ b/packages/SettingsProvider/res/drawable/ic_launcher_settings.png
Binary files differ
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
new file mode 100644
index 0000000..72d88e2
--- /dev/null
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, 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.
+ */
+-->
+<resources>
+    <bool name="def_dim_screen">true</bool>
+    <integer name="def_screen_off_timeout">60000</integer>
+    <bool name="def_airplane_mode_on">false</bool>
+    <!-- Comma-separated list of bluetooth, wifi, and cell. -->
+    <string name="def_airplane_mode_radios">cell,bluetooth,wifi</string>
+    <bool name="def_auto_time">true</bool>
+    <bool name="def_accelerometer_rotation">true</bool>
+    <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
+    <integer name="def_screen_brightness">102</integer>
+    <fraction name="def_window_animation_scale">0%</fraction>
+    <fraction name="def_window_transition_scale">0%</fraction>
+    
+    <bool name="def_bluetooth_on">false</bool>
+    <bool name="def_install_non_market_apps">false</bool>
+    <!-- Comma-separated list of providers. -->
+    <string name="def_location_providers_allowed">network</string>
+    <!--  0 == mobile, 1 == wifi. -->
+    <integer name="def_network_preference">1</integer>
+    <bool name="def_usb_mass_storage_enabled">true</bool>
+    <bool name="def_wifi_on">false</bool>
+    <bool name="def_networks_available_notification_on">true</bool>
+</resources>
diff --git a/packages/SettingsProvider/res/values/strings.xml b/packages/SettingsProvider/res/values/strings.xml
new file mode 100644
index 0000000..8a00091
--- /dev/null
+++ b/packages/SettingsProvider/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2007, 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.
+ */
+-->
+<resources>
+    <string name="permlab_writeGservices">Write Gservices settings.</string>
+    <string name="permdesc_writeGservices">Allows the application to
+      change the settings in Gservices.</string>
+</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
new file mode 100644
index 0000000..f8b5700
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2007 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.settings;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.media.AudioManager;
+import android.media.AudioService;
+import android.net.ConnectivityManager;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternView;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Database helper class for {@link SettingsProvider}.
+ * Mostly just has a bit {@link #onCreate} to initialize the database.
+ */
+class DatabaseHelper extends SQLiteOpenHelper {
+    /**
+     * Path to file containing default bookmarks, relative to ANDROID_ROOT.
+     */
+    private static final String DEFAULT_BOOKMARKS_PATH = "etc/bookmarks.xml";
+
+    private static final String TAG = "SettingsProvider";
+    private static final String DATABASE_NAME = "settings.db";
+    private static final int DATABASE_VERSION = 33;
+    
+    private Context mContext;
+
+    public DatabaseHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        mContext = context;
+    }
+
+    private void createSecureTable(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE secure (" +
+                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                "name TEXT UNIQUE ON CONFLICT REPLACE," +
+                "value TEXT" +
+                ");");
+        db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
+    }
+    
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE system (" +
+                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                    "name TEXT UNIQUE ON CONFLICT REPLACE," +
+                    "value TEXT" +
+                    ");");
+        db.execSQL("CREATE INDEX systemIndex1 ON system (name);");
+
+        createSecureTable(db);
+
+        db.execSQL("CREATE TABLE gservices (" +
+                   "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                   "name TEXT UNIQUE ON CONFLICT REPLACE," +
+                   "value TEXT" +
+                   ");");
+        db.execSQL("CREATE INDEX gservicesIndex1 ON gservices (name);");
+
+        db.execSQL("CREATE TABLE bluetooth_devices (" +
+                    "_id INTEGER PRIMARY KEY," +
+                    "name TEXT," +
+                    "addr TEXT," +
+                    "channel INTEGER," +
+                    "type INTEGER" +
+                    ");");
+
+        db.execSQL("CREATE TABLE bookmarks (" +
+                    "_id INTEGER PRIMARY KEY," +
+                    "title TEXT," +
+                    "folder TEXT," +
+                    "intent TEXT," +
+                    "shortcut INTEGER," +
+                    "ordering INTEGER" +
+                    ");");
+
+        db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);");
+        db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");
+
+        // Populate bookmarks table with initial bookmarks
+        loadBookmarks(db);
+
+        // Load initial volume levels into DB
+        loadVolumeLevels(db);
+
+        // Load inital settings values
+        loadSettings(db);
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+        Log.w(TAG, "Upgrading settings database from version " + oldVersion + " to "
+                + currentVersion);
+        
+        int upgradeVersion = oldVersion;
+
+        // Pattern for upgrade blocks:
+        //
+        //    if (upgradeVersion == [the DATABASE_VERSION you set] - 1) {
+        //        .. your upgrade logic..
+        //        upgradeVersion = [the DATABASE_VERSION you set]
+        //    }
+        
+        if (upgradeVersion == 20) {
+            /*
+             * Version 21 is part of the volume control refresh. There is no
+             * longer a UI-visible for setting notification vibrate on/off (in
+             * our design), but the functionality still exists. Force the
+             * notification vibrate to on.
+             */
+            loadVibrateSetting(db, true);
+            if (Config.LOGD) Log.d(TAG, "Reset system vibrate setting");
+
+            upgradeVersion = 21;
+        }
+        
+        if (upgradeVersion < 22) {
+            upgradeVersion = 22;
+            // Upgrade the lock gesture storage location and format
+            upgradeLockPatternLocation(db);
+        }
+
+        if (upgradeVersion < 23) {
+            db.execSQL("UPDATE favorites SET iconResource=0 WHERE iconType=0");
+            upgradeVersion = 23;
+        }
+
+        if (upgradeVersion == 23) {
+            db.beginTransaction();
+            try {
+                db.execSQL("ALTER TABLE favorites ADD spanX INTEGER");
+                db.execSQL("ALTER TABLE favorites ADD spanY INTEGER");
+                // Shortcuts, applications, folders
+                db.execSQL("UPDATE favorites SET spanX=1, spanY=1 WHERE itemType<=0");
+                // Photo frames, clocks
+                db.execSQL("UPDATE favorites SET spanX=2, spanY=2 WHERE itemType=1000 or itemType=1002");
+                // Search boxes
+                db.execSQL("UPDATE favorites SET spanX=4, spanY=1 WHERE itemType=1001");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 24;
+        }
+        
+        if (upgradeVersion == 24) {
+            db.beginTransaction();
+            try {
+                // The value of the constants for preferring wifi or preferring mobile have been
+                // swapped, so reload the default.
+                db.execSQL("DELETE FROM system WHERE name='network_preference'");
+                db.execSQL("INSERT INTO system ('name', 'value') values ('network_preference', '" +
+                        ConnectivityManager.DEFAULT_NETWORK_PREFERENCE + "')");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 25;
+        }
+
+        if (upgradeVersion == 25) {
+            db.beginTransaction();
+            try {
+                db.execSQL("ALTER TABLE favorites ADD uri TEXT");
+                db.execSQL("ALTER TABLE favorites ADD displayMode INTEGER");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 26;
+        }
+        
+        if (upgradeVersion == 26) {
+            // This introduces the new secure settings table.
+            db.beginTransaction();
+            try {
+                createSecureTable(db);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 27;
+        }
+        
+        if (upgradeVersion == 27) {
+            // Copy settings values from 'system' to 'secure' and delete them from 'system'
+            SQLiteStatement insertStmt = null;
+            SQLiteStatement deleteStmt = null;
+            
+            db.beginTransaction();
+            try {
+                insertStmt =
+                    db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM "
+                        + "system WHERE name=?");
+                deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?");
+
+                String[] settingsToMove = {
+                    Settings.Secure.ADB_ENABLED,
+                    Settings.Secure.ANDROID_ID,
+                    Settings.Secure.BLUETOOTH_ON,
+                    Settings.Secure.DATA_ROAMING,
+                    Settings.Secure.DEVICE_PROVISIONED,
+                    Settings.Secure.HTTP_PROXY,
+                    Settings.Secure.INSTALL_NON_MARKET_APPS,
+                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                    Settings.Secure.LOGGING_ID,
+                    Settings.Secure.NETWORK_PREFERENCE,
+                    Settings.Secure.PARENTAL_CONTROL_ENABLED,
+                    Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
+                    Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL,
+                    Settings.Secure.SETTINGS_CLASSNAME,
+                    Settings.Secure.USB_MASS_STORAGE_ENABLED,
+                    Settings.Secure.USE_GOOGLE_MAIL,
+                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+                    Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT,
+                    Settings.Secure.WIFI_ON,
+                    Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+                    Settings.Secure.WIFI_WATCHDOG_AP_COUNT,
+                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+                    Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+                    Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS,
+                    Settings.Secure.WIFI_WATCHDOG_ON,
+                    Settings.Secure.WIFI_WATCHDOG_PING_COUNT,
+                    Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS,
+                    Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+                };
+                
+                for (String setting : settingsToMove) {
+                    insertStmt.bindString(1, setting);
+                    insertStmt.execute();
+                    
+                    deleteStmt.bindString(1, setting);
+                    deleteStmt.execute();
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (insertStmt != null) {
+                    insertStmt.close();
+                }
+                if (deleteStmt != null) {
+                    deleteStmt.close();
+                }
+            }
+            upgradeVersion = 28;
+        }
+        
+        if (upgradeVersion == 28 || upgradeVersion == 29) {
+            // Note: The upgrade to 28 was flawed since it didn't delete the old
+            // setting first before inserting. Combining 28 and 29 with the
+            // fixed version.
+
+            // This upgrade adds the STREAM_NOTIFICATION type to the list of
+            // types affected by ringer modes (silent, vibrate, etc.)
+            db.beginTransaction();
+            try {
+                db.execSQL("DELETE FROM system WHERE name='"
+                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'");
+                int newValue = (1 << AudioManager.STREAM_RING)
+                        | (1 << AudioManager.STREAM_NOTIFICATION)
+                        | (1 << AudioManager.STREAM_SYSTEM);
+                db.execSQL("INSERT INTO system ('name', 'value') values ('"
+                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '"
+                        + String.valueOf(newValue) + "')");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            
+            upgradeVersion = 30;
+        }
+        
+        if (upgradeVersion == 30) {
+            /*
+             * Upgrade 31 clears the title for all quick launch shortcuts so the
+             * activities' titles will be resolved at display time. Also, the
+             * folder is changed to '@quicklaunch'.
+             */
+            db.beginTransaction();
+            try {
+                db.execSQL("UPDATE bookmarks SET folder = '@quicklaunch'");
+                db.execSQL("UPDATE bookmarks SET title = ''");
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 31;
+        }
+
+        if (upgradeVersion == 31) {
+            /*
+             * Animations are now turned off by default.
+             */
+            db.beginTransaction();
+            try {
+                db.execSQL("DELETE FROM system WHERE name='"
+                        + Settings.System.WINDOW_ANIMATION_SCALE + "'");
+                db.execSQL("DELETE FROM system WHERE name='"
+                        + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
+                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadDefaultAnimationSettings(stmt);
+                stmt.close();
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 32;
+        }
+
+        if (upgradeVersion == 32) {
+            // The Wi-Fi watchdog SSID list is now seeded with the value of
+            // the property ro.com.android.wifi-watchlist
+            String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
+            if (!TextUtils.isEmpty(wifiWatchList)) {
+                db.beginTransaction();
+                try {
+                    db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
+                            Settings.Secure.WIFI_WATCHDOG_WATCH_LIST + "','" +
+                            wifiWatchList + "');");
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            upgradeVersion = 33;
+        }
+
+        if (upgradeVersion != currentVersion) {
+            Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+                    + ", must wipe the settings provider");
+            db.execSQL("DROP TABLE IF EXISTS system");
+            db.execSQL("DROP INDEX IF EXISTS systemIndex1");
+            db.execSQL("DROP TABLE IF EXISTS secure");
+            db.execSQL("DROP INDEX IF EXISTS secureIndex1");
+            db.execSQL("DROP TABLE IF EXISTS gservices");
+            db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
+            db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
+            db.execSQL("DROP TABLE IF EXISTS bookmarks");
+            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
+            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
+            db.execSQL("DROP TABLE IF EXISTS favorites");
+            onCreate(db);
+        }
+    }
+
+    private void upgradeLockPatternLocation(SQLiteDatabase db) {
+        Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'", 
+                null, null, null, null);
+        if (c.getCount() > 0) {
+            c.moveToFirst();
+            String lockPattern = c.getString(1);
+            if (!TextUtils.isEmpty(lockPattern)) {
+                // Convert lock pattern
+                try {
+                    LockPatternUtils lpu = new LockPatternUtils(mContext.getContentResolver());
+                    List<LockPatternView.Cell> cellPattern = 
+                            LockPatternUtils.stringToPattern(lockPattern);
+                    lpu.saveLockPattern(cellPattern);
+                } catch (IllegalArgumentException e) {
+                    // Don't want corrupted lock pattern to hang the reboot process
+                }
+            }
+            c.close();
+            db.delete("system", "name='lock_pattern'", null);
+        } else {
+            c.close();
+        }
+    }
+
+    /**
+     * Loads the default set of bookmarked shortcuts from an xml file.
+     *
+     * @param db The database to write the values into
+     * @param startingIndex The zero-based position at which bookmarks in this file should begin
+     * @param subPath The relative path from ANDROID_ROOT to the file to read
+     * @param quiet If true, do no complain if the file is missing
+     */
+    private int loadBookmarks(SQLiteDatabase db, int startingIndex, String subPath,
+            boolean quiet) {
+        FileReader bookmarksReader;
+
+        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
+        final File favFile = new File(Environment.getRootDirectory(), subPath);
+        try {
+            bookmarksReader = new FileReader(favFile);
+        } catch (FileNotFoundException e) {
+            if (!quiet) {
+                Log.e(TAG, "Couldn't find or open bookmarks file " + favFile);
+            }
+            return 0;
+        }
+
+        Intent intent = new Intent(Intent.ACTION_MAIN, null);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        ContentValues values = new ContentValues();
+
+        PackageManager packageManager = mContext.getPackageManager();
+        ActivityInfo info;
+        int i = startingIndex;
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(bookmarksReader);
+
+            XmlUtils.beginDocument(parser, "bookmarks");
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                String name = parser.getName();
+                if (!"bookmark".equals(name)) {
+                    break;
+                }
+
+                String pkg = parser.getAttributeValue(null, "package");
+                String cls = parser.getAttributeValue(null, "class");
+                String shortcutStr = parser.getAttributeValue(null, "shortcut");
+                int shortcutValue = (int) shortcutStr.charAt(0);
+                if (TextUtils.isEmpty(shortcutStr)) {
+                    Log.w(TAG, "Unable to get shortcut for: " + pkg + "/" + cls);
+                }
+                try {
+                    ComponentName cn = new ComponentName(pkg, cls);
+                    info = packageManager.getActivityInfo(cn, 0);
+                    intent.setComponent(cn);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    values.put(Settings.Bookmarks.INTENT, intent.toURI());
+                    values.put(Settings.Bookmarks.TITLE,
+                            info.loadLabel(packageManager).toString());
+                    values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
+                    db.insert("bookmarks", null, values);
+                    i++;
+                } catch (PackageManager.NameNotFoundException e) {
+                    Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
+                }
+            }
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Got execption parsing bookmarks.", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Got execption parsing bookmarks.", e);
+        }
+
+        return i;
+    }
+
+    /**
+     * Loads the default set of bookmark packages.
+     *
+     * @param db The database to write the values into
+     */
+    private void loadBookmarks(SQLiteDatabase db) {
+        loadBookmarks(db, 0, DEFAULT_BOOKMARKS_PATH, false);
+    }
+
+    /**
+     * Loads the default volume levels. It is actually inserting the index of
+     * the volume array for each of the volume controls.
+     *
+     * @param db the database to insert the volume levels into
+     */
+    private void loadVolumeLevels(SQLiteDatabase db) {
+        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+                + " VALUES(?,?);");
+
+        loadSetting(stmt, Settings.System.VOLUME_MUSIC,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
+        loadSetting(stmt, Settings.System.VOLUME_RING,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_RING]);
+        loadSetting(stmt, Settings.System.VOLUME_SYSTEM,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
+        loadSetting(
+                stmt,
+                Settings.System.VOLUME_VOICE,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
+        loadSetting(stmt, Settings.System.VOLUME_ALARM,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_ALARM]);
+        loadSetting(
+                stmt,
+                Settings.System.VOLUME_NOTIFICATION,
+                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_NOTIFICATION]);
+        loadSetting(stmt, Settings.System.MODE_RINGER,
+                AudioManager.RINGER_MODE_NORMAL);
+
+        loadVibrateSetting(db, false);
+        
+        // By default, only the ring/notification and system streams are affected
+        loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+                (1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) |
+                (1 << AudioManager.STREAM_SYSTEM));
+        
+        loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
+                ((1 << AudioManager.STREAM_MUSIC) |
+                 (1 << AudioManager.STREAM_RING) |
+                 (1 << AudioManager.STREAM_NOTIFICATION) |
+                 (1 << AudioManager.STREAM_SYSTEM)));
+
+        stmt.close();
+    }
+
+    private void loadVibrateSetting(SQLiteDatabase db, boolean deleteOld) {
+        if (deleteOld) {
+            db.execSQL("DELETE FROM system WHERE name='" + Settings.System.VIBRATE_ON + "'");
+        }
+        
+        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+                + " VALUES(?,?);");
+
+        // Vibrate off by default for ringer, on for notification
+        int vibrate = 0;
+        vibrate = AudioService.getValueForVibrateSetting(vibrate,
+                AudioManager.VIBRATE_TYPE_NOTIFICATION, AudioManager.VIBRATE_SETTING_ON);
+        vibrate = AudioService.getValueForVibrateSetting(vibrate,
+                AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
+        loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
+    }
+
+    private void loadSettings(SQLiteDatabase db) {
+        loadSystemSettings(db);
+        loadSecureSettings(db);   
+    }
+    
+    private void loadSystemSettings(SQLiteDatabase db) {
+        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+                + " VALUES(?,?);");
+        
+        Resources r = mContext.getResources();
+        loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
+                R.bool.def_dim_screen);
+        loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN, 
+                "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
+        loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
+                R.integer.def_screen_off_timeout);
+        
+        loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
+                R.bool.def_airplane_mode_on);
+        
+        loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
+                R.string.def_airplane_mode_radios);
+        
+        loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
+                R.bool.def_auto_time); // Sync time to NITZ
+        
+        loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
+                R.integer.def_screen_brightness);
+        
+        loadDefaultAnimationSettings(stmt);
+
+        loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
+                R.bool.def_accelerometer_rotation);
+        
+        // Default date format based on build
+        loadSetting(stmt, Settings.System.DATE_FORMAT,
+                SystemProperties.get("ro.com.android.dateformat", 
+                        "MM-dd-yyyy"));
+        stmt.close();
+    }
+    
+    private void loadDefaultAnimationSettings(SQLiteStatement stmt) {
+        loadFractionSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE,
+                R.fraction.def_window_animation_scale, 1);
+        loadFractionSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE,
+                R.fraction.def_window_transition_scale, 1);
+    }
+    
+    private void loadSecureSettings(SQLiteDatabase db) {
+        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+                + " VALUES(?,?);");
+        
+        loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON,
+                R.bool.def_bluetooth_on);
+        
+        // Data roaming default, based on build
+        loadSetting(stmt, Settings.Secure.DATA_ROAMING, 
+                "true".equalsIgnoreCase(
+                        SystemProperties.get("ro.com.android.dataroaming", 
+                                "false")) ? 1 : 0);        
+        
+        loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
+                R.bool.def_install_non_market_apps);
+        
+        loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                R.string.def_location_providers_allowed);
+        
+        loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
+                R.integer.def_network_preference);
+        
+        loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED,
+                R.bool.def_usb_mass_storage_enabled);
+        
+        loadBooleanSetting(stmt, Settings.Secure.WIFI_ON,
+                R.bool.def_wifi_on);
+        loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                R.bool.def_networks_available_notification_on);
+
+        String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
+        if (!TextUtils.isEmpty(wifiWatchList)) {
+            loadSetting(stmt, Settings.Secure.WIFI_WATCHDOG_WATCH_LIST, wifiWatchList);
+        }
+
+        // Don't do this.  The SystemServer will initialize ADB_ENABLED from a
+        // persistent system property instead.
+        //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
+        
+        // Allow mock locations default, based on build
+        loadSetting(stmt, Settings.Secure.ALLOW_MOCK_LOCATION, 
+                "1".equals(SystemProperties.get("ro.allow.mock.location")) ? 1 : 0);
+        
+        stmt.close();
+    }
+
+    private void loadSetting(SQLiteStatement stmt, String key, Object value) {
+        stmt.bindString(1, key);
+        stmt.bindString(2, value.toString());
+        stmt.execute();
+    }
+    
+    private void loadStringSetting(SQLiteStatement stmt, String key, int resid) {
+        loadSetting(stmt, key, mContext.getResources().getString(resid));
+    }
+    
+    private void loadBooleanSetting(SQLiteStatement stmt, String key, int resid) {
+        loadSetting(stmt, key,
+                mContext.getResources().getBoolean(resid) ? "1" : "0");
+    }
+    
+    private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) {
+        loadSetting(stmt, key,
+                Integer.toString(mContext.getResources().getInteger(resid)));
+    }
+    
+    private void loadFractionSetting(SQLiteStatement stmt, String key, int resid, int base) {
+        loadSetting(stmt, key,
+                Float.toString(mContext.getResources().getFraction(resid, base, base)));
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
new file mode 100644
index 0000000..333a450
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2007 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.settings;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
+import android.provider.DrmStore;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+
+public class SettingsProvider extends ContentProvider {
+    private static final String TAG = "SettingsProvider";
+    private static final boolean LOCAL_LOGV = false;
+
+    private static final String TABLE_FAVORITES = "favorites";
+    private static final String TABLE_OLD_FAVORITES = "old_favorites";
+
+    private DatabaseHelper mOpenHelper;
+
+    /**
+     * Decode a content URL into the table, projection, and arguments
+     * used to access the corresponding database rows.
+     */
+    private static class SqlArguments {
+        public String table;
+        public final String where;
+        public final String[] args;
+
+        /** Operate on existing rows. */
+        SqlArguments(Uri url, String where, String[] args) {
+            if (url.getPathSegments().size() == 1) {
+                this.table = url.getPathSegments().get(0);
+                this.where = where;
+                this.args = args;
+            } else if (url.getPathSegments().size() != 2) {
+                throw new IllegalArgumentException("Invalid URI: " + url);
+            } else if (!TextUtils.isEmpty(where)) {
+                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
+            } else {
+                this.table = url.getPathSegments().get(0);
+                if ("gservices".equals(this.table) || "system".equals(this.table)
+                        || "secure".equals(this.table)) {
+                    this.where = Settings.NameValueTable.NAME + "=?";
+                    this.args = new String[] { url.getPathSegments().get(1) };
+                } else {
+                    this.where = "_id=" + ContentUris.parseId(url);
+                    this.args = null;
+                }
+            }
+        }
+
+        /** Insert new rows (no where clause allowed). */
+        SqlArguments(Uri url) {
+            if (url.getPathSegments().size() == 1) {
+                this.table = url.getPathSegments().get(0);
+                this.where = null;
+                this.args = null;
+            } else {
+                throw new IllegalArgumentException("Invalid URI: " + url);
+            }
+        }
+    }
+
+    /**
+     * Get the content URI of a row added to a table.
+     * @param tableUri of the entire table
+     * @param values found in the row
+     * @param rowId of the row
+     * @return the content URI for this particular row
+     */
+    private Uri getUriFor(Uri tableUri, ContentValues values, long rowId) {
+        if (tableUri.getPathSegments().size() != 1) {
+            throw new IllegalArgumentException("Invalid URI: " + tableUri);
+        }
+        String table = tableUri.getPathSegments().get(0);
+        if ("gservices".equals(table) || "system".equals(table)
+                || "secure".equals(table)) {
+            String name = values.getAsString(Settings.NameValueTable.NAME);
+            return Uri.withAppendedPath(tableUri, name);
+        } else {
+            return ContentUris.withAppendedId(tableUri, rowId);
+        }
+    }
+
+    /**
+     * Send a notification when a particular content URI changes.
+     * Modify the system property used to communicate the version of
+     * this table, for tables which have such a property.  (The Settings
+     * contract class uses these to provide client-side caches.)
+     * @param uri to send notifications for
+     */
+    private void sendNotify(Uri uri) {
+        // Update the system property *first*, so if someone is listening for
+        // a notification and then using the contract class to get their data,
+        // the system property will be updated and they'll get the new data.
+
+        String property = null, table = uri.getPathSegments().get(0);
+        if (table.equals("system")) {
+            property = Settings.System.SYS_PROP_SETTING_VERSION;
+        } else if (table.equals("secure")) {
+            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+        } else if (table.equals("gservices")) {
+            property = Settings.Gservices.SYS_PROP_SETTING_VERSION;
+        }
+
+        if (property != null) {
+            long version = SystemProperties.getLong(property, 0) + 1;
+            if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
+            SystemProperties.set(property, Long.toString(version));
+        }
+
+        // Now send the notification through the content framework.
+
+        String notify = uri.getQueryParameter("notify");
+        if (notify == null || "true".equals(notify)) {
+            getContext().getContentResolver().notifyChange(uri, null);
+            if (LOCAL_LOGV) Log.v(TAG, "notifying: " + uri);
+        } else {
+            if (LOCAL_LOGV) Log.v(TAG, "notification suppressed: " + uri);
+        }
+    }
+
+    /**
+     * Make sure the caller has permission to write this data.
+     * @param args supplied by the caller
+     * @throws SecurityException if the caller is forbidden to write.
+     */
+    private void checkWritePermissions(SqlArguments args) {
+        if ("secure".equals(args.table) &&
+                getContext().checkCallingOrSelfPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+                    PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Cannot write secure settings table");
+        
+        // TODO: Move gservices into its own provider so we don't need this nonsense.
+        } else if ("gservices".equals(args.table) &&
+            getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.WRITE_GSERVICES) !=
+                PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Cannot write gservices table");
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        mOpenHelper = new DatabaseHelper(getContext());
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
+        SqlArguments args = new SqlArguments(url, where, whereArgs);
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
+        // The favorites table was moved from this provider to a provider inside Home
+        // Home still need to query this table to upgrade from pre-cupcake builds
+        // However, a cupcake+ build with no data does not contain this table which will
+        // cause an exception in the SQL stack. The following line is a special case to
+        // let the caller of the query have a chance to recover and avoid the exception
+        if (TABLE_FAVORITES.equals(args.table)) {
+            return null;
+        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
+            args.table = TABLE_FAVORITES;
+            Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
+            if (cursor != null) {
+                boolean exists = cursor.getCount() > 0;
+                cursor.close();
+                if (!exists) return null;
+            } else {
+                return null;
+            }
+        }
+
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+        qb.setTables(args.table);
+
+        Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
+        ret.setNotificationUri(getContext().getContentResolver(), url);
+        return ret;
+    }
+
+    @Override
+    public String getType(Uri url) {
+        // If SqlArguments supplies a where clause, then it must be an item
+        // (because we aren't supplying our own where clause).
+        SqlArguments args = new SqlArguments(url, null, null);
+        if (TextUtils.isEmpty(args.where)) {
+            return "vnd.android.cursor.dir/" + args.table;
+        } else {
+            return "vnd.android.cursor.item/" + args.table;
+        }
+    }
+
+    @Override
+    public int bulkInsert(Uri uri, ContentValues[] values) {
+        SqlArguments args = new SqlArguments(uri);
+        if (TABLE_FAVORITES.equals(args.table)) {
+            return 0;
+        }
+        checkWritePermissions(args);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            int numValues = values.length;
+            for (int i = 0; i < numValues; i++) {
+                if (db.insert(args.table, null, values[i]) < 0) return 0;
+                if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]);
+            }
+            db.setTransactionSuccessful();
+        } finally {
+            db.endTransaction();
+        }
+
+        sendNotify(uri);
+        return values.length;
+    }
+
+    @Override
+    public Uri insert(Uri url, ContentValues initialValues) {
+        SqlArguments args = new SqlArguments(url);
+        if (TABLE_FAVORITES.equals(args.table)) {
+            return null;
+        }
+        checkWritePermissions(args);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        final long rowId = db.insert(args.table, null, initialValues);
+        if (rowId <= 0) return null;
+
+        if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues);
+        url = getUriFor(url, initialValues, rowId);
+        sendNotify(url);
+        return url;
+    }
+
+    @Override
+    public int delete(Uri url, String where, String[] whereArgs) {
+        SqlArguments args = new SqlArguments(url, where, whereArgs);
+        if (TABLE_FAVORITES.equals(args.table)) {
+            return 0;
+        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
+            args.table = TABLE_FAVORITES;
+        }
+        checkWritePermissions(args);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count = db.delete(args.table, args.where, args.args);
+        if (count > 0) sendNotify(url);
+        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
+        return count;
+    }
+
+    @Override
+    public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
+        SqlArguments args = new SqlArguments(url, where, whereArgs);
+        if (TABLE_FAVORITES.equals(args.table)) {
+            return 0;
+        }
+        checkWritePermissions(args);
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count = db.update(args.table, initialValues, args.where, args.args);
+        if (count > 0) sendNotify(url);
+        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
+        return count;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+
+        /*
+         * When a client attempts to openFile the default ringtone or
+         * notification setting Uri, we will proxy the call to the current
+         * default ringtone's Uri (if it is in the DRM or media provider).
+         */ 
+        int ringtoneType = RingtoneManager.getDefaultType(uri);
+        // Above call returns -1 if the Uri doesn't match a default type
+        if (ringtoneType != -1) {
+            Context context = getContext();
+            
+            // Get the current value for the default sound
+            Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
+            if (soundUri == null) {
+                // Fallback on any valid ringtone Uri
+                soundUri = RingtoneManager.getValidRingtoneUri(context);
+            }
+
+            if (soundUri != null) { 
+                // Only proxy the openFile call to drm or media providers
+                String authority = soundUri.getAuthority();
+                boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
+                if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
+
+                    if (isDrmAuthority) {
+                        try {
+                            // Check DRM access permission here, since once we
+                            // do the below call the DRM will be checking our
+                            // permission, not our caller's permission
+                            DrmStore.enforceAccessDrmPermission(context);
+                        } catch (SecurityException e) {
+                            throw new FileNotFoundException(e.getMessage());
+                        }
+                    }
+                    
+                    return context.getContentResolver().openFileDescriptor(soundUri, mode);
+                }
+            }
+        }
+
+        return super.openFile(uri, mode);
+    }
+}
diff --git a/packages/SubscribedFeedsProvider/Android.mk b/packages/SubscribedFeedsProvider/Android.mk
new file mode 100644
index 0000000..bed6a16
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SubscribedFeedsProvider
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
new file mode 100644
index 0000000..6ecda48
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.providers.subscribedfeeds"
+        android:sharedUserId="android.uid.system">
+
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
+    <uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
+
+    <application android:process="system"
+                 android:allowClearUserData="false"
+                 android:icon="@drawable/app_icon"
+                 android:label="Sync Feeds">
+        <uses-library android:name="com.google.android.gtalkservice" />
+        <provider android:name="SubscribedFeedsProvider"
+                android:authorities="subscribedfeeds" android:syncable="false"
+                android:multiprocess="false"
+                android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ"
+                android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
+        <receiver android:name="SubscribedFeedsBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+                <category android:name="GSYNC_TICKLE"/>
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.subscribedfeeds.action.REFRESH" />
+            </intent-filter>
+        </receiver>
+        <service android:name="SubscribedFeedsIntentService"/>
+    </application>
+</manifest>
diff --git a/packages/SubscribedFeedsProvider/MODULE_LICENSE_APACHE2 b/packages/SubscribedFeedsProvider/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/MODULE_LICENSE_APACHE2
diff --git a/packages/SubscribedFeedsProvider/NOTICE b/packages/SubscribedFeedsProvider/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/packages/SubscribedFeedsProvider/res/drawable/app_icon.png b/packages/SubscribedFeedsProvider/res/drawable/app_icon.png
new file mode 100644
index 0000000..13d8cdd
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/res/drawable/app_icon.png
Binary files differ
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
new file mode 100644
index 0000000..3513215
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
@@ -0,0 +1,41 @@
+/*
+** Copyright 2006, 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.subscribedfeeds;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * Handles the XMPP_CONNECTED_ACTION intent by updating all the
+ * subscribed feeds with the new jabber id and initiating a sync
+ * for all subscriptions.
+ *
+ * Handles the TICKLE_ACTION intent by finding the matching
+ * subscribed feed and intiating a sync for it.
+ */
+public class SubscribedFeedsBroadcastReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "Sync";
+
+    public void onReceive(Context context, Intent intent) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received intent " + intent);
+            intent.setClass(context, SubscribedFeedsIntentService.class);
+        context.startService(intent);
+    }
+}
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
new file mode 100644
index 0000000..df599c7
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -0,0 +1,192 @@
+package com.android.providers.subscribedfeeds;
+
+import android.content.Intent;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.SharedPreferences;
+import android.util.Log;
+import android.util.Config;
+import android.util.EventLog;
+import android.app.IntentService;
+import android.provider.Sync;
+import android.provider.SubscribedFeeds;
+import android.provider.SyncConstValue;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteFullException;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.os.Bundle;
+import android.os.Debug;
+import android.text.TextUtils;
+import android.net.Uri;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+
+/**
+ * A service to handle various intents asynchronously.
+ */
+public class SubscribedFeedsIntentService extends IntentService {
+    private static final String TAG = "Sync";
+
+    private static final String[] sAccountProjection =
+            new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
+
+    /** How often to refresh the subscriptions, in milliseconds */
+    private static final long SUBSCRIPTION_REFRESH_INTERVAL = 1000L * 60 * 60 * 24; // one day
+
+    private static final String sRefreshTime = "refreshTime";
+
+    private static final String sSubscribedFeedsPrefs = "subscribedFeeds";
+
+    private static final String GTALK_DATA_MESSAGE_RECEIVED =
+            "android.intent.action.GTALK_DATA_MESSAGE_RECEIVED";
+
+    private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
+            "com.android.subscribedfeeds.action.REFRESH";
+
+    private static final int LOG_TICKLE = 2742;
+
+    public SubscribedFeedsIntentService() {
+        super("SubscribedFeedsIntentService");
+    }
+
+    protected void onHandleIntent(Intent intent) {
+        if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
+            boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
+            if (fromTrustedServer) {
+                String account = intent.getStringExtra("account");
+                String token = intent.getStringExtra("message_token");
+
+                if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
+                    if (Config.LOGD) {
+                        Log.d(TAG, "Ignoring malformed tickle -- missing account or token.");
+                    }
+                    return;
+                }
+
+                if (Config.LOGD) {
+                    Log.d(TAG, "Received network tickle for "
+                            + account + " - " + token);
+                }
+
+                handleTickle(this, account, token);
+            } else {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Ignoring tickle -- not from trusted server.");
+                }
+            }
+
+        } else if (Intent.ACTION_BOOT_COMPLETED.equals(
+                intent.getAction())) {
+            if (Config.LOGD) {
+                Log.d(TAG, "Received boot completed action");
+            }
+            // load the time from the shared preferences and schedule an alarm
+            long refreshTime = getSharedPreferences(
+                    sSubscribedFeedsPrefs,
+                    Context.MODE_WORLD_READABLE).getLong(sRefreshTime, 0);
+            scheduleRefresh(this, refreshTime);
+        } else if (SUBSCRIBED_FEEDS_REFRESH_ACTION.equals(intent.getAction())) {
+            if (Config.LOGD) {
+                Log.d(TAG, "Received sSubscribedFeedsRefreshIntent");
+            }
+            handleRefreshAlarm(this);
+        }
+    }
+    private void scheduleRefresh(Context context, long when) {
+        AlarmManager alarmManager = (AlarmManager) context.getSystemService(
+                Context.ALARM_SERVICE);
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
+                0, new Intent(SUBSCRIBED_FEEDS_REFRESH_ACTION), 0);
+        alarmManager.set(AlarmManager.RTC, when, pendingIntent);
+    }
+
+    private void handleTickle(Context context, String account, String feed) {
+        Cursor c = null;
+        Sync.Settings.QueryMap syncSettings =
+                new Sync.Settings.QueryMap(context.getContentResolver(),
+                        false /* don't keep updated */,
+                        null /* not needed since keep updated is false */);
+        final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? "
+                + "and " + SubscribedFeeds.Feeds.FEED + "= ?";
+        try {
+            c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
+                    null, where, new String[]{account, feed}, null);
+            if (c.getCount() == 0) {
+                Log.w(TAG, "received tickle for non-existent feed: "
+                        + "account " + account + ", feed " + feed);
+                EventLog.writeEvent(LOG_TICKLE, "unknown");
+            }
+            while (c.moveToNext()) {
+                // initiate a sync
+                String authority = c.getString(c.getColumnIndexOrThrow(
+                        SubscribedFeeds.Feeds.AUTHORITY));
+                EventLog.writeEvent(LOG_TICKLE, authority);
+                if (!syncSettings.getSyncProviderAutomatically(authority)) {
+                    Log.d(TAG, "supressing tickle since provider " + authority
+                            + " is configured to not sync automatically");
+                    continue;
+                }
+                Uri uri = Uri.parse("content://" + authority);
+                Bundle extras = new Bundle();
+                extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+                extras.putString("feed", feed);
+                context.getContentResolver().startSync(uri, extras);
+            }
+        } finally {
+            if (c != null) c.deactivate();
+            syncSettings.close();
+        }
+    }
+
+    /**
+     * Cause all the subscribed feeds to be marked dirty and their
+     * authtokens to be refreshed, which will result in new authtokens
+     * being sent to the subscription server. Then reschedules this
+     * event for one week in the future.
+     *
+     * @param context Context we are running within
+     */
+    private void handleRefreshAlarm(Context context) {
+        // retrieve the list of accounts from the subscribed feeds
+        ArrayList<String> accounts = new ArrayList<String>();
+        ContentResolver contentResolver = context.getContentResolver();
+        Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
+                sAccountProjection, null, null, null);
+        while (c.moveToNext()) {
+            String account = c.getString(0);
+            if (TextUtils.isEmpty(account)) {
+                continue;
+            }
+            accounts.add(account);
+        }
+        c.deactivate();
+
+        // Clear the auth tokens for all these accounts so that we are sure
+        // they will still be valid until the next time we refresh them.
+        // TODO: add this when the google login service is done
+
+        // mark the feeds dirty, by setting the accounts to the same value,
+        //  which will trigger a sync.
+        try {
+            ContentValues values = new ContentValues();
+            for (String account : accounts) {
+                values.put(SyncConstValue._SYNC_ACCOUNT, account);
+                contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
+                        SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+            }
+        } catch (SQLiteFullException e) {
+            Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
+        }
+
+        // Schedule a refresh.
+        long refreshTime = Calendar.getInstance().getTimeInMillis() + SUBSCRIPTION_REFRESH_INTERVAL;
+        scheduleRefresh(context, refreshTime);
+        SharedPreferences.Editor editor = context.getSharedPreferences(sSubscribedFeedsPrefs,
+                Context.MODE_WORLD_READABLE).edit();
+        editor.putLong(sRefreshTime, refreshTime);
+        editor.commit();
+    }
+}
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
new file mode 100644
index 0000000..9ecc3d6
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -0,0 +1,373 @@
+/*
+** Copyright 2006, 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.subscribedfeeds;
+
+import android.content.UriMatcher;
+import android.content.*;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.provider.SubscribedFeeds;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Manages a list of feeds for which this client is interested in receiving
+ * change notifications.
+ */
+public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
+    private static final String TAG = "SubscribedFeedsProvider";
+    private static final String DATABASE_NAME = "subscribedfeeds.db";
+    private static final int DATABASE_VERSION = 10;
+
+    private static final int FEEDS = 1;
+    private static final int FEED_ID = 2;
+    private static final int DELETED_FEEDS = 3;
+    private static final int ACCOUNTS = 4;
+
+    private static final Map<String, String> ACCOUNTS_PROJECTION_MAP;
+
+    private static final UriMatcher sURLMatcher =
+            new UriMatcher(UriMatcher.NO_MATCH);
+
+    private static String sFeedsTable = "feeds";
+    private static Uri sFeedsUrl =
+            Uri.parse("content://subscribedfeeds/feeds/");
+    private static String sDeletedFeedsTable = "_deleted_feeds";
+    private static Uri sDeletedFeedsUrl =
+            Uri.parse("content://subscribedfeeds/deleted_feeds/");
+
+    public SubscribedFeedsProvider() {
+        super(DATABASE_NAME, DATABASE_VERSION, sFeedsUrl);
+    }
+
+    static {
+        sURLMatcher.addURI("subscribedfeeds", "feeds", FEEDS);
+        sURLMatcher.addURI("subscribedfeeds", "feeds/#", FEED_ID);
+        sURLMatcher.addURI("subscribedfeeds", "deleted_feeds", DELETED_FEEDS);
+        sURLMatcher.addURI("subscribedfeeds", "accounts", ACCOUNTS);
+    }
+
+    @Override
+    protected boolean upgradeDatabase(SQLiteDatabase db,
+            int oldVersion, int newVersion) {
+        Log.w(TAG, "Upgrading database from version " + oldVersion +
+                " to " + newVersion +
+                ", which will destroy all old data");
+        db.execSQL("DROP TRIGGER IF EXISTS feed_cleanup");
+        db.execSQL("DROP TABLE IF EXISTS _deleted_feeds");
+        db.execSQL("DROP TABLE IF EXISTS feeds");
+        bootstrapDatabase(db);
+        return false; // this was lossy
+    }
+
+    @Override
+    protected void bootstrapDatabase(SQLiteDatabase db) {
+        super.bootstrapDatabase(db);
+        db.execSQL("CREATE TABLE feeds (" +
+                    "_id INTEGER PRIMARY KEY," +
+                    "_sync_account TEXT," + // From the sync source
+                    "_sync_id TEXT," + // From the sync source
+                    "_sync_time TEXT," + // From the sync source
+                    "_sync_version TEXT," + // From the sync source
+                    "_sync_local_id INTEGER," + // Used while syncing,
+                                                // never stored persistently
+                    "_sync_dirty INTEGER," + // if syncable, set if the record
+                                             // has local, unsynced, changes
+                    "_sync_mark INTEGER," + // Used to filter out new rows
+                    "feed TEXT," +
+                    "authority TEXT," +
+                    "service TEXT" +
+                    ");");
+
+        // Trigger to completely remove feeds data when they're deleted
+        db.execSQL("CREATE TRIGGER feed_cleanup DELETE ON feeds " +
+                    "WHEN old._sync_id is not null " +
+                    "BEGIN " +
+                        "INSERT INTO _deleted_feeds " +
+                            "(_sync_id, _sync_account, _sync_version) " +
+                            "VALUES (old._sync_id, old._sync_account, " +
+                            "old._sync_version);" +
+                    "END");
+
+        db.execSQL("CREATE TABLE _deleted_feeds (" +
+                    "_sync_version TEXT," + // From the sync source
+                    "_sync_id TEXT," +
+                    (isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
+                    "_sync_account TEXT," +
+                    "_sync_mark INTEGER, " + // Used to filter out new rows
+                    "UNIQUE(_sync_id))");
+    }
+
+    @Override
+    protected void onDatabaseOpened(SQLiteDatabase db) {
+        db.markTableSyncable("feeds", "_deleted_feeds");
+    }
+
+    @Override
+    protected Iterable<FeedMerger> getMergers() {
+        return Collections.singletonList(new FeedMerger());
+    }
+
+    @Override
+    public String getType(Uri url) {
+        int match = sURLMatcher.match(url);
+        switch (match) {
+            case FEEDS:
+                return SubscribedFeeds.Feeds.CONTENT_TYPE;
+            case FEED_ID:
+                return SubscribedFeeds.Feeds.CONTENT_ITEM_TYPE;
+            default:
+                throw new IllegalArgumentException("Unknown URL");
+        }
+    }
+
+    @Override
+    public Cursor queryInternal(Uri url, String[] projection,
+            String selection, String[] selectionArgs, String sortOrder) {
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+
+
+        // Generate the body of the query
+        int match = sURLMatcher.match(url);
+
+        if (Config.LOGV) Log.v(TAG, "SubscribedFeedsProvider.query: url=" +
+                url + ", match is " + match);
+
+        switch (match) {
+            case FEEDS:
+                qb.setTables(sFeedsTable);
+                break;
+            case DELETED_FEEDS:
+                if (!isTemporary()) {
+                    throw new UnsupportedOperationException();
+                }
+                qb.setTables(sDeletedFeedsTable);
+                break;
+            case ACCOUNTS:
+                qb.setTables(sFeedsTable);
+                qb.setDistinct(true);
+                qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
+                return qb.query(getDatabase(), projection, selection, selectionArgs,
+                        SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
+            case FEED_ID:
+                qb.setTables(sFeedsTable);
+                qb.appendWhere(sFeedsTable + "._id=");
+                qb.appendWhere(url.getPathSegments().get(1));
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown URL " + url);
+        }
+
+        // run the query
+        return qb.query(getDatabase(), projection, selection, selectionArgs,
+                null, null, sortOrder);
+    }
+
+    @Override
+    public Uri insertInternal(Uri url, ContentValues initialValues) {
+        final SQLiteDatabase db = getDatabase();
+        Uri resultUri = null;
+        long rowID;
+
+        int match = sURLMatcher.match(url);
+        switch (match) {
+            case FEEDS:
+                ContentValues values = new ContentValues(initialValues);
+                values.put(SubscribedFeeds.Feeds._SYNC_DIRTY, 1);
+                rowID = db.insert(sFeedsTable, "feed", values);
+                if (rowID > 0) {
+                    resultUri = Uri.parse(
+                            "content://subscribedfeeds/feeds/" + rowID);
+                }
+                break;
+
+            case DELETED_FEEDS:
+                if (!isTemporary()) {
+                    throw new UnsupportedOperationException();
+                }
+                rowID = db.insert(sDeletedFeedsTable, "_sync_id",
+                        initialValues);
+                if (rowID > 0) {
+                    resultUri = Uri.parse(
+                            "content://subscribedfeeds/deleted_feeds/" + rowID);
+                }
+                break;
+
+            default:
+                throw new UnsupportedOperationException(
+                        "Cannot insert into URL: " + url);
+        }
+
+        return resultUri;
+    }
+
+    @Override
+    public int deleteInternal(Uri url, String userWhere, String[] whereArgs) {
+        final SQLiteDatabase db = getDatabase();
+        String changedItemId;
+
+        switch (sURLMatcher.match(url)) {
+            case FEEDS:
+                changedItemId = null;
+                break;
+            case FEED_ID:
+                changedItemId = url.getPathSegments().get(1);
+                break;
+            default:
+                throw new UnsupportedOperationException(
+                        "Cannot delete that URL: " + url);
+        }
+
+        String where = addIdToWhereClause(changedItemId, userWhere);
+        return db.delete(sFeedsTable, where, whereArgs);
+    }
+
+    @Override
+    public int updateInternal(Uri url, ContentValues initialValues,
+            String userWhere, String[] whereArgs) {
+        final SQLiteDatabase db = getDatabase();
+        ContentValues values = new ContentValues(initialValues);
+        values.put(SubscribedFeeds.Feeds._SYNC_DIRTY, 1);
+
+        String changedItemId;
+        switch (sURLMatcher.match(url)) {
+            case FEEDS:
+                changedItemId = null;
+                break;
+
+            case FEED_ID:
+                changedItemId = url.getPathSegments().get(1);
+                break;
+
+            default:
+                throw new UnsupportedOperationException(
+                        "Cannot update URL: " + url);
+        }
+
+        String where = addIdToWhereClause(changedItemId, userWhere);
+        return db.update(sFeedsTable, values, where, whereArgs);
+    }
+
+    private static String addIdToWhereClause(String id, String where) {
+        if (id != null) {
+            StringBuilder whereSb = new StringBuilder("_id=");
+            whereSb.append(id);
+            if (!TextUtils.isEmpty(where)) {
+                whereSb.append(" AND (");
+                whereSb.append(where);
+                whereSb.append(')');
+            }
+            return whereSb.toString();
+        } else {
+            return where;
+        }
+    }
+
+    private class FeedMerger extends AbstractTableMerger {
+        private ContentValues mValues = new ContentValues();
+        FeedMerger() {
+            super(getDatabase(), sFeedsTable, sFeedsUrl, sDeletedFeedsTable, sDeletedFeedsUrl);
+        }
+
+        @Override
+        protected void notifyChanges() {
+            getContext().getContentResolver().notifyChange(
+                    sFeedsUrl, null /* data change observer */,
+                    false /* do not sync to network */);
+        }
+
+        @Override
+        public void insertRow(ContentProvider diffs, Cursor diffsCursor) {
+            final SQLiteDatabase db = getDatabase();
+            // We don't ever want to add entries from the server, instead
+            // we want to tell the server to delete any entries we receive
+            // from the server that aren't already known by the client.
+            mValues.clear();
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_ID, mValues);
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_ACCOUNT, mValues);
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
+            db.replace(mDeletedTable, SubscribedFeeds.Feeds._SYNC_ID, mValues);
+        }
+
+        @Override
+        public void updateRow(long localPersonID, ContentProvider diffs,
+                Cursor diffsCursor) {
+            updateOrResolveRow(localPersonID, null, diffs, diffsCursor, false);
+        }
+
+        @Override
+        public void resolveRow(long localPersonID, String syncID,
+                ContentProvider diffs, Cursor diffsCursor) {
+            updateOrResolveRow(localPersonID, syncID, diffs, diffsCursor, true);
+        }
+
+        protected void updateOrResolveRow(long localPersonID, String syncID,
+                ContentProvider diffs, Cursor diffsCursor, boolean conflicts) {
+            mValues.clear();
+            // only copy over the fields that the server owns
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_ID, mValues);
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_TIME, mValues);
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
+            mValues.put(SubscribedFeeds.Feeds._SYNC_DIRTY, conflicts ? 1 : 0);
+            final SQLiteDatabase db = getDatabase();
+            db.update(mTable, mValues,
+                    SubscribedFeeds.Feeds._ID + '=' + localPersonID, null);
+        }
+
+        @Override
+        public void deleteRow(Cursor localCursor) {
+            // Since the client is the authority we don't actually delete
+            // the row when the server says it has been deleted. Instead
+            // we break the association with the server by clearing out
+            // the id, time, and version, then we mark it dirty so that
+            // it will be synced back to the server.
+            long localPersonId = localCursor.getLong(localCursor.getColumnIndex(
+                    SubscribedFeeds.Feeds._ID));
+            mValues.clear();
+            mValues.put(SubscribedFeeds.Feeds._SYNC_DIRTY, 1);
+            mValues.put(SubscribedFeeds.Feeds._SYNC_ID, (String) null);
+            mValues.put(SubscribedFeeds.Feeds._SYNC_TIME, (Long) null);
+            mValues.put(SubscribedFeeds.Feeds._SYNC_VERSION, (String) null);
+            final SQLiteDatabase db = getDatabase();
+            db.update(mTable, mValues, SubscribedFeeds.Feeds._ID + '=' + localPersonId, null);
+            localCursor.moveToNext();
+        }
+    }
+
+    static {
+        Map<String, String> map;
+
+        map = new HashMap<String, String>();
+        ACCOUNTS_PROJECTION_MAP = map;
+        map.put(SubscribedFeeds.Accounts._COUNT, "COUNT(*) AS _count");
+        map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT, SubscribedFeeds.Accounts._SYNC_ACCOUNT);
+    }
+}