Home | History | Annotate | Download | only in search
      1 /*
      2  * Copyright (C) 2014 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 
     17 package com.android.settings.search;
     18 
     19 import android.content.Context;
     20 import android.database.Cursor;
     21 import android.database.sqlite.SQLiteDatabase;
     22 import android.database.sqlite.SQLiteOpenHelper;
     23 import android.os.Build;
     24 import android.util.Log;
     25 
     26 public class IndexDatabaseHelper extends SQLiteOpenHelper {
     27 
     28     private static final String TAG = "IndexDatabaseHelper";
     29 
     30     private static final String DATABASE_NAME = "search_index.db";
     31     private static final int DATABASE_VERSION = 115;
     32 
     33     private static final String INDEX = "index";
     34 
     35     public interface Tables {
     36         public static final String TABLE_PREFS_INDEX = "prefs_index";
     37         public static final String TABLE_META_INDEX = "meta_index";
     38         public static final String TABLE_SAVED_QUERIES = "saved_queries";
     39     }
     40 
     41     public interface IndexColumns {
     42         public static final String DOCID = "docid";
     43         public static final String LOCALE = "locale";
     44         public static final String DATA_RANK = "data_rank";
     45         public static final String DATA_TITLE = "data_title";
     46         public static final String DATA_TITLE_NORMALIZED = "data_title_normalized";
     47         public static final String DATA_SUMMARY_ON = "data_summary_on";
     48         public static final String DATA_SUMMARY_ON_NORMALIZED = "data_summary_on_normalized";
     49         public static final String DATA_SUMMARY_OFF = "data_summary_off";
     50         public static final String DATA_SUMMARY_OFF_NORMALIZED = "data_summary_off_normalized";
     51         public static final String DATA_ENTRIES = "data_entries";
     52         public static final String DATA_KEYWORDS = "data_keywords";
     53         public static final String CLASS_NAME = "class_name";
     54         public static final String SCREEN_TITLE = "screen_title";
     55         public static final String INTENT_ACTION = "intent_action";
     56         public static final String INTENT_TARGET_PACKAGE = "intent_target_package";
     57         public static final String INTENT_TARGET_CLASS = "intent_target_class";
     58         public static final String ICON = "icon";
     59         public static final String ENABLED = "enabled";
     60         public static final String DATA_KEY_REF = "data_key_reference";
     61         public static final String USER_ID = "user_id";
     62     }
     63 
     64     public interface MetaColumns {
     65         public static final String BUILD = "build";
     66     }
     67 
     68     public interface SavedQueriesColums {
     69         public static final String QUERY = "query";
     70         public static final String TIME_STAMP = "timestamp";
     71     }
     72 
     73     private static final String CREATE_INDEX_TABLE =
     74             "CREATE VIRTUAL TABLE " + Tables.TABLE_PREFS_INDEX + " USING fts4" +
     75                     "(" +
     76                     IndexColumns.LOCALE +
     77                     ", " +
     78                     IndexColumns.DATA_RANK +
     79                     ", " +
     80                     IndexColumns.DATA_TITLE +
     81                     ", " +
     82                     IndexColumns.DATA_TITLE_NORMALIZED +
     83                     ", " +
     84                     IndexColumns.DATA_SUMMARY_ON +
     85                     ", " +
     86                     IndexColumns.DATA_SUMMARY_ON_NORMALIZED +
     87                     ", " +
     88                     IndexColumns.DATA_SUMMARY_OFF +
     89                     ", " +
     90                     IndexColumns.DATA_SUMMARY_OFF_NORMALIZED +
     91                     ", " +
     92                     IndexColumns.DATA_ENTRIES +
     93                     ", " +
     94                     IndexColumns.DATA_KEYWORDS +
     95                     ", " +
     96                     IndexColumns.SCREEN_TITLE +
     97                     ", " +
     98                     IndexColumns.CLASS_NAME +
     99                     ", " +
    100                     IndexColumns.ICON +
    101                     ", " +
    102                     IndexColumns.INTENT_ACTION +
    103                     ", " +
    104                     IndexColumns.INTENT_TARGET_PACKAGE +
    105                     ", " +
    106                     IndexColumns.INTENT_TARGET_CLASS +
    107                     ", " +
    108                     IndexColumns.ENABLED +
    109                     ", " +
    110                     IndexColumns.DATA_KEY_REF +
    111                     ", " +
    112                     IndexColumns.USER_ID +
    113                     ");";
    114 
    115     private static final String CREATE_META_TABLE =
    116             "CREATE TABLE " + Tables.TABLE_META_INDEX +
    117                     "(" +
    118                     MetaColumns.BUILD + " VARCHAR(32) NOT NULL" +
    119                     ")";
    120 
    121     private static final String CREATE_SAVED_QUERIES_TABLE =
    122             "CREATE TABLE " + Tables.TABLE_SAVED_QUERIES +
    123                     "(" +
    124                     SavedQueriesColums.QUERY + " VARCHAR(64) NOT NULL" +
    125                     ", " +
    126                     SavedQueriesColums.TIME_STAMP + " INTEGER" +
    127                     ")";
    128 
    129     private static final String INSERT_BUILD_VERSION =
    130             "INSERT INTO " + Tables.TABLE_META_INDEX +
    131                     " VALUES ('" + Build.VERSION.INCREMENTAL + "');";
    132 
    133     private static final String SELECT_BUILD_VERSION =
    134             "SELECT " + MetaColumns.BUILD + " FROM " + Tables.TABLE_META_INDEX + " LIMIT 1;";
    135 
    136     private static IndexDatabaseHelper sSingleton;
    137 
    138     private final Context mContext;
    139 
    140     public static synchronized IndexDatabaseHelper getInstance(Context context) {
    141         if (sSingleton == null) {
    142             sSingleton = new IndexDatabaseHelper(context);
    143         }
    144         return sSingleton;
    145     }
    146 
    147     public IndexDatabaseHelper(Context context) {
    148         super(context, DATABASE_NAME, null, DATABASE_VERSION);
    149         mContext = context;
    150     }
    151 
    152     @Override
    153     public void onCreate(SQLiteDatabase db) {
    154         bootstrapDB(db);
    155     }
    156 
    157     private void bootstrapDB(SQLiteDatabase db) {
    158         db.execSQL(CREATE_INDEX_TABLE);
    159         db.execSQL(CREATE_META_TABLE);
    160         db.execSQL(CREATE_SAVED_QUERIES_TABLE);
    161         db.execSQL(INSERT_BUILD_VERSION);
    162         Log.i(TAG, "Bootstrapped database");
    163     }
    164 
    165     @Override
    166     public void onOpen(SQLiteDatabase db) {
    167         super.onOpen(db);
    168 
    169         Log.i(TAG, "Using schema version: " + db.getVersion());
    170 
    171         if (!Build.VERSION.INCREMENTAL.equals(getBuildVersion(db))) {
    172             Log.w(TAG, "Index needs to be rebuilt as build-version is not the same");
    173             // We need to drop the tables and recreate them
    174             reconstruct(db);
    175         } else {
    176             Log.i(TAG, "Index is fine");
    177         }
    178     }
    179 
    180     @Override
    181     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    182         if (oldVersion < DATABASE_VERSION) {
    183             Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
    184                     "Index needs to be rebuilt for schema version '" + newVersion + "'.");
    185             // We need to drop the tables and recreate them
    186             reconstruct(db);
    187         }
    188     }
    189 
    190     @Override
    191     public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    192         Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
    193                 "Index needs to be rebuilt for schema version '" + newVersion + "'.");
    194         // We need to drop the tables and recreate them
    195         reconstruct(db);
    196     }
    197 
    198     private void reconstruct(SQLiteDatabase db) {
    199         dropTables(db);
    200         bootstrapDB(db);
    201     }
    202 
    203     private String getBuildVersion(SQLiteDatabase db) {
    204         String version = null;
    205         Cursor cursor = null;
    206         try {
    207             cursor = db.rawQuery(SELECT_BUILD_VERSION, null);
    208             if (cursor.moveToFirst()) {
    209                 version = cursor.getString(0);
    210             }
    211         } catch (Exception e) {
    212             Log.e(TAG, "Cannot get build version from Index metadata");
    213         } finally {
    214             if (cursor != null) {
    215                 cursor.close();
    216             }
    217         }
    218         return version;
    219     }
    220 
    221     public static void clearLocalesIndexed(Context context) {
    222         context.getSharedPreferences(INDEX, 0).edit().clear().commit();
    223     }
    224 
    225     public static void setLocaleIndexed(Context context, String locale) {
    226         context.getSharedPreferences(INDEX, 0).edit().putBoolean(locale, true).commit();
    227     }
    228 
    229     public static boolean isLocaleAlreadyIndexed(Context context, String locale) {
    230         return context.getSharedPreferences(INDEX, 0).getBoolean(locale, false);
    231     }
    232 
    233     private void dropTables(SQLiteDatabase db) {
    234         clearLocalesIndexed(mContext);
    235         db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_META_INDEX);
    236         db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_PREFS_INDEX);
    237         db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SAVED_QUERIES);
    238     }
    239 }
    240