1937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar/*
2937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Copyright (C) 2016 The Android Open Source Project
3937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar *
4937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * you may not use this file except in compliance with the License.
6937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * You may obtain a copy of the License at
7937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar *
8937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar *
10937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * See the License for the specific language governing permissions and
14937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * limitations under the License.
15937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */
16937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.sqlite.db.framework;
18937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
19937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarimport android.content.Context;
20937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarimport android.database.DatabaseErrorHandler;
21937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarimport android.database.sqlite.SQLiteDatabase;
22937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarimport android.database.sqlite.SQLiteOpenHelper;
23937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarimport android.os.Build;
24ba069d50913c3fb250bb60ec310439db36895337Alan Viverette
25ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteDatabase;
26ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteOpenHelper;
27937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
28937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarclass FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
29937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    private final OpenHelper mDelegate;
3064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar
312b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar    FrameworkSQLiteOpenHelper(Context context, String name,
322b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            Callback callback) {
332b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        mDelegate = createDelegate(context, name, callback);
34937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
35937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
362b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar    private OpenHelper createDelegate(Context context, String name, Callback callback) {
372b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        final FrameworkSQLiteDatabase[] dbRef = new FrameworkSQLiteDatabase[1];
382b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        return new OpenHelper(context, name, dbRef, callback);
39937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
40937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
41937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    @Override
42937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    public String getDatabaseName() {
43937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        return mDelegate.getDatabaseName();
44937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
45937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
46937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    @Override
47fbdf0efb750162aa24df0f1a24c8420f1c780ac7Aurimas Liutikas    @androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
48937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    public void setWriteAheadLoggingEnabled(boolean enabled) {
49937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        mDelegate.setWriteAheadLoggingEnabled(enabled);
50937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
51937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
52937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    @Override
53937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    public SupportSQLiteDatabase getWritableDatabase() {
54937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        return mDelegate.getWritableSupportDatabase();
55937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
56937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
57937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    @Override
58937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    public SupportSQLiteDatabase getReadableDatabase() {
59937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        return mDelegate.getReadableSupportDatabase();
60937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
61937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
62937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    @Override
63937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    public void close() {
64937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        mDelegate.close();
65937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
66937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
672b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar    static class OpenHelper extends SQLiteOpenHelper {
682b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        /**
692b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar         * This is used as an Object reference so that we can access the wrapped database inside
702b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar         * the constructor. SQLiteOpenHelper requires the error handler to be passed in the
712b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar         * constructor.
722b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar         */
732b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        final FrameworkSQLiteDatabase[] mDbRef;
742b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        final Callback mCallback;
75f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar        // see b/78359448
76f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar        private boolean mMigrated;
772b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
782b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,
792b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                final Callback callback) {
802b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            super(context, name, null, callback.version,
812b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                    new DatabaseErrorHandler() {
822b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                        @Override
832b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                        public void onCorruption(SQLiteDatabase dbObj) {
842b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                            FrameworkSQLiteDatabase db = dbRef[0];
852b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                            if (db != null) {
862b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                                callback.onCorruption(db);
872b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                            }
882b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                        }
892b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                    });
902b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mCallback = callback;
912b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mDbRef = dbRef;
92937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        }
93937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
94f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar        synchronized SupportSQLiteDatabase getWritableSupportDatabase() {
95f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            mMigrated = false;
96937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            SQLiteDatabase db = super.getWritableDatabase();
97f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            if (mMigrated) {
98f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                // there might be a connection w/ stale structure, we should re-open.
99f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                close();
100f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                return getWritableSupportDatabase();
101f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            }
102937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            return getWrappedDb(db);
103937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        }
104937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
105f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar        synchronized SupportSQLiteDatabase getReadableSupportDatabase() {
106f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            mMigrated = false;
107937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            SQLiteDatabase db = super.getReadableDatabase();
108f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            if (mMigrated) {
109f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                // there might be a connection w/ stale structure, we should re-open.
110f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                close();
111f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar                return getReadableSupportDatabase();
112f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            }
113937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            return getWrappedDb(db);
114937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        }
115937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
116937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
1172b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            FrameworkSQLiteDatabase dbRef = mDbRef[0];
1182b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            if (dbRef == null) {
1192b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                dbRef = new FrameworkSQLiteDatabase(sqLiteDatabase);
1202b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar                mDbRef[0] = dbRef;
121937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            }
1222b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            return mDbRef[0];
1232b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        }
1242b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
1252b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        @Override
1262b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        public void onCreate(SQLiteDatabase sqLiteDatabase) {
1272b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mCallback.onCreate(getWrappedDb(sqLiteDatabase));
1282b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        }
1292b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
1302b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        @Override
1312b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
132f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            mMigrated = true;
1332b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mCallback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
1342b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        }
1352b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
1362b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        @Override
1372b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        public void onConfigure(SQLiteDatabase db) {
1382b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mCallback.onConfigure(getWrappedDb(db));
1392b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        }
1402b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
1412b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        @Override
1422b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
143f841d6b7490821ca9a843a673a89d41b266f280dYigit Boyar            mMigrated = true;
1442b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mCallback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
1452b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        }
1462b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar
1472b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        @Override
1482b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar        public void onOpen(SQLiteDatabase db) {
1498c7ba17f0a8d862f2de744e5bf5879a7e175927dYigit Boyar            if (!mMigrated) {
1508c7ba17f0a8d862f2de744e5bf5879a7e175927dYigit Boyar                // if we've migrated, we'll re-open the db so we  should not call the callback.
1518c7ba17f0a8d862f2de744e5bf5879a7e175927dYigit Boyar                mCallback.onOpen(getWrappedDb(db));
1528c7ba17f0a8d862f2de744e5bf5879a7e175927dYigit Boyar            }
153937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        }
154937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar
155937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        @Override
156937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        public synchronized void close() {
157937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar            super.close();
1582b4a201ee53be9d5e3995e62c76f83c07a1ddfddYigit Boyar            mDbRef[0] = null;
159937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar        }
160937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar    }
161937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar}
162