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