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