Remove search indexing pipeline from Settings
Index is already handled by SettingsIntelligenec. No longer needed in Settings. Change-Id: Id43fb3100dc2759185744441cff8cb9cd2d2da20 Fixes: 69808376 Test: robotests
This commit is contained in:
@@ -31,8 +31,8 @@ import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.connecteddevice.BluetoothDashboardFragment;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
@@ -106,7 +106,7 @@ public class BluetoothSliceBuilder {
|
||||
final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString();
|
||||
final Uri contentUri = new Uri.Builder().appendPath(
|
||||
SettingsSlicesContract.KEY_BLUETOOTH).build();
|
||||
return DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle,
|
||||
MetricsProto.MetricsEvent.SETTINGS_CONNECTED_DEVICE_CATEGORY)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
|
@@ -19,7 +19,6 @@ import android.content.IntentFilter;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.slices.SliceData;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -286,14 +285,4 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
|
||||
*/
|
||||
public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ResultPayload} corresponding to the search result type for the preference.
|
||||
* TODO (b/69808376) Remove this method.
|
||||
* Do not extend this method. It will not launch with P.
|
||||
*/
|
||||
@Deprecated
|
||||
public ResultPayload getResultPayload() {
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -18,7 +18,6 @@ package com.android.settings.core;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
@@ -58,15 +57,4 @@ public interface PreferenceControllerMixin {
|
||||
*/
|
||||
default void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ResultPayload} corresponding to the search result type for the preference.
|
||||
*
|
||||
* Do not rely on this method for intent-based or inline results. It will be removed in the
|
||||
* unbundling effort.
|
||||
*/
|
||||
@Deprecated
|
||||
default ResultPayload getResultPayload() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -16,18 +16,12 @@
|
||||
package com.android.settings.display;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.security.LockscreenDashboardFragment;
|
||||
|
||||
public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreferenceController {
|
||||
|
||||
@@ -99,15 +93,4 @@ public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreference
|
||||
public static boolean accessibilityInversionEnabled(AmbientDisplayConfiguration config) {
|
||||
return config.accessibilityInversionEnabled(MY_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
LockscreenDashboardFragment.class.getName(), getPreferenceKey(),
|
||||
mContext.getString(R.string.ambient_display_screen_title));
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.DOZE_ALWAYS_ON,
|
||||
ResultPayload.SettingsSource.SECURE, ON /* onValue */, intent, isAvailable(),
|
||||
ON /* defaultValue */);
|
||||
}
|
||||
}
|
||||
|
@@ -17,19 +17,13 @@ import static android.provider.Settings.Secure.DOZE_ENABLED;
|
||||
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_AMBIENT_DISPLAY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.security.LockscreenDashboardFragment;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -95,16 +89,4 @@ public class AmbientDisplayNotificationsPreferenceController extends
|
||||
public boolean isSliceable() {
|
||||
return TextUtils.equals(getPreferenceKey(), "ambient_display_notification");
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO (b/69808376): Remove result payload
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
LockscreenDashboardFragment.class.getName(), KEY_AMBIENT_DISPLAY_NOTIFICATIONS,
|
||||
mContext.getString(R.string.ambient_display_screen_title));
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.DOZE_ENABLED,
|
||||
ResultPayload.SettingsSource.SECURE, ON /* onValue */, intent, isAvailable(),
|
||||
ON /* defaultValue */);
|
||||
}
|
||||
}
|
||||
|
@@ -18,16 +18,10 @@ import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
||||
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.DisplaySettings;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
|
||||
|
||||
public class AutoBrightnessPreferenceController extends TogglePreferenceController {
|
||||
@@ -65,16 +59,4 @@ public class AutoBrightnessPreferenceController extends TogglePreferenceControll
|
||||
public boolean isSliceable() {
|
||||
return TextUtils.equals(getPreferenceKey(), "auto_brightness");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
// TODO remove result payload
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
DisplaySettings.class.getName(), getPreferenceKey(),
|
||||
mContext.getString(R.string.display_settings));
|
||||
|
||||
return new InlineSwitchPayload(SYSTEM_KEY,
|
||||
ResultPayload.SettingsSource.SYSTEM, SCREEN_BRIGHTNESS_MODE_AUTOMATIC, intent,
|
||||
isAvailable(), DEFAULT_VALUE);
|
||||
}
|
||||
}
|
@@ -20,15 +20,11 @@ import static android.provider.Settings.Secure.ASSIST_GESTURE_ENABLED;
|
||||
import static android.provider.Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
@@ -138,15 +134,4 @@ public class AssistGestureSettingsPreferenceController extends GesturePreference
|
||||
public boolean isChecked() {
|
||||
return Settings.Secure.getInt(mContext.getContentResolver(), SECURE_KEY_ASSIST, OFF) == ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO (b/69808376): Remove result payload
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
AssistGestureSettings.class.getName(), mAssistGesturePrefKey,
|
||||
mContext.getString(R.string.display_settings));
|
||||
|
||||
return new InlineSwitchPayload(SECURE_KEY_ASSIST, ResultPayload.SettingsSource.SECURE,
|
||||
ON /* onValue */, intent, isAvailable(), ON /* defaultValue */);
|
||||
}
|
||||
}
|
||||
|
@@ -19,16 +19,10 @@ package com.android.settings.gestures;
|
||||
import static android.provider.Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
public class DoubleTapPowerPreferenceController extends GesturePreferenceController {
|
||||
@@ -85,15 +79,4 @@ public class DoubleTapPowerPreferenceController extends GesturePreferenceControl
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(), SECURE_KEY,
|
||||
isChecked ? ON : OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO (b/69808376): Remove result payload
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
DoubleTapPowerSettings.class.getName(), mDoubleTapPowerKey,
|
||||
mContext.getString(R.string.display_settings));
|
||||
|
||||
return new InlineSwitchPayload(SECURE_KEY, ResultPayload.SettingsSource.SECURE,
|
||||
ON /* onValue */, intent, isAvailable(), ON /* defaultValue */);
|
||||
}
|
||||
}
|
||||
|
@@ -20,17 +20,12 @@ import static android.provider.Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
@@ -110,17 +105,6 @@ public class DoubleTapScreenPreferenceController extends GesturePreferenceContro
|
||||
return mAmbientConfig.pulseOnDoubleTapEnabled(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO (b/69808376): Remove result payload
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
DoubleTapScreenSettings.class.getName(), mDoubleTapScreenPrefKey,
|
||||
mContext.getString(R.string.display_settings));
|
||||
|
||||
return new InlineSwitchPayload(SECURE_KEY, ResultPayload.SettingsSource.SECURE,
|
||||
ON /* onValue */, intent, isAvailable(), ON /* defaultValue */);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canHandleClicks() {
|
||||
return !mAmbientConfig.alwaysOnEnabled(mUserId);
|
||||
|
@@ -20,17 +20,12 @@ import static android.provider.Settings.Secure.DOZE_PULSE_ON_PICK_UP;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
@@ -115,16 +110,6 @@ public class PickupGesturePreferenceController extends GesturePreferenceControll
|
||||
return pulseOnPickupCanBeModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
PickupGestureSettings.class.getName(), mPickUpPrefKey,
|
||||
mContext.getString(R.string.display_settings));
|
||||
|
||||
return new InlineSwitchPayload(SECURE_KEY, ResultPayload.SettingsSource.SECURE,
|
||||
ON /* onValue */, intent, isAvailable(), ON /* defaultValue */);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean pulseOnPickupCanBeModified() {
|
||||
return mAmbientConfig.pulseOnPickupCanBeModified(mUserId);
|
||||
|
@@ -24,9 +24,6 @@ import android.provider.Settings.Secure;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineListPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
@@ -111,15 +108,4 @@ public class LocationPreferenceController extends AbstractPreferenceController
|
||||
}
|
||||
return context.getString(R.string.location_off_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
LocationSettings.class.getName(), KEY_LOCATION,
|
||||
mContext.getString(R.string.location_settings_title));
|
||||
|
||||
return new InlineListPayload(Secure.LOCATION_MODE,
|
||||
ResultPayload.SettingsSource.SECURE, intent, isAvailable(),
|
||||
Secure.LOCATION_MODE_HIGH_ACCURACY + 1, Secure.LOCATION_MODE_OFF);
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
@@ -80,7 +80,7 @@ public class LocationSliceBuilder {
|
||||
public static Intent getIntent(Context context) {
|
||||
final String screenTitle = context.getText(R.string.location_settings_title).toString();
|
||||
final Uri contentUri = new Uri.Builder().appendPath(KEY_LOCATION).build();
|
||||
return DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
LocationSettings.class.getName(), KEY_LOCATION, screenTitle,
|
||||
MetricsEvent.LOCATION)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
|
@@ -20,19 +20,14 @@ import static android.provider.Settings.Secure.NOTIFICATION_BADGING;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
@@ -132,15 +127,4 @@ public class BadgingNotificationPreferenceController extends TogglePreferenceCon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload getResultPayload() {
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(mContext,
|
||||
ConfigureNotificationSettings.class.getName(), getPreferenceKey(),
|
||||
mContext.getString(R.string.configure_notification_settings));
|
||||
|
||||
return new InlineSwitchPayload(Settings.Secure.NOTIFICATION_BADGING,
|
||||
ResultPayload.SettingsSource.SECURE, ON /* onValue */, intent, isAvailable(),
|
||||
ON /* defaultValue */);
|
||||
}
|
||||
}
|
||||
|
@@ -33,9 +33,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.slices.SettingsSliceProvider;
|
||||
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
@@ -122,7 +122,7 @@ public class ZenModeSliceBuilder {
|
||||
public static Intent getIntent(Context context) {
|
||||
final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build();
|
||||
final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString();
|
||||
return DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle,
|
||||
MetricsEvent.NOTIFICATION_ZEN_MODE)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
|
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
|
||||
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_ID;
|
||||
import static com.android.settings.search.DatabaseResultLoader
|
||||
.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
|
||||
import static com.android.settings.search.DatabaseResultLoader.COLUMN_INDEX_KEY;
|
||||
import static com.android.settings.search.DatabaseResultLoader.SELECT_COLUMNS;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns
|
||||
.DATA_SUMMARY_ON_NORMALIZED;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.LOCALE;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.SCREEN_TITLE;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.USER_ID;
|
||||
import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.Build;
|
||||
import android.provider.SearchIndexablesContract;
|
||||
import android.provider.SearchIndexablesContract.SiteMapColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.search.indexing.IndexData;
|
||||
import com.android.settings.search.indexing.IndexDataConverter;
|
||||
import com.android.settings.search.indexing.PreIndexData;
|
||||
import com.android.settings.search.indexing.PreIndexDataCollector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Consumes the SearchIndexableProvider content providers.
|
||||
* Updates the Resource, Raw Data and non-indexable data for Search.
|
||||
*
|
||||
* TODO(b/33577327) this class needs to be refactored by moving most of its methods into controllers
|
||||
*/
|
||||
public class DatabaseIndexingManager {
|
||||
|
||||
private static final String LOG_TAG = "DatabaseIndexingManager";
|
||||
|
||||
private PreIndexDataCollector mCollector;
|
||||
private IndexDataConverter mConverter;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public DatabaseIndexingManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate all data and non-indexable keys from each of the content-providers.
|
||||
* Only the first indexing for the default language gets static search results - subsequent
|
||||
* calls will only gather non-indexable keys.
|
||||
*/
|
||||
public void performIndexing() {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
|
||||
final List<ResolveInfo> providers =
|
||||
mContext.getPackageManager().queryIntentContentProviders(intent, 0);
|
||||
|
||||
final String localeStr = Locale.getDefault().toString();
|
||||
final String fingerprint = Build.FINGERPRINT;
|
||||
final String providerVersionedNames =
|
||||
IndexDatabaseHelper.buildProviderVersionedNames(providers);
|
||||
|
||||
final boolean isFullIndex = isFullIndex(mContext, localeStr, fingerprint,
|
||||
providerVersionedNames);
|
||||
|
||||
if (isFullIndex) {
|
||||
rebuildDatabase();
|
||||
}
|
||||
|
||||
PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);
|
||||
|
||||
final long updateDatabaseStartTime = System.currentTimeMillis();
|
||||
updateDatabase(indexData, isFullIndex);
|
||||
if (SettingsSearchIndexablesProvider.DEBUG) {
|
||||
final long updateDatabaseTime = System.currentTimeMillis() - updateDatabaseStartTime;
|
||||
Log.d(LOG_TAG, "performIndexing updateDatabase took time: " + updateDatabaseTime);
|
||||
}
|
||||
|
||||
//TODO(63922686): Setting indexed should be a single method, not 3 separate setters.
|
||||
IndexDatabaseHelper.setLocaleIndexed(mContext, localeStr);
|
||||
IndexDatabaseHelper.setBuildIndexed(mContext, fingerprint);
|
||||
IndexDatabaseHelper.setProvidersIndexed(mContext, providerVersionedNames);
|
||||
|
||||
if (SettingsSearchIndexablesProvider.DEBUG) {
|
||||
final long indexingTime = System.currentTimeMillis() - startTime;
|
||||
Log.d(LOG_TAG, "performIndexing took time: " + indexingTime
|
||||
+ "ms. Full index? " + isFullIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
PreIndexData getIndexDataFromProviders(List<ResolveInfo> providers, boolean isFullIndex) {
|
||||
if (mCollector == null) {
|
||||
mCollector = new PreIndexDataCollector(mContext);
|
||||
}
|
||||
return mCollector.collectIndexableData(providers, isFullIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the indexed data is obsolete, when either:
|
||||
* - Device language has changed
|
||||
* - Device has taken an OTA.
|
||||
* In both cases, the device requires a full index.
|
||||
*
|
||||
* @param locale is the default for the device
|
||||
* @param fingerprint id for the current build.
|
||||
* @return true if a full index should be preformed.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
boolean isFullIndex(Context context, String locale, String fingerprint,
|
||||
String providerVersionedNames) {
|
||||
final boolean isLocaleIndexed = IndexDatabaseHelper.isLocaleAlreadyIndexed(context, locale);
|
||||
final boolean isBuildIndexed = IndexDatabaseHelper.isBuildIndexed(context, fingerprint);
|
||||
final boolean areProvidersIndexed = IndexDatabaseHelper
|
||||
.areProvidersIndexed(context, providerVersionedNames);
|
||||
|
||||
return !(isLocaleIndexed && isBuildIndexed && areProvidersIndexed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the currently stored database, and clear the flags which mark the database as indexed.
|
||||
*/
|
||||
private void rebuildDatabase() {
|
||||
// Drop the database when the locale or build has changed. This eliminates rows which are
|
||||
// dynamically inserted in the old language, or deprecated settings.
|
||||
final SQLiteDatabase db = getWritableDatabase();
|
||||
IndexDatabaseHelper.getInstance(mContext).reconstruct(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new data to the database and verifies the correctness of the ENABLED column.
|
||||
* First, the data to be updated and all non-indexable keys are copied locally.
|
||||
* Then all new data to be added is inserted.
|
||||
* Then search results are verified to have the correct value of enabled.
|
||||
* Finally, we record that the locale has been indexed.
|
||||
*
|
||||
* @param needsReindexing true the database needs to be rebuilt.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void updateDatabase(PreIndexData preIndexData, boolean needsReindexing) {
|
||||
final Map<String, Set<String>> nonIndexableKeys = preIndexData.nonIndexableKeys;
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
if (database == null) {
|
||||
Log.w(LOG_TAG, "Cannot indexDatabase Index as I cannot get a writable database");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
database.beginTransaction();
|
||||
|
||||
// Convert all Pre-index data to Index data.
|
||||
List<IndexData> indexData = getIndexData(preIndexData);
|
||||
insertIndexData(database, indexData);
|
||||
|
||||
// Only check for non-indexable key updates after initial index.
|
||||
// Enabled state with non-indexable keys is checked when items are first inserted.
|
||||
if (!needsReindexing) {
|
||||
updateDataInDatabase(database, nonIndexableKeys);
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<IndexData> getIndexData(PreIndexData data) {
|
||||
if (mConverter == null) {
|
||||
mConverter = new IndexDataConverter(mContext);
|
||||
}
|
||||
return mConverter.convertPreIndexDataToIndexData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts all of the entries in {@param indexData} into the {@param database}
|
||||
* as Search Data and as part of the Information Hierarchy.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void insertIndexData(SQLiteDatabase database, List<IndexData> indexData) {
|
||||
ContentValues values;
|
||||
|
||||
for (IndexData dataRow : indexData) {
|
||||
if (TextUtils.isEmpty(dataRow.normalizedTitle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values = new ContentValues();
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DOCID, dataRow.getDocId());
|
||||
values.put(LOCALE, dataRow.locale);
|
||||
values.put(DATA_TITLE, dataRow.updatedTitle);
|
||||
values.put(DATA_TITLE_NORMALIZED, dataRow.normalizedTitle);
|
||||
values.put(DATA_SUMMARY_ON, dataRow.updatedSummaryOn);
|
||||
values.put(DATA_SUMMARY_ON_NORMALIZED, dataRow.normalizedSummaryOn);
|
||||
values.put(DATA_ENTRIES, dataRow.entries);
|
||||
values.put(DATA_KEYWORDS, dataRow.spaceDelimitedKeywords);
|
||||
values.put(CLASS_NAME, dataRow.className);
|
||||
values.put(SCREEN_TITLE, dataRow.screenTitle);
|
||||
values.put(INTENT_ACTION, dataRow.intentAction);
|
||||
values.put(INTENT_TARGET_PACKAGE, dataRow.intentTargetPackage);
|
||||
values.put(INTENT_TARGET_CLASS, dataRow.intentTargetClass);
|
||||
values.put(ICON, dataRow.iconResId);
|
||||
values.put(ENABLED, dataRow.enabled);
|
||||
values.put(DATA_KEY_REF, dataRow.key);
|
||||
values.put(USER_ID, dataRow.userId);
|
||||
values.put(PAYLOAD_TYPE, dataRow.payloadType);
|
||||
values.put(PAYLOAD, dataRow.payload);
|
||||
|
||||
database.replaceOrThrow(TABLE_PREFS_INDEX, null, values);
|
||||
|
||||
if (!TextUtils.isEmpty(dataRow.className)
|
||||
&& !TextUtils.isEmpty(dataRow.childClassName)) {
|
||||
final ContentValues siteMapPair = new ContentValues();
|
||||
siteMapPair.put(SiteMapColumns.PARENT_CLASS, dataRow.className);
|
||||
siteMapPair.put(SiteMapColumns.PARENT_TITLE, dataRow.screenTitle);
|
||||
siteMapPair.put(SiteMapColumns.CHILD_CLASS, dataRow.childClassName);
|
||||
siteMapPair.put(SiteMapColumns.CHILD_TITLE, dataRow.updatedTitle);
|
||||
|
||||
database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP,
|
||||
null /* nullColumnHack */, siteMapPair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upholds the validity of enabled data for the user.
|
||||
* All rows which are enabled but are now flagged with non-indexable keys will become disabled.
|
||||
* All rows which are disabled but no longer a non-indexable key will become enabled.
|
||||
*
|
||||
* @param database The database to validate.
|
||||
* @param nonIndexableKeys A map between package name and the set of non-indexable keys for it.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void updateDataInDatabase(SQLiteDatabase database,
|
||||
Map<String, Set<String>> nonIndexableKeys) {
|
||||
final String whereEnabled = ENABLED + " = 1";
|
||||
final String whereDisabled = ENABLED + " = 0";
|
||||
|
||||
final Cursor enabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,
|
||||
whereEnabled, null, null, null, null);
|
||||
|
||||
final ContentValues enabledToDisabledValue = new ContentValues();
|
||||
enabledToDisabledValue.put(ENABLED, 0);
|
||||
|
||||
String packageName;
|
||||
// TODO Refactor: Move these two loops into one method.
|
||||
while (enabledResults.moveToNext()) {
|
||||
// Package name is the key for remote providers.
|
||||
// If package name is null, the provider is Settings.
|
||||
packageName = enabledResults.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
|
||||
if (packageName == null) {
|
||||
packageName = mContext.getPackageName();
|
||||
}
|
||||
|
||||
final String key = enabledResults.getString(COLUMN_INDEX_KEY);
|
||||
final Set<String> packageKeys = nonIndexableKeys.get(packageName);
|
||||
|
||||
// The indexed item is set to Enabled but is now non-indexable
|
||||
if (packageKeys != null && packageKeys.contains(key)) {
|
||||
final String whereClause = DOCID + " = " + enabledResults.getInt(COLUMN_INDEX_ID);
|
||||
database.update(TABLE_PREFS_INDEX, enabledToDisabledValue, whereClause, null);
|
||||
}
|
||||
}
|
||||
enabledResults.close();
|
||||
|
||||
final Cursor disabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,
|
||||
whereDisabled, null, null, null, null);
|
||||
|
||||
final ContentValues disabledToEnabledValue = new ContentValues();
|
||||
disabledToEnabledValue.put(ENABLED, 1);
|
||||
|
||||
while (disabledResults.moveToNext()) {
|
||||
// Package name is the key for remote providers.
|
||||
// If package name is null, the provider is Settings.
|
||||
packageName = disabledResults.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
|
||||
if (packageName == null) {
|
||||
packageName = mContext.getPackageName();
|
||||
}
|
||||
|
||||
final String key = disabledResults.getString(COLUMN_INDEX_KEY);
|
||||
final Set<String> packageKeys = nonIndexableKeys.get(packageName);
|
||||
|
||||
// The indexed item is set to Disabled but is no longer non-indexable.
|
||||
// We do not enable keys when packageKeys is null because it means the keys came
|
||||
// from an unrecognized package and therefore should not be surfaced as results.
|
||||
if (packageKeys != null && !packageKeys.contains(key)) {
|
||||
String whereClause = DOCID + " = " + disabledResults.getInt(COLUMN_INDEX_ID);
|
||||
database.update(TABLE_PREFS_INDEX, disabledToEnabledValue, whereClause, null);
|
||||
}
|
||||
}
|
||||
disabledResults.close();
|
||||
}
|
||||
|
||||
private SQLiteDatabase getWritableDatabase() {
|
||||
try {
|
||||
return IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
} catch (SQLiteException e) {
|
||||
Log.e(LOG_TAG, "Cannot open writable database", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,23 +17,9 @@
|
||||
|
||||
package com.android.settings.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class for {@like DatabaseIndexingManager} to handle the mapping between Payloads
|
||||
@@ -46,96 +32,6 @@ public class DatabaseIndexingUtils {
|
||||
public static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
|
||||
"SEARCH_INDEX_DATA_PROVIDER";
|
||||
|
||||
/**
|
||||
* Builds intent that launches the search destination as a sub-setting.
|
||||
*/
|
||||
public static Intent buildSearchResultPageIntent(Context context, String className, String key,
|
||||
String screenTitle) {
|
||||
return buildSearchResultPageIntent(context, className, key, screenTitle,
|
||||
MetricsProto.MetricsEvent.DASHBOARD_SEARCH_RESULTS);
|
||||
}
|
||||
|
||||
public static Intent buildSearchResultPageIntent(Context context, String className, String key,
|
||||
String screenTitle, int sourceMetricsCategory) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
final Intent searchDestination = new SubSettingLauncher(context)
|
||||
.setDestination(className)
|
||||
.setArguments(args)
|
||||
.setTitleText(screenTitle)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.toIntent();
|
||||
searchDestination.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key)
|
||||
.setAction("com.android.settings.SEARCH_RESULT_TRAMPOLINE")
|
||||
.setComponent(null);
|
||||
return searchDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param className which wil provide the map between from {@link Uri}s to
|
||||
* {@link PreferenceControllerMixin}
|
||||
* @return A map between {@link Uri}s and {@link PreferenceControllerMixin}s to get the payload
|
||||
* types for Settings.
|
||||
*/
|
||||
public static Map<String, ResultPayload> getPayloadKeyMap(String className, Context context) {
|
||||
ArrayMap<String, ResultPayload> map = new ArrayMap<>();
|
||||
if (context == null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
final Class<?> clazz = getIndexableClass(className);
|
||||
|
||||
if (clazz == null) {
|
||||
Log.d(TAG, "SearchIndexableResource '" + className +
|
||||
"' should implement the " + Indexable.class.getName() + " interface!");
|
||||
return map;
|
||||
}
|
||||
|
||||
// Will be non null only for a Local provider implementing a
|
||||
// SEARCH_INDEX_DATA_PROVIDER field
|
||||
final Indexable.SearchIndexProvider provider = getSearchIndexProvider(clazz);
|
||||
|
||||
final List<AbstractPreferenceController> controllers =
|
||||
provider.getPreferenceControllers(context);
|
||||
|
||||
if (controllers == null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (AbstractPreferenceController controller : controllers) {
|
||||
ResultPayload payload;
|
||||
if (controller instanceof PreferenceControllerMixin) {
|
||||
payload = ((PreferenceControllerMixin) controller).getResultPayload();
|
||||
|
||||
} else if (controller instanceof BasePreferenceController) {
|
||||
payload = ((BasePreferenceController) controller).getResultPayload();
|
||||
} else {
|
||||
throw new IllegalStateException(controller.getClass().getName()
|
||||
+ " must implement " + PreferenceControllerMixin.class.getName());
|
||||
}
|
||||
if (payload != null) {
|
||||
map.put(controller.getPreferenceKey(), payload);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Class<?> getIndexableClass(String className) {
|
||||
final Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.d(TAG, "Cannot find class: " + className);
|
||||
return null;
|
||||
}
|
||||
return isIndexableClass(clazz) ? clazz : null;
|
||||
}
|
||||
|
||||
public static boolean isIndexableClass(final Class<?> clazz) {
|
||||
return (clazz != null) && Indexable.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public static Indexable.SearchIndexProvider getSearchIndexProvider(final Class<?> clazz) {
|
||||
try {
|
||||
final Field f = clazz.getField(FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
|
||||
|
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.android.settings.search.IndexDatabaseHelper.IndexColumns;
|
||||
|
||||
/**
|
||||
* AsyncTask to retrieve Settings, first party app and any intent based results.
|
||||
*/
|
||||
public class DatabaseResultLoader {
|
||||
|
||||
private static final String TAG = "DatabaseResultLoader";
|
||||
|
||||
public static final String[] SELECT_COLUMNS = {
|
||||
IndexColumns.DOCID,
|
||||
IndexColumns.DATA_TITLE,
|
||||
IndexColumns.DATA_SUMMARY_ON,
|
||||
IndexColumns.DATA_SUMMARY_OFF,
|
||||
IndexColumns.CLASS_NAME,
|
||||
IndexColumns.SCREEN_TITLE,
|
||||
IndexColumns.ICON,
|
||||
IndexColumns.INTENT_ACTION,
|
||||
IndexColumns.INTENT_TARGET_PACKAGE,
|
||||
IndexColumns.INTENT_TARGET_CLASS,
|
||||
IndexColumns.DATA_KEY_REF,
|
||||
IndexColumns.PAYLOAD_TYPE,
|
||||
IndexColumns.PAYLOAD
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* IndexDatabaseHelper
|
||||
*/
|
||||
public static final int COLUMN_INDEX_ID = 0;
|
||||
public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
|
||||
public static final int COLUMN_INDEX_KEY = 10;
|
||||
}
|
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
import android.provider.SearchIndexablesContract.SiteMapColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
public class IndexDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String TAG = "IndexDatabaseHelper";
|
||||
|
||||
private static final String DATABASE_NAME = "search_index.db";
|
||||
private static final int DATABASE_VERSION = 118;
|
||||
|
||||
private static final String SHARED_PREFS_TAG = "indexing_manager";
|
||||
|
||||
private static final String PREF_KEY_INDEXED_PROVIDERS = "indexed_providers";
|
||||
|
||||
public interface Tables {
|
||||
String TABLE_PREFS_INDEX = "prefs_index";
|
||||
String TABLE_SITE_MAP = "site_map";
|
||||
String TABLE_META_INDEX = "meta_index";
|
||||
String TABLE_SAVED_QUERIES = "saved_queries";
|
||||
}
|
||||
|
||||
public interface IndexColumns {
|
||||
String DOCID = "docid";
|
||||
String LOCALE = "locale";
|
||||
String DATA_RANK = "data_rank";
|
||||
String DATA_TITLE = "data_title";
|
||||
String DATA_TITLE_NORMALIZED = "data_title_normalized";
|
||||
String DATA_SUMMARY_ON = "data_summary_on";
|
||||
String DATA_SUMMARY_ON_NORMALIZED = "data_summary_on_normalized";
|
||||
String DATA_SUMMARY_OFF = "data_summary_off";
|
||||
String DATA_SUMMARY_OFF_NORMALIZED = "data_summary_off_normalized";
|
||||
String DATA_ENTRIES = "data_entries";
|
||||
String DATA_KEYWORDS = "data_keywords";
|
||||
String CLASS_NAME = "class_name";
|
||||
String SCREEN_TITLE = "screen_title";
|
||||
String INTENT_ACTION = "intent_action";
|
||||
String INTENT_TARGET_PACKAGE = "intent_target_package";
|
||||
String INTENT_TARGET_CLASS = "intent_target_class";
|
||||
String ICON = "icon";
|
||||
String ENABLED = "enabled";
|
||||
String DATA_KEY_REF = "data_key_reference";
|
||||
String USER_ID = "user_id";
|
||||
String PAYLOAD_TYPE = "payload_type";
|
||||
String PAYLOAD = "payload";
|
||||
}
|
||||
|
||||
public interface MetaColumns {
|
||||
String BUILD = "build";
|
||||
}
|
||||
|
||||
public interface SavedQueriesColumns {
|
||||
String QUERY = "query";
|
||||
String TIME_STAMP = "timestamp";
|
||||
}
|
||||
|
||||
private static final String CREATE_INDEX_TABLE =
|
||||
"CREATE VIRTUAL TABLE " + Tables.TABLE_PREFS_INDEX + " USING fts4" +
|
||||
"(" +
|
||||
IndexColumns.LOCALE +
|
||||
", " +
|
||||
IndexColumns.DATA_RANK +
|
||||
", " +
|
||||
IndexColumns.DATA_TITLE +
|
||||
", " +
|
||||
IndexColumns.DATA_TITLE_NORMALIZED +
|
||||
", " +
|
||||
IndexColumns.DATA_SUMMARY_ON +
|
||||
", " +
|
||||
IndexColumns.DATA_SUMMARY_ON_NORMALIZED +
|
||||
", " +
|
||||
IndexColumns.DATA_SUMMARY_OFF +
|
||||
", " +
|
||||
IndexColumns.DATA_SUMMARY_OFF_NORMALIZED +
|
||||
", " +
|
||||
IndexColumns.DATA_ENTRIES +
|
||||
", " +
|
||||
IndexColumns.DATA_KEYWORDS +
|
||||
", " +
|
||||
IndexColumns.SCREEN_TITLE +
|
||||
", " +
|
||||
IndexColumns.CLASS_NAME +
|
||||
", " +
|
||||
IndexColumns.ICON +
|
||||
", " +
|
||||
IndexColumns.INTENT_ACTION +
|
||||
", " +
|
||||
IndexColumns.INTENT_TARGET_PACKAGE +
|
||||
", " +
|
||||
IndexColumns.INTENT_TARGET_CLASS +
|
||||
", " +
|
||||
IndexColumns.ENABLED +
|
||||
", " +
|
||||
IndexColumns.DATA_KEY_REF +
|
||||
", " +
|
||||
IndexColumns.USER_ID +
|
||||
", " +
|
||||
IndexColumns.PAYLOAD_TYPE +
|
||||
", " +
|
||||
IndexColumns.PAYLOAD +
|
||||
");";
|
||||
|
||||
private static final String CREATE_META_TABLE =
|
||||
"CREATE TABLE " + Tables.TABLE_META_INDEX +
|
||||
"(" +
|
||||
MetaColumns.BUILD + " VARCHAR(32) NOT NULL" +
|
||||
")";
|
||||
|
||||
private static final String CREATE_SAVED_QUERIES_TABLE =
|
||||
"CREATE TABLE " + Tables.TABLE_SAVED_QUERIES +
|
||||
"(" +
|
||||
SavedQueriesColumns.QUERY + " VARCHAR(64) NOT NULL" +
|
||||
", " +
|
||||
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 =
|
||||
"INSERT INTO " + Tables.TABLE_META_INDEX +
|
||||
" VALUES ('" + Build.VERSION.INCREMENTAL + "');";
|
||||
|
||||
private static final String SELECT_BUILD_VERSION =
|
||||
"SELECT " + MetaColumns.BUILD + " FROM " + Tables.TABLE_META_INDEX + " LIMIT 1;";
|
||||
|
||||
private static IndexDatabaseHelper sSingleton;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public static synchronized IndexDatabaseHelper getInstance(Context context) {
|
||||
if (sSingleton == null) {
|
||||
sSingleton = new IndexDatabaseHelper(context);
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
public IndexDatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
mContext = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
bootstrapDB(db);
|
||||
}
|
||||
|
||||
private void bootstrapDB(SQLiteDatabase db) {
|
||||
db.execSQL(CREATE_INDEX_TABLE);
|
||||
db.execSQL(CREATE_META_TABLE);
|
||||
db.execSQL(CREATE_SAVED_QUERIES_TABLE);
|
||||
db.execSQL(CREATE_SITE_MAP_TABLE);
|
||||
db.execSQL(INSERT_BUILD_VERSION);
|
||||
Log.i(TAG, "Bootstrapped database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(SQLiteDatabase db) {
|
||||
super.onOpen(db);
|
||||
|
||||
Log.i(TAG, "Using schema version: " + db.getVersion());
|
||||
|
||||
if (!Build.VERSION.INCREMENTAL.equals(getBuildVersion(db))) {
|
||||
Log.w(TAG, "Index needs to be rebuilt as build-version is not the same");
|
||||
// We need to drop the tables and recreate them
|
||||
reconstruct(db);
|
||||
} else {
|
||||
Log.i(TAG, "Index is fine");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion < DATABASE_VERSION) {
|
||||
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
|
||||
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
|
||||
// We need to drop the tables and recreate them
|
||||
reconstruct(db);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
|
||||
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
|
||||
// We need to drop the tables and recreate them
|
||||
reconstruct(db);
|
||||
}
|
||||
|
||||
public void reconstruct(SQLiteDatabase db) {
|
||||
mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.clear()
|
||||
.commit();
|
||||
dropTables(db);
|
||||
bootstrapDB(db);
|
||||
}
|
||||
|
||||
private String getBuildVersion(SQLiteDatabase db) {
|
||||
String version = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.rawQuery(SELECT_BUILD_VERSION, null);
|
||||
if (cursor.moveToFirst()) {
|
||||
version = cursor.getString(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Cannot get build version from Index metadata");
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String buildProviderVersionedNames(List<ResolveInfo> providers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (ResolveInfo info : providers) {
|
||||
sb.append(info.providerInfo.packageName)
|
||||
.append(':')
|
||||
.append(info.providerInfo.applicationInfo.longVersionCode)
|
||||
.append(',');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static void setLocaleIndexed(Context context, String locale) {
|
||||
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putBoolean(locale, true)
|
||||
.apply();
|
||||
}
|
||||
|
||||
static void setProvidersIndexed(Context context, String providerVersionedNames) {
|
||||
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putString(PREF_KEY_INDEXED_PROVIDERS, providerVersionedNames)
|
||||
.apply();
|
||||
}
|
||||
|
||||
static boolean isLocaleAlreadyIndexed(Context context, String locale) {
|
||||
return context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
|
||||
.getBoolean(locale, false);
|
||||
}
|
||||
|
||||
static boolean areProvidersIndexed(Context context, String providerVersionedNames) {
|
||||
final String indexedProviders =
|
||||
context.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
|
||||
.getString(PREF_KEY_INDEXED_PROVIDERS, null);
|
||||
return TextUtils.equals(indexedProviders, providerVersionedNames);
|
||||
}
|
||||
|
||||
static boolean isBuildIndexed(Context context, String buildNo) {
|
||||
return context.getSharedPreferences(SHARED_PREFS_TAG,
|
||||
Context.MODE_PRIVATE).getBoolean(buildNo, false);
|
||||
}
|
||||
|
||||
static void setBuildIndexed(Context context, String buildNo) {
|
||||
// Use #apply() instead of #commit() since #commit() Robolectric loop indefinitely in sdk 26
|
||||
context.getSharedPreferences(SHARED_PREFS_TAG, 0).edit().putBoolean(buildNo, true).apply();
|
||||
}
|
||||
|
||||
private void dropTables(SQLiteDatabase db) {
|
||||
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_SAVED_QUERIES);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SITE_MAP);
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Payload for settings which are selected from multiple values. For example, Location can be
|
||||
* set to multiple degrees of accuracy.
|
||||
*/
|
||||
public class InlineListPayload extends InlinePayload {
|
||||
|
||||
/**
|
||||
* Number of selections in the list.
|
||||
*/
|
||||
private int mNumOptions;
|
||||
|
||||
public InlineListPayload(String key, @PayloadType int payloadType, Intent intent,
|
||||
boolean isDeviceSupported, int numOptions, int defaultValue) {
|
||||
super(key, payloadType, intent, isDeviceSupported, defaultValue);
|
||||
mNumOptions = numOptions;
|
||||
}
|
||||
|
||||
private InlineListPayload(Parcel in) {
|
||||
super(in);
|
||||
mNumOptions = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(mNumOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int standardizeInput(int input) throws IllegalArgumentException {
|
||||
if (input < 0 || input >= mNumOptions) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid argument for ListSelect. Expected between 0 and "
|
||||
+ mNumOptions + " but found: " + input);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PayloadType public int getType() {
|
||||
return PayloadType.INLINE_LIST;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<InlineListPayload> CREATOR =
|
||||
new Parcelable.Creator<InlineListPayload>() {
|
||||
@Override
|
||||
public InlineListPayload createFromParcel(Parcel in) {
|
||||
return new InlineListPayload(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InlineListPayload[] newArray(int size) {
|
||||
return new InlineListPayload[size];
|
||||
}
|
||||
};
|
||||
}
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.provider.Settings;
|
||||
|
||||
/**
|
||||
* Abstract Payload for inline settings results.
|
||||
*/
|
||||
public abstract class InlinePayload extends ResultPayload {
|
||||
|
||||
public static final int FALSE = 0;
|
||||
public static final int TRUE = 1;
|
||||
|
||||
/**
|
||||
* Defines the key to access and store the Setting the inline result represents.
|
||||
*/
|
||||
private final String mSettingKey;
|
||||
|
||||
/**
|
||||
* Defines where the Setting is stored.
|
||||
*/
|
||||
@SettingsSource final int mSettingSource;
|
||||
|
||||
/**
|
||||
* True when the setting is available for the device.
|
||||
*/
|
||||
final boolean mIsDeviceSupported;
|
||||
|
||||
/**
|
||||
* The default value for the setting.
|
||||
*/
|
||||
final int mDefaultvalue;
|
||||
|
||||
/**
|
||||
* @param key uniquely identifies the stored setting.
|
||||
* @param source of the setting. Used to determine where to get and set the setting.
|
||||
* @param intent to the setting page.
|
||||
* @param isDeviceSupported is true when the setting is valid for the given device.
|
||||
*/
|
||||
public InlinePayload(String key, @SettingsSource int source, Intent intent,
|
||||
boolean isDeviceSupported, int defaultValue) {
|
||||
super(intent);
|
||||
mSettingKey = key;
|
||||
mSettingSource = source;
|
||||
mIsDeviceSupported = isDeviceSupported;
|
||||
mDefaultvalue = defaultValue;
|
||||
}
|
||||
|
||||
InlinePayload(Parcel parcel) {
|
||||
super(parcel.readParcelable(Intent.class.getClassLoader()));
|
||||
mSettingKey = parcel.readString();
|
||||
mSettingSource = parcel.readInt();
|
||||
mIsDeviceSupported = parcel.readInt() == TRUE;
|
||||
mDefaultvalue = parcel.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(mSettingKey);
|
||||
dest.writeInt(mSettingSource);
|
||||
dest.writeInt(mIsDeviceSupported ? TRUE : FALSE);
|
||||
dest.writeInt(mDefaultvalue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PayloadType public abstract int getType();
|
||||
|
||||
/**
|
||||
* @returns the status of the underlying setting. See {@link ResultPayload.Availability} for
|
||||
* possible values.
|
||||
*/
|
||||
@Availability public int getAvailability() {
|
||||
if (mIsDeviceSupported) {
|
||||
return Availability.AVAILABLE;
|
||||
}
|
||||
return Availability.DISABLED_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the input is valid for the given setting.
|
||||
*
|
||||
* @param input The number to be get or set for the setting.
|
||||
* @return {@param input} mapped to the public-facing API for settings.
|
||||
* @throws IllegalArgumentException when the input is not valid for the given inline type.
|
||||
*/
|
||||
protected abstract int standardizeInput(int input) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* @returns the current value of the setting.
|
||||
*/
|
||||
public int getValue(Context context) {
|
||||
int settingsValue = -1;
|
||||
switch(mSettingSource) {
|
||||
case SettingsSource.SECURE:
|
||||
settingsValue = Settings.Secure.getInt(context.getContentResolver(),
|
||||
mSettingKey, mDefaultvalue);
|
||||
break;
|
||||
case SettingsSource.SYSTEM:
|
||||
settingsValue = Settings.System.getInt(context.getContentResolver(),
|
||||
mSettingKey, mDefaultvalue);
|
||||
break;
|
||||
|
||||
case SettingsSource.GLOBAL:
|
||||
settingsValue = Settings.Global.getInt(context.getContentResolver(),
|
||||
mSettingKey, mDefaultvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
return standardizeInput(settingsValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set the setting value.
|
||||
*
|
||||
* @param newValue is the requested value for the setting.
|
||||
* @returns true when the setting was changed, and false otherwise.
|
||||
*/
|
||||
public boolean setValue(Context context, int newValue) {
|
||||
newValue = standardizeInput(newValue);
|
||||
|
||||
switch(mSettingSource) {
|
||||
case SettingsSource.GLOBAL:
|
||||
return Settings.Global.putInt(context.getContentResolver(), mSettingKey, newValue);
|
||||
case SettingsSource.SECURE:
|
||||
return Settings.Secure.putInt(context.getContentResolver(), mSettingKey, newValue);
|
||||
case SettingsSource.SYSTEM:
|
||||
return Settings.System.putInt(context.getContentResolver(), mSettingKey, newValue);
|
||||
case SettingsSource.UNKNOWN:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return mSettingKey;
|
||||
}
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Payload for inline Switch results. Mappings from integer to boolean.
|
||||
*/
|
||||
public class InlineSwitchPayload extends InlinePayload {
|
||||
|
||||
private static final int ON = 1;
|
||||
private static final int OFF = 0;
|
||||
|
||||
/**
|
||||
* Provides a mapping for how switches are stored.
|
||||
* If mIsStandard is true, then (0 == false) and (1 == true)
|
||||
* If mIsStandard is false, then (1 == false) and (0 == true)
|
||||
*/
|
||||
private boolean mIsStandard;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key uniquely identifies the stored setting.
|
||||
* @param source of the setting. Used to determine where to get and set the setting.
|
||||
* @param onValue is the value stored as on for the switch. Should be 0 or 1.
|
||||
* @param intent to the setting page.
|
||||
* @param isDeviceSupported is true when the setting is valid for the given device.
|
||||
*/
|
||||
public InlineSwitchPayload(String key, @SettingsSource int source,
|
||||
int onValue, Intent intent, boolean isDeviceSupported, int defaultValue) {
|
||||
super(key, source, intent, isDeviceSupported, defaultValue);
|
||||
// If on is stored as TRUE then the switch is standard.
|
||||
mIsStandard = onValue == TRUE;
|
||||
}
|
||||
|
||||
private InlineSwitchPayload(Parcel in) {
|
||||
super(in);
|
||||
mIsStandard = in.readInt() == TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PayloadType public int getType() {
|
||||
return PayloadType.INLINE_SWITCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int standardizeInput(int value) {
|
||||
if (value != OFF && value != ON) {
|
||||
throw new IllegalArgumentException("Invalid input for InlineSwitch. Expected: "
|
||||
+ ON + " or " + OFF
|
||||
+ " but found: " + value);
|
||||
}
|
||||
return mIsStandard
|
||||
? value
|
||||
: 1 - value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(mIsStandard ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
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 isStandard() {
|
||||
return mIsStandard;
|
||||
}
|
||||
}
|
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* A interface for search results types. Examples include Inline results, third party apps
|
||||
* or any future possibilities.
|
||||
*/
|
||||
public class ResultPayload implements Parcelable {
|
||||
protected final Intent mIntent;
|
||||
|
||||
@IntDef({PayloadType.INTENT, PayloadType.INLINE_SLIDER, PayloadType.INLINE_SWITCH,
|
||||
PayloadType.INLINE_LIST, PayloadType.SAVED_QUERY})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PayloadType {
|
||||
/**
|
||||
* Resulting page will be started using an mIntent
|
||||
*/
|
||||
int INTENT = 0;
|
||||
|
||||
/**
|
||||
* Result is a inline widget, using a slider widget as UI.
|
||||
*/
|
||||
int INLINE_SLIDER = 1;
|
||||
|
||||
/**
|
||||
* Result is a inline widget, using a toggle widget as UI.
|
||||
*/
|
||||
int INLINE_SWITCH = 2;
|
||||
|
||||
/**
|
||||
* Result is an inline list-select, with an undefined UI.
|
||||
*/
|
||||
int INLINE_LIST = 3;
|
||||
|
||||
/**
|
||||
* Result is a recently saved query.
|
||||
*/
|
||||
int SAVED_QUERY = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates the possible values for the Availability of a setting.
|
||||
*/
|
||||
@IntDef({Availability.AVAILABLE,
|
||||
Availability.DISABLED_DEPENDENT_SETTING,
|
||||
Availability.DISABLED_DEPENDENT_APP,
|
||||
Availability.DISABLED_UNSUPPORTED,
|
||||
Availability.RESOURCE_CONTENTION,
|
||||
Availability.INTENT_ONLY,
|
||||
Availability.DISABLED_FOR_USER,})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Availability {
|
||||
/**
|
||||
* The setting is available.
|
||||
*/
|
||||
int AVAILABLE = 0;
|
||||
|
||||
/**
|
||||
* The setting has a dependency in settings app which is currently disabled, blocking
|
||||
* access.
|
||||
*/
|
||||
int DISABLED_DEPENDENT_SETTING = 1;
|
||||
|
||||
/**
|
||||
* The setting is not supported by the device.
|
||||
*/
|
||||
int DISABLED_UNSUPPORTED = 2;
|
||||
|
||||
/**
|
||||
* The setting you are trying to change is being used by another application and cannot
|
||||
* be changed until it is released by said application.
|
||||
*/
|
||||
int RESOURCE_CONTENTION = 3;
|
||||
|
||||
/**
|
||||
* The setting is disabled because corresponding app is disabled.
|
||||
*/
|
||||
int DISABLED_DEPENDENT_APP = 4;
|
||||
|
||||
/**
|
||||
* This setting is supported on the device but cannot be changed inline.
|
||||
*/
|
||||
int INTENT_ONLY = 5;
|
||||
|
||||
/**
|
||||
* The setting cannot be changed by the current user.
|
||||
* ex: MobileNetworkTakeMeThereSetting should not be available to a secondary user.
|
||||
*/
|
||||
int DISABLED_FOR_USER = 6;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
private ResultPayload(Parcel in) {
|
||||
mIntent = in.readParcelable(ResultPayload.class.getClassLoader());
|
||||
}
|
||||
|
||||
public ResultPayload(Intent intent) {
|
||||
mIntent = intent;
|
||||
}
|
||||
|
||||
@ResultPayload.PayloadType
|
||||
public int getType() {
|
||||
return PayloadType.INTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(mIntent, flags);
|
||||
}
|
||||
|
||||
public static final Creator<ResultPayload> CREATOR = new Creator<ResultPayload>() {
|
||||
@Override
|
||||
public ResultPayload createFromParcel(Parcel in) {
|
||||
return new ResultPayload(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultPayload[] newArray(int size) {
|
||||
return new ResultPayload[size];
|
||||
}
|
||||
};
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Utility class to Marshall and Unmarshall the payloads stored in the SQLite Database
|
||||
*/
|
||||
public class ResultPayloadUtils {
|
||||
|
||||
private static final String TAG = "PayloadUtil";
|
||||
|
||||
public static byte[] marshall(ResultPayload payload) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
payload.writeToParcel(parcel, 0);
|
||||
byte[] bytes = parcel.marshall();
|
||||
parcel.recycle();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static <T> T unmarshall(byte[] bytes, Parcelable.Creator<T> creator) {
|
||||
T result;
|
||||
Parcel parcel = unmarshall(bytes);
|
||||
result = creator.createFromParcel(parcel);
|
||||
parcel.recycle();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Parcel unmarshall(byte[] bytes) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parcel.unmarshall(bytes, 0, bytes.length);
|
||||
parcel.setDataPosition(0);
|
||||
return parcel;
|
||||
}
|
||||
}
|
@@ -42,13 +42,6 @@ public interface SearchFeatureProvider {
|
||||
void verifyLaunchSearchResultPageCaller(Context context, @NonNull ComponentName caller)
|
||||
throws SecurityException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Synchronously updates the Settings database.
|
||||
*/
|
||||
void updateIndex(Context context);
|
||||
|
||||
DatabaseIndexingManager getIndexingManager(Context context);
|
||||
|
||||
/**
|
||||
* @return a {@link SearchIndexableResources} to be used for indexing search results.
|
||||
*/
|
||||
|
@@ -21,14 +21,9 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.indexing.IndexData;
|
||||
import com.android.settingslib.search.SearchIndexableResources;
|
||||
import com.android.settingslib.search.SearchIndexableResourcesMobile;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* FeatureProvider for the refactored search code.
|
||||
*/
|
||||
@@ -36,8 +31,6 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
||||
|
||||
private static final String TAG = "SearchFeatureProvider";
|
||||
|
||||
private static final String METRICS_ACTION_SETTINGS_INDEX = "search_synchronous_indexing";
|
||||
private DatabaseIndexingManager mDatabaseIndexingManager;
|
||||
private SearchIndexableResources mSearchIndexableResources;
|
||||
|
||||
@Override
|
||||
@@ -58,23 +51,6 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
||||
+ "whitelisted package.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseIndexingManager getIndexingManager(Context context) {
|
||||
if (mDatabaseIndexingManager == null) {
|
||||
mDatabaseIndexingManager = new DatabaseIndexingManager(context.getApplicationContext());
|
||||
}
|
||||
return mDatabaseIndexingManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIndex(Context context) {
|
||||
long indexStartTime = System.currentTimeMillis();
|
||||
getIndexingManager(context).performIndexing();
|
||||
int indexingTime = (int) (System.currentTimeMillis() - indexStartTime);
|
||||
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
|
||||
.histogram(context, METRICS_ACTION_SETTINGS_INDEX, indexingTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchIndexableResources getSearchIndexableResources() {
|
||||
if (mSearchIndexableResources == null) {
|
||||
@@ -86,20 +62,4 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
|
||||
protected boolean isSignatureWhitelisted(Context context, String callerPackage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic method to make the query suitable for searching the database.
|
||||
*
|
||||
* @return the cleaned query string
|
||||
*/
|
||||
@VisibleForTesting
|
||||
String cleanQuery(String query) {
|
||||
if (TextUtils.isEmpty(query)) {
|
||||
return null;
|
||||
}
|
||||
if (Locale.getDefault().equals(Locale.JAPAN)) {
|
||||
query = IndexData.normalizeJapaneseString(query);
|
||||
}
|
||||
return query.trim();
|
||||
}
|
||||
}
|
||||
|
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.ResultPayloadUtils;
|
||||
|
||||
import java.text.Normalizer;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Data class representing a single row in the Setting Search results database.
|
||||
*/
|
||||
public class IndexData {
|
||||
public final String locale;
|
||||
public final String updatedTitle;
|
||||
public final String normalizedTitle;
|
||||
public final String updatedSummaryOn;
|
||||
public final String normalizedSummaryOn;
|
||||
public final String entries;
|
||||
public final String className;
|
||||
public final String childClassName;
|
||||
public final String screenTitle;
|
||||
public final int iconResId;
|
||||
public final String spaceDelimitedKeywords;
|
||||
public final String intentAction;
|
||||
public final String intentTargetPackage;
|
||||
public final String intentTargetClass;
|
||||
public final boolean enabled;
|
||||
public final String key;
|
||||
public final int userId;
|
||||
public final int payloadType;
|
||||
public final byte[] payload;
|
||||
|
||||
private static final String NON_BREAKING_HYPHEN = "\u2011";
|
||||
private static final String EMPTY = "";
|
||||
private static final String HYPHEN = "-";
|
||||
private static final String SPACE = " ";
|
||||
// Regex matching a comma, and any number of subsequent white spaces.
|
||||
private static final String LIST_DELIMITERS = "[,]\\s*";
|
||||
|
||||
private static final Pattern REMOVE_DIACRITICALS_PATTERN
|
||||
= Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
|
||||
|
||||
private IndexData(Builder builder) {
|
||||
locale = Locale.getDefault().toString();
|
||||
updatedTitle = normalizeHyphen(builder.mTitle);
|
||||
updatedSummaryOn = normalizeHyphen(builder.mSummaryOn);
|
||||
if (Locale.JAPAN.toString().equalsIgnoreCase(locale)) {
|
||||
// Special case for JP. Convert charset to the same type for indexing purpose.
|
||||
normalizedTitle = normalizeJapaneseString(builder.mTitle);
|
||||
normalizedSummaryOn = normalizeJapaneseString(builder.mSummaryOn);
|
||||
} else {
|
||||
normalizedTitle = normalizeString(builder.mTitle);
|
||||
normalizedSummaryOn = normalizeString(builder.mSummaryOn);
|
||||
}
|
||||
entries = builder.mEntries;
|
||||
className = builder.mClassName;
|
||||
childClassName = builder.mChildClassName;
|
||||
screenTitle = builder.mScreenTitle;
|
||||
iconResId = builder.mIconResId;
|
||||
spaceDelimitedKeywords = normalizeKeywords(builder.mKeywords);
|
||||
intentAction = builder.mIntentAction;
|
||||
intentTargetPackage = builder.mIntentTargetPackage;
|
||||
intentTargetClass = builder.mIntentTargetClass;
|
||||
enabled = builder.mEnabled;
|
||||
key = builder.mKey;
|
||||
userId = builder.mUserId;
|
||||
payloadType = builder.mPayloadType;
|
||||
payload = builder.mPayload != null ? ResultPayloadUtils.marshall(builder.mPayload)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the doc id for this row.
|
||||
*/
|
||||
public int getDocId() {
|
||||
// Eventually we want all DocIds to be the data_reference key. For settings values,
|
||||
// this will be preference keys, and for non-settings they should be unique.
|
||||
return TextUtils.isEmpty(key)
|
||||
? Objects.hash(updatedTitle, className, screenTitle, intentTargetClass)
|
||||
: key.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(updatedTitle)
|
||||
.append(": ")
|
||||
.append(updatedSummaryOn)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* In the list of keywords, replace the comma and all subsequent whitespace with a single space.
|
||||
*/
|
||||
public static String normalizeKeywords(String input) {
|
||||
return (input != null) ? input.replaceAll(LIST_DELIMITERS, SPACE) : EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@param input} where all non-standard hyphens are replaced by normal hyphens.
|
||||
*/
|
||||
public static String normalizeHyphen(String input) {
|
||||
return (input != null) ? input.replaceAll(NON_BREAKING_HYPHEN, HYPHEN) : EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@param input} with all hyphens removed, and all letters lower case.
|
||||
*/
|
||||
public static String normalizeString(String input) {
|
||||
final String normalizedHypen = normalizeHyphen(input);
|
||||
final String nohyphen = (input != null) ? normalizedHypen.replaceAll(HYPHEN, EMPTY) : EMPTY;
|
||||
final String normalized = Normalizer.normalize(nohyphen, Normalizer.Form.NFD);
|
||||
|
||||
return REMOVE_DIACRITICALS_PATTERN.matcher(normalized).replaceAll("").toLowerCase();
|
||||
}
|
||||
|
||||
public static String normalizeJapaneseString(String input) {
|
||||
final String nohyphen = (input != null) ? input.replaceAll(HYPHEN, EMPTY) : EMPTY;
|
||||
final String normalized = Normalizer.normalize(nohyphen, Normalizer.Form.NFKD);
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
final int length = normalized.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = normalized.charAt(i);
|
||||
// Convert Hiragana to full-width Katakana
|
||||
if (c >= '\u3041' && c <= '\u3096') {
|
||||
sb.append((char) (c - '\u3041' + '\u30A1'));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return REMOVE_DIACRITICALS_PATTERN.matcher(sb.toString()).replaceAll("").toLowerCase();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String mTitle;
|
||||
private String mSummaryOn;
|
||||
private String mEntries;
|
||||
private String mClassName;
|
||||
private String mChildClassName;
|
||||
private String mScreenTitle;
|
||||
private int mIconResId;
|
||||
private String mKeywords;
|
||||
private String mIntentAction;
|
||||
private String mIntentTargetPackage;
|
||||
private String mIntentTargetClass;
|
||||
private boolean mEnabled;
|
||||
private String mKey;
|
||||
private int mUserId;
|
||||
@ResultPayload.PayloadType
|
||||
private int mPayloadType;
|
||||
private ResultPayload mPayload;
|
||||
|
||||
public Builder setTitle(String title) {
|
||||
mTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSummaryOn(String summaryOn) {
|
||||
mSummaryOn = summaryOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEntries(String entries) {
|
||||
mEntries = entries;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setClassName(String className) {
|
||||
mClassName = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setChildClassName(String childClassName) {
|
||||
mChildClassName = childClassName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setScreenTitle(String screenTitle) {
|
||||
mScreenTitle = screenTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIconResId(int iconResId) {
|
||||
mIconResId = iconResId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setKeywords(String keywords) {
|
||||
mKeywords = keywords;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIntentAction(String intentAction) {
|
||||
mIntentAction = intentAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIntentTargetPackage(String intentTargetPackage) {
|
||||
mIntentTargetPackage = intentTargetPackage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIntentTargetClass(String intentTargetClass) {
|
||||
mIntentTargetClass = intentTargetClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setKey(String key) {
|
||||
mKey = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUserId(int userId) {
|
||||
mUserId = userId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPayload(ResultPayload payload) {
|
||||
mPayload = payload;
|
||||
|
||||
if (mPayload != null) {
|
||||
setPayloadType(mPayload.getType());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payload type is added when a Payload is added to the Builder in {setPayload}
|
||||
*
|
||||
* @param payloadType PayloadType
|
||||
* @return The Builder
|
||||
*/
|
||||
private Builder setPayloadType(@ResultPayload.PayloadType int payloadType) {
|
||||
mPayloadType = payloadType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds intent to inline payloads, or creates an Intent Payload as a fallback if the
|
||||
* payload is null.
|
||||
*/
|
||||
private void setIntent(Context context) {
|
||||
if (mPayload != null) {
|
||||
return;
|
||||
}
|
||||
final Intent intent = buildIntent(context);
|
||||
mPayload = new ResultPayload(intent);
|
||||
mPayloadType = ResultPayload.PayloadType.INTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Intent payload to builder.
|
||||
*/
|
||||
private Intent buildIntent(Context context) {
|
||||
final Intent intent;
|
||||
|
||||
boolean isEmptyIntentAction = TextUtils.isEmpty(mIntentAction);
|
||||
// No intent action is set, or the intent action is for a subsetting.
|
||||
if (isEmptyIntentAction) {
|
||||
// Action is null, we will launch it as a sub-setting
|
||||
intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, mClassName,
|
||||
mKey, mScreenTitle);
|
||||
} else {
|
||||
intent = new Intent(mIntentAction);
|
||||
final String targetClass = mIntentTargetClass;
|
||||
if (!TextUtils.isEmpty(mIntentTargetPackage)
|
||||
&& !TextUtils.isEmpty(targetClass)) {
|
||||
final ComponentName component = new ComponentName(mIntentTargetPackage,
|
||||
targetClass);
|
||||
intent.setComponent(component);
|
||||
}
|
||||
intent.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, mKey);
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
public IndexData build(Context context) {
|
||||
setIntent(context);
|
||||
return new IndexData(this);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.provider.SearchIndexableData;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.settings.core.PreferenceXmlParserUtils;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
/**
|
||||
* Helper class to convert {@link PreIndexData} to {@link IndexData}.
|
||||
*/
|
||||
public class IndexDataConverter {
|
||||
|
||||
private static final String LOG_TAG = "IndexDataConverter";
|
||||
|
||||
private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
|
||||
private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
|
||||
private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public IndexDataConverter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the collection of {@param preIndexData} converted into {@link IndexData}.
|
||||
*
|
||||
* @param preIndexData a collection of {@link SearchIndexableResource},
|
||||
* {@link SearchIndexableRaw} and non-indexable keys.
|
||||
*/
|
||||
public List<IndexData> convertPreIndexDataToIndexData(PreIndexData preIndexData) {
|
||||
final long current = System.currentTimeMillis();
|
||||
final List<SearchIndexableData> indexableData = preIndexData.dataToUpdate;
|
||||
final Map<String, Set<String>> nonIndexableKeys = preIndexData.nonIndexableKeys;
|
||||
final List<IndexData> indexData = new ArrayList<>();
|
||||
|
||||
for (SearchIndexableData data : indexableData) {
|
||||
if (data instanceof SearchIndexableRaw) {
|
||||
final SearchIndexableRaw rawData = (SearchIndexableRaw) data;
|
||||
final Set<String> rawNonIndexableKeys = nonIndexableKeys.get(
|
||||
rawData.intentTargetPackage);
|
||||
final IndexData.Builder builder = convertRaw(rawData, rawNonIndexableKeys);
|
||||
|
||||
if (builder != null) {
|
||||
indexData.add(builder.build(mContext));
|
||||
}
|
||||
} else if (data instanceof SearchIndexableResource) {
|
||||
final SearchIndexableResource sir = (SearchIndexableResource) data;
|
||||
final Set<String> resourceNonIndexableKeys =
|
||||
getNonIndexableKeysForResource(nonIndexableKeys, sir.packageName);
|
||||
final List<IndexData> resourceData = convertResource(sir, resourceNonIndexableKeys);
|
||||
indexData.addAll(resourceData);
|
||||
}
|
||||
}
|
||||
|
||||
final long endConversion = System.currentTimeMillis();
|
||||
Log.d(LOG_TAG, "Converting pre-index data to index data took: "
|
||||
+ (endConversion - current));
|
||||
|
||||
return indexData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the conversion of {@link SearchIndexableRaw} to {@link IndexData}.
|
||||
* The fields of {@link SearchIndexableRaw} are a subset of {@link IndexData},
|
||||
* and there is some data sanitization in the conversion.
|
||||
*/
|
||||
@Nullable
|
||||
private IndexData.Builder convertRaw(SearchIndexableRaw raw, Set<String> nonIndexableKeys) {
|
||||
// A row is enabled if it does not show up as an nonIndexableKey
|
||||
boolean enabled = !(nonIndexableKeys != null && nonIndexableKeys.contains(raw.key));
|
||||
|
||||
IndexData.Builder builder = new IndexData.Builder();
|
||||
builder.setTitle(raw.title)
|
||||
.setSummaryOn(raw.summaryOn)
|
||||
.setEntries(raw.entries)
|
||||
.setKeywords(raw.keywords)
|
||||
.setClassName(raw.className)
|
||||
.setScreenTitle(raw.screenTitle)
|
||||
.setIconResId(raw.iconResId)
|
||||
.setIntentAction(raw.intentAction)
|
||||
.setIntentTargetPackage(raw.intentTargetPackage)
|
||||
.setIntentTargetClass(raw.intentTargetClass)
|
||||
.setEnabled(enabled)
|
||||
.setKey(raw.key)
|
||||
.setUserId(raw.userId);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the conversion of the {@link SearchIndexableResource} to {@link IndexData}.
|
||||
* Each of the elements in the xml layout attribute of {@param sir} is a candidate to be
|
||||
* converted (including the header element).
|
||||
*
|
||||
* TODO (b/33577327) simplify this method.
|
||||
*/
|
||||
private List<IndexData> convertResource(SearchIndexableResource sir,
|
||||
Set<String> nonIndexableKeys) {
|
||||
final Context context = sir.context;
|
||||
XmlResourceParser parser = null;
|
||||
|
||||
List<IndexData> resourceIndexData = new ArrayList<>();
|
||||
try {
|
||||
parser = context.getResources().getXml(sir.xmlResId);
|
||||
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& type != XmlPullParser.START_TAG) {
|
||||
// Parse next until start tag is found
|
||||
}
|
||||
|
||||
String nodeName = parser.getName();
|
||||
if (!NODE_NAME_PREFERENCE_SCREEN.equals(nodeName)) {
|
||||
throw new RuntimeException(
|
||||
"XML document must start with <PreferenceScreen> tag; found"
|
||||
+ nodeName + " at " + parser.getPositionDescription());
|
||||
}
|
||||
|
||||
final int outerDepth = parser.getDepth();
|
||||
final AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
final String screenTitle = PreferenceXmlParserUtils.getDataTitle(context, attrs);
|
||||
String key = PreferenceXmlParserUtils.getDataKey(context, attrs);
|
||||
|
||||
String title;
|
||||
String headerTitle;
|
||||
String summary;
|
||||
String headerSummary;
|
||||
String keywords;
|
||||
String headerKeywords;
|
||||
String childFragment;
|
||||
@DrawableRes int iconResId;
|
||||
ResultPayload payload;
|
||||
boolean enabled;
|
||||
final String fragmentName = sir.className;
|
||||
final String intentAction = sir.intentAction;
|
||||
final String intentTargetPackage = sir.intentTargetPackage;
|
||||
final String intentTargetClass = sir.intentTargetClass;
|
||||
|
||||
Map<String, ResultPayload> controllerUriMap = new HashMap<>();
|
||||
|
||||
if (fragmentName != null) {
|
||||
controllerUriMap = DatabaseIndexingUtils
|
||||
.getPayloadKeyMap(fragmentName, context);
|
||||
}
|
||||
|
||||
headerTitle = PreferenceXmlParserUtils.getDataTitle(context, attrs);
|
||||
headerSummary = PreferenceXmlParserUtils.getDataSummary(context, attrs);
|
||||
headerKeywords = PreferenceXmlParserUtils.getDataKeywords(context, attrs);
|
||||
enabled = !nonIndexableKeys.contains(key);
|
||||
|
||||
// TODO: Set payload type for header results
|
||||
IndexData.Builder headerBuilder = new IndexData.Builder();
|
||||
headerBuilder.setTitle(headerTitle)
|
||||
.setSummaryOn(headerSummary)
|
||||
.setKeywords(headerKeywords)
|
||||
.setClassName(fragmentName)
|
||||
.setScreenTitle(screenTitle)
|
||||
.setIntentAction(intentAction)
|
||||
.setIntentTargetPackage(intentTargetPackage)
|
||||
.setIntentTargetClass(intentTargetClass)
|
||||
.setEnabled(enabled)
|
||||
.setKey(key)
|
||||
.setUserId(-1 /* default user id */);
|
||||
|
||||
// Flag for XML headers which a child element's title.
|
||||
boolean isHeaderUnique = true;
|
||||
IndexData.Builder builder;
|
||||
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nodeName = parser.getName();
|
||||
|
||||
title = PreferenceXmlParserUtils.getDataTitle(context, attrs);
|
||||
key = PreferenceXmlParserUtils.getDataKey(context, attrs);
|
||||
enabled = !nonIndexableKeys.contains(key);
|
||||
keywords = PreferenceXmlParserUtils.getDataKeywords(context, attrs);
|
||||
iconResId = PreferenceXmlParserUtils.getDataIcon(context, attrs);
|
||||
|
||||
if (isHeaderUnique && TextUtils.equals(headerTitle, title)) {
|
||||
isHeaderUnique = false;
|
||||
}
|
||||
|
||||
builder = new IndexData.Builder();
|
||||
builder.setTitle(title)
|
||||
.setKeywords(keywords)
|
||||
.setClassName(fragmentName)
|
||||
.setScreenTitle(screenTitle)
|
||||
.setIconResId(iconResId)
|
||||
.setIntentAction(intentAction)
|
||||
.setIntentTargetPackage(intentTargetPackage)
|
||||
.setIntentTargetClass(intentTargetClass)
|
||||
.setEnabled(enabled)
|
||||
.setKey(key)
|
||||
.setUserId(-1 /* default user id */);
|
||||
|
||||
if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
|
||||
summary = PreferenceXmlParserUtils.getDataSummary(context, attrs);
|
||||
|
||||
String entries = null;
|
||||
|
||||
if (nodeName.endsWith(NODE_NAME_LIST_PREFERENCE)) {
|
||||
entries = PreferenceXmlParserUtils.getDataEntries(context, attrs);
|
||||
}
|
||||
|
||||
// TODO (b/62254931) index primitives instead of payload
|
||||
payload = controllerUriMap.get(key);
|
||||
childFragment = PreferenceXmlParserUtils.getDataChildFragment(context, attrs);
|
||||
|
||||
builder.setSummaryOn(summary)
|
||||
.setEntries(entries)
|
||||
.setChildClassName(childFragment)
|
||||
.setPayload(payload);
|
||||
|
||||
resourceIndexData.add(builder.build(mContext));
|
||||
} else {
|
||||
// TODO (b/33577327) We removed summary off here. We should check if we can
|
||||
// merge this 'else' section with the one above. Put a break point to
|
||||
// investigate.
|
||||
String summaryOn = PreferenceXmlParserUtils.getDataSummaryOn(context, attrs);
|
||||
String summaryOff = PreferenceXmlParserUtils.getDataSummaryOff(context, attrs);
|
||||
|
||||
if (TextUtils.isEmpty(summaryOn) && TextUtils.isEmpty(summaryOff)) {
|
||||
summaryOn = PreferenceXmlParserUtils.getDataSummary(context, attrs);
|
||||
}
|
||||
|
||||
builder.setSummaryOn(summaryOn);
|
||||
|
||||
resourceIndexData.add(builder.build(mContext));
|
||||
}
|
||||
}
|
||||
|
||||
// The xml header's title does not match the title of one of the child settings.
|
||||
if (isHeaderUnique) {
|
||||
resourceIndexData.add(headerBuilder.build(mContext));
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Log.w(LOG_TAG, "XML Error parsing PreferenceScreen: ", e);
|
||||
} catch (IOException e) {
|
||||
Log.w(LOG_TAG, "IO Error parsing PreferenceScreen: ", e);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
Log.w(LOG_TAG, "Resoucre not found error parsing PreferenceScreen: ", e);
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
return resourceIndexData;
|
||||
}
|
||||
|
||||
private Set<String> getNonIndexableKeysForResource(Map<String, Set<String>> nonIndexableKeys,
|
||||
String packageName) {
|
||||
return nonIndexableKeys.containsKey(packageName)
|
||||
? nonIndexableKeys.get(packageName)
|
||||
: new HashSet<>();
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import android.provider.SearchIndexableData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Holds Data sources for indexable data.
|
||||
* TODO (b/33577327) add getters and setters for data.
|
||||
*/
|
||||
public class PreIndexData {
|
||||
public List<SearchIndexableData> dataToUpdate;
|
||||
public Map<String, Set<String>> nonIndexableKeys;
|
||||
|
||||
public PreIndexData() {
|
||||
dataToUpdate = new ArrayList<>();
|
||||
nonIndexableKeys = new HashMap<>();
|
||||
}
|
||||
|
||||
public PreIndexData(PreIndexData other) {
|
||||
dataToUpdate = new ArrayList<>(other.dataToUpdate);
|
||||
nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
|
||||
}
|
||||
|
||||
public PreIndexData copy() {
|
||||
return new PreIndexData(this);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
dataToUpdate.clear();
|
||||
nonIndexableKeys.clear();
|
||||
}
|
||||
}
|
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_CLASS_NAME;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ENTRIES;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_ICON_RESID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_ACTION;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_CLASS;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEY;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_KEYWORDS;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_RANK;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SCREEN_TITLE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_OFF;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_SUMMARY_ON;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_TITLE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_RAW_USER_ID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
|
||||
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.SearchIndexablesContract;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.search.SettingsSearchIndexablesProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Collects all data from {@link android.provider.SearchIndexablesProvider} to be indexed.
|
||||
*/
|
||||
public class PreIndexDataCollector {
|
||||
|
||||
private static final String TAG = "IndexableDataCollector";
|
||||
|
||||
// TODO (b/64938328) update to new search package.
|
||||
private final String BASE_AUTHORITY = "com.android.settings";
|
||||
|
||||
private static final List<String> EMPTY_LIST = Collections.emptyList();
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private PreIndexData mIndexData;
|
||||
|
||||
public PreIndexDataCollector(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public PreIndexData collectIndexableData(List<ResolveInfo> providers, boolean isFullIndex) {
|
||||
mIndexData = new PreIndexData();
|
||||
|
||||
for (final ResolveInfo info : providers) {
|
||||
if (!isWellKnownProvider(info)) {
|
||||
continue;
|
||||
}
|
||||
final String authority = info.providerInfo.authority;
|
||||
final String packageName = info.providerInfo.packageName;
|
||||
|
||||
if (isFullIndex) {
|
||||
addIndexablesFromRemoteProvider(packageName, authority);
|
||||
}
|
||||
|
||||
final long nonIndexableStartTime = System.currentTimeMillis();
|
||||
addNonIndexablesKeysFromRemoteProvider(packageName, authority);
|
||||
if (SettingsSearchIndexablesProvider.DEBUG) {
|
||||
final long nonIndexableTime = System.currentTimeMillis() - nonIndexableStartTime;
|
||||
Log.d(TAG, "performIndexing update non-indexable for package " + packageName
|
||||
+ " took time: " + nonIndexableTime);
|
||||
}
|
||||
}
|
||||
|
||||
return mIndexData;
|
||||
}
|
||||
|
||||
private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
|
||||
try {
|
||||
final Context context = BASE_AUTHORITY.equals(authority) ?
|
||||
mContext : mContext.createPackageContext(packageName, 0);
|
||||
|
||||
final Uri uriForResources = buildUriForXmlResources(authority);
|
||||
mIndexData.dataToUpdate.addAll(getIndexablesForXmlResourceUri(context, packageName,
|
||||
uriForResources, SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS));
|
||||
|
||||
final Uri uriForRawData = buildUriForRawData(authority);
|
||||
mIndexData.dataToUpdate.addAll(getIndexablesForRawDataUri(context, packageName,
|
||||
uriForRawData, SearchIndexablesContract.INDEXABLES_RAW_COLUMNS));
|
||||
return true;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Could not create context for " + packageName + ": "
|
||||
+ Log.getStackTraceString(e));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<SearchIndexableResource> getIndexablesForXmlResourceUri(Context packageContext,
|
||||
String packageName, Uri uri, String[] projection) {
|
||||
|
||||
final ContentResolver resolver = packageContext.getContentResolver();
|
||||
final Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
List<SearchIndexableResource> resources = new ArrayList<>();
|
||||
|
||||
if (cursor == null) {
|
||||
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
|
||||
return resources;
|
||||
}
|
||||
|
||||
try {
|
||||
final int count = cursor.getCount();
|
||||
if (count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
final int xmlResId = cursor.getInt(COLUMN_INDEX_XML_RES_RESID);
|
||||
|
||||
final String className = cursor.getString(COLUMN_INDEX_XML_RES_CLASS_NAME);
|
||||
final int iconResId = cursor.getInt(COLUMN_INDEX_XML_RES_ICON_RESID);
|
||||
|
||||
final String action = cursor.getString(COLUMN_INDEX_XML_RES_INTENT_ACTION);
|
||||
final String targetPackage = cursor.getString(
|
||||
COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE);
|
||||
final String targetClass = cursor.getString(
|
||||
COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS);
|
||||
|
||||
SearchIndexableResource sir = new SearchIndexableResource(packageContext);
|
||||
sir.xmlResId = xmlResId;
|
||||
sir.className = className;
|
||||
sir.packageName = packageName;
|
||||
sir.iconResId = iconResId;
|
||||
sir.intentAction = action;
|
||||
sir.intentTargetPackage = targetPackage;
|
||||
sir.intentTargetClass = targetClass;
|
||||
|
||||
resources.add(sir);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
private void addNonIndexablesKeysFromRemoteProvider(String packageName,
|
||||
String authority) {
|
||||
final List<String> keys =
|
||||
getNonIndexablesKeysFromRemoteProvider(packageName, authority);
|
||||
|
||||
if (keys != null && !keys.isEmpty()) {
|
||||
mIndexData.nonIndexableKeys.put(authority, new ArraySet<>(keys));
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<String> getNonIndexablesKeysFromRemoteProvider(String packageName,
|
||||
String authority) {
|
||||
try {
|
||||
final Context packageContext = mContext.createPackageContext(packageName, 0);
|
||||
|
||||
final Uri uriForNonIndexableKeys = buildUriForNonIndexableKeys(authority);
|
||||
return getNonIndexablesKeys(packageContext, uriForNonIndexableKeys,
|
||||
SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Could not create context for " + packageName + ": "
|
||||
+ Log.getStackTraceString(e));
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Uri buildUriForXmlResources(String authority) {
|
||||
return Uri.parse("content://" + authority + "/" +
|
||||
SearchIndexablesContract.INDEXABLES_XML_RES_PATH);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Uri buildUriForRawData(String authority) {
|
||||
return Uri.parse("content://" + authority + "/" +
|
||||
SearchIndexablesContract.INDEXABLES_RAW_PATH);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Uri buildUriForNonIndexableKeys(String authority) {
|
||||
return Uri.parse("content://" + authority + "/" +
|
||||
SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<SearchIndexableRaw> getIndexablesForRawDataUri(Context packageContext, String packageName,
|
||||
Uri uri, String[] projection) {
|
||||
final ContentResolver resolver = packageContext.getContentResolver();
|
||||
final Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
List<SearchIndexableRaw> rawData = new ArrayList<>();
|
||||
|
||||
if (cursor == null) {
|
||||
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
|
||||
return rawData;
|
||||
}
|
||||
|
||||
try {
|
||||
final int count = cursor.getCount();
|
||||
if (count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
final int providerRank = cursor.getInt(COLUMN_INDEX_RAW_RANK);
|
||||
// TODO Remove rank
|
||||
final String title = cursor.getString(COLUMN_INDEX_RAW_TITLE);
|
||||
final String summaryOn = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
|
||||
final String summaryOff = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_OFF);
|
||||
final String entries = cursor.getString(COLUMN_INDEX_RAW_ENTRIES);
|
||||
final String keywords = cursor.getString(COLUMN_INDEX_RAW_KEYWORDS);
|
||||
|
||||
final String screenTitle = cursor.getString(COLUMN_INDEX_RAW_SCREEN_TITLE);
|
||||
|
||||
final String className = cursor.getString(COLUMN_INDEX_RAW_CLASS_NAME);
|
||||
final int iconResId = cursor.getInt(COLUMN_INDEX_RAW_ICON_RESID);
|
||||
|
||||
final String action = cursor.getString(COLUMN_INDEX_RAW_INTENT_ACTION);
|
||||
final String targetPackage = cursor.getString(
|
||||
COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE);
|
||||
final String targetClass = cursor.getString(
|
||||
COLUMN_INDEX_RAW_INTENT_TARGET_CLASS);
|
||||
|
||||
final String key = cursor.getString(COLUMN_INDEX_RAW_KEY);
|
||||
final int userId = cursor.getInt(COLUMN_INDEX_RAW_USER_ID);
|
||||
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(packageContext);
|
||||
data.title = title;
|
||||
data.summaryOn = summaryOn;
|
||||
data.summaryOff = summaryOff;
|
||||
data.entries = entries;
|
||||
data.keywords = keywords;
|
||||
data.screenTitle = screenTitle;
|
||||
data.className = className;
|
||||
data.packageName = packageName;
|
||||
data.iconResId = iconResId;
|
||||
data.intentAction = action;
|
||||
data.intentTargetPackage = targetPackage;
|
||||
data.intentTargetClass = targetClass;
|
||||
data.key = key;
|
||||
data.userId = userId;
|
||||
|
||||
rawData.add(data);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return rawData;
|
||||
}
|
||||
|
||||
private List<String> getNonIndexablesKeys(Context packageContext, Uri uri,
|
||||
String[] projection) {
|
||||
|
||||
final ContentResolver resolver = packageContext.getContentResolver();
|
||||
final List<String> result = new ArrayList<>();
|
||||
Cursor cursor;
|
||||
try {
|
||||
cursor = resolver.query(uri, projection, null, null, null);
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "Exception querying the keys!", e);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cursor == null) {
|
||||
Log.w(TAG, "Cannot add index data for Uri: " + uri.toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
final int count = cursor.getCount();
|
||||
if (count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
final String key = cursor.getString(COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE);
|
||||
|
||||
if (TextUtils.isEmpty(key) && Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Empty non-indexable key from: "
|
||||
+ packageContext.getPackageName());
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only allow a "well known" SearchIndexablesProvider. The provider should:
|
||||
*
|
||||
* - have read/write {@link Manifest.permission#READ_SEARCH_INDEXABLES}
|
||||
* - be from a privileged package
|
||||
*/
|
||||
@VisibleForTesting
|
||||
boolean isWellKnownProvider(ResolveInfo info) {
|
||||
final String authority = info.providerInfo.authority;
|
||||
final String packageName = info.providerInfo.applicationInfo.packageName;
|
||||
|
||||
if (TextUtils.isEmpty(authority) || TextUtils.isEmpty(packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String readPermission = info.providerInfo.readPermission;
|
||||
final String writePermission = info.providerInfo.writePermission;
|
||||
|
||||
if (TextUtils.isEmpty(readPermission) || TextUtils.isEmpty(writePermission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(readPermission) ||
|
||||
!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(writePermission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isPrivilegedPackage(packageName, mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the {@param packageName} is privileged.
|
||||
*/
|
||||
private boolean isPrivilegedPackage(String packageName, Context context) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
|
||||
return ((packInfo.applicationInfo.privateFlags
|
||||
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,6 +26,7 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@@ -34,13 +35,14 @@ import android.util.Pair;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SliderPreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -212,10 +214,26 @@ public class SliceBuilderUtils {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Intent buildSearchResultPageIntent(Context context, String className, String key,
|
||||
String screenTitle, int sourceMetricsCategory) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key);
|
||||
final Intent searchDestination = new SubSettingLauncher(context)
|
||||
.setDestination(className)
|
||||
.setArguments(args)
|
||||
.setTitleText(screenTitle)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.toIntent();
|
||||
searchDestination.putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key)
|
||||
.setAction("com.android.settings.SEARCH_RESULT_TRAMPOLINE")
|
||||
.setComponent(null);
|
||||
return searchDestination;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Intent getContentIntent(Context context, SliceData sliceData) {
|
||||
final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
final Intent intent = buildSearchResultPageIntent(context,
|
||||
sliceData.getFragmentClassName(), sliceData.getKey(),
|
||||
sliceData.getScreenTitle().toString(), 0 /* TODO */);
|
||||
intent.setClassName(context.getPackageName(), SubSettings.class.getName());
|
||||
|
@@ -36,8 +36,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
@@ -120,7 +120,7 @@ public class WifiSliceBuilder {
|
||||
public static Intent getIntent(Context context) {
|
||||
final String screenTitle = context.getText(R.string.wifi_settings).toString();
|
||||
final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build();
|
||||
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
|
||||
final Intent intent = SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
WifiSettings.class.getName(), KEY_WIFI, screenTitle,
|
||||
MetricsEvent.DIALOG_WIFI_AP_EDIT)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
|
@@ -1,2 +1,2 @@
|
||||
com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard
|
||||
com.android.settings.search.indexing.FakeSettingsFragment
|
||||
com.android.settings.search.FakeSettingsFragment
|
||||
|
@@ -18,7 +18,7 @@ package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.MagnificationPreferenceFragment.OFF;
|
||||
import static com.android.settings.accessibility.MagnificationPreferenceFragment.ON;
|
||||
import static com.android.settings.search.ResultPayload.Availability.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
|
@@ -23,7 +23,6 @@ import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
@@ -35,7 +34,6 @@ import android.provider.Settings;
|
||||
import android.text.BidiFormatter;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.search.DatabaseIndexingManager;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||
@@ -202,9 +200,6 @@ public class BuildNumberPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
public void onActivityResult_confirmPasswordRequestCompleted_enableDevPref() {
|
||||
when(mFactory.searchFeatureProvider.getIndexingManager(any(Context.class)))
|
||||
.thenReturn(mock(DatabaseIndexingManager.class));
|
||||
|
||||
mController =
|
||||
new BuildNumberPreferenceController(mContext, mActivity, mFragment, mLifecycle);
|
||||
|
||||
|
@@ -18,7 +18,6 @@ package com.android.settings.display;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
@@ -26,8 +25,6 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
|
||||
@@ -116,40 +113,6 @@ public class AmbientDisplayAlwaysOnPreferenceControllerTest {
|
||||
assertThat(mCallbackInvoked).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false);
|
||||
mController = spy(mController);
|
||||
|
||||
assertThat(mController.getResultPayload()).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false);
|
||||
mController = spy(mController);
|
||||
final int newValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, 0 /* value */);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
final int updatedValue = Settings.Secure.
|
||||
getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, 1 /* default */);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue_correctValueReturned() {
|
||||
when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false);
|
||||
mController = spy(mController);
|
||||
final int currentValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, currentValue);
|
||||
|
||||
final int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSliceableCorrectKey_returnsTrue() {
|
||||
final AmbientDisplayAlwaysOnPreferenceController controller =
|
||||
|
@@ -31,8 +31,6 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
@@ -157,33 +155,6 @@ public class AmbientDisplayNotificationsPreferenceControllerTest {
|
||||
verifyNoMoreInteractions(mMetricsFeatureProvider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
assertThat(mController.getResultPayload()).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
int newValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ENABLED, 0);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
int updatedValue =
|
||||
Settings.Secure.getInt(mContentResolver, Settings.Secure.DOZE_ENABLED, 1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int currentValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ENABLED, currentValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSliceableCorrectKey_returnsTrue() {
|
||||
final AmbientDisplayNotificationsPreferenceController controller =
|
||||
|
@@ -19,14 +19,8 @@ package com.android.settings.gestures;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Secure;
|
||||
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
@@ -37,7 +31,6 @@ 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;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@@ -71,38 +64,5 @@ public class AssistGestureSettingsPreferenceControllerTest {
|
||||
when(mFactory.assistGestureFeatureProvider.isSupported(mContext)).thenReturn(false);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
AssistGestureSettingsPreferenceController controller =
|
||||
new AssistGestureSettingsPreferenceController(context, KEY_ASSIST);
|
||||
controller.setAssistOnly(false);
|
||||
ResultPayload payload = controller.getResultPayload();
|
||||
assertThat(payload).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Secure.ASSIST_GESTURE_ENABLED, 0);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
int updatedValue = Settings.Secure.getInt(resolver, Secure.ASSIST_GESTURE_ENABLED, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int currentValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.ASSIST_GESTURE_ENABLED, currentValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -28,12 +28,8 @@ import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -99,42 +95,6 @@ public class DoubleTapPowerPreferenceControllerTest {
|
||||
assertThat(mController.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
DoubleTapPowerPreferenceController controller =
|
||||
new DoubleTapPowerPreferenceController(mContext, KEY_DOUBLE_TAP_POWER);
|
||||
ResultPayload payload = controller.getResultPayload();
|
||||
assertThat(payload).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
int newValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver,
|
||||
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0);
|
||||
|
||||
InlinePayload payload = ((InlineSwitchPayload) mController.getResultPayload());
|
||||
payload.setValue(mContext, newValue);
|
||||
int updatedValue = Settings.Secure.getInt(mContentResolver,
|
||||
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, -1);
|
||||
updatedValue = 1 - updatedValue; // DoubleTapPower is a non-standard switch
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int currentValue = 1;
|
||||
Settings.Secure.putInt(mContentResolver,
|
||||
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, currentValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
newValue = 1 - newValue; // DoubleTapPower is a non-standard switch
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSuggestionCompleted_doubleTapPower_trueWhenNotAvailable() {
|
||||
SettingsShadowResources.overrideResource(
|
||||
|
@@ -23,18 +23,12 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -43,7 +37,6 @@ import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class DoubleTapScreenPreferenceControllerTest {
|
||||
@@ -78,42 +71,6 @@ public class DoubleTapScreenPreferenceControllerTest {
|
||||
assertThat(mController.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
DoubleTapScreenPreferenceController controller =
|
||||
new DoubleTapScreenPreferenceController(context, KEY_DOUBLE_TAP_SCREEN);
|
||||
controller.setConfig(mAmbientDisplayConfiguration);
|
||||
ResultPayload payload = controller.getResultPayload();
|
||||
assertThat(payload).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, 0);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
int updatedValue = Settings.Secure.getInt(resolver,
|
||||
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int currentValue = 1;
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, currentValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSuggestionCompleted_ambientDisplay_falseWhenNotVisited() {
|
||||
when(mAmbientDisplayConfiguration.pulseOnDoubleTapAvailable()).thenReturn(true);
|
||||
@@ -183,7 +140,7 @@ public class DoubleTapScreenPreferenceControllerTest {
|
||||
@Test
|
||||
public void isSliceableCorrectKey_returnsTrue() {
|
||||
final DoubleTapScreenPreferenceController controller =
|
||||
new DoubleTapScreenPreferenceController(mContext,"gesture_double_tap_screen");
|
||||
new DoubleTapScreenPreferenceController(mContext, "gesture_double_tap_screen");
|
||||
assertThat(controller.isSliceable()).isTrue();
|
||||
}
|
||||
|
||||
|
@@ -25,16 +25,11 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -96,40 +91,6 @@ public class PickupGesturePreferenceControllerTest {
|
||||
assertThat(mController.canHandleClicks()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
PickupGesturePreferenceController controller =
|
||||
new PickupGesturePreferenceController(context, KEY_PICK_UP);
|
||||
controller.setConfig(mAmbientDisplayConfiguration);
|
||||
ResultPayload payload = controller.getResultPayload();
|
||||
assertThat(payload).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.DOZE_PULSE_ON_PICK_UP, 0);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
int updatedValue = Settings.Secure.getInt(resolver,
|
||||
Settings.Secure.DOZE_PULSE_ON_PICK_UP, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int currentValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.DOZE_PULSE_ON_PICK_UP, currentValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSuggestionCompleted_ambientDisplayPickup_trueWhenVisited() {
|
||||
when(mContext.getResources().getBoolean(anyInt())).thenReturn(true);
|
||||
@@ -173,7 +134,7 @@ public class PickupGesturePreferenceControllerTest {
|
||||
@Test
|
||||
public void isSliceableCorrectKey_returnsTrue() {
|
||||
final PickupGesturePreferenceController controller =
|
||||
new PickupGesturePreferenceController(mContext,"gesture_pick_up");
|
||||
new PickupGesturePreferenceController(mContext, "gesture_pick_up");
|
||||
assertThat(controller.isSliceable()).isTrue();
|
||||
}
|
||||
|
||||
|
@@ -29,15 +29,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.LocationManager;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Secure;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.InlineListPayload;
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -46,8 +41,6 @@ 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 androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
@@ -155,38 +148,4 @@ public class LocationPreferenceControllerTest {
|
||||
|
||||
verify(mPreference).setSummary(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
mController = new LocationPreferenceController(context, null /* lifecycle */);
|
||||
ResultPayload payload = mController.getResultPayload();
|
||||
assertThat(payload).isInstanceOf(InlineListPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
final int newValue = Secure.LOCATION_MODE_BATTERY_SAVING;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
final int updatedValue =
|
||||
Settings.Secure.getInt(resolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testGetValue_correctValueReturned() {
|
||||
int expectedValue = Secure.LOCATION_MODE_BATTERY_SAVING;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Secure.LOCATION_MODE, expectedValue);
|
||||
|
||||
int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(expectedValue);
|
||||
}
|
||||
}
|
||||
|
@@ -24,14 +24,9 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.search.InlinePayload;
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -40,7 +35,6 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
@@ -116,37 +110,6 @@ public class BadgingNotificationPreferenceControllerTest {
|
||||
verify(preference).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceController_ProperResultPayloadType() {
|
||||
assertThat(mController.getResultPayload()).isInstanceOf(InlineSwitchPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testSetValue_updatesCorrectly() {
|
||||
final int newValue = 0;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.NOTIFICATION_BADGING, ON);
|
||||
|
||||
((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue);
|
||||
final int updatedValue =
|
||||
Settings.Secure.getInt(resolver, Settings.Secure.NOTIFICATION_BADGING, ON);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSecureSettings.class)
|
||||
public void testGetValue_correctValueReturned() {
|
||||
final int currentValue = 1;
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, Settings.Secure.NOTIFICATION_BADGING, currentValue);
|
||||
|
||||
final int newValue = ((InlinePayload) mController.getResultPayload()).getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isChecked_settingIsOff_shouldReturnFalse() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, OFF);
|
||||
|
@@ -1,388 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyList;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Build;
|
||||
import android.provider.SearchIndexableData;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.settings.search.indexing.PreIndexData;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowRunnableAsyncTask;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowRunnableAsyncTask.class)
|
||||
public class DatabaseIndexingManagerTest {
|
||||
|
||||
private final String localeStr = "en_US";
|
||||
|
||||
private final int rank = 8;
|
||||
private final String title = "title\u2011title";
|
||||
private final String updatedTitle = "title-title";
|
||||
private final String normalizedTitle = "titletitle";
|
||||
private final String summaryOn = "summary\u2011on";
|
||||
private final String updatedSummaryOn = "summary-on";
|
||||
private final String normalizedSummaryOn = "summaryon";
|
||||
private final String summaryOff = "summary\u2011off";
|
||||
private final String entries = "entries";
|
||||
private final String keywords = "keywords, keywordss, keywordsss";
|
||||
private final String spaceDelimittedKeywords = "keywords keywordss keywordsss";
|
||||
private final String screenTitle = "screen title";
|
||||
private final String className = "class name";
|
||||
private final int iconResId = 0xff;
|
||||
private final String action = "action";
|
||||
private final String targetPackage = "target package";
|
||||
private final String targetClass = "target class";
|
||||
private final String packageName = "package name";
|
||||
private final String key = "key";
|
||||
private final int userId = -1;
|
||||
private final boolean enabled = true;
|
||||
|
||||
private final String TITLE_ONE = "title one";
|
||||
private final String TITLE_TWO = "title two";
|
||||
private final String KEY_ONE = "key one";
|
||||
private final String KEY_TWO = "key two";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private DatabaseIndexingManager mManager;
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
private final List<ResolveInfo> FAKE_PROVIDER_LIST = new ArrayList<>();
|
||||
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mManager = spy(new DatabaseIndexingManager(mContext));
|
||||
mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
|
||||
|
||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||
doReturn(FAKE_PROVIDER_LIST).when(mPackageManager)
|
||||
.queryIntentContentProviders(any(Intent.class), anyInt());
|
||||
FakeFeatureFactory.setupForTest();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
DatabaseTestUtils.clearDb(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDatabaseSchema() {
|
||||
Cursor dbCursor = mDb.query("prefs_index", null, null, null, null, null, null);
|
||||
List<String> columnNames = new ArrayList<>(Arrays.asList(dbCursor.getColumnNames()));
|
||||
// Note that docid is not included.
|
||||
List<String> expColumnNames = Arrays.asList(
|
||||
"locale",
|
||||
"data_rank",
|
||||
"data_title",
|
||||
"data_title_normalized",
|
||||
"data_summary_on",
|
||||
"data_summary_on_normalized",
|
||||
"data_summary_off",
|
||||
"data_summary_off_normalized",
|
||||
"data_entries",
|
||||
"data_keywords",
|
||||
"class_name",
|
||||
"screen_title",
|
||||
"intent_action",
|
||||
"intent_target_package",
|
||||
"intent_target_class",
|
||||
"icon",
|
||||
"enabled",
|
||||
"data_key_reference",
|
||||
"user_id",
|
||||
"payload_type",
|
||||
"payload"
|
||||
);
|
||||
// Prevent database schema regressions
|
||||
assertThat(columnNames).containsAllIn(expColumnNames);
|
||||
}
|
||||
|
||||
// Test new public indexing flow
|
||||
|
||||
@Test
|
||||
public void testPerformIndexing_fullIndex_getsDataFromProviders() {
|
||||
SearchIndexableRaw rawData = getFakeRaw();
|
||||
PreIndexData data = getPreIndexData(rawData);
|
||||
doReturn(data).when(mManager).getIndexDataFromProviders(anyList(), anyBoolean());
|
||||
doReturn(true).when(mManager)
|
||||
.isFullIndex(any(Context.class), anyString(), anyString(), anyString());
|
||||
|
||||
mManager.performIndexing();
|
||||
|
||||
verify(mManager).updateDatabase(data, true /* isFullIndex */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformIndexing_fullIndex_databaseDropped() {
|
||||
// Initialize the Manager and force rebuild
|
||||
DatabaseIndexingManager manager =
|
||||
spy(new DatabaseIndexingManager(mContext));
|
||||
doReturn(false).when(mManager)
|
||||
.isFullIndex(any(Context.class), anyString(), anyString(), anyString());
|
||||
|
||||
// Insert data point which will be dropped
|
||||
insertSpecialCase("Ceci n'est pas un pipe", true, "oui oui mon ami");
|
||||
|
||||
manager.performIndexing();
|
||||
|
||||
// Assert that the Old Title is no longer in the database, since it was dropped
|
||||
final Cursor oldCursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
|
||||
|
||||
assertThat(oldCursor.getCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformIndexing_isfullIndex() {
|
||||
SearchIndexableRaw rawData = getFakeRaw();
|
||||
PreIndexData data = getPreIndexData(rawData);
|
||||
doReturn(data).when(mManager).getIndexDataFromProviders(anyList(), anyBoolean());
|
||||
doReturn(true).when(mManager)
|
||||
.isFullIndex(any(Context.class), anyString(), anyString(), anyString());
|
||||
|
||||
mManager.performIndexing();
|
||||
|
||||
verify(mManager).updateDatabase(data, true /* isFullIndex */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformIndexing_onOta_buildNumberIsCached() {
|
||||
mManager.performIndexing();
|
||||
|
||||
assertThat(IndexDatabaseHelper.isBuildIndexed(mContext, Build.FINGERPRINT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocaleUpdated_afterIndexing_localeNotAdded() {
|
||||
PreIndexData emptydata = new PreIndexData();
|
||||
mManager.updateDatabase(emptydata, true /* isFullIndex */);
|
||||
|
||||
assertThat(IndexDatabaseHelper.isLocaleAlreadyIndexed(mContext, localeStr)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocaleUpdated_afterFullIndexing_localeAdded() {
|
||||
mManager.performIndexing();
|
||||
|
||||
assertThat(IndexDatabaseHelper.isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDatabase_newEligibleData_addedToDatabase() {
|
||||
// Test that addDataToDatabase is called when dataToUpdate is non-empty
|
||||
PreIndexData indexData = new PreIndexData();
|
||||
indexData.dataToUpdate.add(getFakeRaw());
|
||||
mManager.updateDatabase(indexData, true /* isFullIndex */);
|
||||
|
||||
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
|
||||
cursor.moveToPosition(0);
|
||||
|
||||
// Locale
|
||||
assertThat(cursor.getString(0)).isEqualTo(localeStr);
|
||||
// Data Title
|
||||
assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
|
||||
// Normalized Title
|
||||
assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
|
||||
// Summary On
|
||||
assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
|
||||
// Summary On Normalized
|
||||
assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
|
||||
// Entries
|
||||
assertThat(cursor.getString(8)).isEqualTo(entries);
|
||||
// Keywords
|
||||
assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
|
||||
// Screen Title
|
||||
assertThat(cursor.getString(10)).isEqualTo(screenTitle);
|
||||
// Class Name
|
||||
assertThat(cursor.getString(11)).isEqualTo(className);
|
||||
// Icon
|
||||
assertThat(cursor.getInt(12)).isEqualTo(iconResId);
|
||||
// Intent Action
|
||||
assertThat(cursor.getString(13)).isEqualTo(action);
|
||||
// Target Package
|
||||
assertThat(cursor.getString(14)).isEqualTo(targetPackage);
|
||||
// Target Class
|
||||
assertThat(cursor.getString(15)).isEqualTo(targetClass);
|
||||
// Enabled
|
||||
assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
|
||||
// Data ref key
|
||||
assertThat(cursor.getString(17)).isNotNull();
|
||||
// User Id
|
||||
assertThat(cursor.getInt(18)).isEqualTo(userId);
|
||||
// Payload Type - default is 0
|
||||
assertThat(cursor.getInt(19)).isEqualTo(0);
|
||||
// Payload
|
||||
byte[] payload = cursor.getBlob(20);
|
||||
ResultPayload unmarshalledPayload = ResultPayloadUtils.unmarshall(payload,
|
||||
ResultPayload.CREATOR);
|
||||
assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDataInDatabase_enabledResultsAreNonIndexable_becomeDisabled() {
|
||||
// Both results are enabled, and then TITLE_ONE gets disabled.
|
||||
final boolean enabled = true;
|
||||
insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
|
||||
insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
|
||||
Map<String, Set<String>> niks = new ArrayMap<>();
|
||||
Set<String> keys = new HashSet<>();
|
||||
keys.add(KEY_ONE);
|
||||
niks.put(targetPackage, keys);
|
||||
|
||||
mManager.updateDataInDatabase(mDb, niks);
|
||||
|
||||
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
|
||||
cursor.moveToPosition(0);
|
||||
|
||||
assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDataInDatabase_disabledResultsAreIndexable_becomeEnabled() {
|
||||
// Both results are initially disabled, and then TITLE_TWO gets enabled.
|
||||
final boolean enabled = false;
|
||||
insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
|
||||
insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
|
||||
Map<String, Set<String>> niks = new ArrayMap<>();
|
||||
Set<String> keys = new HashSet<>();
|
||||
keys.add(KEY_ONE);
|
||||
niks.put(targetPackage, keys);
|
||||
|
||||
mManager.updateDataInDatabase(mDb, niks);
|
||||
|
||||
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
|
||||
cursor.moveToPosition(0);
|
||||
|
||||
assertThat(cursor.getString(2)).isEqualTo(TITLE_TWO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyNonIndexableKeys_emptyDataKeyResources_addedToDatabase() {
|
||||
insertSpecialCase(TITLE_ONE, true /* enabled */, null /* dataReferenceKey */);
|
||||
PreIndexData emptydata = new PreIndexData();
|
||||
mManager.updateDatabase(emptydata, false /* needsReindexing */);
|
||||
|
||||
Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
|
||||
cursor.moveToPosition(0);
|
||||
assertThat(cursor.getCount()).isEqualTo(1);
|
||||
assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
|
||||
}
|
||||
|
||||
// Util functions
|
||||
|
||||
private SearchIndexableRaw getFakeRaw() {
|
||||
return getFakeRaw(localeStr);
|
||||
}
|
||||
|
||||
private SearchIndexableRaw getFakeRaw(String localeStr) {
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||
data.locale = new Locale(localeStr);
|
||||
data.rank = rank;
|
||||
data.title = title;
|
||||
data.summaryOn = summaryOn;
|
||||
data.summaryOff = summaryOff;
|
||||
data.entries = entries;
|
||||
data.keywords = keywords;
|
||||
data.screenTitle = screenTitle;
|
||||
data.className = className;
|
||||
data.packageName = packageName;
|
||||
data.iconResId = iconResId;
|
||||
data.intentAction = action;
|
||||
data.intentTargetPackage = targetPackage;
|
||||
data.intentTargetClass = targetClass;
|
||||
data.key = key;
|
||||
data.userId = userId;
|
||||
data.enabled = enabled;
|
||||
return data;
|
||||
}
|
||||
|
||||
private void insertSpecialCase(String specialCase, boolean enabled, String key) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DOCID, specialCase.hashCode());
|
||||
values.put(IndexDatabaseHelper.IndexColumns.LOCALE, localeStr);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, specialCase);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, targetPackage);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
|
||||
values.put(IndexDatabaseHelper.IndexColumns.ENABLED, enabled);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, key);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
|
||||
values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
|
||||
|
||||
mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
|
||||
}
|
||||
|
||||
private PreIndexData getPreIndexData(SearchIndexableData fakeData) {
|
||||
PreIndexData data = new PreIndexData();
|
||||
data.dataToUpdate.add(fakeData);
|
||||
return data;
|
||||
}
|
||||
}
|
@@ -1,65 +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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class DatabaseIndexingUtilsTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPreferenceControllerUriMap_BadClassName_ReturnsNull() {
|
||||
Map map = DatabaseIndexingUtils.getPayloadKeyMap("dummy", mContext);
|
||||
assertThat(map).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPreferenceControllerUriMap_NullContext_ReturnsNull() {
|
||||
Map map = DatabaseIndexingUtils.getPayloadKeyMap("dummy", null);
|
||||
assertThat(map).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPayloadFromMap_NullMap_ReturnsNull() {
|
||||
final String className = "com.android.settings.system.SystemDashboardFragment";
|
||||
final Map<String, ResultPayload> map =
|
||||
DatabaseIndexingUtils.getPayloadKeyMap(className, mContext);
|
||||
ResultPayload payload = map.get(null);
|
||||
assertThat(payload).isNull();
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -12,18 +12,15 @@
|
||||
* 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.search.indexing;
|
||||
package com.android.settings.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import java.util.ArrayList;
|
@@ -1,105 +0,0 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class InlineListPayloadTest {
|
||||
|
||||
private static final String DUMMY_SETTING = "inline_list_key";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor_DataRetained() {
|
||||
final String uri = "test.com";
|
||||
final int type = ResultPayload.PayloadType.INLINE_LIST;
|
||||
final int source = ResultPayload.SettingsSource.SYSTEM;
|
||||
final String intentKey = "key";
|
||||
final String intentVal = "value";
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(intentKey, intentVal);
|
||||
|
||||
InlineListPayload payload = new InlineListPayload(uri, source,
|
||||
intent, true /* isAvailable */, 1 /* numOptions */, 1 /* default */);
|
||||
|
||||
final Intent retainedIntent = payload.getIntent();
|
||||
assertThat(payload.getKey()).isEqualTo(uri);
|
||||
assertThat(payload.getType()).isEqualTo(type);
|
||||
assertThat(payload.mSettingSource).isEqualTo(source);
|
||||
assertThat(payload.getAvailability()).isEqualTo(ResultPayload.Availability.AVAILABLE);
|
||||
assertThat(retainedIntent.getStringExtra(intentKey)).isEqualTo(intentVal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelConstructor_DataRetained() {
|
||||
String uri = "test.com";
|
||||
int type = ResultPayload.PayloadType.INLINE_LIST;
|
||||
int source = ResultPayload.SettingsSource.SYSTEM;
|
||||
final String intentKey = "key";
|
||||
final String intentVal = "value";
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(intentKey, intentVal);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parcel.writeParcelable(intent, 0);
|
||||
parcel.writeString(uri);
|
||||
parcel.writeInt(source);
|
||||
parcel.writeInt(InlineSwitchPayload.TRUE);
|
||||
parcel.writeInt(InlineSwitchPayload.TRUE);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
InlineListPayload payload = InlineListPayload.CREATOR.createFromParcel(parcel);
|
||||
|
||||
final Intent builtIntent = payload.getIntent();
|
||||
assertThat(payload.getKey()).isEqualTo(uri);
|
||||
assertThat(payload.getType()).isEqualTo(type);
|
||||
assertThat(payload.mSettingSource).isEqualTo(source);
|
||||
assertThat(payload.getAvailability()).isEqualTo(ResultPayload.Availability.AVAILABLE);
|
||||
assertThat(builtIntent.getStringExtra(intentKey)).isEqualTo(intentVal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInputStandardization_inputDoesntChange() {
|
||||
InlineListPayload payload = new InlineListPayload(DUMMY_SETTING,
|
||||
ResultPayload.SettingsSource.SYSTEM, null /* intent */, true /* isDeviceSupport */,
|
||||
3 /* numOptions */, 0 /* default */);
|
||||
int input = 2;
|
||||
|
||||
assertThat(payload.standardizeInput(input)).isEqualTo(input);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetSystem_negativeValue_throwsError() {
|
||||
InlineListPayload payload = new InlineListPayload(DUMMY_SETTING,
|
||||
ResultPayload.SettingsSource.SYSTEM, null /* intent */, true /* isDeviceSupport */,
|
||||
3 /* numOptions */, 0 /* default */);
|
||||
|
||||
payload.setValue(mContext, -1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetSystem_exceedsMaxValue_throwsError() {
|
||||
int maxOptions = 4;
|
||||
InlineListPayload payload = new InlineListPayload(DUMMY_SETTING,
|
||||
ResultPayload.SettingsSource.SYSTEM, null /* intent */, true /* isDeviceSupport */,
|
||||
maxOptions /* numOptions */, 0 /* default */);
|
||||
|
||||
payload.setValue(mContext, maxOptions + 1);
|
||||
}
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.search.ResultPayload.SettingsSource;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class InlinePayloadTest {
|
||||
|
||||
private static final String KEY = "key";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecure_returnsSecureSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.SECURE);
|
||||
int currentValue = 2;
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), KEY, currentValue);
|
||||
|
||||
int newValue = payload.getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetGlobal_returnsGlobalSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.GLOBAL);
|
||||
int currentValue = 2;
|
||||
Settings.Global.putInt(mContext.getContentResolver(), KEY, currentValue);
|
||||
|
||||
int newValue = payload.getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSystem_returnsSystemSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.SYSTEM);
|
||||
int currentValue = 2;
|
||||
Settings.System.putInt(mContext.getContentResolver(), KEY, currentValue);
|
||||
|
||||
int newValue = payload.getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSecure_updatesSecureSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.SECURE);
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Secure.putInt(resolver, KEY, 0);
|
||||
|
||||
payload.setValue(mContext, newValue);
|
||||
int updatedValue = Settings.System.getInt(resolver, KEY, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGlobal_updatesGlobalSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.GLOBAL);
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.Global.putInt(resolver, KEY, 0);
|
||||
|
||||
payload.setValue(mContext, newValue);
|
||||
int updatedValue = Settings.Global.getInt(resolver, KEY, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSystem_updatesSystemSetting() {
|
||||
InlinePayload payload = getDummyPayload(SettingsSource.SECURE);
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.System.putInt(resolver, SCREEN_BRIGHTNESS_MODE, 0);
|
||||
|
||||
payload.setValue(mContext, newValue);
|
||||
int updatedValue = Settings.System.getInt(resolver, KEY, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(newValue);
|
||||
}
|
||||
|
||||
private InlinePayload getDummyPayload(int source) {
|
||||
return new ConcreteInlinePayload(KEY, source, null /* intent */,
|
||||
true /* isDeviceSupported */);
|
||||
}
|
||||
|
||||
private class ConcreteInlinePayload extends InlinePayload {
|
||||
|
||||
private ConcreteInlinePayload(String key, @SettingsSource int source, Intent intent,
|
||||
boolean isDeviceSupported) {
|
||||
super(key, source, intent, isDeviceSupported, 0 /* defaultValue */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int standardizeInput(int input) throws IllegalArgumentException {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,145 +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.search;
|
||||
|
||||
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.search.ResultPayload.Availability;
|
||||
import com.android.settings.search.ResultPayload.SettingsSource;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class InlineSwitchPayloadTest {
|
||||
|
||||
private static final String DUMMY_SETTING = "inline_test";
|
||||
private static final int STANDARD_ON = 1;
|
||||
private static final int FLIPPED_ON = 0;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor_DataRetained() {
|
||||
final String uri = "test.com";
|
||||
final int type = ResultPayload.PayloadType.INLINE_SWITCH;
|
||||
final int source = SettingsSource.SECURE;
|
||||
final String intentKey = "key";
|
||||
final String intentVal = "value";
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(intentKey, intentVal);
|
||||
|
||||
InlineSwitchPayload payload =
|
||||
new InlineSwitchPayload(uri, source, 1, intent, true, 1 /* default */);
|
||||
final Intent retainedIntent = payload.getIntent();
|
||||
assertThat(payload.getKey()).isEqualTo(uri);
|
||||
assertThat(payload.getType()).isEqualTo(type);
|
||||
assertThat(payload.mSettingSource).isEqualTo(source);
|
||||
assertThat(payload.isStandard()).isTrue();
|
||||
assertThat(payload.getAvailability()).isEqualTo(ResultPayload.Availability.AVAILABLE);
|
||||
assertThat(retainedIntent.getStringExtra(intentKey)).isEqualTo(intentVal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelConstructor_DataRetained() {
|
||||
String uri = "test.com";
|
||||
int type = ResultPayload.PayloadType.INLINE_SWITCH;
|
||||
int source = SettingsSource.SECURE;
|
||||
final String intentKey = "key";
|
||||
final String intentVal = "value";
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(intentKey, intentVal);
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parcel.writeParcelable(intent, 0);
|
||||
parcel.writeString(uri);
|
||||
parcel.writeInt(source);
|
||||
parcel.writeInt(InlineSwitchPayload.TRUE);
|
||||
parcel.writeInt(InlineSwitchPayload.TRUE);
|
||||
parcel.writeInt(InlineSwitchPayload.TRUE);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
InlineSwitchPayload payload = InlineSwitchPayload.CREATOR.createFromParcel(parcel);
|
||||
|
||||
final Intent builtIntent = payload.getIntent();
|
||||
assertThat(payload.getKey()).isEqualTo(uri);
|
||||
assertThat(payload.getType()).isEqualTo(type);
|
||||
assertThat(payload.mSettingSource).isEqualTo(source);
|
||||
assertThat(payload.isStandard()).isTrue();
|
||||
assertThat(payload.getAvailability()).isEqualTo(Availability.AVAILABLE);
|
||||
assertThat(builtIntent.getStringExtra(intentKey)).isEqualTo(intentVal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSystem_flippedSetting_returnsFlippedValue() {
|
||||
// Stores 1s as 0s, and vis versa
|
||||
InlineSwitchPayload payload = new InlineSwitchPayload(DUMMY_SETTING, SettingsSource.SYSTEM,
|
||||
FLIPPED_ON, null /* intent */, true, 1 /* default */);
|
||||
int currentValue = 1;
|
||||
Settings.System.putInt(mContext.getContentResolver(), DUMMY_SETTING, currentValue);
|
||||
|
||||
int newValue = payload.getValue(mContext);
|
||||
|
||||
assertThat(newValue).isEqualTo(1 - currentValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSystem_flippedSetting_updatesToFlippedValue() {
|
||||
// Stores 1s as 0s, and vis versa
|
||||
InlineSwitchPayload payload = new InlineSwitchPayload(DUMMY_SETTING, SettingsSource.SYSTEM,
|
||||
FLIPPED_ON, null /* intent */, true, 1 /* default */);
|
||||
int newValue = 1;
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Settings.System.putInt(resolver, SCREEN_BRIGHTNESS_MODE, newValue);
|
||||
|
||||
payload.setValue(mContext, newValue);
|
||||
int updatedValue = Settings.System.getInt(resolver, DUMMY_SETTING, -1);
|
||||
|
||||
assertThat(updatedValue).isEqualTo(1 - newValue);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetSystem_negativeValue_ThrowsError() {
|
||||
InlineSwitchPayload payload = new InlineSwitchPayload(DUMMY_SETTING, SettingsSource.SYSTEM,
|
||||
STANDARD_ON, null /* intent */, true, 1 /* default */);
|
||||
|
||||
payload.setValue(mContext, -1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetSystem_highValue_ThrowsError() {
|
||||
InlineSwitchPayload payload = new InlineSwitchPayload(DUMMY_SETTING, SettingsSource.SYSTEM,
|
||||
STANDARD_ON, null /* intent */, true, 1 /* default */);
|
||||
|
||||
payload.setValue(mContext, 2);
|
||||
}
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class ResultPayloadTest {
|
||||
|
||||
private static final String EXTRA_KEY = "key";
|
||||
private static final String EXTRA_VALUE = "value";
|
||||
|
||||
@Test
|
||||
public void testParcelOrdering_StaysValid() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_KEY, EXTRA_VALUE);
|
||||
Parcel parcel = Parcel.obtain();
|
||||
|
||||
final ResultPayload payload = new ResultPayload(intent);
|
||||
payload.writeToParcel(parcel, 0);
|
||||
// Reset parcel for reading
|
||||
parcel.setDataPosition(0);
|
||||
ResultPayload newPayload = ResultPayload.CREATOR.createFromParcel(parcel);
|
||||
|
||||
String originalIntentExtra = payload.getIntent().getStringExtra(EXTRA_KEY);
|
||||
String copiedIntentExtra = newPayload.getIntent().getStringExtra(EXTRA_KEY);
|
||||
assertThat(originalIntentExtra).isEqualTo(copiedIntentExtra);
|
||||
}
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class ResultPayloadUtilsTest {
|
||||
|
||||
private static final String EXTRA_KEY = "key";
|
||||
private static final String EXTRA_VALUE = "value";
|
||||
|
||||
private ResultPayload payload;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_KEY, EXTRA_VALUE);
|
||||
payload = new ResultPayload(intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnmarshallBadData_ExceptionThrown() {
|
||||
byte[] badData = "I'm going to fail :)".getBytes();
|
||||
try {
|
||||
ResultPayloadUtils.unmarshall(badData, ResultPayload.CREATOR);
|
||||
fail("unmarshall should throw exception");
|
||||
} catch (RuntimeException e) {
|
||||
assertThat(e).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarshallResultPayload_NonEmptyArray() {
|
||||
byte[] marshalledPayload = ResultPayloadUtils.marshall(payload);
|
||||
assertThat(marshalledPayload).isNotNull();
|
||||
assertThat(marshalledPayload).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnmarshall_PreservedData() {
|
||||
byte[] marshalledPayload = ResultPayloadUtils.marshall(payload);
|
||||
ResultPayload newPayload =
|
||||
ResultPayloadUtils.unmarshall(marshalledPayload, ResultPayload.CREATOR);
|
||||
|
||||
String originalIntentExtra = payload.getIntent().getStringExtra(EXTRA_KEY);
|
||||
String copiedIntentExtra = newPayload.getIntent().getStringExtra(EXTRA_KEY);
|
||||
assertThat(originalIntentExtra).isEqualTo(copiedIntentExtra);
|
||||
}
|
||||
}
|
@@ -86,12 +86,4 @@ public class SearchFeatureProviderImplTest {
|
||||
final ComponentName cn = new ComponentName(packageName, "class");
|
||||
mProvider.verifyLaunchSearchResultPageCaller(mActivity, cn);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleanQuery_trimsWhitespace() {
|
||||
final String query = " space ";
|
||||
final String cleanQuery = "space";
|
||||
|
||||
assertThat(mProvider.cleanQuery(query)).isEqualTo(cleanQuery);
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import android.net.Uri;
|
||||
import android.provider.SearchIndexablesContract;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.indexing.FakeSettingsFragment;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
|
@@ -1,369 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.ResultPayloadUtils;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(qualifiers = "mcc999")
|
||||
public class IndexDataConverterTest {
|
||||
|
||||
private static final String localeStr = "en_US";
|
||||
|
||||
private static final String title = "title\u2011title";
|
||||
private static final String updatedTitle = "title-title";
|
||||
private static final String normalizedTitle = "titletitle";
|
||||
private static final String summaryOn = "summary\u2011on";
|
||||
private static final String updatedSummaryOn = "summary-on";
|
||||
private static final String summaryOff = "summary\u2011off";
|
||||
private static final String entries = "entries";
|
||||
private static final String keywords = "keywords, keywordss, keywordsss";
|
||||
private static final String spaceDelimittedKeywords = "keywords keywordss keywordsss";
|
||||
private static final String screenTitle = "screen title";
|
||||
private static final String className = "class name";
|
||||
private static final int iconResId = 0xff;
|
||||
private static final String action = "action";
|
||||
private static final String targetPackage = "target package";
|
||||
private static final String targetClass = "target class";
|
||||
private static final String packageName = "package name";
|
||||
private static final String key = "key";
|
||||
private static final int userId = -1;
|
||||
private static final boolean enabled = true;
|
||||
|
||||
// There are 6 entries in the fake display_settings.xml preference.
|
||||
private static final int NUM_DISPLAY_ENTRIES = 6;
|
||||
private static final String PAGE_TITLE = "page_title";
|
||||
private static final String TITLE_ONE = "pref_title_1";
|
||||
private static final String TITLE_TWO = "pref_title_2";
|
||||
private static final String TITLE_THREE = "pref_title_3";
|
||||
private static final String TITLE_FOUR = "pref_title_4";
|
||||
private static final String TITLE_FIVE = "pref_title_5";
|
||||
private static final String DISPLAY_SPACE_DELIM_KEYWORDS = "keywords1 keywords2 keywords3";
|
||||
|
||||
// There is a title and one preference.
|
||||
private static final int NUM_LEGAL_SETTINGS = 2;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private IndexDataConverter mConverter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mConverter = spy(new IndexDataConverter(mContext));
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
DatabaseTestUtils.clearDb(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertRawColumn_rowConverted() {
|
||||
final SearchIndexableRaw raw = getFakeRaw();
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(raw);
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData.size()).isEqualTo(1);
|
||||
final IndexData row = indexData.get(0);
|
||||
|
||||
assertThat(row.normalizedTitle).isEqualTo(normalizedTitle);
|
||||
assertThat(row.updatedTitle).isEqualTo(updatedTitle);
|
||||
assertThat(row.locale).isEqualTo(localeStr);
|
||||
assertThat(row.updatedSummaryOn).isEqualTo(updatedSummaryOn);
|
||||
assertThat(row.entries).isEqualTo(entries);
|
||||
assertThat(row.spaceDelimitedKeywords).isEqualTo(spaceDelimittedKeywords);
|
||||
assertThat(row.screenTitle).isEqualTo(screenTitle);
|
||||
assertThat(row.className).isEqualTo(className);
|
||||
assertThat(row.iconResId).isEqualTo(iconResId);
|
||||
assertThat(row.intentAction).isEqualTo(action);
|
||||
assertThat(row.intentTargetPackage).isEqualTo(targetPackage);
|
||||
assertThat(row.intentTargetClass).isEqualTo(targetClass);
|
||||
assertThat(row.enabled).isEqualTo(enabled);
|
||||
assertThat(row.key).isEqualTo(key);
|
||||
assertThat(row.userId).isEqualTo(userId);
|
||||
assertThat(row.payloadType).isEqualTo(0);
|
||||
ResultPayload unmarshalledPayload =
|
||||
ResultPayloadUtils.unmarshall(row.payload, ResultPayload.CREATOR);
|
||||
assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertRawColumn_nonIndexableKey_resultIsDisabled() {
|
||||
final SearchIndexableRaw raw = getFakeRaw();
|
||||
// Add non-indexable key for raw row.
|
||||
Set<String> keys = new HashSet<>();
|
||||
keys.add(raw.key);
|
||||
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(raw);
|
||||
preIndexData.nonIndexableKeys.put(raw.intentTargetPackage, keys);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData.size()).isEqualTo(1);
|
||||
assertThat(indexData.get(0).enabled).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO (b/66916397) investigate why locale is attached to IndexData
|
||||
*/
|
||||
@Test
|
||||
public void testInsertRawColumn_mismatchedLocale_rowInserted() {
|
||||
final SearchIndexableRaw raw = getFakeRaw("ca-fr");
|
||||
PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(raw);
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData).hasSize(1);
|
||||
}
|
||||
|
||||
// Tests for the flow: IndexOneResource -> IndexFromResource ->
|
||||
// UpdateOneRowWithFilteredData -> UpdateOneRow
|
||||
|
||||
@Test
|
||||
public void testNullResource_NothingInserted() {
|
||||
PreIndexData preIndexData = new PreIndexData();
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResource_RowsInserted() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
final List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
int numEnabled = getEnabledResultCount(indexData);
|
||||
|
||||
assertThat(numEnabled).isEqualTo(NUM_DISPLAY_ENTRIES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResource_withNIKs_rowsInsertedDisabled() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
Set<String> keys = new HashSet<>();
|
||||
keys.add("pref_key_1");
|
||||
keys.add("pref_key_3");
|
||||
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
preIndexData.nonIndexableKeys.put(packageName, keys);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData.size()).isEqualTo(NUM_DISPLAY_ENTRIES);
|
||||
assertThat(getEnabledResultCount(indexData)).isEqualTo(NUM_DISPLAY_ENTRIES - 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResourceHeader_rowsMatch() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
final IndexData row = findIndexDataForTitle(indexData, PAGE_TITLE);
|
||||
|
||||
// Header exists
|
||||
assertThat(row).isNotNull();
|
||||
assertThat(row.spaceDelimitedKeywords).isEqualTo("keywords");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResource_checkboxPreference_rowsMatch() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
String checkBoxSummaryOn = "summary_on";
|
||||
String checkBoxKey = "pref_key_5";
|
||||
final IndexData row = findIndexDataForTitle(indexData, TITLE_FIVE);
|
||||
|
||||
assertDisplaySetting(row, TITLE_FIVE, checkBoxSummaryOn, checkBoxKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResource_listPreference_rowsMatch() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
String listSummary = "summary_4";
|
||||
String listKey = "pref_key_4";
|
||||
final IndexData row = findIndexDataForTitle(indexData, TITLE_FOUR);
|
||||
|
||||
assertDisplaySetting(row, TITLE_FOUR, listSummary, listKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddResource_iconAddedFromXml() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
final IndexData row = findIndexDataForTitle(indexData, TITLE_THREE);
|
||||
|
||||
assertThat(row).isNotNull();
|
||||
assertThat(row.iconResId).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResource_sameTitleForSettingAndPage_titleNotInserted() {
|
||||
final SearchIndexableResource resource = getFakeResource(R.xml.about_legal);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
int numEnabled = getEnabledResultCount(indexData);
|
||||
final IndexData nonTitlePref = findIndexDataForKey(indexData, "pref_key_1");
|
||||
|
||||
assertThat(indexData.size()).isEqualTo(NUM_LEGAL_SETTINGS - 1);
|
||||
assertThat(numEnabled).isEqualTo(NUM_LEGAL_SETTINGS - 1);
|
||||
assertThat(nonTitlePref).isNotNull();
|
||||
assertThat(nonTitlePref.enabled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceWithoutXml_shouldNotCrash() {
|
||||
final SearchIndexableResource resource = getFakeResource(0);
|
||||
final PreIndexData preIndexData = new PreIndexData();
|
||||
preIndexData.dataToUpdate.add(resource);
|
||||
|
||||
List<IndexData> indexData = mConverter.convertPreIndexDataToIndexData(preIndexData);
|
||||
|
||||
assertThat(indexData).isEmpty();
|
||||
}
|
||||
|
||||
private void assertDisplaySetting(IndexData row, String title, String summaryOn, String key) {
|
||||
assertThat(row.normalizedTitle).isEqualTo(title);
|
||||
assertThat(row.locale).isEqualTo(localeStr);
|
||||
assertThat(row.updatedSummaryOn).isEqualTo(summaryOn);
|
||||
assertThat(row.spaceDelimitedKeywords).isEqualTo(DISPLAY_SPACE_DELIM_KEYWORDS);
|
||||
assertThat(row.screenTitle).isEqualTo(PAGE_TITLE);
|
||||
assertThat(row.className).isEqualTo(className);
|
||||
assertThat(row.enabled).isEqualTo(true);
|
||||
assertThat(row.key).isEqualTo(key);
|
||||
assertThat(row.payloadType).isEqualTo(0);
|
||||
ResultPayload unmarshalledPayload =
|
||||
ResultPayloadUtils.unmarshall(row.payload, ResultPayload.CREATOR);
|
||||
assertThat(unmarshalledPayload).isInstanceOf(ResultPayload.class);
|
||||
}
|
||||
|
||||
private SearchIndexableRaw getFakeRaw() {
|
||||
return getFakeRaw(localeStr);
|
||||
}
|
||||
|
||||
private SearchIndexableRaw getFakeRaw(String localeStr) {
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||
data.locale = new Locale(localeStr);
|
||||
data.title = title;
|
||||
data.summaryOn = summaryOn;
|
||||
data.summaryOff = summaryOff;
|
||||
data.entries = entries;
|
||||
data.keywords = keywords;
|
||||
data.screenTitle = screenTitle;
|
||||
data.className = className;
|
||||
data.packageName = packageName;
|
||||
data.iconResId = iconResId;
|
||||
data.intentAction = action;
|
||||
data.intentTargetPackage = targetPackage;
|
||||
data.intentTargetClass = targetClass;
|
||||
data.key = key;
|
||||
data.userId = userId;
|
||||
data.enabled = enabled;
|
||||
return data;
|
||||
}
|
||||
|
||||
private SearchIndexableResource getFakeResource(int xml) {
|
||||
SearchIndexableResource sir = new SearchIndexableResource(mContext);
|
||||
sir.xmlResId = xml;
|
||||
sir.className = className;
|
||||
sir.packageName = packageName;
|
||||
sir.iconResId = iconResId;
|
||||
sir.intentAction = action;
|
||||
sir.intentTargetPackage = targetPackage;
|
||||
sir.intentTargetClass = targetClass;
|
||||
sir.enabled = enabled;
|
||||
return sir;
|
||||
}
|
||||
|
||||
private static int getEnabledResultCount(List<IndexData> indexData) {
|
||||
int enabledCount = 0;
|
||||
for (IndexData data : indexData) {
|
||||
if (data.enabled) {
|
||||
enabledCount++;
|
||||
}
|
||||
}
|
||||
return enabledCount;
|
||||
}
|
||||
|
||||
private static IndexData findIndexDataForTitle(List<IndexData> indexData,
|
||||
String indexDataTitle) {
|
||||
for (IndexData row : indexData) {
|
||||
if (TextUtils.equals(row.updatedTitle, indexDataTitle)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IndexData findIndexDataForKey(List<IndexData> indexData, String indexDataKey) {
|
||||
for (IndexData row : indexData) {
|
||||
if (TextUtils.equals(row.key, indexDataKey)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.settings.search.InlineSwitchPayload;
|
||||
import com.android.settings.search.ResultPayload;
|
||||
import com.android.settings.search.ResultPayloadUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class IndexDataTest {
|
||||
|
||||
private IndexData.Builder mBuilder;
|
||||
|
||||
private static final String LOCALE = "en_US";
|
||||
private static final String TITLE = "updated-title";
|
||||
private static final String NORM_TITLE = "updatedtitle";
|
||||
private static final String SUMMARY_ON = "updated-summary-on";
|
||||
private static final String NORM_SUMMARY_ON = "updatedsummaryon";
|
||||
private static final String SUMMARY_OFF = "updated-summary-off";
|
||||
private static final String NORM_SUMMARY_OFF = "updatedsummaryoff";
|
||||
private static final String ENTRIES = "entries";
|
||||
private static final String CLASS_NAME = "class name";
|
||||
private static final String SCREEN_TITLE = "screen title";
|
||||
private static final int ICON_RES_ID = 0xff;
|
||||
private static final String SPACE_DELIMITED_KEYWORDS = "keywords";
|
||||
private static final String INTENT_ACTION = "intent action";
|
||||
private static final String INTENT_TARGET_PACKAGE = "target package";
|
||||
private static final String INTENT_TARGET_CLASS = "target class";
|
||||
private static final boolean ENABLED = true;
|
||||
private static final String KEY = "key";
|
||||
private static final int USER_ID = 1;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mBuilder = createBuilder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullRowBuild_nonNull() {
|
||||
IndexData row = generateRow();
|
||||
assertThat(row).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimitivesBuild_noDataLoss() {
|
||||
IndexData row = generateRow();
|
||||
|
||||
assertThat(row.locale).isEqualTo(LOCALE);
|
||||
assertThat(row.updatedTitle).isEqualTo(TITLE);
|
||||
assertThat(row.normalizedTitle).isEqualTo(NORM_TITLE);
|
||||
assertThat(row.updatedSummaryOn).isEqualTo(SUMMARY_ON);
|
||||
assertThat(row.normalizedSummaryOn).isEqualTo(NORM_SUMMARY_ON);
|
||||
assertThat(row.entries).isEqualTo(ENTRIES);
|
||||
assertThat(row.className).isEqualTo(CLASS_NAME);
|
||||
assertThat(row.screenTitle).isEqualTo(SCREEN_TITLE);
|
||||
assertThat(row.iconResId).isEqualTo(ICON_RES_ID);
|
||||
assertThat(row.spaceDelimitedKeywords).isEqualTo(SPACE_DELIMITED_KEYWORDS);
|
||||
assertThat(row.intentAction).isEqualTo(INTENT_ACTION);
|
||||
assertThat(row.intentTargetClass).isEqualTo(INTENT_TARGET_CLASS);
|
||||
assertThat(row.intentTargetPackage).isEqualTo(INTENT_TARGET_PACKAGE);
|
||||
assertThat(row.enabled).isEqualTo(ENABLED);
|
||||
assertThat(row.userId).isEqualTo(USER_ID);
|
||||
assertThat(row.key).isEqualTo(KEY);
|
||||
assertThat(row.payloadType).isEqualTo(ResultPayload.PayloadType.INTENT);
|
||||
assertThat(row.payload).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericIntent_addedToPayload() {
|
||||
final IndexData row = generateRow();
|
||||
final ResultPayload payload =
|
||||
ResultPayloadUtils.unmarshall(row.payload, ResultPayload.CREATOR);
|
||||
final ComponentName name = payload.getIntent().getComponent();
|
||||
assertThat(name.getClassName()).isEqualTo(INTENT_TARGET_CLASS);
|
||||
assertThat(name.getPackageName()).isEqualTo(INTENT_TARGET_PACKAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRowWithInlinePayload_genericPayloadNotAdded() {
|
||||
final String URI = "test uri";
|
||||
final InlineSwitchPayload payload = new InlineSwitchPayload(URI, 0 /* mSettingSource */,
|
||||
1 /* onValue */, null /* intent */, true /* isDeviceSupported */, 1 /* default */);
|
||||
mBuilder.setPayload(payload);
|
||||
final IndexData row = generateRow();
|
||||
final InlineSwitchPayload unmarshalledPayload =
|
||||
ResultPayloadUtils.unmarshall(row.payload, InlineSwitchPayload.CREATOR);
|
||||
|
||||
assertThat(row.payloadType).isEqualTo(ResultPayload.PayloadType.INLINE_SWITCH);
|
||||
assertThat(unmarshalledPayload.getKey()).isEqualTo(URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRowWithInlinePayload_intentAddedToInlinePayload() {
|
||||
final String URI = "test uri";
|
||||
final ComponentName component =
|
||||
new ComponentName(INTENT_TARGET_PACKAGE, INTENT_TARGET_CLASS);
|
||||
final Intent intent = new Intent();
|
||||
intent.setComponent(component);
|
||||
|
||||
final InlineSwitchPayload payload = new InlineSwitchPayload(URI, 0 /* mSettingSource */,
|
||||
1 /* onValue */, intent, true /* isDeviceSupported */, 1 /* default */);
|
||||
mBuilder.setPayload(payload);
|
||||
final IndexData row = generateRow();
|
||||
final InlineSwitchPayload unmarshalledPayload = ResultPayloadUtils
|
||||
.unmarshall(row.payload, InlineSwitchPayload.CREATOR);
|
||||
final ComponentName name = unmarshalledPayload.getIntent().getComponent();
|
||||
|
||||
assertThat(name.getClassName()).isEqualTo(INTENT_TARGET_CLASS);
|
||||
assertThat(name.getPackageName()).isEqualTo(INTENT_TARGET_PACKAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeJapaneseString() {
|
||||
final String japaneseString = "\u3042\u3077\u308a";
|
||||
final String normalizedJapaneseString = "\u30a2\u30d5\u309a\u30ea";
|
||||
|
||||
String result = IndexData.normalizeJapaneseString(japaneseString);
|
||||
assertThat(result).isEqualTo(normalizedJapaneseString);
|
||||
}
|
||||
|
||||
private IndexData generateRow() {
|
||||
return mBuilder.build(mContext);
|
||||
}
|
||||
|
||||
private IndexData.Builder createBuilder() {
|
||||
mBuilder = new IndexData.Builder();
|
||||
mBuilder.setTitle(TITLE)
|
||||
.setSummaryOn(SUMMARY_ON)
|
||||
.setEntries(ENTRIES)
|
||||
.setClassName(CLASS_NAME)
|
||||
.setScreenTitle(SCREEN_TITLE)
|
||||
.setIconResId(ICON_RES_ID)
|
||||
.setKeywords(SPACE_DELIMITED_KEYWORDS)
|
||||
.setIntentAction(INTENT_ACTION)
|
||||
.setIntentTargetPackage(INTENT_TARGET_PACKAGE)
|
||||
.setIntentTargetClass(INTENT_TARGET_CLASS)
|
||||
.setEnabled(ENABLED)
|
||||
.setKey(KEY)
|
||||
.setUserId(USER_ID);
|
||||
return mBuilder;
|
||||
}
|
||||
}
|
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* 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.search.indexing;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class PreIndexDataCollectorTest {
|
||||
|
||||
private static final String AUTHORITY_ONE = "authority";
|
||||
private static final String PACKAGE_ONE = "com.android.settings";
|
||||
|
||||
@Mock
|
||||
private ContentResolver mResolver;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private PreIndexDataCollector mDataCollector;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
doReturn(mResolver).when(mContext).getContentResolver();
|
||||
|
||||
mDataCollector = spy(new PreIndexDataCollector(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectIndexableData_addsResourceData() {
|
||||
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
|
||||
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
|
||||
|
||||
List<SearchIndexableResource> resources = getFakeResource();
|
||||
doReturn(resources).when(mDataCollector).getIndexablesForXmlResourceUri(
|
||||
any(Context.class), anyString(), any(Uri.class), any(String[].class));
|
||||
|
||||
PreIndexData data =
|
||||
mDataCollector.collectIndexableData(providerInfo, true /* isFullIndex */);
|
||||
|
||||
assertThat(data.dataToUpdate).containsAllIn(resources);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectIndexableData_addsRawData() {
|
||||
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
|
||||
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
|
||||
|
||||
List<SearchIndexableRaw> rawData = getFakeRaw();
|
||||
doReturn(rawData).when(mDataCollector).getIndexablesForRawDataUri(any(Context.class),
|
||||
anyString(), any(Uri.class), any(String[].class));
|
||||
|
||||
|
||||
PreIndexData data =
|
||||
mDataCollector.collectIndexableData(providerInfo, true /* isFullIndex */);
|
||||
|
||||
assertThat(data.dataToUpdate).containsAllIn(rawData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectIndexableData_addsNonIndexables() {
|
||||
final List<ResolveInfo> providerInfo = getDummyResolveInfo();
|
||||
doReturn(true).when(mDataCollector).isWellKnownProvider(any(ResolveInfo.class));
|
||||
|
||||
List<String> niks = getFakeNonIndexables();
|
||||
|
||||
doReturn(niks).when(mDataCollector)
|
||||
.getNonIndexablesKeysFromRemoteProvider(anyString(), anyString());
|
||||
|
||||
PreIndexData data = mDataCollector.collectIndexableData(providerInfo,
|
||||
true /* isFullIndex */);
|
||||
|
||||
assertThat(data.nonIndexableKeys.get(AUTHORITY_ONE)).containsAllIn(niks);
|
||||
}
|
||||
|
||||
private List<ResolveInfo> getDummyResolveInfo() {
|
||||
List<ResolveInfo> infoList = new ArrayList<>();
|
||||
ResolveInfo info = new ResolveInfo();
|
||||
info.providerInfo = new ProviderInfo();
|
||||
info.providerInfo.exported = true;
|
||||
info.providerInfo.authority = AUTHORITY_ONE;
|
||||
info.providerInfo.packageName = PACKAGE_ONE;
|
||||
info.providerInfo.applicationInfo = new ApplicationInfo();
|
||||
infoList.add(info);
|
||||
|
||||
return infoList;
|
||||
}
|
||||
|
||||
private List<SearchIndexableResource> getFakeResource() {
|
||||
List<SearchIndexableResource> resources = new ArrayList<>();
|
||||
final String BLANK = "";
|
||||
|
||||
SearchIndexableResource sir = new SearchIndexableResource(mContext);
|
||||
sir.rank = 0;
|
||||
sir.xmlResId = 0;
|
||||
sir.className = BLANK;
|
||||
sir.packageName = BLANK;
|
||||
sir.iconResId = 0;
|
||||
sir.intentAction = BLANK;
|
||||
sir.intentTargetPackage = BLANK;
|
||||
sir.intentTargetClass = BLANK;
|
||||
sir.enabled = true;
|
||||
resources.add(sir);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private List<SearchIndexableRaw> getFakeRaw() {
|
||||
List<SearchIndexableRaw> rawData = new ArrayList<>();
|
||||
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||
data.title = "bront";
|
||||
data.key = "brint";
|
||||
rawData.add(data);
|
||||
|
||||
return rawData;
|
||||
}
|
||||
|
||||
private List<String> getFakeNonIndexables() {
|
||||
List<String> niks = new ArrayList<>();
|
||||
niks.add("they're");
|
||||
niks.add("good");
|
||||
niks.add("dogs");
|
||||
niks.add("brent");
|
||||
return niks;
|
||||
}
|
||||
}
|
@@ -20,7 +20,6 @@ import android.content.Context;
|
||||
|
||||
import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
|
||||
import com.android.settings.search.IndexDatabaseHelper;
|
||||
import com.android.settings.slices.SlicesDatabaseHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -28,7 +27,6 @@ import java.lang.reflect.Field;
|
||||
public class DatabaseTestUtils {
|
||||
|
||||
public static void clearDb(Context context) {
|
||||
clearSearchDb(context);
|
||||
clearSlicesDb(context);
|
||||
clearAnomalyDb(context);
|
||||
clearAnomalyDbManager();
|
||||
@@ -64,21 +62,6 @@ public class DatabaseTestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void clearSearchDb(Context context) {
|
||||
IndexDatabaseHelper helper = IndexDatabaseHelper.getInstance(context);
|
||||
helper.close();
|
||||
|
||||
Field instance;
|
||||
Class clazz = IndexDatabaseHelper.class;
|
||||
try {
|
||||
instance = clazz.getDeclaredField("sSingleton");
|
||||
instance.setAccessible(true);
|
||||
instance.set(null, null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void clearAnomalyDbManager() {
|
||||
Field instance;
|
||||
Class clazz = BatteryDatabaseManager.class;
|
||||
|
Reference in New Issue
Block a user