Build slice from indexed data in SliceProvider
Connect the SliceIndexing data to the SliceProvider, such that a query to SliceProvider can build a Slice via the indexed data from SlicesIndexingManager. We take the key from the Uri supplied to the SettingSliceProvider and find a potential matching row in the indexed data. The matched data is then used to Build a slice for the caller. Bug: 67996923 Test: robotests Change-Id: If51bfd1a05c3f3817ae720554f95a98fc7b002e1
This commit is contained in:
@@ -28,6 +28,7 @@ import android.widget.Toolbar;
|
|||||||
|
|
||||||
import com.android.settings.core.FeatureFlags;
|
import com.android.settings.core.FeatureFlags;
|
||||||
import com.android.settings.dashboard.SiteMapManager;
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@@ -185,6 +186,9 @@ public interface SearchFeatureProvider {
|
|||||||
} else {
|
} else {
|
||||||
intent = new Intent(activity, SearchActivity.class);
|
intent = new Intent(activity, SearchActivity.class);
|
||||||
}
|
}
|
||||||
|
FeatureFactory.getFactory(
|
||||||
|
activity.getApplicationContext()).getSlicesFeatureProvider()
|
||||||
|
.indexSliceDataAsync(activity.getApplicationContext());
|
||||||
activity.startActivityForResult(intent, 0 /* requestCode */);
|
activity.startActivityForResult(intent, 0 /* requestCode */);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import android.content.Intent;
|
|||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
@@ -32,13 +33,25 @@ import androidx.app.slice.SliceProvider;
|
|||||||
import androidx.app.slice.builders.ListBuilder;
|
import androidx.app.slice.builders.ListBuilder;
|
||||||
|
|
||||||
public class SettingsSliceProvider extends SliceProvider {
|
public class SettingsSliceProvider extends SliceProvider {
|
||||||
|
|
||||||
|
private static final String TAG = "SettingsSliceProvider";
|
||||||
|
|
||||||
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
|
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
|
||||||
|
|
||||||
public static final String PATH_WIFI = "wifi";
|
public static final String PATH_WIFI = "wifi";
|
||||||
public static final String ACTION_WIFI_CHANGED =
|
public static final String ACTION_WIFI_CHANGED =
|
||||||
"com.android.settings.slice.action.WIFI_CHANGED";
|
"com.android.settings.slice.action.WIFI_CHANGED";
|
||||||
|
|
||||||
|
public static final String ACTION_TOGGLE_CHANGED =
|
||||||
|
"com.android.settings.slice.action.TOGGLE_CHANGED";
|
||||||
|
|
||||||
|
public static final String EXTRA_SLICE_KEY = "com.android.settings.slice.extra.key";
|
||||||
|
|
||||||
// TODO -- Associate slice URI with search result instead of separate hardcoded thing
|
// TODO -- Associate slice URI with search result instead of separate hardcoded thing
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
SlicesDatabaseAccessor mSlicesDatabaseAccessor;
|
||||||
|
|
||||||
public static Uri getUri(String path) {
|
public static Uri getUri(String path) {
|
||||||
return new Uri.Builder()
|
return new Uri.Builder()
|
||||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
@@ -48,19 +61,26 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateSliceProvider() {
|
public boolean onCreateSliceProvider() {
|
||||||
|
mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice onBindSlice(Uri sliceUri) {
|
public Slice onBindSlice(Uri sliceUri) {
|
||||||
String path = sliceUri.getPath();
|
String path = sliceUri.getPath();
|
||||||
|
// If adding a new Slice, do not directly match Slice URIs.
|
||||||
|
// Use {@link SlicesDatabaseAccessor}.
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case "/" + PATH_WIFI:
|
case "/" + PATH_WIFI:
|
||||||
return createWifiSlice(sliceUri);
|
return createWifiSlice(sliceUri);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unrecognized slice uri: " + sliceUri);
|
|
||||||
|
return getHoldingSlice(sliceUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Slice getHoldingSlice(Uri uri) {
|
||||||
|
return new ListBuilder(uri).build();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (b/70622039) remove this when the proper wifi slice is enabled.
|
// TODO (b/70622039) remove this when the proper wifi slice is enabled.
|
||||||
private Slice createWifiSlice(Uri sliceUri) {
|
private Slice createWifiSlice(Uri sliceUri) {
|
||||||
|
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.slices;
|
package com.android.settings.slices;
|
||||||
|
|
||||||
|
import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
|
||||||
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
|
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
|
||||||
|
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
|
||||||
|
|
||||||
import android.app.slice.Slice;
|
import android.app.slice.Slice;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -25,19 +27,34 @@ import android.content.Intent;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.core.TogglePreferenceController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responds to actions performed on slices and notifies slices of updates in state changes.
|
* Responds to actions performed on slices and notifies slices of updates in state changes.
|
||||||
*/
|
*/
|
||||||
public class SliceBroadcastReceiver extends BroadcastReceiver {
|
public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
private static String TAG = "SettSliceBroadcastRec";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO (b/) move wifi action into generalized case.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent i) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
String action = i.getAction();
|
String action = intent.getAction();
|
||||||
|
String key = intent.getStringExtra(EXTRA_SLICE_KEY);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
case ACTION_TOGGLE_CHANGED:
|
||||||
|
handleToggleAction(context, key);
|
||||||
|
break;
|
||||||
case ACTION_WIFI_CHANGED:
|
case ACTION_WIFI_CHANGED:
|
||||||
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
boolean newState = i.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, wm.isWifiEnabled());
|
boolean newState = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE,
|
||||||
|
wm.isWifiEnabled());
|
||||||
wm.setWifiEnabled(newState);
|
wm.setWifiEnabled(newState);
|
||||||
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
|
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
|
||||||
Handler h = new Handler();
|
Handler h = new Handler();
|
||||||
@@ -48,4 +65,28 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleToggleAction(Context context, String key) {
|
||||||
|
if (TextUtils.isEmpty(key)) {
|
||||||
|
throw new IllegalStateException("No key passed to Intent for toggle controller");
|
||||||
|
}
|
||||||
|
|
||||||
|
BasePreferenceController controller = getBasePreferenceController(context, key);
|
||||||
|
|
||||||
|
if (!(controller instanceof TogglePreferenceController)) {
|
||||||
|
throw new IllegalStateException("Toggle action passed for a non-toggle key: " + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
|
||||||
|
// so that it's automatically broadcast to any slice.
|
||||||
|
TogglePreferenceController toggleController = (TogglePreferenceController) controller;
|
||||||
|
boolean currentValue = toggleController.isChecked();
|
||||||
|
toggleController.setChecked(!currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasePreferenceController getBasePreferenceController(Context context, String key) {
|
||||||
|
final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(context);
|
||||||
|
final SliceData sliceData = accessor.getSliceDataFromKey(key);
|
||||||
|
return SliceBuilderUtils.getPreferenceController(context, sliceData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
125
src/com/android/settings/slices/SliceBuilderUtils.java
Normal file
125
src/com/android/settings/slices/SliceBuilderUtils.java
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* 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.SettingsSliceProvider.EXTRA_SLICE_KEY;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.SubSettings;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.core.TogglePreferenceController;
|
||||||
|
import com.android.settings.search.DatabaseIndexingUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import androidx.app.slice.Slice;
|
||||||
|
import androidx.app.slice.builders.ListBuilder;
|
||||||
|
import androidx.app.slice.builders.ListBuilder.RowBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to build Slices objects and Preference Controllers based on the Database managed
|
||||||
|
* by {@link SlicesDatabaseHelper}
|
||||||
|
*/
|
||||||
|
public class SliceBuilderUtils {
|
||||||
|
|
||||||
|
private static final String TAG = "SliceBuilder";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a Slice from {@link SliceData}.
|
||||||
|
*
|
||||||
|
* @return a {@link Slice} based on the data provided by {@param sliceData}.
|
||||||
|
* Will build an {@link Intent} based Slice unless the Preference Controller name in
|
||||||
|
* {@param sliceData} is an inline controller.
|
||||||
|
*/
|
||||||
|
public static Slice buildSlice(Context context, SliceData sliceData) {
|
||||||
|
final PendingIntent contentIntent = getContentIntent(context, sliceData);
|
||||||
|
final Icon icon = Icon.createWithResource(context, sliceData.getIconResource());
|
||||||
|
String summaryText = sliceData.getSummary();
|
||||||
|
String subtitleText = TextUtils.isEmpty(summaryText)
|
||||||
|
? sliceData.getScreenTitle()
|
||||||
|
: summaryText;
|
||||||
|
|
||||||
|
RowBuilder builder = new RowBuilder(sliceData.getUri())
|
||||||
|
.setTitle(sliceData.getTitle())
|
||||||
|
.setTitleItem(icon)
|
||||||
|
.setSubtitle(subtitleText)
|
||||||
|
.setContentIntent(contentIntent);
|
||||||
|
|
||||||
|
BasePreferenceController controller = getPreferenceController(context, sliceData);
|
||||||
|
|
||||||
|
// TODO (b/71640747) Respect setting availability.
|
||||||
|
// TODO (b/71640678) Add dynamic summary text.
|
||||||
|
|
||||||
|
if (controller instanceof TogglePreferenceController) {
|
||||||
|
addToggleAction(context, builder, ((TogglePreferenceController) controller).isChecked(),
|
||||||
|
sliceData.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ListBuilder(sliceData.getUri())
|
||||||
|
.addRow(builder)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks at the {@link SliceData#preferenceController} from {@param sliceData} and attempts to
|
||||||
|
* build a {@link BasePreferenceController}.
|
||||||
|
*/
|
||||||
|
public static BasePreferenceController getPreferenceController(Context context,
|
||||||
|
SliceData sliceData) {
|
||||||
|
// TODO check for context-only controller first.
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(sliceData.getPreferenceController());
|
||||||
|
Constructor<?> preferenceConstructor = clazz.getConstructor(Context.class,
|
||||||
|
String.class);
|
||||||
|
return (BasePreferenceController) preferenceConstructor.newInstance(
|
||||||
|
new Object[]{context, sliceData.getKey()});
|
||||||
|
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
|
||||||
|
IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Invalid preference controller: " + sliceData.getPreferenceController());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addToggleAction(Context context, RowBuilder builder, boolean isChecked,
|
||||||
|
String key) {
|
||||||
|
PendingIntent actionIntent = getActionIntent(context,
|
||||||
|
SettingsSliceProvider.ACTION_TOGGLE_CHANGED, key);
|
||||||
|
builder.addToggle(actionIntent, isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PendingIntent getActionIntent(Context context, String action, String key) {
|
||||||
|
Intent intent = new Intent(action);
|
||||||
|
intent.setClass(context, SliceBroadcastReceiver.class);
|
||||||
|
intent.putExtra(EXTRA_SLICE_KEY, key);
|
||||||
|
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||||
|
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PendingIntent getContentIntent(Context context, SliceData sliceData) {
|
||||||
|
Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||||
|
sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
|
||||||
|
0 /* TODO */);
|
||||||
|
intent.setClassName("com.android.settings", SubSettings.class.getName());
|
||||||
|
return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
|
||||||
|
}
|
||||||
|
}
|
@@ -18,7 +18,6 @@ package com.android.settings.slices;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data class representing a slice stored by {@link SlicesIndexer}.
|
* Data class representing a slice stored by {@link SlicesIndexer}.
|
||||||
* Note that {@link #key} is treated as a primary key for this class and determines equality.
|
* Note that {@link #key} is treated as a primary key for this class and determines equality.
|
||||||
@@ -179,5 +178,4 @@ public class SliceData {
|
|||||||
return mKey;
|
return mKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
141
src/com/android/settings/slices/SlicesDatabaseAccessor.java
Normal file
141
src/com/android/settings/slices/SlicesDatabaseAccessor.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
|
||||||
|
|
||||||
|
import androidx.app.slice.Slice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to map a {@link Uri} from {@link SettingsSliceProvider} to a Slice.
|
||||||
|
*/
|
||||||
|
public class SlicesDatabaseAccessor {
|
||||||
|
|
||||||
|
public static final String[] SELECT_COLUMNS = {
|
||||||
|
IndexColumns.KEY,
|
||||||
|
IndexColumns.TITLE,
|
||||||
|
IndexColumns.SUMMARY,
|
||||||
|
IndexColumns.SCREENTITLE,
|
||||||
|
IndexColumns.ICON_RESOURCE,
|
||||||
|
IndexColumns.FRAGMENT,
|
||||||
|
IndexColumns.CONTROLLER,
|
||||||
|
};
|
||||||
|
|
||||||
|
Context mContext;
|
||||||
|
|
||||||
|
public SlicesDatabaseAccessor(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
String key = uri.getLastPathSegment();
|
||||||
|
Cursor cursor = getIndexedSliceData(key);
|
||||||
|
return buildSliceData(cursor, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getIndexedSliceData(String path) {
|
||||||
|
verifyIndexing();
|
||||||
|
|
||||||
|
final String whereClause = buildWhereClause();
|
||||||
|
final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||||
|
final SQLiteDatabase database = helper.getReadableDatabase();
|
||||||
|
final String[] selection = new String[]{path};
|
||||||
|
|
||||||
|
Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS, 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 buildWhereClause() {
|
||||||
|
return new StringBuilder(IndexColumns.KEY)
|
||||||
|
.append(" = ?")
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SliceData buildSliceData(Cursor cursor, Uri uri) {
|
||||||
|
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 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));
|
||||||
|
|
||||||
|
return new SliceData.Builder()
|
||||||
|
.setKey(key)
|
||||||
|
.setTitle(title)
|
||||||
|
.setSummary(summary)
|
||||||
|
.setScreenTitle(screenTitle)
|
||||||
|
.setIcon(iconResource)
|
||||||
|
.setFragmentName(fragmentClassName)
|
||||||
|
.setPreferenceControllerClassName(controllerClassName)
|
||||||
|
.setUri(uri)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyIndexing() {
|
||||||
|
final long uidToken = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
FeatureFactory.getFactory(
|
||||||
|
mContext).getSlicesFeatureProvider().indexSliceData(mContext);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(uidToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -104,7 +104,7 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
public static synchronized SlicesDatabaseHelper getInstance(Context context) {
|
public static synchronized SlicesDatabaseHelper getInstance(Context context) {
|
||||||
if (sSingleton == null) {
|
if (sSingleton == null) {
|
||||||
sSingleton = new SlicesDatabaseHelper(context);
|
sSingleton = new SlicesDatabaseHelper(context.getApplicationContext());
|
||||||
}
|
}
|
||||||
return sSingleton;
|
return sSingleton;
|
||||||
}
|
}
|
||||||
|
@@ -13,5 +13,15 @@ public interface SlicesFeatureProvider {
|
|||||||
|
|
||||||
SliceDataConverter getSliceDataConverter(Context context);
|
SliceDataConverter getSliceDataConverter(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronous call to index the data used to build Slices.
|
||||||
|
* If the data is already indexed, the data will not change.
|
||||||
|
*/
|
||||||
|
void indexSliceDataAsync(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indexes the data used to build Slices.
|
||||||
|
* If the data is already indexed, the data will not change.
|
||||||
|
*/
|
||||||
void indexSliceData(Context context);
|
void indexSliceData(Context context);
|
||||||
}
|
}
|
@@ -15,7 +15,7 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
|
|||||||
@Override
|
@Override
|
||||||
public SlicesIndexer getSliceIndexer(Context context) {
|
public SlicesIndexer getSliceIndexer(Context context) {
|
||||||
if (mSlicesIndexer == null) {
|
if (mSlicesIndexer == null) {
|
||||||
mSlicesIndexer = new SlicesIndexer(context.getApplicationContext());
|
mSlicesIndexer = new SlicesIndexer(context);
|
||||||
}
|
}
|
||||||
return mSlicesIndexer;
|
return mSlicesIndexer;
|
||||||
}
|
}
|
||||||
@@ -29,9 +29,14 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void indexSliceData(Context context) {
|
public void indexSliceDataAsync(Context context) {
|
||||||
// TODO (b/67996923) add indexing time log
|
|
||||||
SlicesIndexer indexer = getSliceIndexer(context);
|
SlicesIndexer indexer = getSliceIndexer(context);
|
||||||
ThreadUtils.postOnBackgroundThread(indexer);
|
ThreadUtils.postOnBackgroundThread(indexer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void indexSliceData(Context context) {
|
||||||
|
SlicesIndexer indexer = getSliceIndexer(context);
|
||||||
|
indexer.indexSliceData();
|
||||||
|
}
|
||||||
|
}
|
@@ -20,6 +20,7 @@ import android.content.ContentValues;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
class SlicesIndexer implements Runnable {
|
class SlicesIndexer implements Runnable {
|
||||||
|
|
||||||
private static final String TAG = "SlicesIndexingManager";
|
private static final String TAG = "SlicesIndexer";
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
@@ -48,18 +49,27 @@ class SlicesIndexer implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronously takes data obtained from {@link SliceDataConverter} and indexes it into a
|
* Asynchronously index slice data from {@link #indexSliceData()}.
|
||||||
* SQLite database.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
indexSliceData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously takes data obtained from {@link SliceDataConverter} and indexes it into a
|
||||||
|
* SQLite database
|
||||||
|
*/
|
||||||
|
protected void indexSliceData() {
|
||||||
if (mHelper.isSliceDataIndexed()) {
|
if (mHelper.isSliceDataIndexed()) {
|
||||||
|
Log.d(TAG, "Slices already indexed - returning.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLiteDatabase database = mHelper.getWritableDatabase();
|
SQLiteDatabase database = mHelper.getWritableDatabase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
database.beginTransaction();
|
database.beginTransaction();
|
||||||
|
|
||||||
mHelper.reconstruct(mHelper.getWritableDatabase());
|
mHelper.reconstruct(mHelper.getWritableDatabase());
|
||||||
@@ -67,6 +77,10 @@ class SlicesIndexer implements Runnable {
|
|||||||
insertSliceData(database, indexData);
|
insertSliceData(database, indexData);
|
||||||
|
|
||||||
mHelper.setIndexedState();
|
mHelper.setIndexedState();
|
||||||
|
|
||||||
|
// TODO (b/71503044) Log indexing time.
|
||||||
|
Log.d(TAG,
|
||||||
|
"Indexing slices database took: " + (System.currentTimeMillis() - startTime));
|
||||||
database.setTransactionSuccessful();
|
database.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
database.endTransaction();
|
database.endTransaction();
|
||||||
|
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.provider.Settings;
|
||||||
|
|
||||||
|
import com.android.settings.core.TogglePreferenceController;
|
||||||
|
|
||||||
|
public class FakeToggleController extends TogglePreferenceController {
|
||||||
|
|
||||||
|
private String settingKey = "toggle_key";
|
||||||
|
|
||||||
|
private final int ON = 1;
|
||||||
|
private final int OFF = 0;
|
||||||
|
|
||||||
|
public FakeToggleController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
return Settings.System.getInt(mContext.getContentResolver(),
|
||||||
|
settingKey, OFF) == ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setChecked(boolean isChecked) {
|
||||||
|
return Settings.System.putInt(mContext.getContentResolver(), settingKey,
|
||||||
|
isChecked ? ON : OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import androidx.app.slice.Slice;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SettingsSliceProviderTest {
|
||||||
|
|
||||||
|
private final String fakeTitle = "title";
|
||||||
|
private final String KEY = "key";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private SettingsSliceProvider mProvider;
|
||||||
|
private SQLiteDatabase mDb;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
mProvider = spy(new SettingsSliceProvider());
|
||||||
|
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||||
|
SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUp() {
|
||||||
|
DatabaseTestUtils.clearDb(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitialSliceReturned_emmptySlice() {
|
||||||
|
Uri uri = SettingsSliceProvider.getUri(KEY);
|
||||||
|
Slice slice = mProvider.onBindSlice(uri);
|
||||||
|
|
||||||
|
assertThat(slice.getUri()).isEqualTo(uri);
|
||||||
|
assertThat(slice.getItems()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUriBuilder_returnsValidSliceUri() {
|
||||||
|
Uri uri = SettingsSliceProvider.getUri(KEY);
|
||||||
|
|
||||||
|
assertThat(uri.getScheme()).isEqualTo(ContentResolver.SCHEME_CONTENT);
|
||||||
|
assertThat(uri.getAuthority()).isEqualTo(SettingsSliceProvider.SLICE_AUTHORITY);
|
||||||
|
assertThat(uri.getLastPathSegment()).isEqualTo(KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertSpecialCase(String key) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, "s");
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, "s");
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, 1234);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, "test");
|
||||||
|
|
||||||
|
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.search.FakeIndexProvider;
|
||||||
|
import com.android.settings.search.SearchIndexableResources;
|
||||||
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SliceBroadcastReceiverTest {
|
||||||
|
|
||||||
|
private final String fakeTitle = "title";
|
||||||
|
private final String fakeSummary = "summary";
|
||||||
|
private final String fakeScreenTitle = "screen_title";
|
||||||
|
private final int fakeIcon = 1234;
|
||||||
|
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||||
|
private final String fakeControllerName = FakeToggleController.class.getName();
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private SQLiteDatabase mDb;
|
||||||
|
private SliceBroadcastReceiver mReceiver;
|
||||||
|
|
||||||
|
private Set<Class> mProviderClassesCopy;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||||
|
mReceiver = new SliceBroadcastReceiver();
|
||||||
|
mProviderClassesCopy = new HashSet<>(SearchIndexableResources.providerValues());
|
||||||
|
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
|
||||||
|
helper.setIndexedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUp() {
|
||||||
|
DatabaseTestUtils.clearDb(mContext);
|
||||||
|
SearchIndexableResources.providerValues().clear();
|
||||||
|
SearchIndexableResources.providerValues().addAll(mProviderClassesCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnReceive_toggleChanged() {
|
||||||
|
String key = "key";
|
||||||
|
SearchIndexableResources.providerValues().clear();
|
||||||
|
insertSpecialCase(key);
|
||||||
|
// Turn on toggle setting
|
||||||
|
FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
|
||||||
|
fakeToggleController.setChecked(true);
|
||||||
|
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||||
|
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
|
||||||
|
|
||||||
|
assertThat(fakeToggleController.isChecked()).isTrue();
|
||||||
|
|
||||||
|
// Toggle setting
|
||||||
|
mReceiver.onReceive(mContext, intent);
|
||||||
|
|
||||||
|
assertThat(fakeToggleController.isChecked()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testOnReceive_noExtra_illegalSatetException() {
|
||||||
|
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||||
|
mReceiver.onReceive(mContext, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testOnReceive_emptyKey_throwsIllegalStateException() {
|
||||||
|
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
|
||||||
|
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, (String) null);
|
||||||
|
mReceiver.onReceive(mContext, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertSpecialCase(String key) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
|
||||||
|
|
||||||
|
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.search.FakeIndexProvider;
|
||||||
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SlicesDatabaseAccessorTest {
|
||||||
|
|
||||||
|
private final String fakeTitle = "title";
|
||||||
|
private final String fakeSummary = "summary";
|
||||||
|
private final String fakeScreenTitle = "screen_title";
|
||||||
|
private final int fakeIcon = 1234;
|
||||||
|
private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
|
||||||
|
private final String fakeControllerName = FakePreferenceController.class.getName();
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private SQLiteDatabase mDb;
|
||||||
|
private SlicesDatabaseAccessor mAccessor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mAccessor = spy(new SlicesDatabaseAccessor(mContext));
|
||||||
|
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||||
|
SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUp() {
|
||||||
|
DatabaseTestUtils.clearDb(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSliceDataFromKey_validKey_validSliceReturned() {
|
||||||
|
String key = "key";
|
||||||
|
insertSpecialCase(key);
|
||||||
|
|
||||||
|
SliceData data = mAccessor.getSliceDataFromKey(key);
|
||||||
|
|
||||||
|
assertThat(data.getKey()).isEqualTo(key);
|
||||||
|
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||||
|
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||||
|
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||||
|
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||||
|
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||||
|
assertThat(data.getUri()).isNull();
|
||||||
|
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testGetSliceDataFromKey_invalidKey_errorThrown() {
|
||||||
|
String key = "key";
|
||||||
|
|
||||||
|
mAccessor.getSliceDataFromKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSliceFromUri_validUri_validSliceReturned() {
|
||||||
|
String key = "key";
|
||||||
|
insertSpecialCase(key);
|
||||||
|
Uri uri = SettingsSliceProvider.getUri(key);
|
||||||
|
|
||||||
|
SliceData data = mAccessor.getSliceDataFromUri(uri);
|
||||||
|
|
||||||
|
assertThat(data.getKey()).isEqualTo(key);
|
||||||
|
assertThat(data.getTitle()).isEqualTo(fakeTitle);
|
||||||
|
assertThat(data.getSummary()).isEqualTo(fakeSummary);
|
||||||
|
assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
|
||||||
|
assertThat(data.getIconResource()).isEqualTo(fakeIcon);
|
||||||
|
assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
|
||||||
|
assertThat(data.getUri()).isEqualTo(uri);
|
||||||
|
assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testGetSliceFromUri_invalidUri_errorThrown() {
|
||||||
|
Uri uri = SettingsSliceProvider.getUri("durr");
|
||||||
|
|
||||||
|
mAccessor.getSliceDataFromUri(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertSpecialCase(String key) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
|
||||||
|
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
|
||||||
|
|
||||||
|
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.TestConfig.SDK_VERSION;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import androidx.app.slice.Slice;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = SDK_VERSION)
|
||||||
|
public class SlicesDatabaseUtilsTest {
|
||||||
|
|
||||||
|
private final String KEY = "KEY";
|
||||||
|
private final String TITLE = "title";
|
||||||
|
private final String SUMMARY = "summary";
|
||||||
|
private final String SCREEN_TITLE = "screen title";
|
||||||
|
private final String FRAGMENT_NAME = "fragment name";
|
||||||
|
private final int ICON = 1234; // I declare a thumb war
|
||||||
|
private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
|
||||||
|
private final String PREF_CONTROLLER = FakeToggleController.class.getName();
|
||||||
|
;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildSlice_returnsMatchingSlice() {
|
||||||
|
Slice slice = SliceBuilderUtils.buildSlice(mContext, getDummyData());
|
||||||
|
|
||||||
|
assertThat(slice).isNotNull(); // TODO improve test for Slice content
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPreferenceController_buildsMatchingController() {
|
||||||
|
BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
|
||||||
|
getDummyData());
|
||||||
|
|
||||||
|
assertThat(controller).isInstanceOf(FakeToggleController.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SliceData getDummyData() {
|
||||||
|
return new SliceData.Builder()
|
||||||
|
.setKey(KEY)
|
||||||
|
.setTitle(TITLE)
|
||||||
|
.setSummary(SUMMARY)
|
||||||
|
.setScreenTitle(SCREEN_TITLE)
|
||||||
|
.setIcon(ICON)
|
||||||
|
.setFragmentName(FRAGMENT_NAME)
|
||||||
|
.setUri(URI)
|
||||||
|
.setPreferenceControllerClassName(PREF_CONTROLLER)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user