blob: fe4420b26b0ed8207d85ed81f490f7d98c2e77f3 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.slices;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import java.util.Locale;
/**
* Defines the schema for the Slices database.
*/
public class SlicesDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "SlicesDatabaseHelper";
private static final String DATABASE_NAME = "slices_index.db";
private static final String SHARED_PREFS_TAG = "slices_shared_prefs";
private static final int DATABASE_VERSION = 8;
public interface Tables {
String TABLE_SLICES_INDEX = "slices_index";
}
public interface IndexColumns {
/**
* Primary key of the DB. Preference key from preference controllers.
*/
String KEY = "key";
/**
* Title of the Setting.
*/
String TITLE = "title";
/**
* Summary / Subtitle for the setting.
*/
String SUMMARY = "summary";
/**
* Title of the Setting screen on which the Setting lives.
*/
String SCREENTITLE = "screentitle";
/**
* String with a comma separated list of keywords relating to the Slice.
*/
String KEYWORDS = "keywords";
/**
* Resource ID for the icon of the setting. Should be 0 for no icon.
*/
String ICON_RESOURCE = "icon";
/**
* Classname of the fragment name of the page that hosts the setting.
*/
String FRAGMENT = "fragment";
/**
* Class name of the controller backing the setting. Must be a
* {@link com.android.settings.core.BasePreferenceController}.
*/
String CONTROLLER = "controller";
/**
* {@link SliceData.SliceType} representing the inline type of the result.
*/
String SLICE_TYPE = "slice_type";
/**
* Customized subtitle if it's a unavailable slice
*/
String UNAVAILABLE_SLICE_SUBTITLE = "unavailable_slice_subtitle";
/**
* The uri of slice.
*/
String SLICE_URI = "slice_uri";
/**
* Whether the slice should be exposed publicly.
*/
String PUBLIC_SLICE = "public_slice";
}
private static final String CREATE_SLICES_TABLE =
"CREATE VIRTUAL TABLE " + Tables.TABLE_SLICES_INDEX + " USING fts4" +
"(" +
IndexColumns.KEY +
", " +
IndexColumns.SLICE_URI +
", " +
IndexColumns.TITLE +
", " +
IndexColumns.SUMMARY +
", " +
IndexColumns.SCREENTITLE +
", " +
IndexColumns.KEYWORDS +
", " +
IndexColumns.ICON_RESOURCE +
", " +
IndexColumns.FRAGMENT +
", " +
IndexColumns.CONTROLLER +
", " +
IndexColumns.SLICE_TYPE +
", " +
IndexColumns.UNAVAILABLE_SLICE_SUBTITLE +
", "
+
IndexColumns.PUBLIC_SLICE
+
" INTEGER DEFAULT 0 "
+
");";
private final Context mContext;
private static SlicesDatabaseHelper sSingleton;
public static synchronized SlicesDatabaseHelper getInstance(Context context) {
if (sSingleton == null) {
sSingleton = new SlicesDatabaseHelper(context.getApplicationContext());
}
return sSingleton;
}
private SlicesDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null /* CursorFactor */, DATABASE_VERSION);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
createDatabases(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < DATABASE_VERSION) {
Log.d(TAG, "Reconstructing DB from " + oldVersion + " to " + newVersion);
reconstruct(db);
}
}
/**
* Drops the currently stored databases rebuilds them.
* Also un-marks the state of the data such that any subsequent call to
* {@link#isNewIndexingState(Context)} will return {@code true}.
*/
void reconstruct(SQLiteDatabase db) {
mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.edit()
.clear()
.apply();
dropTables(db);
createDatabases(db);
}
/**
* Marks the current state of the device for the validity of the data. Should be called after
* a full index of the TABLE_SLICES_INDEX.
*/
public void setIndexedState() {
setBuildIndexed();
setLocaleIndexed();
}
/**
* Indicates if the indexed slice data reflects the current state of the phone.
*
* @return {@code true} if database should be rebuilt, {@code false} otherwise.
*/
public boolean isSliceDataIndexed() {
return isBuildIndexed() && isLocaleIndexed();
}
private void createDatabases(SQLiteDatabase db) {
db.execSQL(CREATE_SLICES_TABLE);
Log.d(TAG, "Created databases");
}
private void dropTables(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SLICES_INDEX);
}
private void setBuildIndexed() {
mContext.getSharedPreferences(SHARED_PREFS_TAG, 0 /* mode */)
.edit()
.putBoolean(getBuildTag(), true /* value */)
.apply();
}
private void setLocaleIndexed() {
mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
.edit()
.putBoolean(Locale.getDefault().toString(), true /* value */)
.apply();
}
private boolean isBuildIndexed() {
return mContext.getSharedPreferences(SHARED_PREFS_TAG,
Context.MODE_PRIVATE)
.getBoolean(getBuildTag(), false /* default */);
}
private boolean isLocaleIndexed() {
return mContext.getSharedPreferences(SHARED_PREFS_TAG,
Context.MODE_PRIVATE)
.getBoolean(Locale.getDefault().toString(), false /* default */);
}
@VisibleForTesting
String getBuildTag() {
return Build.FINGERPRINT;
}
}