Build a sitemap manager to keep track of breadcrumbs
- Have a new db to track parent-child page relation at index time. - Make a registry class to track (in IA) which page host what type of sub pages. - Make a manager class that queries the db as well as IA to compute breadcrumbs Fix: 32936784 Test: RunSettingsRoboTest Change-Id: I5f1583fae772c3d477d2ad186e111b79cc3e41aa
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.dashboard;
|
||||||
|
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
|
import com.android.settings.DevelopmentSettings;
|
||||||
|
import com.android.settings.DisplaySettings;
|
||||||
|
import com.android.settings.SecuritySettings;
|
||||||
|
import com.android.settings.accounts.UserAndAccountDashboardFragment;
|
||||||
|
import com.android.settings.applications.AdvancedAppSettings;
|
||||||
|
import com.android.settings.applications.AppAndNotificationDashboardFragment;
|
||||||
|
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
||||||
|
import com.android.settings.deviceinfo.StorageDashboardFragment;
|
||||||
|
import com.android.settings.inputmethod.InputAndGestureSettings;
|
||||||
|
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
|
||||||
|
import com.android.settings.network.NetworkDashboardFragment;
|
||||||
|
import com.android.settings.notification.SoundSettings;
|
||||||
|
import com.android.settings.system.SystemDashboardFragment;
|
||||||
|
import com.android.settingslib.drawer.CategoryKey;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A registry to keep track of which page hosts which category.
|
||||||
|
* TODO: Remove DashboardFragment#getCategoryKey() and just use this registry instead.
|
||||||
|
*/
|
||||||
|
public class DashboardFragmentRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from parent fragment to category key. The parent fragment hosts child with
|
||||||
|
* category_key.
|
||||||
|
*/
|
||||||
|
public static final Map<String, String> PARENT_TO_CATEGORY_KEY_MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from category_key to parent. This is a helper to look up which fragment hosts the
|
||||||
|
* category_key.
|
||||||
|
*/
|
||||||
|
public static final Map<String, String> CATEGORY_KEY_TO_PARENT_MAP;
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap<>();
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(
|
||||||
|
NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragment.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_DEVICE);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_APPS);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedAppSettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_APPS_DEFAULT);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(DisplaySettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_DISPLAY);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(SoundSettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_SOUND);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(StorageDashboardFragment.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_STORAGE);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_SECURITY);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(UserAndAccountDashboardFragment.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_ACCOUNT);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(UserAndAccountDashboardFragment.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_ACCOUNT);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(
|
||||||
|
SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(
|
||||||
|
InputAndGestureSettings.class.getName(), CategoryKey.CATEGORY_SYSTEM_INPUT);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(InputMethodAndLanguageSettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
|
||||||
|
PARENT_TO_CATEGORY_KEY_MAP.put(DevelopmentSettings.class.getName(),
|
||||||
|
CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
|
||||||
|
|
||||||
|
CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size());
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> parentToKey : PARENT_TO_CATEGORY_KEY_MAP.entrySet()) {
|
||||||
|
CATEGORY_KEY_TO_PARENT_MAP.put(parentToKey.getValue(), parentToKey.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
src/com/android/settings/dashboard/SiteMapManager.java
Normal file
212
src/com/android/settings/dashboard/SiteMapManager.java
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* 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.dashboard;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.annotation.WorkerThread;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper.IndexColumns;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper.SiteMapColumns;
|
||||||
|
import com.android.settingslib.drawer.DashboardCategory;
|
||||||
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.android.settings.dashboard.DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager class that maintains a "site map" and look up breadcrumb for a certain page on demand.
|
||||||
|
* <p/>
|
||||||
|
* The methods on this class can only be called on a background thread.
|
||||||
|
*/
|
||||||
|
public class SiteMapManager {
|
||||||
|
|
||||||
|
private static final String TAG = "SiteMapManager";
|
||||||
|
private static final boolean DEBUG_TIMING = false;
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
public static final String[] SITE_MAP_COLUMNS = {
|
||||||
|
SiteMapColumns.PARENT_CLASS,
|
||||||
|
SiteMapColumns.PARENT_TITLE,
|
||||||
|
SiteMapColumns.CHILD_CLASS,
|
||||||
|
SiteMapColumns.CHILD_TITLE
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String[] CLASS_TO_SCREEN_TITLE_COLUMNS = {
|
||||||
|
IndexColumns.CLASS_NAME,
|
||||||
|
IndexColumns.SCREEN_TITLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
private final List<SiteMapPair> mPairs = new ArrayList<>();
|
||||||
|
|
||||||
|
private boolean mInitialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a fragment class name and its screen title, build a breadcrumb from Settings root to
|
||||||
|
* this screen.
|
||||||
|
* <p/>
|
||||||
|
* Not all screens have a full breadcrumb path leading up to root, it's because either some
|
||||||
|
* page in the breadcrumb path is not indexed, or it's only reachable via search.
|
||||||
|
*/
|
||||||
|
@WorkerThread
|
||||||
|
public synchronized List<String> buildBreadCrumb(Context context, String clazz,
|
||||||
|
String screenTitle) {
|
||||||
|
init(context);
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
final List<String> breadcrumbs = new ArrayList<>();
|
||||||
|
if (!mInitialized) {
|
||||||
|
Log.w(TAG, "SiteMap is not initialized yet, skipping");
|
||||||
|
return breadcrumbs;
|
||||||
|
}
|
||||||
|
breadcrumbs.add(screenTitle);
|
||||||
|
String currentClass = clazz;
|
||||||
|
String currentTitle = screenTitle;
|
||||||
|
// Look up current page's parent, if found add it to breadcrumb string list, and repeat.
|
||||||
|
while (true) {
|
||||||
|
final SiteMapPair pair = lookUpParent(currentClass, currentTitle);
|
||||||
|
if (pair == null) {
|
||||||
|
if (DEBUG_TIMING) {
|
||||||
|
Log.d(TAG, "BreadCrumb timing: " + (System.currentTimeMillis() - startTime));
|
||||||
|
}
|
||||||
|
return breadcrumbs;
|
||||||
|
}
|
||||||
|
breadcrumbs.add(0, pair.parentTitle);
|
||||||
|
currentClass = pair.parentClass;
|
||||||
|
currentTitle = pair.parentTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a list of {@link SiteMapPair}s. Each pair knows about a single parent-child
|
||||||
|
* page relationship.
|
||||||
|
*
|
||||||
|
* We get the knowledge of such mPairs from 2 sources:
|
||||||
|
* 1. Static indexing time: we know which page(s) a parent can open by parsing its pref xml.
|
||||||
|
* 2. IA: We know from {@link DashboardFeatureProvider} which page can be dynamically
|
||||||
|
* injected to where.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
@WorkerThread
|
||||||
|
synchronized void init(Context context) {
|
||||||
|
if (mInitialized) {
|
||||||
|
// Make sure only init once.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
// First load site map from static index table.
|
||||||
|
final Context appContext = context.getApplicationContext();
|
||||||
|
final SQLiteDatabase db = IndexDatabaseHelper.getInstance(appContext).getReadableDatabase();
|
||||||
|
Cursor sitemap = db.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS, null,
|
||||||
|
null, null, null, null);
|
||||||
|
while (sitemap.moveToNext()) {
|
||||||
|
final SiteMapPair pair = new SiteMapPair(
|
||||||
|
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_CLASS)),
|
||||||
|
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_TITLE)),
|
||||||
|
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_CLASS)),
|
||||||
|
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE)));
|
||||||
|
mPairs.add(pair);
|
||||||
|
}
|
||||||
|
sitemap.close();
|
||||||
|
|
||||||
|
// Then prepare a local map that contains class name -> screen title mapping. This is needed
|
||||||
|
// to figure out the display name for any fragment if it's injected dynamically through IA.
|
||||||
|
final Map<String, String> classToTitleMap = new HashMap<>();
|
||||||
|
final Cursor titleQuery = db.query(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX,
|
||||||
|
CLASS_TO_SCREEN_TITLE_COLUMNS, null, null, null, null, null);
|
||||||
|
while (titleQuery.moveToNext()) {
|
||||||
|
classToTitleMap.put(
|
||||||
|
titleQuery.getString(titleQuery.getColumnIndex(IndexColumns.CLASS_NAME)),
|
||||||
|
titleQuery.getString(titleQuery.getColumnIndex(IndexColumns.SCREEN_TITLE)));
|
||||||
|
}
|
||||||
|
titleQuery.close();
|
||||||
|
|
||||||
|
// Loop through all IA categories and pages and build additional SiteMapPairs
|
||||||
|
List<DashboardCategory> categories = FeatureFactory.getFactory(context)
|
||||||
|
.getDashboardFeatureProvider(context).getAllCategories();
|
||||||
|
|
||||||
|
for (DashboardCategory category : categories) {
|
||||||
|
// Find the category key first.
|
||||||
|
final String parentClass = CATEGORY_KEY_TO_PARENT_MAP.get(category.key);
|
||||||
|
if (parentClass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Use the key to look up parent (which page hosts this key)
|
||||||
|
final String parentName = classToTitleMap.get(parentClass);
|
||||||
|
if (parentName == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Build parent-child mPairs for all children listed under this key.
|
||||||
|
for (Tile tile : category.tiles) {
|
||||||
|
final String childTitle = tile.title.toString();
|
||||||
|
String childClass = null;
|
||||||
|
if (tile.metaData != null) {
|
||||||
|
childClass = tile.metaData.getString(
|
||||||
|
SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
|
||||||
|
}
|
||||||
|
if (childClass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mPairs.add(new SiteMapPair(parentClass, parentName, childClass, childTitle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Done.
|
||||||
|
mInitialized = true;
|
||||||
|
if (DEBUG_TIMING) {
|
||||||
|
Log.d(TAG, "Init timing: " + (System.currentTimeMillis() - startTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private SiteMapPair lookUpParent(String clazz, String title) {
|
||||||
|
for (SiteMapPair pair : mPairs) {
|
||||||
|
if (TextUtils.equals(pair.childClass, clazz)
|
||||||
|
&& TextUtils.equals(title, pair.childTitle)) {
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data model for a parent-child page pair.
|
||||||
|
*/
|
||||||
|
private static class SiteMapPair {
|
||||||
|
public final String parentClass;
|
||||||
|
public final String parentTitle;
|
||||||
|
public final String childClass;
|
||||||
|
public final String childTitle;
|
||||||
|
|
||||||
|
public SiteMapPair(String parentClass, String parentTitle, String childClass,
|
||||||
|
String childTitle) {
|
||||||
|
this.parentClass = parentClass;
|
||||||
|
this.parentTitle = parentTitle;
|
||||||
|
this.childClass = childClass;
|
||||||
|
this.childTitle = childTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -28,12 +28,13 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
private static final String TAG = "IndexDatabaseHelper";
|
private static final String TAG = "IndexDatabaseHelper";
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "search_index.db";
|
private static final String DATABASE_NAME = "search_index.db";
|
||||||
private static final int DATABASE_VERSION = 116;
|
private static final int DATABASE_VERSION = 117;
|
||||||
|
|
||||||
private static final String INDEX = "index";
|
private static final String INDEX = "index";
|
||||||
|
|
||||||
public interface Tables {
|
public interface Tables {
|
||||||
String TABLE_PREFS_INDEX = "prefs_index";
|
String TABLE_PREFS_INDEX = "prefs_index";
|
||||||
|
String TABLE_SITE_MAP = "site_map";
|
||||||
String TABLE_META_INDEX = "meta_index";
|
String TABLE_META_INDEX = "meta_index";
|
||||||
String TABLE_SAVED_QUERIES = "saved_queries";
|
String TABLE_SAVED_QUERIES = "saved_queries";
|
||||||
}
|
}
|
||||||
@@ -72,6 +73,14 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
String TIME_STAMP = "timestamp";
|
String TIME_STAMP = "timestamp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface SiteMapColumns {
|
||||||
|
String DOCID = "docid";
|
||||||
|
String PARENT_CLASS = "parent_class";
|
||||||
|
String CHILD_CLASS = "child_class";
|
||||||
|
String PARENT_TITLE = "parent_title";
|
||||||
|
String CHILD_TITLE = "child_title";
|
||||||
|
}
|
||||||
|
|
||||||
private static final String CREATE_INDEX_TABLE =
|
private static final String CREATE_INDEX_TABLE =
|
||||||
"CREATE VIRTUAL TABLE " + Tables.TABLE_PREFS_INDEX + " USING fts4" +
|
"CREATE VIRTUAL TABLE " + Tables.TABLE_PREFS_INDEX + " USING fts4" +
|
||||||
"(" +
|
"(" +
|
||||||
@@ -132,6 +141,17 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
SavedQueriesColumns.TIME_STAMP + " INTEGER" +
|
SavedQueriesColumns.TIME_STAMP + " INTEGER" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
|
private static final String CREATE_SITE_MAP_TABLE =
|
||||||
|
"CREATE VIRTUAL TABLE " + Tables.TABLE_SITE_MAP + " USING fts4" +
|
||||||
|
"(" +
|
||||||
|
SiteMapColumns.PARENT_CLASS +
|
||||||
|
", " +
|
||||||
|
SiteMapColumns.CHILD_CLASS +
|
||||||
|
", " +
|
||||||
|
SiteMapColumns.PARENT_TITLE +
|
||||||
|
", " +
|
||||||
|
SiteMapColumns.CHILD_TITLE +
|
||||||
|
")";
|
||||||
private static final String INSERT_BUILD_VERSION =
|
private static final String INSERT_BUILD_VERSION =
|
||||||
"INSERT INTO " + Tables.TABLE_META_INDEX +
|
"INSERT INTO " + Tables.TABLE_META_INDEX +
|
||||||
" VALUES ('" + Build.VERSION.INCREMENTAL + "');";
|
" VALUES ('" + Build.VERSION.INCREMENTAL + "');";
|
||||||
@@ -164,6 +184,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(CREATE_INDEX_TABLE);
|
db.execSQL(CREATE_INDEX_TABLE);
|
||||||
db.execSQL(CREATE_META_TABLE);
|
db.execSQL(CREATE_META_TABLE);
|
||||||
db.execSQL(CREATE_SAVED_QUERIES_TABLE);
|
db.execSQL(CREATE_SAVED_QUERIES_TABLE);
|
||||||
|
db.execSQL(CREATE_SITE_MAP_TABLE);
|
||||||
db.execSQL(INSERT_BUILD_VERSION);
|
db.execSQL(INSERT_BUILD_VERSION);
|
||||||
Log.i(TAG, "Bootstrapped database");
|
Log.i(TAG, "Bootstrapped database");
|
||||||
}
|
}
|
||||||
@@ -241,5 +262,6 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_META_INDEX);
|
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_META_INDEX);
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_PREFS_INDEX);
|
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_PREFS_INDEX);
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SAVED_QUERIES);
|
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SAVED_QUERIES);
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SITE_MAP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,8 +28,10 @@ import android.os.BadParcelableException;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -39,18 +41,20 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ID;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SCREEN_TITLE;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_TITLE;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SUMMARY_ON;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_CLASS_NAME;
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_CLASS_NAME;
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ICON;
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ICON;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ID;
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION;
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION;
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
|
import static com.android.settings.search2.DatabaseResultLoader
|
||||||
|
.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader
|
||||||
|
.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_KEY;
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_KEY;
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD_TYPE;
|
|
||||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD;
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD_TYPE;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SCREEN_TITLE;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SUMMARY_ON;
|
||||||
|
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_TITLE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller to Build search results from {@link Cursor} Objects.
|
* Controller to Build search results from {@link Cursor} Objects.
|
||||||
@@ -78,7 +82,8 @@ class CursorToSearchResultConverter {
|
|||||||
mQueryText = queryText;
|
mQueryText = queryText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SearchResult> convertCursor(Cursor cursorResults, int baseRank) {
|
public List<SearchResult> convertCursor(SiteMapManager sitemapManager,
|
||||||
|
Cursor cursorResults, int baseRank) {
|
||||||
if (cursorResults == null) {
|
if (cursorResults == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -86,8 +91,8 @@ class CursorToSearchResultConverter {
|
|||||||
final List<SearchResult> results = new ArrayList<>();
|
final List<SearchResult> results = new ArrayList<>();
|
||||||
|
|
||||||
while (cursorResults.moveToNext()) {
|
while (cursorResults.moveToNext()) {
|
||||||
SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults,
|
SearchResult result = buildSingleSearchResultFromCursor(sitemapManager,
|
||||||
baseRank);
|
contextMap, cursorResults, baseRank);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
results.add(result);
|
results.add(result);
|
||||||
}
|
}
|
||||||
@@ -96,8 +101,8 @@ class CursorToSearchResultConverter {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SearchResult buildSingleSearchResultFromCursor(Map<String, Context> contextMap,
|
private SearchResult buildSingleSearchResultFromCursor(SiteMapManager sitemapManager,
|
||||||
Cursor cursor, int baseRank) {
|
Map<String, Context> contextMap, Cursor cursor, int baseRank) {
|
||||||
final String docId = cursor.getString(COLUMN_INDEX_ID);
|
final String docId = cursor.getString(COLUMN_INDEX_ID);
|
||||||
/* Make sure that this result has not yet been added as a result. Checking the docID
|
/* Make sure that this result has not yet been added as a result. Checking the docID
|
||||||
covers the case of multiple queries matching the same row, but we need to also to check
|
covers the case of multiple queries matching the same row, but we need to also to check
|
||||||
@@ -128,7 +133,7 @@ class CursorToSearchResultConverter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> breadcrumbs = getBreadcrumbs(cursor);
|
final List<String> breadcrumbs = getBreadcrumbs(sitemapManager, cursor);
|
||||||
final int rank = getRank(breadcrumbs, baseRank);
|
final int rank = getRank(breadcrumbs, baseRank);
|
||||||
|
|
||||||
final SearchResult.Builder builder = new SearchResult.Builder();
|
final SearchResult.Builder builder = new SearchResult.Builder();
|
||||||
@@ -210,12 +215,11 @@ class CursorToSearchResultConverter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getBreadcrumbs(Cursor cursor) {
|
private List<String> getBreadcrumbs(SiteMapManager siteMapManager, Cursor cursor) {
|
||||||
final List<String> breadcrumbs = new ArrayList<>();
|
|
||||||
final String screenTitle = cursor.getString(COLUMN_INDEX_SCREEN_TITLE);
|
final String screenTitle = cursor.getString(COLUMN_INDEX_SCREEN_TITLE);
|
||||||
if (!TextUtils.isEmpty(screenTitle)) {
|
final String screenClass = cursor.getString(COLUMN_INDEX_CLASS_NAME);
|
||||||
breadcrumbs.add(screenTitle);
|
final List<String> breadcrumbs = siteMapManager.buildBreadCrumb(mContext, screenClass,
|
||||||
}
|
screenTitle);
|
||||||
return breadcrumbs;
|
return breadcrumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,7 +34,6 @@ import android.provider.SearchIndexableData;
|
|||||||
import android.provider.SearchIndexableResource;
|
import android.provider.SearchIndexableResource;
|
||||||
import android.provider.SearchIndexablesContract;
|
import android.provider.SearchIndexablesContract;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
@@ -582,12 +581,13 @@ public class DatabaseIndexingManager {
|
|||||||
String title;
|
String title;
|
||||||
String summary;
|
String summary;
|
||||||
String keywords;
|
String keywords;
|
||||||
|
String childFragment;
|
||||||
ResultPayload payload;
|
ResultPayload payload;
|
||||||
|
|
||||||
ArrayMap<String, PreferenceController> controllerUriMap = null;
|
Map<String, PreferenceController> controllerUriMap = null;
|
||||||
|
|
||||||
if (fragmentName != null) {
|
if (fragmentName != null) {
|
||||||
controllerUriMap = (ArrayMap) DatabaseIndexingUtils
|
controllerUriMap = DatabaseIndexingUtils
|
||||||
.getPreferenceControllerUriMap(fragmentName, context);
|
.getPreferenceControllerUriMap(fragmentName, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,8 +655,10 @@ public class DatabaseIndexingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payload = DatabaseIndexingUtils.getPayloadFromUriMap(controllerUriMap, key);
|
payload = DatabaseIndexingUtils.getPayloadFromUriMap(controllerUriMap, key);
|
||||||
|
childFragment = XmlParserUtils.getDataChildFragment(context, attrs);
|
||||||
|
|
||||||
builder.setEntries(entries)
|
builder.setEntries(entries)
|
||||||
|
.setChildClassName(childFragment)
|
||||||
.setPayload(payload);
|
.setPayload(payload);
|
||||||
|
|
||||||
// Insert rows for the child nodes of PreferenceScreen
|
// Insert rows for the child nodes of PreferenceScreen
|
||||||
@@ -811,6 +813,18 @@ public class DatabaseIndexingManager {
|
|||||||
values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, row.payload);
|
values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, row.payload);
|
||||||
|
|
||||||
database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
|
database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(row.className) && !TextUtils.isEmpty(row.childClassName)) {
|
||||||
|
ContentValues siteMapPair = new ContentValues();
|
||||||
|
final int pairDocId = Objects.hash(row.className, row.childClassName);
|
||||||
|
siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.DOCID, pairDocId);
|
||||||
|
siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_CLASS, row.className);
|
||||||
|
siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE, row.screenTitle);
|
||||||
|
siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS, row.childClassName);
|
||||||
|
siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE, row.updatedTitle);
|
||||||
|
|
||||||
|
database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null, siteMapPair);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -950,6 +964,7 @@ public class DatabaseIndexingManager {
|
|||||||
public final String normalizedSummaryOff;
|
public final String normalizedSummaryOff;
|
||||||
public final String entries;
|
public final String entries;
|
||||||
public final String className;
|
public final String className;
|
||||||
|
public final String childClassName;
|
||||||
public final String screenTitle;
|
public final String screenTitle;
|
||||||
public final int iconResId;
|
public final int iconResId;
|
||||||
public final int rank;
|
public final int rank;
|
||||||
@@ -973,6 +988,7 @@ public class DatabaseIndexingManager {
|
|||||||
normalizedSummaryOff = builder.mNormalizedSummaryOff;
|
normalizedSummaryOff = builder.mNormalizedSummaryOff;
|
||||||
entries = builder.mEntries;
|
entries = builder.mEntries;
|
||||||
className = builder.mClassName;
|
className = builder.mClassName;
|
||||||
|
childClassName = builder.mChildClassName;
|
||||||
screenTitle = builder.mScreenTitle;
|
screenTitle = builder.mScreenTitle;
|
||||||
iconResId = builder.mIconResId;
|
iconResId = builder.mIconResId;
|
||||||
rank = builder.mRank;
|
rank = builder.mRank;
|
||||||
@@ -1008,6 +1024,7 @@ public class DatabaseIndexingManager {
|
|||||||
private String mNormalizedSummaryOff;
|
private String mNormalizedSummaryOff;
|
||||||
private String mEntries;
|
private String mEntries;
|
||||||
private String mClassName;
|
private String mClassName;
|
||||||
|
private String mChildClassName;
|
||||||
private String mScreenTitle;
|
private String mScreenTitle;
|
||||||
private int mIconResId;
|
private int mIconResId;
|
||||||
private int mRank;
|
private int mRank;
|
||||||
@@ -1067,6 +1084,11 @@ public class DatabaseIndexingManager {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setChildClassName(String childClassName) {
|
||||||
|
mChildClassName = childClassName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setScreenTitle(String screenTitle) {
|
public Builder setScreenTitle(String screenTitle) {
|
||||||
mScreenTitle = screenTitle;
|
mScreenTitle = screenTitle;
|
||||||
return this;
|
return this;
|
||||||
|
@@ -105,7 +105,7 @@ public class DatabaseIndexingUtils {
|
|||||||
* @return The Payload from the {@link PreferenceController} specified by the key, if it exists.
|
* @return The Payload from the {@link PreferenceController} specified by the key, if it exists.
|
||||||
* Otherwise null.
|
* Otherwise null.
|
||||||
*/
|
*/
|
||||||
public static ResultPayload getPayloadFromUriMap(ArrayMap<String, PreferenceController> uriMap,
|
public static ResultPayload getPayloadFromUriMap(Map<String, PreferenceController> uriMap,
|
||||||
String key) {
|
String key) {
|
||||||
if (uriMap == null) {
|
if (uriMap == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@@ -20,6 +20,8 @@ import android.content.Context;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.search.IndexDatabaseHelper;
|
import com.android.settings.search.IndexDatabaseHelper;
|
||||||
import com.android.settings.utils.AsyncLoader;
|
import com.android.settings.utils.AsyncLoader;
|
||||||
|
|
||||||
@@ -35,11 +37,6 @@ import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS
|
|||||||
*/
|
*/
|
||||||
public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
||||||
private static final String LOG = "DatabaseResultLoader";
|
private static final String LOG = "DatabaseResultLoader";
|
||||||
private final String mQueryText;
|
|
||||||
|
|
||||||
protected final SQLiteDatabase mDatabase;
|
|
||||||
|
|
||||||
private final CursorToSearchResultConverter mConverter;
|
|
||||||
|
|
||||||
/* These indices are used to match the columns of the this loader's SELECT statement.
|
/* These indices are used to match the columns of the this loader's SELECT statement.
|
||||||
These are not necessarily the same order nor similar coverage as the schema defined in
|
These are not necessarily the same order nor similar coverage as the schema defined in
|
||||||
@@ -99,8 +96,15 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
*/
|
*/
|
||||||
private static final int[] BASE_RANKS = {1, 4, 7};
|
private static final int[] BASE_RANKS = {1, 4, 7};
|
||||||
|
|
||||||
|
private final String mQueryText;
|
||||||
|
private final SQLiteDatabase mDatabase;
|
||||||
|
private final CursorToSearchResultConverter mConverter;
|
||||||
|
private final SiteMapManager mSiteMapManager;
|
||||||
|
|
||||||
public DatabaseResultLoader(Context context, String queryText) {
|
public DatabaseResultLoader(Context context, String queryText) {
|
||||||
super(context);
|
super(context);
|
||||||
|
mSiteMapManager = FeatureFactory.getFactory(context)
|
||||||
|
.getSearchFeatureProvider().getSiteMapManager();
|
||||||
mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase();
|
mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase();
|
||||||
mQueryText = cleanQuery(queryText);
|
mQueryText = cleanQuery(queryText);
|
||||||
mConverter = new CursorToSearchResultConverter(context, mQueryText);
|
mConverter = new CursorToSearchResultConverter(context, mQueryText);
|
||||||
@@ -144,7 +148,7 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
|
|
||||||
final Cursor resultCursor = mDatabase.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
|
final Cursor resultCursor = mDatabase.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
|
||||||
selection, null, null, null);
|
selection, null, null, null);
|
||||||
return mConverter.convertCursor(resultCursor, baseRank);
|
return mConverter.convertCursor(mSiteMapManager, resultCursor, baseRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -155,6 +159,7 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic method to make the query suitable for searching the database.
|
* A generic method to make the query suitable for searching the database.
|
||||||
|
*
|
||||||
* @return the cleaned query string
|
* @return the cleaned query string
|
||||||
*/
|
*/
|
||||||
private static String cleanQuery(String query) {
|
private static String cleanQuery(String query) {
|
||||||
|
@@ -29,7 +29,10 @@ import android.provider.Settings;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.applications.ManageApplications;
|
||||||
import com.android.settings.applications.PackageManagerWrapper;
|
import com.android.settings.applications.PackageManagerWrapper;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.utils.AsyncLoader;
|
import com.android.settings.utils.AsyncLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -46,7 +49,8 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
|
private static final Intent LAUNCHER_PROBE = new Intent(Intent.ACTION_MAIN)
|
||||||
.addCategory(Intent.CATEGORY_LAUNCHER);
|
.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||||
|
|
||||||
private final List<String> mBreadcrumb;
|
private List<String> mBreadcrumb;
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
private final String mQuery;
|
private final String mQuery;
|
||||||
private final UserManager mUserManager;
|
private final UserManager mUserManager;
|
||||||
private final PackageManagerWrapper mPackageManager;
|
private final PackageManagerWrapper mPackageManager;
|
||||||
@@ -55,9 +59,8 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper,
|
public InstalledAppResultLoader(Context context, PackageManagerWrapper pmWrapper,
|
||||||
String query) {
|
String query) {
|
||||||
super(context);
|
super(context);
|
||||||
mBreadcrumb = new ArrayList<>();
|
mSiteMapManager = FeatureFactory.getFactory(context)
|
||||||
mBreadcrumb.add(context.getString(R.string.app_and_notification_dashboard_title));
|
.getSearchFeatureProvider().getSiteMapManager();
|
||||||
mBreadcrumb.add(context.getString(R.string.applications_settings));
|
|
||||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||||
mPackageManager = pmWrapper;
|
mPackageManager = pmWrapper;
|
||||||
mQuery = query;
|
mQuery = query;
|
||||||
@@ -92,7 +95,7 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
builder.addIcon(info.loadIcon(pm))
|
builder.addIcon(info.loadIcon(pm))
|
||||||
.addTitle(info.loadLabel(pm))
|
.addTitle(info.loadLabel(pm))
|
||||||
.addRank(wordDiff)
|
.addRank(wordDiff)
|
||||||
.addBreadcrumbs(mBreadcrumb)
|
.addBreadcrumbs(getBreadCrumb())
|
||||||
.addPayload(new IntentPayload(intent));
|
.addPayload(new IntentPayload(intent));
|
||||||
results.add(builder.build());
|
results.add(builder.build());
|
||||||
}
|
}
|
||||||
@@ -162,4 +165,14 @@ public class InstalledAppResultLoader extends AsyncLoader<List<SearchResult>> {
|
|||||||
// to infinity.
|
// to infinity.
|
||||||
return valueText.length - queryTokens.length;
|
return valueText.length - queryTokens.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getBreadCrumb() {
|
||||||
|
if (mBreadcrumb == null || mBreadcrumb.isEmpty()) {
|
||||||
|
final Context context = getContext();
|
||||||
|
mBreadcrumb = mSiteMapManager.buildBreadCrumb(
|
||||||
|
context, ManageApplications.class.getName(),
|
||||||
|
context.getString(R.string.applications_settings));
|
||||||
|
}
|
||||||
|
return mBreadcrumb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,8 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FeatureProvider for Settings Search
|
* FeatureProvider for Settings Search
|
||||||
*/
|
*/
|
||||||
@@ -57,6 +59,11 @@ public interface SearchFeatureProvider {
|
|||||||
*/
|
*/
|
||||||
DatabaseIndexingManager getIndexingManager(Context context);
|
DatabaseIndexingManager getIndexingManager(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the manager for looking up breadcrumbs.
|
||||||
|
*/
|
||||||
|
SiteMapManager getSiteMapManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the Settings indexes
|
* Updates the Settings indexes
|
||||||
*/
|
*/
|
||||||
|
@@ -25,6 +25,7 @@ import android.view.MenuItem;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.PackageManagerWrapperImpl;
|
import com.android.settings.applications.PackageManagerWrapperImpl;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
import com.android.settings.search.Index;
|
import com.android.settings.search.Index;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,7 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
|||||||
private static final String TAG = "SearchFeatureProvider";
|
private static final String TAG = "SearchFeatureProvider";
|
||||||
|
|
||||||
private DatabaseIndexingManager mDatabaseIndexingManager;
|
private DatabaseIndexingManager mDatabaseIndexingManager;
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(Context context) {
|
public boolean isEnabled(Context context) {
|
||||||
@@ -86,6 +88,13 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
|||||||
return mDatabaseIndexingManager;
|
return mDatabaseIndexingManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SiteMapManager getSiteMapManager() {
|
||||||
|
if (mSiteMapManager == null) {
|
||||||
|
mSiteMapManager = new SiteMapManager();
|
||||||
|
}
|
||||||
|
return mSiteMapManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateIndex(Context context) {
|
public void updateIndex(Context context) {
|
||||||
long indexStartTime = System.currentTimeMillis();
|
long indexStartTime = System.currentTimeMillis();
|
||||||
|
@@ -24,9 +24,6 @@ import android.util.TypedValue;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.text.Normalizer;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to parse elements of XML preferences
|
* Utility class to parse elements of XML preferences
|
||||||
*/
|
*/
|
||||||
@@ -74,6 +71,14 @@ public class XmlParserUtils {
|
|||||||
return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_keywords);
|
return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_keywords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fragment name if this preference launches a child fragment.
|
||||||
|
*/
|
||||||
|
public static String getDataChildFragment(Context context, AttributeSet attrs) {
|
||||||
|
return getData(context, attrs, R.styleable.Preference,
|
||||||
|
R.styleable.Preference_android_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getData(Context context, AttributeSet set, int[] attrs, int resId) {
|
private static String getData(Context context, AttributeSet set, int[] attrs, int resId) {
|
||||||
final TypedArray sa = context.obtainStyledAttributes(set, attrs);
|
final TypedArray sa = context.obtainStyledAttributes(set, attrs);
|
||||||
final TypedValue tv = sa.peekValue(resId);
|
final TypedValue tv = sa.peekValue(resId);
|
||||||
|
@@ -25,6 +25,7 @@ import android.provider.SearchIndexableResource;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper.SiteMapColumns;
|
||||||
import com.android.settings.search2.DatabaseIndexingManager;
|
import com.android.settings.search2.DatabaseIndexingManager;
|
||||||
import com.android.settings.testutils.DatabaseTestUtils;
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static com.android.settings.dashboard.SiteMapManager.SITE_MAP_COLUMNS;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
@@ -263,6 +265,29 @@ public class DatabaseIndexingManagerTest {
|
|||||||
assertThat(cursor.getBlob(20)).isNull();
|
assertThat(cursor.getBlob(20)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddResourceWithChildFragment_shouldUpdateSiteMapDb() {
|
||||||
|
SearchIndexableResource resource = getFakeResource(R.xml.network_and_internet);
|
||||||
|
mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
|
||||||
|
new HashMap<>());
|
||||||
|
Cursor query = mDb.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS,
|
||||||
|
null, null, null, null, null);
|
||||||
|
query.moveToPosition(-1);
|
||||||
|
int count = 0;
|
||||||
|
while (query.moveToNext()) {
|
||||||
|
count++;
|
||||||
|
assertThat(query.getString(query.getColumnIndex(SiteMapColumns.PARENT_CLASS)))
|
||||||
|
.isEqualTo(className);
|
||||||
|
assertThat(query.getString(query.getColumnIndex(SiteMapColumns.PARENT_TITLE)))
|
||||||
|
.isEqualTo(mContext.getString(R.string.network_dashboard_title));
|
||||||
|
assertThat(query.getString(query.getColumnIndex(SiteMapColumns.CHILD_CLASS)))
|
||||||
|
.isNotEmpty();
|
||||||
|
assertThat(query.getString(query.getColumnIndex(SiteMapColumns.CHILD_TITLE)))
|
||||||
|
.isNotEmpty();
|
||||||
|
}
|
||||||
|
assertThat(count).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddResourceCustomSetting_RowsMatch() {
|
public void testAddResourceCustomSetting_RowsMatch() {
|
||||||
SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings);
|
SearchIndexableResource resource = getFakeResource(R.xml.gesture_settings);
|
||||||
@@ -393,9 +418,11 @@ public class DatabaseIndexingManagerTest {
|
|||||||
// Normalized Title
|
// Normalized Title
|
||||||
assertThat(cursor.getString(3)).isEqualTo("preferred install location");
|
assertThat(cursor.getString(3)).isEqualTo("preferred install location");
|
||||||
// Summary On
|
// Summary On
|
||||||
assertThat(cursor.getString(4)).isEqualTo("Change the preferred installation location for new apps");
|
assertThat(cursor.getString(4)).isEqualTo(
|
||||||
|
"Change the preferred installation location for new apps");
|
||||||
// Summary On Normalized
|
// Summary On Normalized
|
||||||
assertThat(cursor.getString(5)).isEqualTo("change the preferred installation location for new apps");
|
assertThat(cursor.getString(5)).isEqualTo(
|
||||||
|
"change the preferred installation location for new apps");
|
||||||
// Summary Off - only on for checkbox preferences
|
// Summary Off - only on for checkbox preferences
|
||||||
assertThat(cursor.getString(6)).isEmpty();
|
assertThat(cursor.getString(6)).isEmpty();
|
||||||
// Summary off normalized - only on for checkbox preferences
|
// Summary off normalized - only on for checkbox preferences
|
||||||
|
@@ -23,31 +23,51 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
|
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
import com.android.settings.search2.DatabaseIndexingUtils;
|
import com.android.settings.search2.DatabaseIndexingUtils;
|
||||||
import com.android.settings.search2.DatabaseResultLoader;
|
import com.android.settings.search2.DatabaseResultLoader;
|
||||||
import com.android.settings.testutils.DatabaseTestUtils;
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
public class DatabaseResultLoaderTest {
|
public class DatabaseResultLoaderTest {
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private Context mMockContext;
|
||||||
|
@Mock
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
|
private Context mContext;
|
||||||
private DatabaseResultLoader loader;
|
private DatabaseResultLoader loader;
|
||||||
|
|
||||||
SQLiteDatabase mDb;
|
SQLiteDatabase mDb;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
|
FakeFeatureFactory.setupForTest(mMockContext);
|
||||||
|
FakeFeatureFactory factory =
|
||||||
|
(FakeFeatureFactory) FakeFeatureFactory.getFactory(mMockContext);
|
||||||
|
when(factory.searchFeatureProvider.getSiteMapManager())
|
||||||
|
.thenReturn(mSiteMapManager);
|
||||||
mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||||
setUpDb();
|
setUpDb();
|
||||||
}
|
}
|
||||||
@@ -61,6 +81,7 @@ public class DatabaseResultLoaderTest {
|
|||||||
public void testMatchTitle() {
|
public void testMatchTitle() {
|
||||||
loader = new DatabaseResultLoader(mContext, "title");
|
loader = new DatabaseResultLoader(mContext, "title");
|
||||||
assertThat(loader.loadInBackground().size()).isEqualTo(3);
|
assertThat(loader.loadInBackground().size()).isEqualTo(3);
|
||||||
|
verify(mSiteMapManager, times(3)).buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -19,17 +19,13 @@ package com.android.settings.search;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
import com.android.settings.search2.DatabaseIndexingManager;
|
|
||||||
import com.android.settings.search2.SearchFeatureProviderImpl;
|
import com.android.settings.search2.SearchFeatureProviderImpl;
|
||||||
|
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
|
||||||
import com.android.settingslib.drawer.DashboardCategory;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -76,6 +72,14 @@ public class SearchFeatureProviderImplTest {
|
|||||||
verify(menu).add(anyInt(), anyInt(), anyInt(), anyString());
|
verify(menu).add(anyInt(), anyInt(), anyInt(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSiteMapManager_shouldCacheInstanec() {
|
||||||
|
final SiteMapManager manager1 = mProvider.getSiteMapManager();
|
||||||
|
final SiteMapManager manager2 = mProvider.getSiteMapManager();
|
||||||
|
|
||||||
|
assertThat(manager1).isSameAs(manager2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateIndexNewSearch_UsesDatabaseIndexingManager() {
|
public void testUpdateIndexNewSearch_UsesDatabaseIndexingManager() {
|
||||||
mProvider = spy(new SearchFeatureProviderImpl());
|
mProvider = spy(new SearchFeatureProviderImpl());
|
||||||
|
@@ -28,12 +28,16 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.SubSettings;
|
import com.android.settings.SubSettings;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
import com.android.settings.gestures.GestureSettings;
|
import com.android.settings.gestures.GestureSettings;
|
||||||
import com.android.settings.search2.ResultPayload.PayloadType;
|
import com.android.settings.search2.ResultPayload.PayloadType;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@@ -57,11 +61,14 @@ public class CursorToSearchResultConverterTest {
|
|||||||
private static final int BASE_RANK = 1;
|
private static final int BASE_RANK = 1;
|
||||||
private static final int EXAMPLES = 3;
|
private static final int EXAMPLES = 3;
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
private Drawable mDrawable;
|
private Drawable mDrawable;
|
||||||
private CursorToSearchResultConverter mConverter;
|
private CursorToSearchResultConverter mConverter;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
Context context = Robolectric.buildActivity(Activity.class).get();
|
Context context = Robolectric.buildActivity(Activity.class).get();
|
||||||
mDrawable = context.getDrawable(ICON);
|
mDrawable = context.getDrawable(ICON);
|
||||||
mConverter = new CursorToSearchResultConverter(context, QUERY);
|
mConverter = new CursorToSearchResultConverter(context, QUERY);
|
||||||
@@ -69,19 +76,21 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseNullResults_ReturnsNull() {
|
public void testParseNullResults_ReturnsNull() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(null, BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(mSiteMapManager, null, BASE_RANK);
|
||||||
assertThat(results).isNull();
|
assertThat(results).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_NotNull() {
|
public void testParseCursor_NotNull() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
assertThat(results).isNotNull();
|
assertThat(results).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesRank() {
|
public void testParseCursor_MatchesRank() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
assertThat(results.get(i).rank).isEqualTo(BASE_RANK);
|
assertThat(results.get(i).rank).isEqualTo(BASE_RANK);
|
||||||
}
|
}
|
||||||
@@ -89,7 +98,8 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesTitle() {
|
public void testParseCursor_MatchesTitle() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
assertThat(results.get(i).title).isEqualTo(TITLES[i]);
|
assertThat(results.get(i).title).isEqualTo(TITLES[i]);
|
||||||
}
|
}
|
||||||
@@ -97,7 +107,8 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesSummary() {
|
public void testParseCursor_MatchesSummary() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
assertThat(results.get(i).summary).isEqualTo(SUMMARY);
|
assertThat(results.get(i).summary).isEqualTo(SUMMARY);
|
||||||
}
|
}
|
||||||
@@ -105,7 +116,8 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesIcon() {
|
public void testParseCursor_MatchesIcon() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
Drawable resultDrawable = results.get(i).icon;
|
Drawable resultDrawable = results.get(i).icon;
|
||||||
assertThat(resultDrawable).isNotNull();
|
assertThat(resultDrawable).isNotNull();
|
||||||
@@ -116,7 +128,7 @@ public class CursorToSearchResultConverterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testParseCursor_NoIcon() {
|
public void testParseCursor_NoIcon() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
getDummyCursor(false /* hasIcon */), BASE_RANK);
|
mSiteMapManager, getDummyCursor(false /* hasIcon */), BASE_RANK);
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
Drawable resultDrawable = results.get(i).icon;
|
Drawable resultDrawable = results.get(i).icon;
|
||||||
assertThat(resultDrawable).isNull();
|
assertThat(resultDrawable).isNull();
|
||||||
@@ -125,7 +137,8 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesPayloadType() {
|
public void testParseCursor_MatchesPayloadType() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
ResultPayload payload;
|
ResultPayload payload;
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
payload = results.get(i).payload;
|
payload = results.get(i).payload;
|
||||||
@@ -152,7 +165,7 @@ public class CursorToSearchResultConverterTest {
|
|||||||
0, // Payload Type
|
0, // Payload Type
|
||||||
null // Payload
|
null // Payload
|
||||||
});
|
});
|
||||||
List<SearchResult> results = mConverter.convertCursor(cursor, BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK);
|
||||||
IntentPayload payload = (IntentPayload) results.get(0).payload;
|
IntentPayload payload = (IntentPayload) results.get(0).payload;
|
||||||
Intent intent = payload.intent;
|
Intent intent = payload.intent;
|
||||||
assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName());
|
assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName());
|
||||||
@@ -160,7 +173,8 @@ public class CursorToSearchResultConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCursor_MatchesIntentPayload() {
|
public void testParseCursor_MatchesIntentPayload() {
|
||||||
List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(
|
||||||
|
mSiteMapManager, getDummyCursor(), BASE_RANK);
|
||||||
IntentPayload payload;
|
IntentPayload payload;
|
||||||
for (int i = 0; i < EXAMPLES; i++) {
|
for (int i = 0; i < EXAMPLES; i++) {
|
||||||
payload = (IntentPayload) results.get(i).payload;
|
payload = (IntentPayload) results.get(i).payload;
|
||||||
@@ -187,7 +201,7 @@ public class CursorToSearchResultConverterTest {
|
|||||||
PayloadType.INTENT, // Payload Type
|
PayloadType.INTENT, // Payload Type
|
||||||
null // Payload
|
null // Payload
|
||||||
});
|
});
|
||||||
List<SearchResult> results = mConverter.convertCursor(cursor, BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK);
|
||||||
IntentPayload payload = (IntentPayload) results.get(0).payload;
|
IntentPayload payload = (IntentPayload) results.get(0).payload;
|
||||||
Intent intent = payload.intent;
|
Intent intent = payload.intent;
|
||||||
|
|
||||||
@@ -222,7 +236,7 @@ public class CursorToSearchResultConverterTest {
|
|||||||
type, // Payload Type
|
type, // Payload Type
|
||||||
ResultPayloadUtils.marshall(payload) // Payload
|
ResultPayloadUtils.marshall(payload) // Payload
|
||||||
});
|
});
|
||||||
List<SearchResult> results = mConverter.convertCursor(cursor, BASE_RANK);
|
List<SearchResult> results = mConverter.convertCursor(mSiteMapManager, cursor, BASE_RANK);
|
||||||
InlineSwitchPayload newPayload = (InlineSwitchPayload) results.get(0).payload;
|
InlineSwitchPayload newPayload = (InlineSwitchPayload) results.get(0).payload;
|
||||||
|
|
||||||
assertThat(newPayload.settingsUri).isEqualTo(uri);
|
assertThat(newPayload.settingsUri).isEqualTo(uri);
|
||||||
|
@@ -22,10 +22,13 @@ import android.content.pm.ResolveInfo;
|
|||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.TestConfig;
|
import com.android.settings.TestConfig;
|
||||||
import com.android.settings.applications.PackageManagerWrapper;
|
import com.android.settings.applications.PackageManagerWrapper;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
import com.android.settings.testutils.ApplicationTestUtils;
|
import com.android.settings.testutils.ApplicationTestUtils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -44,7 +47,12 @@ import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
@@ -57,16 +65,24 @@ public class InstalledAppResultLoaderTest {
|
|||||||
private PackageManagerWrapper mPackageManagerWrapper;
|
private PackageManagerWrapper mPackageManagerWrapper;
|
||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
|
@Mock
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
|
|
||||||
private InstalledAppResultLoader mLoader;
|
private InstalledAppResultLoader mLoader;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
|
FakeFeatureFactory factory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||||
|
when(factory.searchFeatureProvider.getSiteMapManager())
|
||||||
|
.thenReturn(mSiteMapManager);
|
||||||
final List<UserInfo> infos = new ArrayList<>();
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
infos.add(new UserInfo(1, "user 1", 0));
|
infos.add(new UserInfo(1, "user 1", 0));
|
||||||
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||||
|
when(mContext.getString(R.string.applications_settings))
|
||||||
|
.thenReturn("app");
|
||||||
when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
|
when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
|
||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM,
|
ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM,
|
||||||
@@ -94,9 +110,14 @@ public class InstalledAppResultLoaderTest {
|
|||||||
public void query_matchingQuery_shouldReturnNonSystemApps() {
|
public void query_matchingQuery_shouldReturnNonSystemApps() {
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query));
|
||||||
|
when(mLoader.getContext()).thenReturn(mContext);
|
||||||
|
when(mSiteMapManager.buildBreadCrumb(eq(mContext), anyString(), anyString()))
|
||||||
|
.thenReturn(Arrays.asList(new String[]{"123"}));
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(2);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(2);
|
||||||
|
verify(mSiteMapManager)
|
||||||
|
.buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -107,9 +128,12 @@ public class InstalledAppResultLoaderTest {
|
|||||||
0 /* targetSdkVersion */)));
|
0 /* targetSdkVersion */)));
|
||||||
final String query = "app";
|
final String query = "app";
|
||||||
|
|
||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query));
|
||||||
|
when(mLoader.getContext()).thenReturn(mContext);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
assertThat(mLoader.loadInBackground().size()).isEqualTo(1);
|
||||||
|
verify(mSiteMapManager)
|
||||||
|
.buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -132,7 +156,7 @@ public class InstalledAppResultLoaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void query_matchingQuery_shouldNOtReturnSystemAppIfNotLaunchable() {
|
public void query_matchingQuery_shouldNotReturnSystemAppIfNotLaunchable() {
|
||||||
when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
|
when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt()))
|
||||||
.thenReturn(Arrays.asList(
|
.thenReturn(Arrays.asList(
|
||||||
ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM,
|
ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM,
|
||||||
@@ -146,6 +170,8 @@ public class InstalledAppResultLoaderTest {
|
|||||||
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query);
|
||||||
|
|
||||||
assertThat(mLoader.loadInBackground()).isEmpty();
|
assertThat(mLoader.loadInBackground()).isEmpty();
|
||||||
|
verify(mSiteMapManager, never())
|
||||||
|
.buildBreadCrumb(eq(mContext), anyString(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.search2;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.dashboard.SiteMapManager;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper;
|
||||||
|
import com.android.settings.search.IndexDatabaseHelper.SiteMapColumns;
|
||||||
|
import com.android.settings.system.SystemDashboardFragment;
|
||||||
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settingslib.drawer.CategoryKey;
|
||||||
|
import com.android.settingslib.drawer.DashboardCategory;
|
||||||
|
import com.android.settingslib.drawer.Tile;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class SiteMapManagerTest {
|
||||||
|
|
||||||
|
private static final int STATIC_DB_DEPTH = 4;
|
||||||
|
private static final String CLASS_PREFIX = "class_";
|
||||||
|
private static final String TITLE_PREFIX = "title_";
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private Context mMockContext;
|
||||||
|
private Context mContext;
|
||||||
|
private SQLiteDatabase mDb;
|
||||||
|
private SiteMapManager mSiteMapManager;
|
||||||
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
FakeFeatureFactory.setupForTest(mMockContext);
|
||||||
|
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mMockContext);
|
||||||
|
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||||
|
buildDb();
|
||||||
|
mSiteMapManager = new SiteMapManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUp() {
|
||||||
|
DatabaseTestUtils.clearDb();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildBreadCrumb_onlyFromSiteMapDb_breadcrumbShouldLinkUp() {
|
||||||
|
List<String> breadcrumb = mSiteMapManager.buildBreadCrumb(mContext,
|
||||||
|
CLASS_PREFIX + 0, TITLE_PREFIX + 0);
|
||||||
|
assertThat(breadcrumb.size()).isEqualTo(STATIC_DB_DEPTH + 1);
|
||||||
|
for (int i = 0; i < STATIC_DB_DEPTH; i++) {
|
||||||
|
assertThat(breadcrumb.get(i)).isEqualTo(TITLE_PREFIX + (STATIC_DB_DEPTH - i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildBreadCrumb_fromSiteMapDbAndDashboardProvider_breadcrumbShouldLinkUp() {
|
||||||
|
final String iaClass = SystemDashboardFragment.class.getName();
|
||||||
|
final String iaTitle = "ia_title";
|
||||||
|
|
||||||
|
ContentValues index = new ContentValues();
|
||||||
|
index.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, iaClass);
|
||||||
|
index.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, iaTitle);
|
||||||
|
mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, index);
|
||||||
|
|
||||||
|
final DashboardCategory category = new DashboardCategory();
|
||||||
|
category.key = CategoryKey.CATEGORY_SYSTEM;
|
||||||
|
category.tiles.add(new Tile());
|
||||||
|
category.tiles.get(0).title = TITLE_PREFIX + STATIC_DB_DEPTH;
|
||||||
|
category.tiles.get(0).metaData = new Bundle();
|
||||||
|
category.tiles.get(0).metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS,
|
||||||
|
CLASS_PREFIX + STATIC_DB_DEPTH);
|
||||||
|
when(mFeatureFactory.dashboardFeatureProvider.getAllCategories())
|
||||||
|
.thenReturn(Arrays.asList(category));
|
||||||
|
|
||||||
|
final List<String> breadcrumb = mSiteMapManager.buildBreadCrumb(mContext,
|
||||||
|
CLASS_PREFIX + 0, TITLE_PREFIX + 0);
|
||||||
|
|
||||||
|
assertThat(breadcrumb.size()).isEqualTo(STATIC_DB_DEPTH + 2);
|
||||||
|
assertThat(breadcrumb.get(0))
|
||||||
|
.isEqualTo(iaTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildBreadCrumb_classNotIndexed_shouldNotHaveBreadCrumb() {
|
||||||
|
final String title = "wrong_title";
|
||||||
|
|
||||||
|
final List<String> breadcrumb = mSiteMapManager.buildBreadCrumb(mContext,
|
||||||
|
"wrong_class", title);
|
||||||
|
|
||||||
|
assertThat(breadcrumb.size()).isEqualTo(1);
|
||||||
|
assertThat(breadcrumb.get(0)).isEqualTo(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDb() {
|
||||||
|
for (int i = 0; i < STATIC_DB_DEPTH; i++) {
|
||||||
|
final ContentValues siteMapPair = new ContentValues();
|
||||||
|
siteMapPair.put(SiteMapColumns.DOCID, i);
|
||||||
|
siteMapPair.put(SiteMapColumns.PARENT_CLASS, CLASS_PREFIX + (i + 1));
|
||||||
|
siteMapPair.put(SiteMapColumns.PARENT_TITLE, TITLE_PREFIX + (i + 1));
|
||||||
|
siteMapPair.put(SiteMapColumns.CHILD_CLASS, CLASS_PREFIX + i);
|
||||||
|
siteMapPair.put(SiteMapColumns.CHILD_TITLE, TITLE_PREFIX + i);
|
||||||
|
mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null, siteMapPair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user