DatabaseHelper.java revision 7444c906faef1f7a9a6e6f7a443ba156f1e856be
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
17package com.android.server.voiceinteraction;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.database.Cursor;
22import android.database.sqlite.SQLiteDatabase;
23import android.database.sqlite.SQLiteOpenHelper;
24import android.hardware.soundtrigger.SoundTrigger;
25import android.hardware.soundtrigger.Keyphrase;
26import android.hardware.soundtrigger.KeyphraseSoundModel;
27import android.util.Slog;
28
29import java.util.ArrayList;
30import java.util.List;
31import java.util.UUID;
32
33/**
34 * Helper to manage the database of the sound models that have been registered on the device.
35 *
36 * @hide
37 */
38public class DatabaseHelper extends SQLiteOpenHelper {
39    static final String TAG = "SoundModelDBHelper";
40
41    private static final String NAME = "sound_model.db";
42    private static final int VERSION = 1;
43
44    public static interface KeyphraseContract {
45        public static final String TABLE = "keyphrase";
46        public static final String KEY_ID = "_id";
47        public static final String KEY_RECOGNITION_MODES = "modes";
48        public static final String KEY_LOCALE = "locale";
49        public static final String KEY_HINT_TEXT = "hint_text";
50        public static final String KEY_USERS = "users";
51        public static final String KEY_SOUND_MODEL_ID = "sound_model_id";
52    }
53
54    public static interface SoundModelContract {
55        public static final String TABLE = "sound_model";
56        public static final String KEY_ID = "_id";
57        public static final String KEY_TYPE = "type";
58        public static final String KEY_DATA = "data";
59    }
60
61    // Table Create Statements
62    private static final String CREATE_TABLE_KEYPRHASES = "CREATE TABLE "
63            + KeyphraseContract.TABLE + "("
64            + KeyphraseContract.KEY_ID + " INTEGER PRIMARY KEY,"
65            + KeyphraseContract.KEY_RECOGNITION_MODES + " INTEGER,"
66            + KeyphraseContract.KEY_USERS + " INTEGER,"
67            + KeyphraseContract.KEY_SOUND_MODEL_ID + " TEXT,"
68            + KeyphraseContract.KEY_LOCALE + " TEXT,"
69            + KeyphraseContract.KEY_HINT_TEXT + " TEXT" + ")";
70
71    private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
72            + SoundModelContract.TABLE + "("
73            + SoundModelContract.KEY_ID + " TEXT PRIMARY KEY,"
74            + SoundModelContract.KEY_TYPE + " INTEGER,"
75            + SoundModelContract.KEY_DATA + " BLOB" + ")";
76
77    public DatabaseHelper(Context context) {
78        super(context, NAME, null, VERSION);
79    }
80
81    @Override
82    public void onCreate(SQLiteDatabase db) {
83        // creating required tables
84        db.execSQL(CREATE_TABLE_KEYPRHASES);
85        db.execSQL(CREATE_TABLE_SOUND_MODEL);
86    }
87
88    @Override
89    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
90        // TODO: For now, drop older tables and recreate new ones.
91        db.execSQL("DROP TABLE IF EXISTS " + KeyphraseContract.TABLE);
92        db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
93        onCreate(db);
94    }
95
96    public boolean addOrUpdateKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
97        SQLiteDatabase db = getWritableDatabase();
98        ContentValues values = new ContentValues();
99        // Generate a random ID for the model.
100        values.put(SoundModelContract.KEY_ID, soundModel.uuid.toString());
101        values.put(SoundModelContract.KEY_DATA, soundModel.data);
102        values.put(SoundModelContract.KEY_TYPE, SoundTrigger.SoundModel.TYPE_KEYPHRASE);
103
104        boolean status = true;
105        if (db.insertWithOnConflict(
106                SoundModelContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1) {
107            for (Keyphrase keyphrase : soundModel.keyphrases) {
108                status &= addOrUpdateKeyphrase(db, soundModel.uuid, keyphrase);
109            }
110            db.close();
111            return status;
112        } else {
113            Slog.w(TAG, "Failed to persist sound model to database");
114            db.close();
115            return false;
116        }
117    }
118
119    private boolean addOrUpdateKeyphrase(SQLiteDatabase db, UUID modelId, Keyphrase keyphrase) {
120        ContentValues values = new ContentValues();
121        values.put(KeyphraseContract.KEY_ID, keyphrase.id);
122        values.put(KeyphraseContract.KEY_RECOGNITION_MODES, keyphrase.recognitionModeFlags);
123        values.put(KeyphraseContract.KEY_SOUND_MODEL_ID, modelId.toString());
124        values.put(KeyphraseContract.KEY_HINT_TEXT, keyphrase.hintText);
125        values.put(KeyphraseContract.KEY_LOCALE, keyphrase.locale);
126        if (db.insertWithOnConflict(
127                KeyphraseContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1) {
128            return true;
129        } else {
130            Slog.w(TAG, "Failed to persist keyphrase to database");
131            return false;
132        }
133    }
134
135    /**
136     * Deletes the sound model and associated keyphrases.
137     */
138    public boolean deleteKeyphraseSoundModel(UUID uuid) {
139        SQLiteDatabase db = getWritableDatabase();
140        String modelId = uuid.toString();
141        String soundModelClause = SoundModelContract.KEY_ID + "=" + modelId;
142        boolean status = true;
143        if (db.delete(SoundModelContract.TABLE, soundModelClause, null) == 0) {
144            Slog.w(TAG, "No sound models deleted from the database");
145            status = false;
146        }
147        String keyphraseClause = KeyphraseContract.KEY_SOUND_MODEL_ID + "=" + modelId;
148        if (db.delete(KeyphraseContract.TABLE, keyphraseClause, null) == 0) {
149            Slog.w(TAG, "No keyphrases deleted from the database");
150            status = false;
151        }
152        db.close();
153        return status;
154    }
155
156    /**
157     * Lists all the keyphrase sound models currently registered with the system.
158     */
159    public List<KeyphraseSoundModel> getKephraseSoundModels() {
160        List<KeyphraseSoundModel> models = new ArrayList<>();
161        String selectQuery = "SELECT  * FROM " + SoundModelContract.TABLE;
162        SQLiteDatabase db = getReadableDatabase();
163        Cursor c = db.rawQuery(selectQuery, null);
164
165        // looping through all rows and adding to list
166        if (c.moveToFirst()) {
167            do {
168                int type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
169                if (type != SoundTrigger.SoundModel.TYPE_KEYPHRASE) {
170                    // Ignore non-keyphrase sound models.
171                    continue;
172                }
173                String id = c.getString(c.getColumnIndex(SoundModelContract.KEY_ID));
174                byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
175                // Get all the keyphrases for this this sound model.
176                models.add(new KeyphraseSoundModel(
177                        UUID.fromString(id), data, getKeyphrasesForSoundModel(db, id)));
178            } while (c.moveToNext());
179        }
180        c.close();
181        db.close();
182        return models;
183    }
184
185    private Keyphrase[] getKeyphrasesForSoundModel(SQLiteDatabase db, String modelId) {
186        List<Keyphrase> keyphrases = new ArrayList<>();
187        String selectQuery = "SELECT  * FROM " + KeyphraseContract.TABLE
188                + " WHERE " + KeyphraseContract.KEY_SOUND_MODEL_ID + " = '" + modelId + "'";
189        Cursor c = db.rawQuery(selectQuery, null);
190
191        // looping through all rows and adding to list
192        if (c.moveToFirst()) {
193            do {
194                int id = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_ID));
195                int modes = c.getInt(c.getColumnIndex(KeyphraseContract.KEY_RECOGNITION_MODES));
196                int[] users = {c.getInt(c.getColumnIndex(KeyphraseContract.KEY_USERS))};
197                String locale = c.getString(c.getColumnIndex(KeyphraseContract.KEY_LOCALE));
198                String hintText = c.getString(c.getColumnIndex(KeyphraseContract.KEY_HINT_TEXT));
199
200                keyphrases.add(new Keyphrase(id, hintText, locale, modes, users));
201            } while (c.moveToNext());
202        }
203        Keyphrase[] keyphraseArr = new Keyphrase[keyphrases.size()];
204        keyphrases.toArray(keyphraseArr);
205        c.close();
206        return keyphraseArr;
207    }
208}
209