DatabaseHelper.java revision ae3ed706702a5ebe6ffcc08b941b1401c9a24b89
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.settings;
18
19import android.content.ComponentName;
20import android.content.ContentValues;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.ActivityInfo;
24import android.content.pm.PackageManager;
25import android.content.res.Resources;
26import android.database.Cursor;
27import android.database.sqlite.SQLiteDatabase;
28import android.database.sqlite.SQLiteDoneException;
29import android.database.sqlite.SQLiteException;
30import android.database.sqlite.SQLiteOpenHelper;
31import android.database.sqlite.SQLiteStatement;
32import android.media.AudioManager;
33import android.media.AudioService;
34import android.net.ConnectivityManager;
35import android.os.Environment;
36import android.os.SystemProperties;
37import android.provider.Settings;
38import android.text.TextUtils;
39import android.util.Config;
40import android.util.Log;
41import android.util.Xml;
42import com.android.internal.util.XmlUtils;
43import com.android.internal.telephony.RILConstants;
44
45import com.android.internal.widget.LockPatternUtils;
46import com.android.internal.widget.LockPatternView;
47
48import org.xmlpull.v1.XmlPullParser;
49import org.xmlpull.v1.XmlPullParserException;
50
51import java.io.File;
52import java.io.FileNotFoundException;
53import java.io.FileReader;
54import java.io.IOException;
55import java.util.List;
56
57/**
58 * Database helper class for {@link SettingsProvider}.
59 * Mostly just has a bit {@link #onCreate} to initialize the database.
60 */
61public class DatabaseHelper extends SQLiteOpenHelper {
62    /**
63     * Path to file containing default bookmarks, relative to ANDROID_ROOT.
64     */
65    private static final String DEFAULT_BOOKMARKS_PATH = "etc/bookmarks.xml";
66
67    private static final String TAG = "SettingsProvider";
68    private static final String DATABASE_NAME = "settings.db";
69
70    // Please, please please. If you update the database version, check to make sure the
71    // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
72    // is properly propagated through your change.  Not doing so will result in a loss of user
73    // settings.
74    private static final int DATABASE_VERSION = 43;
75
76    private Context mContext;
77
78    public DatabaseHelper(Context context) {
79        super(context, DATABASE_NAME, null, DATABASE_VERSION);
80        mContext = context;
81    }
82
83    private void createSecureTable(SQLiteDatabase db) {
84        db.execSQL("CREATE TABLE secure (" +
85                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
86                "name TEXT UNIQUE ON CONFLICT REPLACE," +
87                "value TEXT" +
88                ");");
89        db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
90    }
91
92    @Override
93    public void onCreate(SQLiteDatabase db) {
94        db.execSQL("CREATE TABLE system (" +
95                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
96                    "name TEXT UNIQUE ON CONFLICT REPLACE," +
97                    "value TEXT" +
98                    ");");
99        db.execSQL("CREATE INDEX systemIndex1 ON system (name);");
100
101        createSecureTable(db);
102
103        db.execSQL("CREATE TABLE gservices (" +
104                   "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
105                   "name TEXT UNIQUE ON CONFLICT REPLACE," +
106                   "value TEXT" +
107                   ");");
108        db.execSQL("CREATE INDEX gservicesIndex1 ON gservices (name);");
109
110        db.execSQL("CREATE TABLE bluetooth_devices (" +
111                    "_id INTEGER PRIMARY KEY," +
112                    "name TEXT," +
113                    "addr TEXT," +
114                    "channel INTEGER," +
115                    "type INTEGER" +
116                    ");");
117
118        db.execSQL("CREATE TABLE bookmarks (" +
119                    "_id INTEGER PRIMARY KEY," +
120                    "title TEXT," +
121                    "folder TEXT," +
122                    "intent TEXT," +
123                    "shortcut INTEGER," +
124                    "ordering INTEGER" +
125                    ");");
126
127        db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);");
128        db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");
129
130        // Populate bookmarks table with initial bookmarks
131        loadBookmarks(db);
132
133        // Load initial volume levels into DB
134        loadVolumeLevels(db);
135
136        // Load inital settings values
137        loadSettings(db);
138    }
139
140    @Override
141    public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
142        Log.w(TAG, "Upgrading settings database from version " + oldVersion + " to "
143                + currentVersion);
144
145        int upgradeVersion = oldVersion;
146
147        // Pattern for upgrade blocks:
148        //
149        //    if (upgradeVersion == [the DATABASE_VERSION you set] - 1) {
150        //        .. your upgrade logic..
151        //        upgradeVersion = [the DATABASE_VERSION you set]
152        //    }
153
154        if (upgradeVersion == 20) {
155            /*
156             * Version 21 is part of the volume control refresh. There is no
157             * longer a UI-visible for setting notification vibrate on/off (in
158             * our design), but the functionality still exists. Force the
159             * notification vibrate to on.
160             */
161            loadVibrateSetting(db, true);
162            if (Config.LOGD) Log.d(TAG, "Reset system vibrate setting");
163
164            upgradeVersion = 21;
165        }
166
167        if (upgradeVersion < 22) {
168            upgradeVersion = 22;
169            // Upgrade the lock gesture storage location and format
170            upgradeLockPatternLocation(db);
171        }
172
173        if (upgradeVersion < 23) {
174            db.execSQL("UPDATE favorites SET iconResource=0 WHERE iconType=0");
175            upgradeVersion = 23;
176        }
177
178        if (upgradeVersion == 23) {
179            db.beginTransaction();
180            try {
181                db.execSQL("ALTER TABLE favorites ADD spanX INTEGER");
182                db.execSQL("ALTER TABLE favorites ADD spanY INTEGER");
183                // Shortcuts, applications, folders
184                db.execSQL("UPDATE favorites SET spanX=1, spanY=1 WHERE itemType<=0");
185                // Photo frames, clocks
186                db.execSQL(
187                    "UPDATE favorites SET spanX=2, spanY=2 WHERE itemType=1000 or itemType=1002");
188                // Search boxes
189                db.execSQL("UPDATE favorites SET spanX=4, spanY=1 WHERE itemType=1001");
190                db.setTransactionSuccessful();
191            } finally {
192                db.endTransaction();
193            }
194            upgradeVersion = 24;
195        }
196
197        if (upgradeVersion == 24) {
198            db.beginTransaction();
199            try {
200                // The value of the constants for preferring wifi or preferring mobile have been
201                // swapped, so reload the default.
202                db.execSQL("DELETE FROM system WHERE name='network_preference'");
203                db.execSQL("INSERT INTO system ('name', 'value') values ('network_preference', '" +
204                        ConnectivityManager.DEFAULT_NETWORK_PREFERENCE + "')");
205                db.setTransactionSuccessful();
206            } finally {
207                db.endTransaction();
208            }
209            upgradeVersion = 25;
210        }
211
212        if (upgradeVersion == 25) {
213            db.beginTransaction();
214            try {
215                db.execSQL("ALTER TABLE favorites ADD uri TEXT");
216                db.execSQL("ALTER TABLE favorites ADD displayMode INTEGER");
217                db.setTransactionSuccessful();
218            } finally {
219                db.endTransaction();
220            }
221            upgradeVersion = 26;
222        }
223
224        if (upgradeVersion == 26) {
225            // This introduces the new secure settings table.
226            db.beginTransaction();
227            try {
228                createSecureTable(db);
229                db.setTransactionSuccessful();
230            } finally {
231                db.endTransaction();
232            }
233            upgradeVersion = 27;
234        }
235
236        if (upgradeVersion == 27) {
237            // Copy settings values from 'system' to 'secure' and delete them from 'system'
238            SQLiteStatement insertStmt = null;
239            SQLiteStatement deleteStmt = null;
240
241            db.beginTransaction();
242            try {
243                insertStmt =
244                    db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM "
245                        + "system WHERE name=?");
246                deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?");
247
248                String[] settingsToMove = {
249                    Settings.Secure.ADB_ENABLED,
250                    Settings.Secure.ANDROID_ID,
251                    Settings.Secure.BLUETOOTH_ON,
252                    Settings.Secure.DATA_ROAMING,
253                    Settings.Secure.DEVICE_PROVISIONED,
254                    Settings.Secure.HTTP_PROXY,
255                    Settings.Secure.INSTALL_NON_MARKET_APPS,
256                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
257                    Settings.Secure.LOGGING_ID,
258                    Settings.Secure.NETWORK_PREFERENCE,
259                    Settings.Secure.PARENTAL_CONTROL_ENABLED,
260                    Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
261                    Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL,
262                    Settings.Secure.SETTINGS_CLASSNAME,
263                    Settings.Secure.USB_MASS_STORAGE_ENABLED,
264                    Settings.Secure.USE_GOOGLE_MAIL,
265                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
266                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
267                    Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT,
268                    Settings.Secure.WIFI_ON,
269                    Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
270                    Settings.Secure.WIFI_WATCHDOG_AP_COUNT,
271                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
272                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
273                    Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
274                    Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
275                    Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS,
276                    Settings.Secure.WIFI_WATCHDOG_ON,
277                    Settings.Secure.WIFI_WATCHDOG_PING_COUNT,
278                    Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS,
279                    Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS,
280                };
281
282                for (String setting : settingsToMove) {
283                    insertStmt.bindString(1, setting);
284                    insertStmt.execute();
285
286                    deleteStmt.bindString(1, setting);
287                    deleteStmt.execute();
288                }
289                db.setTransactionSuccessful();
290            } finally {
291                db.endTransaction();
292                if (insertStmt != null) {
293                    insertStmt.close();
294                }
295                if (deleteStmt != null) {
296                    deleteStmt.close();
297                }
298            }
299            upgradeVersion = 28;
300        }
301
302        if (upgradeVersion == 28 || upgradeVersion == 29) {
303            // Note: The upgrade to 28 was flawed since it didn't delete the old
304            // setting first before inserting. Combining 28 and 29 with the
305            // fixed version.
306
307            // This upgrade adds the STREAM_NOTIFICATION type to the list of
308            // types affected by ringer modes (silent, vibrate, etc.)
309            db.beginTransaction();
310            try {
311                db.execSQL("DELETE FROM system WHERE name='"
312                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'");
313                int newValue = (1 << AudioManager.STREAM_RING)
314                        | (1 << AudioManager.STREAM_NOTIFICATION)
315                        | (1 << AudioManager.STREAM_SYSTEM);
316                db.execSQL("INSERT INTO system ('name', 'value') values ('"
317                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '"
318                        + String.valueOf(newValue) + "')");
319                db.setTransactionSuccessful();
320            } finally {
321                db.endTransaction();
322            }
323
324            upgradeVersion = 30;
325        }
326
327        if (upgradeVersion == 30) {
328            /*
329             * Upgrade 31 clears the title for all quick launch shortcuts so the
330             * activities' titles will be resolved at display time. Also, the
331             * folder is changed to '@quicklaunch'.
332             */
333            db.beginTransaction();
334            try {
335                db.execSQL("UPDATE bookmarks SET folder = '@quicklaunch'");
336                db.execSQL("UPDATE bookmarks SET title = ''");
337                db.setTransactionSuccessful();
338            } finally {
339                db.endTransaction();
340            }
341            upgradeVersion = 31;
342        }
343
344        if (upgradeVersion == 31) {
345            /*
346             * Animations are now managed in preferences, and may be
347             * enabled or disabled based on product resources.
348             */
349            db.beginTransaction();
350            try {
351                db.execSQL("DELETE FROM system WHERE name='"
352                        + Settings.System.WINDOW_ANIMATION_SCALE + "'");
353                db.execSQL("DELETE FROM system WHERE name='"
354                        + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
355                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
356                        + " VALUES(?,?);");
357                loadDefaultAnimationSettings(stmt);
358                stmt.close();
359                db.setTransactionSuccessful();
360            } finally {
361                db.endTransaction();
362            }
363            upgradeVersion = 32;
364        }
365
366        if (upgradeVersion == 32) {
367            // The Wi-Fi watchdog SSID list is now seeded with the value of
368            // the property ro.com.android.wifi-watchlist
369            String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
370            if (!TextUtils.isEmpty(wifiWatchList)) {
371                db.beginTransaction();
372                try {
373                    db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
374                            Settings.Secure.WIFI_WATCHDOG_WATCH_LIST + "','" +
375                            wifiWatchList + "');");
376                    db.setTransactionSuccessful();
377                } finally {
378                    db.endTransaction();
379                }
380            }
381            upgradeVersion = 33;
382        }
383
384        if (upgradeVersion == 33) {
385            // Set the default zoom controls to: tap-twice to bring up +/-
386            db.beginTransaction();
387            try {
388                db.execSQL("INSERT INTO system(name,value) values('zoom','2');");
389                db.setTransactionSuccessful();
390            } finally {
391                db.endTransaction();
392            }
393            upgradeVersion = 34;
394        }
395
396        if (upgradeVersion == 34) {
397            db.beginTransaction();
398            try {
399                SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
400                        + " VALUES(?,?);");
401                loadSecure35Settings(stmt);
402                stmt.close();
403                db.setTransactionSuccessful();
404            } finally {
405                db.endTransaction();
406            }
407            upgradeVersion = 35;
408        }
409            // due to a botched merge from donut to eclair, the initialization of ASSISTED_GPS_ENABLED
410            // was accidentally done out of order here.
411            // to fix this, ASSISTED_GPS_ENABLED is now initialized while upgrading from 38 to 39,
412            // and we intentionally do nothing from 35 to 36 now.
413        if (upgradeVersion == 35) {
414            upgradeVersion = 36;
415        }
416
417        if (upgradeVersion == 36) {
418           // This upgrade adds the STREAM_SYSTEM_ENFORCED type to the list of
419            // types affected by ringer modes (silent, vibrate, etc.)
420            db.beginTransaction();
421            try {
422                db.execSQL("DELETE FROM system WHERE name='"
423                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'");
424                int newValue = (1 << AudioManager.STREAM_RING)
425                        | (1 << AudioManager.STREAM_NOTIFICATION)
426                        | (1 << AudioManager.STREAM_SYSTEM)
427                        | (1 << AudioManager.STREAM_SYSTEM_ENFORCED);
428                db.execSQL("INSERT INTO system ('name', 'value') values ('"
429                        + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '"
430                        + String.valueOf(newValue) + "')");
431                db.setTransactionSuccessful();
432            } finally {
433                db.endTransaction();
434            }
435            upgradeVersion = 37;
436        }
437
438        if (upgradeVersion == 37) {
439            db.beginTransaction();
440            try {
441                SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
442                        + " VALUES(?,?);");
443                loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
444                        R.string.airplane_mode_toggleable_radios);
445                stmt.close();
446                db.setTransactionSuccessful();
447            } finally {
448                db.endTransaction();
449            }
450            upgradeVersion = 38;
451        }
452
453        if (upgradeVersion == 38) {
454            db.beginTransaction();
455            try {
456                String value =
457                        mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0";
458                db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
459                        Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');");
460                db.setTransactionSuccessful();
461            } finally {
462                db.endTransaction();
463            }
464
465            upgradeVersion = 39;
466        }
467
468        if (upgradeVersion == 39) {
469            db.beginTransaction();
470            try {
471                String value =
472                        mContext.getResources().getBoolean(
473                        R.bool.def_screen_brightness_automatic_mode) ? "1" : "0";
474                db.execSQL("INSERT OR IGNORE INTO system(name,value) values('" +
475                        Settings.System.SCREEN_BRIGHTNESS_MODE + "','" + value + "');");
476                db.setTransactionSuccessful();
477            } finally {
478                db.endTransaction();
479            }
480
481            upgradeVersion = 40;
482        }
483
484        if (upgradeVersion == 40) {
485            /*
486             * All animations are now turned on by default!
487             */
488            db.beginTransaction();
489            try {
490                db.execSQL("DELETE FROM system WHERE name='"
491                        + Settings.System.WINDOW_ANIMATION_SCALE + "'");
492                db.execSQL("DELETE FROM system WHERE name='"
493                        + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
494                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
495                        + " VALUES(?,?);");
496                loadDefaultAnimationSettings(stmt);
497                stmt.close();
498                db.setTransactionSuccessful();
499            } finally {
500                db.endTransaction();
501            }
502            upgradeVersion = 41;
503        }
504
505        if (upgradeVersion == 41) {
506            /*
507             * Initialize newly public haptic feedback setting
508             */
509            db.beginTransaction();
510            try {
511                db.execSQL("DELETE FROM system WHERE name='"
512                        + Settings.System.HAPTIC_FEEDBACK_ENABLED + "'");
513                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
514                        + " VALUES(?,?);");
515                loadDefaultHapticSettings(stmt);
516                stmt.close();
517                db.setTransactionSuccessful();
518            } finally {
519                db.endTransaction();
520            }
521            upgradeVersion = 42;
522        }
523
524        if (upgradeVersion == 42) {
525            /*
526             * Initialize new notification pulse setting
527             */
528            db.beginTransaction();
529            try {
530                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
531                        + " VALUES(?,?);");
532                loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
533                        R.bool.def_notification_pulse);
534                stmt.close();
535                db.setTransactionSuccessful();
536            } finally {
537                db.endTransaction();
538            }
539            upgradeVersion = 43;
540        }
541
542        if (upgradeVersion != currentVersion) {
543            Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
544                    + ", must wipe the settings provider");
545            db.execSQL("DROP TABLE IF EXISTS system");
546            db.execSQL("DROP INDEX IF EXISTS systemIndex1");
547            db.execSQL("DROP TABLE IF EXISTS secure");
548            db.execSQL("DROP INDEX IF EXISTS secureIndex1");
549            db.execSQL("DROP TABLE IF EXISTS gservices");
550            db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
551            db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
552            db.execSQL("DROP TABLE IF EXISTS bookmarks");
553            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
554            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
555            db.execSQL("DROP TABLE IF EXISTS favorites");
556            onCreate(db);
557        }
558    }
559
560    private void upgradeLockPatternLocation(SQLiteDatabase db) {
561        Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'",
562                null, null, null, null);
563        if (c.getCount() > 0) {
564            c.moveToFirst();
565            String lockPattern = c.getString(1);
566            if (!TextUtils.isEmpty(lockPattern)) {
567                // Convert lock pattern
568                try {
569                    LockPatternUtils lpu = new LockPatternUtils(mContext.getContentResolver());
570                    List<LockPatternView.Cell> cellPattern =
571                            LockPatternUtils.stringToPattern(lockPattern);
572                    lpu.saveLockPattern(cellPattern);
573                } catch (IllegalArgumentException e) {
574                    // Don't want corrupted lock pattern to hang the reboot process
575                }
576            }
577            c.close();
578            db.delete("system", "name='lock_pattern'", null);
579        } else {
580            c.close();
581        }
582    }
583
584    /**
585     * Loads the default set of bookmarked shortcuts from an xml file.
586     *
587     * @param db The database to write the values into
588     * @param startingIndex The zero-based position at which bookmarks in this file should begin
589     * @param subPath The relative path from ANDROID_ROOT to the file to read
590     * @param quiet If true, do no complain if the file is missing
591     */
592    private int loadBookmarks(SQLiteDatabase db, int startingIndex, String subPath,
593            boolean quiet) {
594        FileReader bookmarksReader;
595
596        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
597        final File favFile = new File(Environment.getRootDirectory(), subPath);
598        try {
599            bookmarksReader = new FileReader(favFile);
600        } catch (FileNotFoundException e) {
601            if (!quiet) {
602                Log.e(TAG, "Couldn't find or open bookmarks file " + favFile);
603            }
604            return 0;
605        }
606
607        Intent intent = new Intent(Intent.ACTION_MAIN, null);
608        intent.addCategory(Intent.CATEGORY_LAUNCHER);
609        ContentValues values = new ContentValues();
610
611        PackageManager packageManager = mContext.getPackageManager();
612        ActivityInfo info;
613        int i = startingIndex;
614        try {
615            XmlPullParser parser = Xml.newPullParser();
616            parser.setInput(bookmarksReader);
617
618            XmlUtils.beginDocument(parser, "bookmarks");
619
620            while (true) {
621                XmlUtils.nextElement(parser);
622
623                String name = parser.getName();
624                if (!"bookmark".equals(name)) {
625                    break;
626                }
627
628                String pkg = parser.getAttributeValue(null, "package");
629                String cls = parser.getAttributeValue(null, "class");
630                String shortcutStr = parser.getAttributeValue(null, "shortcut");
631                int shortcutValue = (int) shortcutStr.charAt(0);
632                if (TextUtils.isEmpty(shortcutStr)) {
633                    Log.w(TAG, "Unable to get shortcut for: " + pkg + "/" + cls);
634                }
635                try {
636                    ComponentName cn = new ComponentName(pkg, cls);
637                    info = packageManager.getActivityInfo(cn, 0);
638                    intent.setComponent(cn);
639                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
640                    values.put(Settings.Bookmarks.INTENT, intent.toURI());
641                    values.put(Settings.Bookmarks.TITLE,
642                            info.loadLabel(packageManager).toString());
643                    values.put(Settings.Bookmarks.SHORTCUT, shortcutValue);
644                    db.insert("bookmarks", null, values);
645                    i++;
646                } catch (PackageManager.NameNotFoundException e) {
647                    Log.w(TAG, "Unable to add bookmark: " + pkg + "/" + cls, e);
648                }
649            }
650        } catch (XmlPullParserException e) {
651            Log.w(TAG, "Got execption parsing bookmarks.", e);
652        } catch (IOException e) {
653            Log.w(TAG, "Got execption parsing bookmarks.", e);
654        }
655
656        return i;
657    }
658
659    /**
660     * Loads the default set of bookmark packages.
661     *
662     * @param db The database to write the values into
663     */
664    private void loadBookmarks(SQLiteDatabase db) {
665        loadBookmarks(db, 0, DEFAULT_BOOKMARKS_PATH, false);
666    }
667
668    /**
669     * Loads the default volume levels. It is actually inserting the index of
670     * the volume array for each of the volume controls.
671     *
672     * @param db the database to insert the volume levels into
673     */
674    private void loadVolumeLevels(SQLiteDatabase db) {
675        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
676                + " VALUES(?,?);");
677
678        loadSetting(stmt, Settings.System.VOLUME_MUSIC,
679                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
680        loadSetting(stmt, Settings.System.VOLUME_RING,
681                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_RING]);
682        loadSetting(stmt, Settings.System.VOLUME_SYSTEM,
683                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
684        loadSetting(
685                stmt,
686                Settings.System.VOLUME_VOICE,
687                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
688        loadSetting(stmt, Settings.System.VOLUME_ALARM,
689                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_ALARM]);
690        loadSetting(
691                stmt,
692                Settings.System.VOLUME_NOTIFICATION,
693                AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_NOTIFICATION]);
694        loadSetting(stmt, Settings.System.MODE_RINGER,
695                AudioManager.RINGER_MODE_NORMAL);
696
697        loadVibrateSetting(db, false);
698
699        // By default, only the ring/notification and system streams are affected
700        loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
701                (1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) |
702                (1 << AudioManager.STREAM_SYSTEM) | (1 << AudioManager.STREAM_SYSTEM_ENFORCED));
703
704        loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
705                ((1 << AudioManager.STREAM_MUSIC) |
706                 (1 << AudioManager.STREAM_RING) |
707                 (1 << AudioManager.STREAM_NOTIFICATION) |
708                 (1 << AudioManager.STREAM_SYSTEM)));
709
710        stmt.close();
711    }
712
713    private void loadVibrateSetting(SQLiteDatabase db, boolean deleteOld) {
714        if (deleteOld) {
715            db.execSQL("DELETE FROM system WHERE name='" + Settings.System.VIBRATE_ON + "'");
716        }
717
718        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
719                + " VALUES(?,?);");
720
721        // Vibrate off by default for ringer, on for notification
722        int vibrate = 0;
723        vibrate = AudioService.getValueForVibrateSetting(vibrate,
724                AudioManager.VIBRATE_TYPE_NOTIFICATION, AudioManager.VIBRATE_SETTING_ON);
725        vibrate = AudioService.getValueForVibrateSetting(vibrate,
726                AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
727        loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
728    }
729
730    private void loadSettings(SQLiteDatabase db) {
731        loadSystemSettings(db);
732        loadSecureSettings(db);
733    }
734
735    private void loadSystemSettings(SQLiteDatabase db) {
736        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
737                + " VALUES(?,?);");
738
739        Resources r = mContext.getResources();
740
741        loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
742                R.bool.def_dim_screen);
743        loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
744                "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
745        loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
746                R.integer.def_screen_off_timeout);
747
748        // Set default cdma emergency tone
749        loadSetting(stmt, Settings.System.EMERGENCY_TONE, 0);
750
751        // Set default cdma call auto retry
752        loadSetting(stmt, Settings.System.CALL_AUTO_RETRY, 0);
753
754        // Set default cdma DTMF type
755        loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
756
757        // Set default hearing aid
758        loadSetting(stmt, Settings.System.HEARING_AID, 0);
759
760        // Set default tty mode
761        loadSetting(stmt, Settings.System.TTY_MODE, 0);
762
763        loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
764                R.bool.def_airplane_mode_on);
765
766        loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
767                R.string.def_airplane_mode_radios);
768
769        loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
770                R.string.airplane_mode_toggleable_radios);
771
772        loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
773                R.bool.def_auto_time); // Sync time to NITZ
774
775        loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
776                R.integer.def_screen_brightness);
777
778        loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
779                R.bool.def_screen_brightness_automatic_mode);
780
781        loadDefaultAnimationSettings(stmt);
782
783        loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
784                R.bool.def_accelerometer_rotation);
785
786        loadDefaultHapticSettings(stmt);
787
788        loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
789                R.bool.def_notification_pulse);
790        stmt.close();
791    }
792
793    private void loadDefaultAnimationSettings(SQLiteStatement stmt) {
794        loadFractionSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE,
795                R.fraction.def_window_animation_scale, 1);
796        loadFractionSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE,
797                R.fraction.def_window_transition_scale, 1);
798    }
799
800    private void loadDefaultHapticSettings(SQLiteStatement stmt) {
801        loadBooleanSetting(stmt, Settings.System.HAPTIC_FEEDBACK_ENABLED,
802                R.bool.def_haptic_feedback);
803    }
804
805    private void loadSecureSettings(SQLiteDatabase db) {
806        SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
807                + " VALUES(?,?);");
808
809        loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON,
810                R.bool.def_bluetooth_on);
811
812        // Data roaming default, based on build
813        loadSetting(stmt, Settings.Secure.DATA_ROAMING,
814                "true".equalsIgnoreCase(
815                        SystemProperties.get("ro.com.android.dataroaming",
816                                "false")) ? 1 : 0);
817
818        loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
819                R.bool.def_install_non_market_apps);
820
821        loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
822                R.string.def_location_providers_allowed);
823
824        loadBooleanSetting(stmt, Settings.Secure.ASSISTED_GPS_ENABLED,
825                R.bool.assisted_gps_enabled);
826
827        loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
828                R.integer.def_network_preference);
829
830        loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED,
831                R.bool.def_usb_mass_storage_enabled);
832
833        loadBooleanSetting(stmt, Settings.Secure.WIFI_ON,
834                R.bool.def_wifi_on);
835        loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
836                R.bool.def_networks_available_notification_on);
837
838        String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
839        if (!TextUtils.isEmpty(wifiWatchList)) {
840            loadSetting(stmt, Settings.Secure.WIFI_WATCHDOG_WATCH_LIST, wifiWatchList);
841        }
842
843        // Set the preferred network mode to 0 = Global, CDMA default
844        int type = SystemProperties.getInt("ro.telephony.default_network",
845                RILConstants.PREFERRED_NETWORK_MODE);
846        loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type);
847
848        // Enable or disable Cell Broadcast SMS
849        loadSetting(stmt, Settings.Secure.CDMA_CELL_BROADCAST_SMS,
850                RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
851
852        // Set the preferred cdma subscription to 0 = Subscription from RUIM, when available
853        loadSetting(stmt, Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION,
854                RILConstants.PREFERRED_CDMA_SUBSCRIPTION);
855
856        // Don't do this.  The SystemServer will initialize ADB_ENABLED from a
857        // persistent system property instead.
858        //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
859
860        // Allow mock locations default, based on build
861        loadSetting(stmt, Settings.Secure.ALLOW_MOCK_LOCATION,
862                "1".equals(SystemProperties.get("ro.allow.mock.location")) ? 1 : 0);
863
864        loadSecure35Settings(stmt);
865
866        stmt.close();
867    }
868
869    private void loadSecure35Settings(SQLiteStatement stmt) {
870        loadBooleanSetting(stmt, Settings.Secure.BACKUP_ENABLED,
871                R.bool.def_backup_enabled);
872
873        loadStringSetting(stmt, Settings.Secure.BACKUP_TRANSPORT,
874                R.string.def_backup_transport);
875    }
876
877    private void loadSetting(SQLiteStatement stmt, String key, Object value) {
878        stmt.bindString(1, key);
879        stmt.bindString(2, value.toString());
880        stmt.execute();
881    }
882
883    private void loadStringSetting(SQLiteStatement stmt, String key, int resid) {
884        loadSetting(stmt, key, mContext.getResources().getString(resid));
885    }
886
887    private void loadBooleanSetting(SQLiteStatement stmt, String key, int resid) {
888        loadSetting(stmt, key,
889                mContext.getResources().getBoolean(resid) ? "1" : "0");
890    }
891
892    private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) {
893        loadSetting(stmt, key,
894                Integer.toString(mContext.getResources().getInteger(resid)));
895    }
896
897    private void loadFractionSetting(SQLiteStatement stmt, String key, int resid, int base) {
898        loadSetting(stmt, key,
899                Float.toString(mContext.getResources().getFraction(resid, base, base)));
900    }
901}
902