Merge "Add first inline switch result."
This commit is contained in:
committed by
Android (Google) Code Review
commit
9ccd30f167
@@ -20,7 +20,10 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.search2.InlineSwitchPayload;
|
||||
import com.android.settings.search2.ResultPayload;
|
||||
|
||||
public class DoubleTapPowerPreferenceController extends GesturePreferenceController {
|
||||
|
||||
@@ -61,4 +64,14 @@ public class DoubleTapPowerPreferenceController extends GesturePreferenceControl
|
||||
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0);
|
||||
return cameraDisabled == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
ArrayMap<Integer, Boolean> valueMap = new ArrayMap<>();
|
||||
valueMap.put(0, true);
|
||||
valueMap.put(1, false);
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
|
||||
ResultPayload.SettingsSource.SECURE, valueMap);
|
||||
}
|
||||
}
|
||||
|
@@ -21,8 +21,11 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.search2.InlineSwitchPayload;
|
||||
import com.android.settings.search2.ResultPayload;
|
||||
|
||||
public class DoubleTapScreenPreferenceController extends GesturePreferenceController {
|
||||
|
||||
@@ -67,4 +70,14 @@ public class DoubleTapScreenPreferenceController extends GesturePreferenceContro
|
||||
protected boolean isSwitchPrefEnabled() {
|
||||
return mAmbientConfig.pulseOnDoubleTapEnabled(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
ArrayMap<Integer, Boolean> valueMap = new ArrayMap<>();
|
||||
valueMap.put(1, true);
|
||||
valueMap.put(0, false);
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
|
||||
ResultPayload.SettingsSource.SECURE, valueMap);
|
||||
}
|
||||
}
|
||||
|
@@ -24,8 +24,11 @@ import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.search2.InlineSwitchPayload;
|
||||
import com.android.settings.search2.ResultPayload;
|
||||
|
||||
public class DoubleTwistPreferenceController extends GesturePreferenceController {
|
||||
|
||||
@@ -82,4 +85,14 @@ public class DoubleTwistPreferenceController extends GesturePreferenceController
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
ArrayMap<Integer, Boolean> valueMap = new ArrayMap<>();
|
||||
valueMap.put(1, true);
|
||||
valueMap.put(0, false);
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
|
||||
ResultPayload.SettingsSource.SECURE, valueMap);
|
||||
}
|
||||
}
|
||||
|
@@ -167,21 +167,32 @@ public class GestureSettings extends DashboardFragment {
|
||||
@Override
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
|
||||
List<PreferenceController> preferenceControllers =
|
||||
getPreferenceControllers(context);
|
||||
for(PreferenceController controller : preferenceControllers) {
|
||||
controller.updateNonIndexableKeys(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PreferenceController> getPreferenceControllers(Context context) {
|
||||
List<PreferenceController> controllers = new ArrayList<>();
|
||||
AmbientDisplayConfiguration ambientConfig
|
||||
= new AmbientDisplayConfiguration(context);
|
||||
new DoubleTapPowerPreferenceController(context, null /* lifecycle */)
|
||||
.updateNonIndexableKeys(result);
|
||||
new PickupGesturePreferenceController(
|
||||
context, null /* lifecycle */, ambientConfig, UserHandle.myUserId())
|
||||
.updateNonIndexableKeys(result);
|
||||
new DoubleTapScreenPreferenceController(
|
||||
context, null /* lifecycle */, ambientConfig, UserHandle.myUserId())
|
||||
.updateNonIndexableKeys(result);
|
||||
new SwipeToNotificationPreferenceController(context, null /* lifecycle */)
|
||||
.updateNonIndexableKeys(result);
|
||||
new DoubleTwistPreferenceController(context, null /* lifecycle */)
|
||||
.updateNonIndexableKeys(result);
|
||||
return result;
|
||||
|
||||
controllers.add(new DoubleTapPowerPreferenceController(context,
|
||||
null /* lifecycle */));
|
||||
controllers.add(new PickupGesturePreferenceController(context,
|
||||
null /* lifecycle */, ambientConfig, UserHandle.myUserId()));
|
||||
controllers.add(new DoubleTapScreenPreferenceController(context,
|
||||
null /* lifecycle */, ambientConfig, UserHandle.myUserId()));
|
||||
controllers.add(new SwipeToNotificationPreferenceController(context,
|
||||
null /* lifecycle */));
|
||||
controllers.add(new DoubleTwistPreferenceController(context,
|
||||
null /* lifecycle */));
|
||||
return controllers;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -21,8 +21,11 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.search2.InlineSwitchPayload;
|
||||
import com.android.settings.search2.ResultPayload;
|
||||
|
||||
public class PickupGesturePreferenceController extends GesturePreferenceController {
|
||||
|
||||
@@ -68,4 +71,13 @@ public class PickupGesturePreferenceController extends GesturePreferenceControll
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
ArrayMap<Integer, Boolean> valueMap = new ArrayMap<>();
|
||||
valueMap.put(1, true);
|
||||
valueMap.put(0, false);
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.DOZE_PULSE_ON_PICK_UP,
|
||||
ResultPayload.SettingsSource.SECURE, valueMap);
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,10 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import com.android.settings.core.lifecycle.Lifecycle;
|
||||
import com.android.settings.search2.InlineSwitchPayload;
|
||||
import com.android.settings.search2.ResultPayload;
|
||||
|
||||
public class SwipeToNotificationPreferenceController extends GesturePreferenceController {
|
||||
|
||||
@@ -60,4 +63,14 @@ public class SwipeToNotificationPreferenceController extends GesturePreferenceCo
|
||||
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 0)
|
||||
== 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
ArrayMap<Integer, Boolean> valueMap = new ArrayMap<>();
|
||||
valueMap.put(1, true);
|
||||
valueMap.put(0, false);
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
|
||||
ResultPayload.SettingsSource.SECURE, valueMap);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BadParcelableException;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.search.Index;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_RANK;
|
||||
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_ICON;
|
||||
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_KEY;
|
||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD_TYPE;
|
||||
import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_PAYLOAD;
|
||||
|
||||
/**
|
||||
* Controller to Build search results from {@link Cursor} Objects.
|
||||
*
|
||||
* Each converted {@link Cursor} has the following fields:
|
||||
* - String Title
|
||||
* - String Summary
|
||||
* - int rank
|
||||
* - {@link Drawable} icon
|
||||
* - {@link ResultPayload} payload
|
||||
*/
|
||||
class CursorToSearchResultConverter {
|
||||
|
||||
private final String TAG = "CursorConverter";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public CursorToSearchResultConverter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public List<SearchResult> convertCursor(Cursor cursorResults) {
|
||||
if (cursorResults == null) {
|
||||
return null;
|
||||
}
|
||||
final Map<String, Context> contextMap = new HashMap<>();
|
||||
final ArrayList<SearchResult> results = new ArrayList<>();
|
||||
|
||||
while (cursorResults.moveToNext()) {
|
||||
SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults);
|
||||
if (result != null) {
|
||||
results.add(result);
|
||||
}
|
||||
}
|
||||
Collections.sort(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
private SearchResult buildSingleSearchResultFromCursor(Map<String, Context> contextMap,
|
||||
Cursor cursor) {
|
||||
final String pkgName = cursor.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
|
||||
final String action = cursor.getString(COLUMN_INDEX_INTENT_ACTION);
|
||||
final String title = cursor.getString(COLUMN_INDEX_TITLE);
|
||||
final String summaryOn = cursor.getString(COLUMN_INDEX_SUMMARY_ON);
|
||||
final String className = cursor.getString(COLUMN_INDEX_CLASS_NAME);
|
||||
final int rank = cursor.getInt(COLUMN_INDEX_RANK);
|
||||
final String key = cursor.getString(COLUMN_INDEX_KEY);
|
||||
final String iconResStr = cursor.getString(COLUMN_INDEX_ICON);
|
||||
final int payloadType = cursor.getInt(COLUMN_INDEX_PAYLOAD_TYPE);
|
||||
final byte[] marshalledPayload = cursor.getBlob(COLUMN_INDEX_PAYLOAD);
|
||||
final ResultPayload payload;
|
||||
|
||||
if (marshalledPayload != null) {
|
||||
payload = getUnmarshalledPayload(marshalledPayload, payloadType);
|
||||
} else if (payloadType == ResultPayload.PayloadType.INTENT) {
|
||||
payload = getIntentPayload(cursor, action, key, className, pkgName);
|
||||
} else {
|
||||
Log.w(TAG, "Error creating payload - bad marshalling data or mismatched types");
|
||||
return null;
|
||||
}
|
||||
|
||||
final SearchResult.Builder builder = new SearchResult.Builder();
|
||||
builder.addTitle(title)
|
||||
.addSummary(summaryOn)
|
||||
.addRank(rank)
|
||||
.addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr))
|
||||
.addPayload(payload);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Drawable getIconForPackage(Map<String, Context> contextMap, String pkgName,
|
||||
String className, String iconResStr) {
|
||||
final int iconId = TextUtils.isEmpty(iconResStr)
|
||||
? 0 : Integer.parseInt(iconResStr);
|
||||
Drawable icon;
|
||||
Context packageContext;
|
||||
if (iconId == 0) {
|
||||
icon = null;
|
||||
} else {
|
||||
if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(pkgName)) {
|
||||
packageContext = contextMap.get(pkgName);
|
||||
if (packageContext == null) {
|
||||
try {
|
||||
packageContext = mContext.createPackageContext(pkgName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "Cannot create Context for package: " + pkgName);
|
||||
return null;
|
||||
}
|
||||
contextMap.put(pkgName, packageContext);
|
||||
}
|
||||
} else {
|
||||
packageContext = mContext;
|
||||
}
|
||||
try {
|
||||
icon = packageContext.getDrawable(iconId);
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
icon = null;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private IntentPayload getIntentPayload(Cursor cursor, String action, String key,
|
||||
String className, String pkgName ) {
|
||||
IntentPayload payload;
|
||||
if (TextUtils.isEmpty(action)) {
|
||||
final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE);
|
||||
// Action is null, we will launch it as a sub-setting
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
final Intent intent = Utils.onBuildStartFragmentIntent(mContext,
|
||||
className, args, null, 0, screenTitle, false);
|
||||
payload = new IntentPayload(intent);
|
||||
} else {
|
||||
final Intent intent = new Intent(action);
|
||||
final String targetClass = cursor.getString(
|
||||
Index.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS);
|
||||
if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(targetClass)) {
|
||||
final ComponentName component = new ComponentName(pkgName, targetClass);
|
||||
intent.setComponent(component);
|
||||
}
|
||||
intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
payload = new IntentPayload(intent);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
private ResultPayload getUnmarshalledPayload(byte[] unmarshalledPayload, int payloadType) {
|
||||
try {
|
||||
switch (payloadType) {
|
||||
case ResultPayload.PayloadType.INLINE_SWITCH:
|
||||
return ResultPayloadUtils.unmarshall(unmarshalledPayload,
|
||||
InlineSwitchPayload.CREATOR);
|
||||
}
|
||||
} catch (BadParcelableException e) {
|
||||
Log.w(TAG, "Error creating parcelable: " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -66,6 +66,10 @@ public class DatabaseIndexingUtils {
|
||||
*/
|
||||
public static Map<String, PreferenceController> getPreferenceControllerUriMap(
|
||||
String className, Context context) {
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> clazz = getIndexableClass(className);
|
||||
|
||||
if (clazz == null) {
|
||||
@@ -77,6 +81,7 @@ public class DatabaseIndexingUtils {
|
||||
// Will be non null only for a Local provider implementing a
|
||||
// SEARCH_INDEX_DATA_PROVIDER field
|
||||
final Indexable.SearchIndexProvider provider = getSearchIndexProvider(clazz);
|
||||
|
||||
List<PreferenceController> controllers =
|
||||
provider.getPreferenceControllers(context);
|
||||
|
||||
@@ -94,8 +99,9 @@ public class DatabaseIndexingUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uriMap Map between the {@link PreferenceController} keys and the controllers themselves.
|
||||
* @param key The look up key
|
||||
* @param uriMap Map between the {@link PreferenceController} keys
|
||||
* and the controllers themselves.
|
||||
* @param key The look-up key
|
||||
* @return The Payload from the {@link PreferenceController} specified by the key, if it exists.
|
||||
* Otherwise null.
|
||||
*/
|
||||
@@ -135,15 +141,13 @@ public class DatabaseIndexingUtils {
|
||||
} catch (NoSuchFieldException e) {
|
||||
Log.d(TAG, "Cannot find field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
} catch (SecurityException se) {
|
||||
Log.d(TAG,
|
||||
"Security exception for field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
Log.d(TAG, "Security exception for field '" +
|
||||
FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.d(TAG,
|
||||
"Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
Log.d(TAG, "Illegal access to field '" + FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG,
|
||||
"Illegal argument when accessing field '" +
|
||||
FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
Log.d(TAG, "Illegal argument when accessing field '" +
|
||||
FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER + "'");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -48,14 +48,36 @@ import java.util.Map;
|
||||
public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
||||
private static final String LOG = "DatabaseResultLoader";
|
||||
private final String mQueryText;
|
||||
private final Context mContext;
|
||||
|
||||
protected final SQLiteDatabase mDatabase;
|
||||
|
||||
private final CursorToSearchResultConverter mConverter;
|
||||
|
||||
/* These indices are used to match the columns of the this loader's SELECT statement.
|
||||
These are not necessarily the same order or coverage as the schema defined in
|
||||
IndexDatabaseHelper */
|
||||
public static final int COLUMN_INDEX_RANK = 0;
|
||||
public static final int COLUMN_INDEX_TITLE = 1;
|
||||
public static final int COLUMN_INDEX_SUMMARY_ON = 2;
|
||||
public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
|
||||
public static final int COLUMN_INDEX_ENTRIES = 4;
|
||||
public static final int COLUMN_INDEX_KEYWORDS = 5;
|
||||
public static final int COLUMN_INDEX_CLASS_NAME = 6;
|
||||
public static final int COLUMN_INDEX_SCREEN_TITLE = 7;
|
||||
public static final int COLUMN_INDEX_ICON = 8;
|
||||
public static final int COLUMN_INDEX_INTENT_ACTION = 9;
|
||||
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 10;
|
||||
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 11;
|
||||
public static final int COLUMN_INDEX_ENABLED = 12;
|
||||
public static final int COLUMN_INDEX_KEY = 13;
|
||||
public static final int COLUMN_INDEX_PAYLOAD_TYPE = 14;
|
||||
public static final int COLUMN_INDEX_PAYLOAD = 15;
|
||||
|
||||
public DatabaseResultLoader(Context context, String queryText) {
|
||||
super(context);
|
||||
mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase();
|
||||
mQueryText = queryText;
|
||||
mContext = context;
|
||||
mConverter = new CursorToSearchResultConverter(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,7 +94,7 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
||||
String query = getSQLQuery();
|
||||
Cursor result = mDatabase.rawQuery(query, null);
|
||||
|
||||
return parseCursorForSearch(result);
|
||||
return mConverter.convertCursor(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,100 +108,12 @@ public class DatabaseResultLoader extends AsyncLoader<List<SearchResult>> {
|
||||
"data_summary_off, data_entries, data_keywords, class_name, screen_title,"
|
||||
+ " icon, " +
|
||||
"intent_action, intent_target_package, intent_target_class, enabled, " +
|
||||
"data_key_reference FROM prefs_index WHERE prefs_index MATCH "
|
||||
"data_key_reference, payload_type, payload FROM prefs_index WHERE prefs_index MATCH "
|
||||
+ "'data_title:%s* " +
|
||||
"OR data_title_normalized:%s* OR data_keywords:%s*' AND locale = 'en_US'",
|
||||
mQueryText, mQueryText, mQueryText);
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
public ArrayList<SearchResult> parseCursorForSearch(Cursor cursorResults) {
|
||||
if (cursorResults == null) {
|
||||
return null;
|
||||
}
|
||||
final Map<String, Context> contextMap = new HashMap<>();
|
||||
final ArrayList<SearchResult> results = new ArrayList<>();
|
||||
|
||||
while (cursorResults.moveToNext()) {
|
||||
SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults);
|
||||
if (result != null) {
|
||||
results.add(result);
|
||||
}
|
||||
}
|
||||
Collections.sort(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
private SearchResult buildSingleSearchResultFromCursor(Map<String, Context> contextMap,
|
||||
Cursor cursor) {
|
||||
final String pkgName = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
|
||||
final String action = cursor.getString(Index.COLUMN_INDEX_INTENT_ACTION);
|
||||
final String title = cursor.getString(Index.COLUMN_INDEX_TITLE);
|
||||
final String summaryOn = cursor.getString(Index.COLUMN_INDEX_SUMMARY_ON);
|
||||
final String className = cursor.getString(Index.COLUMN_INDEX_CLASS_NAME);
|
||||
final int rank = cursor.getInt(Index.COLUMN_INDEX_RANK);
|
||||
final String key = cursor.getString(Index.COLUMN_INDEX_KEY);
|
||||
final String iconResStr = cursor.getString(Index.COLUMN_INDEX_ICON);
|
||||
|
||||
final ResultPayload payload;
|
||||
if (TextUtils.isEmpty(action)) {
|
||||
final String screenTitle = cursor.getString(Index.COLUMN_INDEX_SCREEN_TITLE);
|
||||
// Action is null, we will launch it as a sub-setting
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
final Intent intent = Utils.onBuildStartFragmentIntent(mContext,
|
||||
className, args, null, 0, screenTitle, false);
|
||||
payload = new IntentPayload(intent);
|
||||
} else {
|
||||
final Intent intent = new Intent(action);
|
||||
final String targetClass = cursor.getString(
|
||||
Index.COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS);
|
||||
if (!TextUtils.isEmpty(pkgName) && !TextUtils.isEmpty(targetClass)) {
|
||||
final ComponentName component = new ComponentName(pkgName, targetClass);
|
||||
intent.setComponent(component);
|
||||
}
|
||||
intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
payload = new IntentPayload(intent);
|
||||
}
|
||||
SearchResult.Builder builder = new SearchResult.Builder();
|
||||
builder.addTitle(title)
|
||||
.addSummary(summaryOn)
|
||||
.addRank(rank)
|
||||
.addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr))
|
||||
.addPayload(payload);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Drawable getIconForPackage(Map<String, Context> contextMap, String pkgName,
|
||||
String className, String iconResStr) {
|
||||
final int iconId = TextUtils.isEmpty(iconResStr)
|
||||
? 0 : Integer.parseInt(iconResStr);
|
||||
Drawable icon;
|
||||
Context packageContext;
|
||||
if (iconId == 0) {
|
||||
icon = null;
|
||||
} else {
|
||||
if (TextUtils.isEmpty(className) && !TextUtils.isEmpty(pkgName)) {
|
||||
packageContext = contextMap.get(pkgName);
|
||||
if (packageContext == null) {
|
||||
try {
|
||||
packageContext = mContext.createPackageContext(pkgName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(LOG, "Cannot create Context for package: " + pkgName);
|
||||
return null;
|
||||
}
|
||||
contextMap.put(pkgName, packageContext);
|
||||
}
|
||||
} else {
|
||||
packageContext = mContext;
|
||||
}
|
||||
try {
|
||||
icon = packageContext.getDrawable(iconId);
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
icon = null;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
}
|
||||
|
43
src/com/android/settings/search2/InlinePayload.java
Normal file
43
src/com/android/settings/search2/InlinePayload.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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;
|
||||
|
||||
/**
|
||||
* Abstract Payload for inline settings results.
|
||||
*/
|
||||
public abstract class InlinePayload extends ResultPayload {
|
||||
/**
|
||||
* Defines the URI to access and store the Setting the inline result represents
|
||||
*/
|
||||
public String settingsUri;
|
||||
|
||||
/**
|
||||
* The UI type for the inline result.
|
||||
*/
|
||||
@PayloadType public int inlineType;
|
||||
|
||||
/**
|
||||
* Defines where the Setting is stored.
|
||||
*/
|
||||
@SettingsSource public int settingSource;
|
||||
|
||||
public InlinePayload(String uri, @PayloadType int type, @SettingsSource int source) {
|
||||
settingsUri = uri;
|
||||
inlineType = type;
|
||||
settingSource = source;
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.net.Uri;
|
||||
import android.os.Parcel;
|
||||
|
||||
/**
|
||||
* Payload for Inline Settings results represented by a Slider.
|
||||
*/
|
||||
public class InlineSliderPayload extends ResultPayload {
|
||||
public final Uri uri;
|
||||
|
||||
private InlineSliderPayload(Parcel in) {
|
||||
uri = in.readParcelable(InlineSliderPayload.class.getClassLoader());
|
||||
}
|
||||
|
||||
public InlineSliderPayload(Uri newUri) {
|
||||
uri = newUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return PayloadType.INLINE_SLIDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(uri, flags);
|
||||
}
|
||||
|
||||
public static final Creator<InlineSliderPayload> CREATOR = new Creator<InlineSliderPayload>() {
|
||||
@Override
|
||||
public InlineSliderPayload createFromParcel(Parcel in) {
|
||||
return new InlineSliderPayload(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSliderPayload[] newArray(int size) {
|
||||
return new InlineSliderPayload[size];
|
||||
}
|
||||
};
|
||||
}
|
138
src/com/android/settings/search2/InlineSwitchPayload.java
Normal file
138
src/com/android/settings/search2/InlineSwitchPayload.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Payload for inline Switch results. Mappings from integer to boolean.
|
||||
*/
|
||||
public class InlineSwitchPayload extends InlinePayload {
|
||||
/**
|
||||
* Maps Inline values to UI-consumable Values.
|
||||
* For example, if you have a switch preference whose values are stored as ints, the two valid
|
||||
* list of mappings would be:
|
||||
* < (0,True), (1, false) >
|
||||
* < (1,True), (0, false) >
|
||||
*/
|
||||
public final Map<Integer, Boolean> valueMap;
|
||||
|
||||
public InlineSwitchPayload(String newUri, @SettingsSource int settingsSource,
|
||||
ArrayMap<Integer, Boolean> map) {
|
||||
super(newUri, PayloadType.INLINE_SWITCH, settingsSource);
|
||||
valueMap = map;
|
||||
}
|
||||
|
||||
private InlineSwitchPayload(Parcel in) {
|
||||
super(in.readString() /* Uri */ , in.readInt() /* Payload Type */,
|
||||
in.readInt() /* Settings Source */);
|
||||
valueMap = in.readHashMap(Integer.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return inlineType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(settingsUri);
|
||||
dest.writeInt(inlineType);
|
||||
dest.writeInt(settingSource);
|
||||
dest.writeMap(valueMap);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<InlineSwitchPayload> CREATOR =
|
||||
new Parcelable.Creator<InlineSwitchPayload>() {
|
||||
@Override
|
||||
public InlineSwitchPayload createFromParcel(Parcel in) {
|
||||
return new InlineSwitchPayload(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineSwitchPayload[] newArray(int size) {
|
||||
return new InlineSwitchPayload[size];
|
||||
}
|
||||
};
|
||||
|
||||
public boolean getSwitchValue(Context context) {
|
||||
if (valueMap == null) {
|
||||
throw new IllegalStateException("Value map is null");
|
||||
}
|
||||
|
||||
int settingsValue = -1;
|
||||
switch(settingSource) {
|
||||
case SettingsSource.SECURE:
|
||||
settingsValue = Settings.Secure.getInt(context.getContentResolver(),
|
||||
settingsUri, 0);
|
||||
}
|
||||
|
||||
if (settingsValue == -1) {
|
||||
throw new IllegalStateException("Unable to find setting from uri: "
|
||||
+ settingsUri.toString());
|
||||
}
|
||||
|
||||
for (Integer key : valueMap.keySet()) {
|
||||
if ((key == settingsValue)) {
|
||||
return valueMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No results matched the key: " + settingsValue);
|
||||
}
|
||||
|
||||
public void setSwitchValue(Context context, boolean isChecked) {
|
||||
if (valueMap == null) {
|
||||
throw new IllegalStateException("Value map is null");
|
||||
}
|
||||
int switchValue = -1;
|
||||
|
||||
for (Map.Entry<Integer, Boolean> pair : valueMap.entrySet()) {
|
||||
if (pair.getValue() == isChecked) {
|
||||
switchValue = pair.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (switchValue == -1) {
|
||||
throw new IllegalStateException("Switch value is not set");
|
||||
}
|
||||
|
||||
switch(settingSource) {
|
||||
case SettingsSource.GLOBAL:
|
||||
return;
|
||||
case SettingsSource.SECURE:
|
||||
Settings.Secure.putInt(context.getContentResolver(), settingsUri, switchValue);
|
||||
case SettingsSource.SYSTEM:
|
||||
return;
|
||||
case SettingsSource.UNKNOWN:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
73
src/com/android/settings/search2/InlineSwitchViewHolder.java
Normal file
73
src/com/android/settings/search2/InlineSwitchViewHolder.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.widget.PreferenceImageView;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* ViewHolder for Settings represented as SwitchPreferences.
|
||||
*/
|
||||
public class InlineSwitchViewHolder extends SearchViewHolder {
|
||||
public final TextView titleView;
|
||||
public final TextView summaryView;
|
||||
public final PreferenceImageView iconView;
|
||||
public final Switch switchView;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private final String TAG = "SwitchViewHolder";
|
||||
|
||||
public InlineSwitchViewHolder(View view, Context context) {
|
||||
super(view);
|
||||
mContext = context;
|
||||
titleView = (TextView) view.findViewById(android.R.id.title);
|
||||
summaryView = (TextView) view.findViewById(android.R.id.summary);
|
||||
iconView = (PreferenceImageView) view.findViewById(android.R.id.icon);
|
||||
switchView = (Switch) view.findViewById(R.id.switchView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(Fragment fragment, SearchResult result) {
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
final InlineSwitchPayload payload = (InlineSwitchPayload) result.payload;
|
||||
switchView.setChecked(payload.getSwitchValue(mContext));
|
||||
|
||||
switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
payload.setSwitchValue(mContext, isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
titleView.setText(result.title);
|
||||
summaryView.setText(result.summary);
|
||||
iconView.setImageDrawable(result.icon);
|
||||
}
|
||||
}
|
@@ -34,13 +34,13 @@ public class IntentSearchViewHolder extends SearchViewHolder {
|
||||
|
||||
public IntentSearchViewHolder(View view) {
|
||||
super(view);
|
||||
titleView = (TextView) view.findViewById(R.id.title);
|
||||
summaryView = (TextView) view.findViewById(R.id.summary);
|
||||
iconView = (ImageView) view.findViewById(R.id.icon);
|
||||
titleView = (TextView) view.findViewById(android.R.id.title);
|
||||
summaryView = (TextView) view.findViewById(android.R.id.summary);
|
||||
iconView = (ImageView) view.findViewById(android.R.id.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(Fragment fragment, SearchResult result) {
|
||||
public void onBind(final Fragment fragment, final SearchResult result) {
|
||||
titleView.setText(result.title);
|
||||
summaryView.setText(result.summary);
|
||||
iconView.setImageDrawable(result.icon);
|
||||
|
@@ -28,7 +28,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
*/
|
||||
public abstract class ResultPayload implements Parcelable {
|
||||
|
||||
@IntDef({PayloadType.INLINE_SLIDER, PayloadType.INLINE_SWITCH, PayloadType.INTENT})
|
||||
@IntDef({PayloadType.INLINE_SLIDER, PayloadType.INLINE_SWITCH,
|
||||
PayloadType.INTENT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PayloadType {
|
||||
/**
|
||||
@@ -47,5 +48,16 @@ public abstract class ResultPayload implements Parcelable {
|
||||
int INLINE_SWITCH = 2;
|
||||
}
|
||||
|
||||
@IntDef({SettingsSource.UNKNOWN, SettingsSource.SYSTEM, SettingsSource.SECURE,
|
||||
SettingsSource.GLOBAL})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SettingsSource {
|
||||
int UNKNOWN = 0;
|
||||
int SYSTEM = 1;
|
||||
int SECURE = 2;
|
||||
int GLOBAL = 3;
|
||||
}
|
||||
|
||||
|
||||
@ResultPayload.PayloadType public abstract int getType();
|
||||
}
|
||||
|
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.settings.search2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -26,7 +28,6 @@ import com.android.settings.R;
|
||||
import com.android.settings.search2.ResultPayload.PayloadType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -38,22 +39,23 @@ public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
|
||||
public SearchResultsAdapter(SearchFragment fragment) {
|
||||
mFragment = fragment;
|
||||
mSearchResults = new ArrayList<>();
|
||||
mResultsMap = new HashMap<>();
|
||||
mResultsMap = new ArrayMap<>();
|
||||
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
switch (viewType) {
|
||||
final Context context = parent.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View view;
|
||||
switch(viewType) {
|
||||
case PayloadType.INTENT:
|
||||
View view = inflater.inflate(R.layout.search_intent_item, parent, false);
|
||||
view = inflater.inflate(R.layout.search_intent_item, parent, false);
|
||||
return new IntentSearchViewHolder(view);
|
||||
case PayloadType.INLINE_SLIDER:
|
||||
return null;
|
||||
case PayloadType.INLINE_SWITCH:
|
||||
return null;
|
||||
view = inflater.inflate(R.layout.search_inline_switch_item, parent, false);
|
||||
return new InlineSwitchViewHolder(view, context);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user