Home | History | Annotate | Download | only in framework
      1 /*
      2  * Copyright (C) 2016 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 androidx.sqlite.db.framework;
     18 
     19 import android.content.Context;
     20 import android.database.DatabaseErrorHandler;
     21 import android.database.sqlite.SQLiteDatabase;
     22 import android.database.sqlite.SQLiteOpenHelper;
     23 import android.os.Build;
     24 
     25 import androidx.sqlite.db.SupportSQLiteDatabase;
     26 import androidx.sqlite.db.SupportSQLiteOpenHelper;
     27 
     28 class FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
     29     private final OpenHelper mDelegate;
     30 
     31     FrameworkSQLiteOpenHelper(Context context, String name,
     32             Callback callback) {
     33         mDelegate = createDelegate(context, name, callback);
     34     }
     35 
     36     private OpenHelper createDelegate(Context context, String name, Callback callback) {
     37         final FrameworkSQLiteDatabase[] dbRef = new FrameworkSQLiteDatabase[1];
     38         return new OpenHelper(context, name, dbRef, callback);
     39     }
     40 
     41     @Override
     42     public String getDatabaseName() {
     43         return mDelegate.getDatabaseName();
     44     }
     45 
     46     @Override
     47     @androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
     48     public void setWriteAheadLoggingEnabled(boolean enabled) {
     49         mDelegate.setWriteAheadLoggingEnabled(enabled);
     50     }
     51 
     52     @Override
     53     public SupportSQLiteDatabase getWritableDatabase() {
     54         return mDelegate.getWritableSupportDatabase();
     55     }
     56 
     57     @Override
     58     public SupportSQLiteDatabase getReadableDatabase() {
     59         return mDelegate.getReadableSupportDatabase();
     60     }
     61 
     62     @Override
     63     public void close() {
     64         mDelegate.close();
     65     }
     66 
     67     static class OpenHelper extends SQLiteOpenHelper {
     68         /**
     69          * This is used as an Object reference so that we can access the wrapped database inside
     70          * the constructor. SQLiteOpenHelper requires the error handler to be passed in the
     71          * constructor.
     72          */
     73         final FrameworkSQLiteDatabase[] mDbRef;
     74         final Callback mCallback;
     75         // see b/78359448
     76         private boolean mMigrated;
     77 
     78         OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,
     79                 final Callback callback) {
     80             super(context, name, null, callback.version,
     81                     new DatabaseErrorHandler() {
     82                         @Override
     83                         public void onCorruption(SQLiteDatabase dbObj) {
     84                             FrameworkSQLiteDatabase db = dbRef[0];
     85                             if (db != null) {
     86                                 callback.onCorruption(db);
     87                             }
     88                         }
     89                     });
     90             mCallback = callback;
     91             mDbRef = dbRef;
     92         }
     93 
     94         synchronized SupportSQLiteDatabase getWritableSupportDatabase() {
     95             mMigrated = false;
     96             SQLiteDatabase db = super.getWritableDatabase();
     97             if (mMigrated) {
     98                 // there might be a connection w/ stale structure, we should re-open.
     99                 close();
    100                 return getWritableSupportDatabase();
    101             }
    102             return getWrappedDb(db);
    103         }
    104 
    105         synchronized SupportSQLiteDatabase getReadableSupportDatabase() {
    106             mMigrated = false;
    107             SQLiteDatabase db = super.getReadableDatabase();
    108             if (mMigrated) {
    109                 // there might be a connection w/ stale structure, we should re-open.
    110                 close();
    111                 return getReadableSupportDatabase();
    112             }
    113             return getWrappedDb(db);
    114         }
    115 
    116         FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
    117             FrameworkSQLiteDatabase dbRef = mDbRef[0];
    118             if (dbRef == null) {
    119                 dbRef = new FrameworkSQLiteDatabase(sqLiteDatabase);
    120                 mDbRef[0] = dbRef;
    121             }
    122             return mDbRef[0];
    123         }
    124 
    125         @Override
    126         public void onCreate(SQLiteDatabase sqLiteDatabase) {
    127             mCallback.onCreate(getWrappedDb(sqLiteDatabase));
    128         }
    129 
    130         @Override
    131         public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
    132             mMigrated = true;
    133             mCallback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
    134         }
    135 
    136         @Override
    137         public void onConfigure(SQLiteDatabase db) {
    138             mCallback.onConfigure(getWrappedDb(db));
    139         }
    140 
    141         @Override
    142         public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    143             mMigrated = true;
    144             mCallback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
    145         }
    146 
    147         @Override
    148         public void onOpen(SQLiteDatabase db) {
    149             if (!mMigrated) {
    150                 // if we've migrated, we'll re-open the db so we  should not call the callback.
    151                 mCallback.onOpen(getWrappedDb(db));
    152             }
    153         }
    154 
    155         @Override
    156         public synchronized void close() {
    157             super.close();
    158             mDbRef[0] = null;
    159         }
    160     }
    161 }
    162