Files
app_Settings/src/com/android/settings/slices/SlicesDatabaseAccessor.java
Matthew Fritze 838d69da50 Index database before getting Uri Descendants
onGetSliceDescendants would return empty results if
the call was made before the database was indexed.
This CL checks the index before building the list.

Change-Id: I2e0f88893138a048dbd529d465d68fa4b1a3dc12
Fixes: 78196823
Test: robotests
2018-04-25 15:53:16 -07:00

194 lines
7.1 KiB
Java

/*
* 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 static com.android.settings.slices.SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.content.Context;
import android.os.Binder;
import android.util.Pair;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
import java.util.ArrayList;
import java.util.List;
import androidx.slice.Slice;
/**
* Class used to map a {@link Uri} from {@link SettingsSliceProvider} to a Slice.
*/
public class SlicesDatabaseAccessor {
public static final String[] SELECT_COLUMNS_ALL = {
IndexColumns.KEY,
IndexColumns.TITLE,
IndexColumns.SUMMARY,
IndexColumns.SCREENTITLE,
IndexColumns.KEYWORDS,
IndexColumns.ICON_RESOURCE,
IndexColumns.FRAGMENT,
IndexColumns.CONTROLLER,
IndexColumns.PLATFORM_SLICE,
IndexColumns.SLICE_TYPE,
};
// Cursor value for boolean true
private final int TRUE = 1;
private final Context mContext;
private final SlicesDatabaseHelper mHelper;
public SlicesDatabaseAccessor(Context context) {
mContext = context;
mHelper = SlicesDatabaseHelper.getInstance(mContext);
}
/**
* Query the slices database and return a {@link SliceData} object corresponding to the row
* matching the key provided by the {@param uri}. Additionally adds the {@param uri} to the
* {@link SliceData} object so the {@link Slice} can bind to the {@link Uri}.
* Used when building a {@link Slice}.
*/
public SliceData getSliceDataFromUri(Uri uri) {
Pair<Boolean, String> pathData = SliceBuilderUtils.getPathData(uri);
Cursor cursor = getIndexedSliceData(pathData.second /* key */);
return buildSliceData(cursor, uri, pathData.first /* isIntentOnly */);
}
/**
* Query the slices database and return a {@link SliceData} object corresponding to the row
* matching the {@param key}.
* Used when handling the action of the {@link Slice}.
*/
public SliceData getSliceDataFromKey(String key) {
Cursor cursor = getIndexedSliceData(key);
return buildSliceData(cursor, null /* uri */, false /* isIntentOnly */);
}
/**
* @return a list of keys in the Slices database matching on {@param isPlatformSlice}.
*/
public List<String> getSliceKeys(boolean isPlatformSlice) {
verifyIndexing();
final String whereClause;
if (isPlatformSlice) {
whereClause = IndexColumns.PLATFORM_SLICE + " = 1";
} else {
whereClause = IndexColumns.PLATFORM_SLICE + " = 0";
}
final SQLiteDatabase database = mHelper.getReadableDatabase();
final String[] columns = new String[]{IndexColumns.KEY};
final List<String> keys = new ArrayList<>();
try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, whereClause,
null /* selection */, null /* groupBy */, null /* having */, null /* orderBy */)) {
if (!resultCursor.moveToFirst()) {
return keys;
}
do {
keys.add(resultCursor.getString(0 /* key index */));
} while (resultCursor.moveToNext());
}
return keys;
}
private Cursor getIndexedSliceData(String path) {
verifyIndexing();
final String whereClause = buildKeyMatchWhereClause();
final SQLiteDatabase database = mHelper.getReadableDatabase();
final String[] selection = new String[]{path};
final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL,
whereClause, selection, null /* groupBy */, null /* having */, null /* orderBy */);
int numResults = resultCursor.getCount();
if (numResults == 0) {
throw new IllegalStateException("Invalid Slices key from path: " + path);
}
if (numResults > 1) {
throw new IllegalStateException(
"Should not match more than 1 slice with path: " + path);
}
resultCursor.moveToFirst();
return resultCursor;
}
private String buildKeyMatchWhereClause() {
return new StringBuilder(IndexColumns.KEY)
.append(" = ?")
.toString();
}
private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isIntentOnly) {
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
final String screenTitle = cursor.getString(
cursor.getColumnIndex(IndexColumns.SCREENTITLE));
final String keywords = cursor.getString(cursor.getColumnIndex(IndexColumns.KEYWORDS));
final int iconResource = cursor.getInt(cursor.getColumnIndex(IndexColumns.ICON_RESOURCE));
final String fragmentClassName = cursor.getString(
cursor.getColumnIndex(IndexColumns.FRAGMENT));
final String controllerClassName = cursor.getString(
cursor.getColumnIndex(IndexColumns.CONTROLLER));
final boolean isPlatformDefined = cursor.getInt(
cursor.getColumnIndex(IndexColumns.PLATFORM_SLICE)) == TRUE;
int sliceType = cursor.getInt(
cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
if (isIntentOnly) {
sliceType = SliceData.SliceType.INTENT;
}
return new SliceData.Builder()
.setKey(key)
.setTitle(title)
.setSummary(summary)
.setScreenTitle(screenTitle)
.setKeywords(keywords)
.setIcon(iconResource)
.setFragmentName(fragmentClassName)
.setPreferenceControllerClassName(controllerClassName)
.setUri(uri)
.setPlatformDefined(isPlatformDefined)
.setSliceType(sliceType)
.build();
}
private void verifyIndexing() {
final long uidToken = Binder.clearCallingIdentity();
try {
FeatureFactory.getFactory(
mContext).getSlicesFeatureProvider().indexSliceData(mContext);
} finally {
Binder.restoreCallingIdentity(uidToken);
}
}
}