• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.settings.slices;
18 
19 import android.content.Context;
20 
21 import android.database.sqlite.SQLiteDatabase;
22 import android.database.sqlite.SQLiteOpenHelper;
23 import android.os.Build;
24 import android.support.annotation.VisibleForTesting;
25 import android.util.Log;
26 
27 import java.util.Locale;
28 
29 /**
30  * Defines the schema for the Slices database.
31  */
32 public class SlicesDatabaseHelper extends SQLiteOpenHelper {
33 
34     private static final String TAG = "SlicesDatabaseHelper";
35 
36     private static final String DATABASE_NAME = "slices_index.db";
37     private static final String SHARED_PREFS_TAG = "slices_shared_prefs";
38 
39     private static final int DATABASE_VERSION = 2;
40 
41     public interface Tables {
42         String TABLE_SLICES_INDEX = "slices_index";
43     }
44 
45     public interface IndexColumns {
46         /**
47          * Primary key of the DB. Preference key from preference controllers.
48          */
49         String KEY = "key";
50 
51         /**
52          * Title of the Setting.
53          */
54         String TITLE = "title";
55 
56         /**
57          * Summary / Subtitle for the setting.
58          */
59         String SUMMARY = "summary";
60 
61         /**
62          * Title of the Setting screen on which the Setting lives.
63          */
64         String SCREENTITLE = "screentitle";
65 
66         /**
67          * String with a comma separated list of keywords relating to the Slice.
68          */
69         String KEYWORDS = "keywords";
70 
71         /**
72          * Resource ID for the icon of the setting. Should be 0 for no icon.
73          */
74         String ICON_RESOURCE = "icon";
75 
76         /**
77          * Classname of the fragment name of the page that hosts the setting.
78          */
79         String FRAGMENT = "fragment";
80 
81         /**
82          * Class name of the controller backing the setting. Must be a
83          * {@link com.android.settings.core.BasePreferenceController}.
84          */
85         String CONTROLLER = "controller";
86 
87         /**
88          * Boolean flag, {@code true} when the Slice is officially platform-supported.
89          */
90         String PLATFORM_SLICE = "platform_slice";
91 
92         /**
93          * {@link SliceData.SliceType} representing the inline type of the result.
94          */
95         String SLICE_TYPE = "slice_type";
96     }
97 
98     private static final String CREATE_SLICES_TABLE =
99             "CREATE VIRTUAL TABLE " + Tables.TABLE_SLICES_INDEX + " USING fts4" +
100                     "(" +
101                     IndexColumns.KEY +
102                     ", " +
103                     IndexColumns.TITLE +
104                     ", " +
105                     IndexColumns.SUMMARY +
106                     ", " +
107                     IndexColumns.SCREENTITLE +
108                     ", " +
109                     IndexColumns.KEYWORDS +
110                     ", " +
111                     IndexColumns.ICON_RESOURCE +
112                     ", " +
113                     IndexColumns.FRAGMENT +
114                     ", " +
115                     IndexColumns.CONTROLLER +
116                     ", " +
117                     IndexColumns.PLATFORM_SLICE +
118                     ", " +
119                     IndexColumns.SLICE_TYPE +
120                     ");";
121 
122     private final Context mContext;
123 
124     private static SlicesDatabaseHelper sSingleton;
125 
getInstance(Context context)126     public static synchronized SlicesDatabaseHelper getInstance(Context context) {
127         if (sSingleton == null) {
128             sSingleton = new SlicesDatabaseHelper(context.getApplicationContext());
129         }
130         return sSingleton;
131     }
132 
SlicesDatabaseHelper(Context context)133     private SlicesDatabaseHelper(Context context) {
134         super(context, DATABASE_NAME, null /* CursorFactor */, DATABASE_VERSION);
135         mContext = context;
136     }
137 
138     @Override
onCreate(SQLiteDatabase db)139     public void onCreate(SQLiteDatabase db) {
140         createDatabases(db);
141     }
142 
143     @Override
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)144     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
145         if (oldVersion < DATABASE_VERSION) {
146             Log.d(TAG, "Reconstructing DB from " + oldVersion + "to " + newVersion);
147             reconstruct(db);
148         }
149     }
150 
151     /**
152      * Drops the currently stored databases rebuilds them.
153      * Also un-marks the state of the data such that any subsequent call to
154      * {@link#isNewIndexingState(Context)} will return {@code true}.
155      */
reconstruct(SQLiteDatabase db)156     void reconstruct(SQLiteDatabase db) {
157         mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
158                 .edit()
159                 .clear()
160                 .apply();
161         dropTables(db);
162         createDatabases(db);
163     }
164 
165     /**
166      * Marks the current state of the device for the validity of the data. Should be called after
167      * a full index of the TABLE_SLICES_INDEX.
168      */
setIndexedState()169     public void setIndexedState() {
170         setBuildIndexed();
171         setLocaleIndexed();
172     }
173 
174     /**
175      * Indicates if the indexed slice data reflects the current state of the phone.
176      *
177      * @return {@code true} if database should be rebuilt, {@code false} otherwise.
178      */
isSliceDataIndexed()179     public boolean isSliceDataIndexed() {
180         return isBuildIndexed() && isLocaleIndexed();
181     }
182 
createDatabases(SQLiteDatabase db)183     private void createDatabases(SQLiteDatabase db) {
184         db.execSQL(CREATE_SLICES_TABLE);
185         Log.d(TAG, "Created databases");
186     }
187 
dropTables(SQLiteDatabase db)188     private void dropTables(SQLiteDatabase db) {
189         db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SLICES_INDEX);
190     }
191 
setBuildIndexed()192     private void setBuildIndexed() {
193         mContext.getSharedPreferences(SHARED_PREFS_TAG, 0 /* mode */)
194                 .edit()
195                 .putBoolean(getBuildTag(), true /* value */)
196                 .apply();
197     }
198 
setLocaleIndexed()199     private void setLocaleIndexed() {
200         mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
201                 .edit()
202                 .putBoolean(Locale.getDefault().toString(), true /* value */)
203                 .apply();
204     }
205 
isBuildIndexed()206     private boolean isBuildIndexed() {
207         return mContext.getSharedPreferences(SHARED_PREFS_TAG,
208                 Context.MODE_PRIVATE)
209                 .getBoolean(getBuildTag(), false /* default */);
210     }
211 
isLocaleIndexed()212     private boolean isLocaleIndexed() {
213         return mContext.getSharedPreferences(SHARED_PREFS_TAG,
214                 Context.MODE_PRIVATE)
215                 .getBoolean(Locale.getDefault().toString(), false /* default */);
216     }
217 
218     @VisibleForTesting
getBuildTag()219     String getBuildTag() {
220         return Build.FINGERPRINT;
221     }
222 }