Merge "Add first inline switch result."

This commit is contained in:
TreeHugger Robot
2016-12-21 22:11:59 +00:00
committed by Android (Google) Code Review
31 changed files with 1281 additions and 330 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
};
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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];
}
};
}

View 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;
}
}
}

View 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);
}
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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;
}