1 /* 2 * Copyright (C) 2019 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.bluetooth.btservice.storage; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.database.SQLException; 22 23 import androidx.room.Database; 24 import androidx.room.Room; 25 import androidx.room.RoomDatabase; 26 import androidx.room.migration.Migration; 27 import androidx.sqlite.db.SupportSQLiteDatabase; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.util.List; 32 33 /** MetadataDatabase is a Room database stores Bluetooth persistence data */ 34 @Database( 35 entities = {Metadata.class}, 36 version = 122) 37 public abstract class MetadataDatabase extends RoomDatabase { 38 /** The metadata database file name */ 39 public static final String DATABASE_NAME = "bluetooth_db"; 40 41 static int sCurrentConnectionNumber = 0; 42 mMetadataDao()43 protected abstract MetadataDao mMetadataDao(); 44 45 /** 46 * Create a {@link MetadataDatabase} database with migrations 47 * 48 * @param context the Context to create database 49 * @return the created {@link MetadataDatabase} 50 */ createDatabase(Context context)51 public static MetadataDatabase createDatabase(Context context) { 52 return Room.databaseBuilder(context, MetadataDatabase.class, DATABASE_NAME) 53 .addMigrations(MIGRATION_100_101) 54 .addMigrations(MIGRATION_101_102) 55 .addMigrations(MIGRATION_102_103) 56 .addMigrations(MIGRATION_103_104) 57 .addMigrations(MIGRATION_104_105) 58 .addMigrations(MIGRATION_105_106) 59 .addMigrations(MIGRATION_106_107) 60 .addMigrations(MIGRATION_107_108) 61 .addMigrations(MIGRATION_108_109) 62 .addMigrations(MIGRATION_109_110) 63 .addMigrations(MIGRATION_110_111) 64 .addMigrations(MIGRATION_111_112) 65 .addMigrations(MIGRATION_112_113) 66 .addMigrations(MIGRATION_113_114) 67 .addMigrations(MIGRATION_114_115) 68 .addMigrations(MIGRATION_115_116) 69 .addMigrations(MIGRATION_116_117) 70 .addMigrations(MIGRATION_117_118) 71 .addMigrations(MIGRATION_118_119) 72 .addMigrations(MIGRATION_119_120) 73 .addMigrations(MIGRATION_120_121) 74 .addMigrations(MIGRATION_121_122) 75 .allowMainThreadQueries() 76 .build(); 77 } 78 79 /** 80 * Create a {@link MetadataDatabase} database without migration, database would be reset if any 81 * load failure happens 82 * 83 * @param context the Context to create database 84 * @return the created {@link MetadataDatabase} 85 */ createDatabaseWithoutMigration(Context context)86 public static MetadataDatabase createDatabaseWithoutMigration(Context context) { 87 return Room.databaseBuilder(context, MetadataDatabase.class, DATABASE_NAME) 88 .fallbackToDestructiveMigration() 89 .allowMainThreadQueries() 90 .build(); 91 } 92 93 /** 94 * Insert a {@link Metadata} to metadata table 95 * 96 * @param metadata the data wish to put into storage 97 */ insert(Metadata... metadata)98 public void insert(Metadata... metadata) { 99 mMetadataDao().insert(metadata); 100 } 101 102 /** 103 * Load all data from metadata table as a {@link List} of {@link Metadata} 104 * 105 * @return a {@link List} of {@link Metadata} 106 */ load()107 public List<Metadata> load() { 108 return mMetadataDao().load(); 109 } 110 111 /** 112 * Delete one of the {@link Metadata} contained in the metadata table 113 * 114 * @param address the address of Metadata to delete 115 */ delete(String address)116 public void delete(String address) { 117 mMetadataDao().delete(address); 118 } 119 120 /** Clear metadata table. */ deleteAll()121 public void deleteAll() { 122 mMetadataDao().deleteAll(); 123 } 124 125 @VisibleForTesting 126 static final Migration MIGRATION_100_101 = 127 new Migration(100, 101) { 128 @Override 129 public void migrate(SupportSQLiteDatabase database) { 130 database.execSQL( 131 "ALTER TABLE metadata ADD COLUMN `pbap_client_priority` INTEGER"); 132 } 133 }; 134 135 @VisibleForTesting 136 static final Migration MIGRATION_101_102 = 137 new Migration(101, 102) { 138 @Override 139 public void migrate(SupportSQLiteDatabase database) { 140 database.execSQL( 141 "CREATE TABLE IF NOT EXISTS `metadata_tmp` (`address` TEXT NOT NULL," 142 + " `migrated` INTEGER NOT NULL, `a2dpSupportsOptionalCodecs`" 143 + " INTEGER NOT NULL, `a2dpOptionalCodecsEnabled` INTEGER NOT NULL," 144 + " `a2dp_priority` INTEGER, `a2dp_sink_priority` INTEGER," 145 + " `hfp_priority` INTEGER, `hfp_client_priority` INTEGER," 146 + " `hid_host_priority` INTEGER, `pan_priority` INTEGER," 147 + " `pbap_priority` INTEGER, `pbap_client_priority` INTEGER," 148 + " `map_priority` INTEGER, `sap_priority` INTEGER," 149 + " `hearing_aid_priority` INTEGER, `map_client_priority` INTEGER," 150 + " `manufacturer_name` BLOB, `model_name` BLOB, `software_version`" 151 + " BLOB, `hardware_version` BLOB, `companion_app` BLOB," 152 + " `main_icon` BLOB, `is_untethered_headset` BLOB," 153 + " `untethered_left_icon` BLOB, `untethered_right_icon` BLOB," 154 + " `untethered_case_icon` BLOB, `untethered_left_battery` BLOB," 155 + " `untethered_right_battery` BLOB, `untethered_case_battery`" 156 + " BLOB, `untethered_left_charging` BLOB," 157 + " `untethered_right_charging` BLOB, `untethered_case_charging`" 158 + " BLOB, `enhanced_settings_ui_uri` BLOB, PRIMARY" 159 + " KEY(`address`))"); 160 161 database.execSQL( 162 "INSERT INTO metadata_tmp (address, migrated," 163 + " a2dpSupportsOptionalCodecs, a2dpOptionalCodecsEnabled," 164 + " a2dp_priority, a2dp_sink_priority, hfp_priority," 165 + " hfp_client_priority, hid_host_priority, pan_priority," 166 + " pbap_priority, pbap_client_priority, map_priority," 167 + " sap_priority, hearing_aid_priority, map_client_priority," 168 + " manufacturer_name, model_name, software_version," 169 + " hardware_version, companion_app, main_icon," 170 + " is_untethered_headset, untethered_left_icon," 171 + " untethered_right_icon, untethered_case_icon," 172 + " untethered_left_battery, untethered_right_battery," 173 + " untethered_case_battery, untethered_left_charging," 174 + " untethered_right_charging, untethered_case_charging," 175 + " enhanced_settings_ui_uri) SELECT address, migrated," 176 + " a2dpSupportsOptionalCodecs, a2dpOptionalCodecsEnabled," 177 + " a2dp_priority, a2dp_sink_priority, hfp_priority," 178 + " hfp_client_priority, hid_host_priority, pan_priority," 179 + " pbap_priority, pbap_client_priority, map_priority," 180 + " sap_priority, hearing_aid_priority, map_client_priority, CAST" 181 + " (manufacturer_name AS BLOB), CAST (model_name AS BLOB), CAST" 182 + " (software_version AS BLOB), CAST (hardware_version AS BLOB)," 183 + " CAST (companion_app AS BLOB), CAST (main_icon AS BLOB), CAST" 184 + " (is_unthethered_headset AS BLOB), CAST (unthethered_left_icon" 185 + " AS BLOB), CAST (unthethered_right_icon AS BLOB), CAST" 186 + " (unthethered_case_icon AS BLOB), CAST (unthethered_left_battery" 187 + " AS BLOB), CAST (unthethered_right_battery AS BLOB), CAST" 188 + " (unthethered_case_battery AS BLOB), CAST" 189 + " (unthethered_left_charging AS BLOB), CAST" 190 + " (unthethered_right_charging AS BLOB), CAST" 191 + " (unthethered_case_charging AS BLOB), CAST" 192 + " (enhanced_settings_ui_uri AS BLOB)FROM metadata"); 193 194 database.execSQL("DROP TABLE `metadata`"); 195 database.execSQL("ALTER TABLE `metadata_tmp` RENAME TO `metadata`"); 196 } 197 }; 198 199 @VisibleForTesting 200 static final Migration MIGRATION_102_103 = 201 new Migration(102, 103) { 202 @Override 203 public void migrate(SupportSQLiteDatabase database) { 204 try { 205 database.execSQL( 206 "CREATE TABLE IF NOT EXISTS `metadata_tmp` (`address` TEXT NOT" 207 + " NULL, `migrated` INTEGER NOT NULL," 208 + " `a2dpSupportsOptionalCodecs` INTEGER NOT NULL," 209 + " `a2dpOptionalCodecsEnabled` INTEGER NOT NULL," 210 + " `a2dp_connection_policy` INTEGER," 211 + " `a2dp_sink_connection_policy` INTEGER," 212 + " `hfp_connection_policy` INTEGER," 213 + " `hfp_client_connection_policy` INTEGER," 214 + " `hid_host_connection_policy` INTEGER," 215 + " `pan_connection_policy` INTEGER, `pbap_connection_policy`" 216 + " INTEGER, `pbap_client_connection_policy` INTEGER," 217 + " `map_connection_policy` INTEGER, `sap_connection_policy`" 218 + " INTEGER, `hearing_aid_connection_policy` INTEGER," 219 + " `map_client_connection_policy` INTEGER, `manufacturer_name`" 220 + " BLOB, `model_name` BLOB, `software_version` BLOB," 221 + " `hardware_version` BLOB, `companion_app` BLOB, `main_icon`" 222 + " BLOB, `is_untethered_headset` BLOB, `untethered_left_icon`" 223 + " BLOB, `untethered_right_icon` BLOB, `untethered_case_icon`" 224 + " BLOB, `untethered_left_battery` BLOB," 225 + " `untethered_right_battery` BLOB, `untethered_case_battery`" 226 + " BLOB, `untethered_left_charging` BLOB," 227 + " `untethered_right_charging` BLOB," 228 + " `untethered_case_charging` BLOB, `enhanced_settings_ui_uri`" 229 + " BLOB, PRIMARY KEY(`address`))"); 230 231 database.execSQL( 232 "INSERT INTO metadata_tmp (address, migrated," 233 + " a2dpSupportsOptionalCodecs, a2dpOptionalCodecsEnabled," 234 + " a2dp_connection_policy, a2dp_sink_connection_policy," 235 + " hfp_connection_policy,hfp_client_connection_policy," 236 + " hid_host_connection_policy,pan_connection_policy," 237 + " pbap_connection_policy,pbap_client_connection_policy," 238 + " map_connection_policy, sap_connection_policy," 239 + " hearing_aid_connection_policy," 240 + " map_client_connection_policy, manufacturer_name," 241 + " model_name, software_version, hardware_version," 242 + " companion_app, main_icon, is_untethered_headset," 243 + " untethered_left_icon, untethered_right_icon," 244 + " untethered_case_icon, untethered_left_battery," 245 + " untethered_right_battery, untethered_case_battery," 246 + " untethered_left_charging, untethered_right_charging," 247 + " untethered_case_charging, enhanced_settings_ui_uri) SELECT" 248 + " address, migrated, a2dpSupportsOptionalCodecs," 249 + " a2dpOptionalCodecsEnabled, a2dp_priority," 250 + " a2dp_sink_priority, hfp_priority, hfp_client_priority," 251 + " hid_host_priority, pan_priority, pbap_priority," 252 + " pbap_client_priority, map_priority, sap_priority," 253 + " hearing_aid_priority, map_client_priority, CAST" 254 + " (manufacturer_name AS BLOB), CAST (model_name AS BLOB)," 255 + " CAST (software_version AS BLOB), CAST (hardware_version AS" 256 + " BLOB), CAST (companion_app AS BLOB), CAST (main_icon AS" 257 + " BLOB), CAST (is_untethered_headset AS BLOB), CAST" 258 + " (untethered_left_icon AS BLOB), CAST (untethered_right_icon" 259 + " AS BLOB), CAST (untethered_case_icon AS BLOB), CAST" 260 + " (untethered_left_battery AS BLOB), CAST" 261 + " (untethered_right_battery AS BLOB), CAST" 262 + " (untethered_case_battery AS BLOB), CAST" 263 + " (untethered_left_charging AS BLOB), CAST" 264 + " (untethered_right_charging AS BLOB), CAST" 265 + " (untethered_case_charging AS BLOB), CAST" 266 + " (enhanced_settings_ui_uri AS BLOB)FROM metadata"); 267 268 database.execSQL( 269 "UPDATE metadata_tmp SET a2dp_connection_policy = 100 " 270 + "WHERE a2dp_connection_policy = 1000"); 271 database.execSQL( 272 "UPDATE metadata_tmp SET a2dp_sink_connection_policy = 100 " 273 + "WHERE a2dp_sink_connection_policy = 1000"); 274 database.execSQL( 275 "UPDATE metadata_tmp SET hfp_connection_policy = 100 " 276 + "WHERE hfp_connection_policy = 1000"); 277 database.execSQL( 278 "UPDATE metadata_tmp SET hfp_client_connection_policy = 100 " 279 + "WHERE hfp_client_connection_policy = 1000"); 280 database.execSQL( 281 "UPDATE metadata_tmp SET hid_host_connection_policy = 100 " 282 + "WHERE hid_host_connection_policy = 1000"); 283 database.execSQL( 284 "UPDATE metadata_tmp SET pan_connection_policy = 100 " 285 + "WHERE pan_connection_policy = 1000"); 286 database.execSQL( 287 "UPDATE metadata_tmp SET pbap_connection_policy = 100 " 288 + "WHERE pbap_connection_policy = 1000"); 289 database.execSQL( 290 "UPDATE metadata_tmp SET pbap_client_connection_policy = 100 " 291 + "WHERE pbap_client_connection_policy = 1000"); 292 database.execSQL( 293 "UPDATE metadata_tmp SET map_connection_policy = 100 " 294 + "WHERE map_connection_policy = 1000"); 295 database.execSQL( 296 "UPDATE metadata_tmp SET sap_connection_policy = 100 " 297 + "WHERE sap_connection_policy = 1000"); 298 database.execSQL( 299 "UPDATE metadata_tmp SET hearing_aid_connection_policy = 100 " 300 + "WHERE hearing_aid_connection_policy = 1000"); 301 database.execSQL( 302 "UPDATE metadata_tmp SET map_client_connection_policy = 100 " 303 + "WHERE map_client_connection_policy = 1000"); 304 305 database.execSQL("DROP TABLE `metadata`"); 306 database.execSQL("ALTER TABLE `metadata_tmp` RENAME TO `metadata`"); 307 } catch (SQLException ex) { 308 // Check if user has new schema, but is just missing the version update 309 Cursor cursor = database.query("SELECT * FROM metadata"); 310 if (cursor == null 311 || cursor.getColumnIndex("a2dp_connection_policy") == -1) { 312 throw ex; 313 } 314 } 315 } 316 }; 317 318 @VisibleForTesting 319 static final Migration MIGRATION_103_104 = 320 new Migration(103, 104) { 321 @Override 322 public void migrate(SupportSQLiteDatabase database) { 323 try { 324 database.execSQL( 325 "ALTER TABLE metadata ADD COLUMN `last_active_time` " 326 + "INTEGER NOT NULL DEFAULT -1"); 327 database.execSQL( 328 "ALTER TABLE metadata ADD COLUMN `is_active_a2dp_device` " 329 + "INTEGER NOT NULL DEFAULT 0"); 330 } catch (SQLException ex) { 331 // Check if user has new schema, but is just missing the version update 332 Cursor cursor = database.query("SELECT * FROM metadata"); 333 if (cursor == null || cursor.getColumnIndex("last_active_time") == -1) { 334 throw ex; 335 } 336 } 337 } 338 }; 339 340 @VisibleForTesting 341 static final Migration MIGRATION_104_105 = 342 new Migration(104, 105) { 343 @Override 344 public void migrate(SupportSQLiteDatabase database) { 345 try { 346 database.execSQL("ALTER TABLE metadata ADD COLUMN `device_type` BLOB"); 347 database.execSQL("ALTER TABLE metadata ADD COLUMN `main_battery` BLOB"); 348 database.execSQL("ALTER TABLE metadata ADD COLUMN `main_charging` BLOB"); 349 database.execSQL( 350 "ALTER TABLE metadata ADD COLUMN " 351 + "`main_low_battery_threshold` BLOB"); 352 database.execSQL( 353 "ALTER TABLE metadata ADD COLUMN " 354 + "`untethered_left_low_battery_threshold` BLOB"); 355 database.execSQL( 356 "ALTER TABLE metadata ADD COLUMN " 357 + "`untethered_right_low_battery_threshold` BLOB"); 358 database.execSQL( 359 "ALTER TABLE metadata ADD COLUMN " 360 + "`untethered_case_low_battery_threshold` BLOB"); 361 } catch (SQLException ex) { 362 // Check if user has new schema, but is just missing the version update 363 Cursor cursor = database.query("SELECT * FROM metadata"); 364 if (cursor == null || cursor.getColumnIndex("device_type") == -1) { 365 throw ex; 366 } 367 } 368 } 369 }; 370 371 @VisibleForTesting 372 static final Migration MIGRATION_105_106 = 373 new Migration(105, 106) { 374 @Override 375 public void migrate(SupportSQLiteDatabase database) { 376 try { 377 database.execSQL( 378 "ALTER TABLE metadata ADD COLUMN `le_audio_connection_policy` " 379 + "INTEGER DEFAULT 100"); 380 } catch (SQLException ex) { 381 // Check if user has new schema, but is just missing the version update 382 Cursor cursor = database.query("SELECT * FROM metadata"); 383 if (cursor == null 384 || cursor.getColumnIndex("le_audio_connection_policy") == -1) { 385 throw ex; 386 } 387 } 388 } 389 }; 390 391 @VisibleForTesting 392 static final Migration MIGRATION_106_107 = 393 new Migration(106, 107) { 394 @Override 395 public void migrate(SupportSQLiteDatabase database) { 396 try { 397 database.execSQL( 398 "ALTER TABLE metadata ADD COLUMN " 399 + "`volume_control_connection_policy` INTEGER DEFAULT 100"); 400 } catch (SQLException ex) { 401 // Check if user has new schema, but is just missing the version update 402 Cursor cursor = database.query("SELECT * FROM metadata"); 403 if (cursor == null 404 || cursor.getColumnIndex("volume_control_connection_policy") 405 == -1) { 406 throw ex; 407 } 408 } 409 } 410 }; 411 412 @VisibleForTesting 413 static final Migration MIGRATION_107_108 = 414 new Migration(107, 108) { 415 @Override 416 public void migrate(SupportSQLiteDatabase database) { 417 try { 418 database.execSQL( 419 "ALTER TABLE metadata ADD COLUMN" 420 + " `csip_set_coordinator_connection_policy` INTEGER DEFAULT" 421 + " 100"); 422 } catch (SQLException ex) { 423 // Check if user has new schema, but is just missing the version update 424 Cursor cursor = database.query("SELECT * FROM metadata"); 425 if (cursor == null 426 || cursor.getColumnIndex("csip_set_coordinator_connection_policy") 427 == -1) { 428 throw ex; 429 } 430 } 431 } 432 }; 433 434 @VisibleForTesting 435 static final Migration MIGRATION_108_109 = 436 new Migration(108, 109) { 437 @Override 438 public void migrate(SupportSQLiteDatabase database) { 439 try { 440 database.execSQL( 441 "ALTER TABLE metadata ADD COLUMN" 442 + " `le_call_control_connection_policy` INTEGER DEFAULT 100"); 443 } catch (SQLException ex) { 444 // Check if user has new schema, but is just missing the version update 445 Cursor cursor = database.query("SELECT * FROM metadata"); 446 if (cursor == null 447 || cursor.getColumnIndex("le_call_control_connection_policy") 448 == -1) { 449 throw ex; 450 } 451 } 452 } 453 }; 454 455 @VisibleForTesting 456 static final Migration MIGRATION_109_110 = 457 new Migration(109, 110) { 458 @Override 459 public void migrate(SupportSQLiteDatabase database) { 460 try { 461 database.execSQL( 462 "ALTER TABLE metadata ADD COLUMN `hap_client_connection_policy` " 463 + "INTEGER DEFAULT 100"); 464 } catch (SQLException ex) { 465 // Check if user has new schema, but is just missing the version update 466 Cursor cursor = database.query("SELECT * FROM metadata"); 467 if (cursor == null 468 || cursor.getColumnIndex("hap_client_connection_policy") == -1) { 469 throw ex; 470 } 471 } 472 } 473 }; 474 475 @VisibleForTesting 476 static final Migration MIGRATION_110_111 = 477 new Migration(110, 111) { 478 @Override 479 public void migrate(SupportSQLiteDatabase database) { 480 try { 481 database.execSQL( 482 "ALTER TABLE metadata ADD COLUMN `bass_client_connection_policy` " 483 + "INTEGER DEFAULT 100"); 484 } catch (SQLException ex) { 485 // Check if user has new schema, but is just missing the version update 486 Cursor cursor = database.query("SELECT * FROM metadata"); 487 if (cursor == null 488 || cursor.getColumnIndex("bass_client_connection_policy") == -1) { 489 throw ex; 490 } 491 } 492 } 493 }; 494 495 @VisibleForTesting 496 static final Migration MIGRATION_111_112 = 497 new Migration(111, 112) { 498 @Override 499 public void migrate(SupportSQLiteDatabase database) { 500 try { 501 database.execSQL( 502 "ALTER TABLE metadata ADD COLUMN `battery_connection_policy` " 503 + "INTEGER DEFAULT 100"); 504 } catch (SQLException ex) { 505 // Check if user has new schema, but is just missing the version update 506 Cursor cursor = database.query("SELECT * FROM metadata"); 507 if (cursor == null 508 || cursor.getColumnIndex("battery_connection_policy") == -1) { 509 throw ex; 510 } 511 } 512 } 513 }; 514 515 @VisibleForTesting 516 static final Migration MIGRATION_112_113 = 517 new Migration(112, 113) { 518 @Override 519 public void migrate(SupportSQLiteDatabase database) { 520 try { 521 database.execSQL("ALTER TABLE metadata ADD COLUMN `spatial_audio` BLOB"); 522 database.execSQL( 523 "ALTER TABLE metadata ADD COLUMN `fastpair_customized` BLOB"); 524 } catch (SQLException ex) { 525 // Check if user has new schema, but is just missing the version update 526 Cursor cursor = database.query("SELECT * FROM metadata"); 527 if (cursor == null || cursor.getColumnIndex("spatial_audio") == -1) { 528 throw ex; 529 } 530 } 531 } 532 }; 533 534 @VisibleForTesting 535 static final Migration MIGRATION_113_114 = 536 new Migration(113, 114) { 537 @Override 538 public void migrate(SupportSQLiteDatabase database) { 539 try { 540 database.execSQL("ALTER TABLE metadata ADD COLUMN `le_audio` BLOB"); 541 } catch (SQLException ex) { 542 // Check if user has new schema, but is just missing the version update 543 Cursor cursor = database.query("SELECT * FROM metadata"); 544 if (cursor == null || cursor.getColumnIndex("le_audio") == -1) { 545 throw ex; 546 } 547 } 548 } 549 }; 550 551 @VisibleForTesting 552 static final Migration MIGRATION_114_115 = 553 new Migration(114, 115) { 554 @Override 555 public void migrate(SupportSQLiteDatabase database) { 556 try { 557 database.execSQL( 558 "ALTER TABLE metadata ADD COLUMN `call_establish_audio_policy` " 559 + "INTEGER DEFAULT 0"); 560 database.execSQL( 561 "ALTER TABLE metadata ADD COLUMN `connecting_time_audio_policy` " 562 + "INTEGER DEFAULT 0"); 563 database.execSQL( 564 "ALTER TABLE metadata ADD COLUMN `in_band_ringtone_audio_policy` " 565 + "INTEGER DEFAULT 0"); 566 } catch (SQLException ex) { 567 // Check if user has new schema, but is just missing the version update 568 Cursor cursor = database.query("SELECT * FROM metadata"); 569 if (cursor == null 570 || cursor.getColumnIndex("call_establish_audio_policy") == -1) { 571 throw ex; 572 } 573 } 574 } 575 }; 576 577 @VisibleForTesting 578 static final Migration MIGRATION_115_116 = 579 new Migration(115, 116) { 580 @Override 581 public void migrate(SupportSQLiteDatabase database) { 582 try { 583 database.execSQL( 584 "ALTER TABLE metadata ADD COLUMN `preferred_output_only_profile` " 585 + "INTEGER NOT NULL DEFAULT 0"); 586 database.execSQL( 587 "ALTER TABLE metadata ADD COLUMN `preferred_duplex_profile` " 588 + "INTEGER NOT NULL DEFAULT 0"); 589 } catch (SQLException ex) { 590 // Check if user has new schema, but is just missing the version update 591 Cursor cursor = database.query("SELECT * FROM metadata"); 592 if (cursor == null 593 || cursor.getColumnIndex("preferred_output_only_profile") == -1 594 || cursor.getColumnIndex("preferred_duplex_profile") == -1) { 595 throw ex; 596 } 597 } 598 } 599 }; 600 601 @VisibleForTesting 602 static final Migration MIGRATION_116_117 = 603 new Migration(116, 117) { 604 @Override 605 public void migrate(SupportSQLiteDatabase database) { 606 try { 607 database.execSQL("ALTER TABLE metadata ADD COLUMN `gmcs_cccd` BLOB"); 608 database.execSQL("ALTER TABLE metadata ADD COLUMN `gtbs_cccd` BLOB"); 609 } catch (SQLException ex) { 610 // Check if user has new schema, but is just missing the version update 611 Cursor cursor = database.query("SELECT * FROM metadata"); 612 if (cursor == null || cursor.getColumnIndex("gmcs_cccd") == -1) { 613 throw ex; 614 } 615 } 616 } 617 }; 618 619 @VisibleForTesting 620 static final Migration MIGRATION_117_118 = 621 new Migration(117, 118) { 622 @Override 623 public void migrate(SupportSQLiteDatabase database) { 624 try { 625 database.execSQL( 626 "ALTER TABLE metadata ADD COLUMN `isActiveHfpDevice` " 627 + "INTEGER NOT NULL DEFAULT 0"); 628 } catch (SQLException ex) { 629 // Check if user has new schema, but is just missing the version update 630 Cursor cursor = database.query("SELECT * FROM metadata"); 631 if (cursor == null || cursor.getColumnIndex("isActiveHfpDevice") == -1) { 632 throw ex; 633 } 634 } 635 } 636 }; 637 638 @VisibleForTesting 639 static final Migration MIGRATION_118_119 = 640 new Migration(118, 119) { 641 @Override 642 public void migrate(SupportSQLiteDatabase database) { 643 try { 644 database.execSQL( 645 "ALTER TABLE metadata ADD COLUMN `exclusive_manager` BLOB"); 646 } catch (SQLException ex) { 647 // Check if user has new schema, but is just missing the version update 648 Cursor cursor = database.query("SELECT * FROM metadata"); 649 if (cursor == null || cursor.getColumnIndex("exclusive_manager") == -1) { 650 throw ex; 651 } 652 } 653 } 654 }; 655 656 @VisibleForTesting 657 static final Migration MIGRATION_119_120 = 658 new Migration(119, 120) { 659 @Override 660 public void migrate(SupportSQLiteDatabase database) { 661 try { 662 database.execSQL( 663 "ALTER TABLE metadata ADD COLUMN" 664 + " `active_audio_device_policy` INTEGER NOT NULL" 665 + " DEFAULT 0"); 666 } catch (SQLException ex) { 667 // Check if user has new schema, but is just missing the version update 668 Cursor cursor = database.query("SELECT * FROM metadata"); 669 if (cursor == null 670 || cursor.getColumnIndex("active_audio_device_policy") == -1) { 671 throw ex; 672 } 673 } 674 } 675 }; 676 677 @VisibleForTesting 678 static final Migration MIGRATION_120_121 = 679 new Migration(120, 121) { 680 @Override 681 public void migrate(SupportSQLiteDatabase database) { 682 try { 683 database.execSQL( 684 "ALTER TABLE metadata ADD COLUMN" 685 + " `is_preferred_microphone_for_calls` INTEGER NOT NULL" 686 + " DEFAULT 1"); 687 } catch (SQLException ex) { 688 // Check if user has new schema, but is just missing the version update 689 Cursor cursor = database.query("SELECT * FROM metadata"); 690 if (cursor == null 691 || cursor.getColumnIndex("is_preferred_microphone_for_calls") 692 == -1) { 693 throw ex; 694 } 695 } 696 } 697 }; 698 699 @VisibleForTesting 700 static final Migration MIGRATION_121_122 = 701 new Migration(121, 122) { 702 @Override 703 public void migrate(SupportSQLiteDatabase database) { 704 try { 705 database.execSQL( 706 "ALTER TABLE metadata ADD COLUMN" 707 + " `key_missing_count` INTEGER NOT NULL" 708 + " DEFAULT 0"); 709 } catch (SQLException ex) { 710 // Check if user has new schema, but is just missing the version update 711 Cursor cursor = database.query("SELECT * FROM metadata"); 712 if (cursor == null 713 || cursor.getColumnIndex("key_missing_count") == -1) { 714 throw ex; 715 } 716 } 717 } 718 }; 719 } 720