Android12 Settings搜索功能屏蔽某个App
Android12 Settings搜索功能屏蔽某个App
1.前言:
之前在Android12Rom定制需求中做了屏蔽Settings某个App的入口,有网络和互联网、已连接的设备、电池和存储,但是在搜索的时候还是能看到入口,所以感觉体验不是很好,于是根据要求屏蔽这几个3App的搜索功能,这里记录一下修改过程。
2.屏蔽存储:
源码路径:package/apps/settings/src/com/android/settings/deviceinfo/storage/StorageDashboardFragment
核心修改:
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.storage_dashboard_fragment) { @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } };
/* * 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.deviceinfo; import android.app.Activity; import android.app.settings.SettingsEnums; import android.app.usage.StorageStatsManager; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.SearchIndexableResource; import android.util.SparseArray; import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController; import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper; import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; import com.android.settings.deviceinfo.storage.UserIconLoader; import com.android.settings.deviceinfo.storage.VolumeSizesLoader; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.deviceinfo.PrivateStorageInfo; import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @SearchIndexable public class StorageDashboardFragment extends DashboardFragment implements LoaderManager.LoaderCallbacks { private static final String TAG = "StorageDashboardFrag"; private static final String SUMMARY_PREF_KEY = "storage_summary"; private static final int STORAGE_JOB_ID = 0; private static final int ICON_JOB_ID = 1; private static final int VOLUME_SIZE_JOB_ID = 2; private VolumeInfo mVolume; private PrivateStorageInfo mStorageInfo; private SparseArray mAppsResult; private CachedStorageValuesHelper mCachedStorageValuesHelper; private StorageItemPreferenceController mPreferenceController; private PrivateVolumeOptionMenuController mOptionMenuController; private List mSecondaryUsers; private boolean mPersonalOnly; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Initialize the storage sizes that we can quickly calc. final Activity activity = getActivity(); StorageManager sm = activity.getSystemService(StorageManager.class); mVolume = Utils.maybeInitializeVolume(sm, getArguments()); mPersonalOnly = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE) == ProfileSelectFragment.ProfileType.PERSONAL; if (mVolume == null) { activity.finish(); return; } initializeOptionsMenu(activity); if (mPersonalOnly) { final Preference summary = getPreferenceScreen().findPreference(SUMMARY_PREF_KEY); if (summary != null) { summary.setVisible(false); } } } @Override public void onAttach(Context context) { super.onAttach(context); use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager( getFragmentManager()); } @VisibleForTesting void initializeOptionsMenu(Activity activity) { mOptionMenuController = new PrivateVolumeOptionMenuController( activity, mVolume, activity.getPackageManager()); getSettingsLifecycle().addObserver(mOptionMenuController); setHasOptionsMenu(true); activity.invalidateOptionsMenu(); } @Override public void onViewCreated(View v, Bundle savedInstanceState) { super.onViewCreated(v, savedInstanceState); initializeCacheProvider(); maybeSetLoading(isQuotaSupported()); final Activity activity = getActivity(); EntityHeaderController.newInstance(activity, this /*fragment*/, null /* header view */) .setRecyclerView(getListView(), getSettingsLifecycle()) .styleActionBar(activity); } @Override public void onResume() { super.onResume(); getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); getLoaderManager() .restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks()); getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks()); } @Override public int getHelpResource() { return R.string.help_url_storage_dashboard; } private void onReceivedSizes() { boolean stopLoading = false; if (mStorageInfo != null) { long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; mPreferenceController.setVolume(mVolume); mPreferenceController.setUsedSize(privateUsedBytes); mPreferenceController.setTotalSize(mStorageInfo.totalBytes); for (int i = 0, size = mSecondaryUsers.size(); i UserIconLoader.loadUserIconsWithContext(getContext())); } @Override public void onLoadFinished( Loader loader, SparseArray data) { mSecondaryUsers .stream() .filter(controller -> controller instanceof UserIconLoader.UserIconHandler) .forEach( controller -> ((UserIconLoader.UserIconHandler) controller) .handleUserIcons(data)); } @Override public void onLoaderReset(Loader loader) { } } public final class VolumeSizeCallbacks implements LoaderManager.LoaderCallbacks { @Override public Loader onCreateLoader(int id, Bundle args) { Context context = getContext(); StorageManager sm = context.getSystemService(StorageManager.class); StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(sm); final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class); return new VolumeSizesLoader(context, smvp, stats, mVolume); } @Override public void onLoaderReset(Loader loader) { } @Override public void onLoadFinished( Loader loader, PrivateStorageInfo privateStorageInfo) { if (privateStorageInfo == null) { getActivity().finish(); return; } mStorageInfo = privateStorageInfo; maybeCacheFreshValues(); onReceivedSizes(); } } }
2.屏蔽已连接的设备:
源码路径:package/apps/settings/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment
关键修改如下:
/** * For Search. */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.connected_devices){ @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } };
/* * 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.connecteddevice; import android.app.settings.SettingsEnums; import android.content.Context; import android.net.Uri; import android.provider.DeviceConfig; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.core.SettingsUIDeviceConfig; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.slices.SlicePreferenceController; import com.android.settingslib.search.SearchIndexable; @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class ConnectedDeviceDashboardFragment extends DashboardFragment { private static final String TAG = "ConnectedDeviceFrag"; @VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list"; @VisibleForTesting static final String KEY_AVAILABLE_DEVICES = "available_device_list"; @Override public int getMetricsCategory() { return SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY; } @Override protected String getLogTag() { return TAG; } @Override protected boolean isParalleledControllers() { return true; } @Override public int getHelpResource() { return R.string.help_url_connected_devices; } @Override protected int getPreferenceScreenResId() { return R.xml.connected_devices; } @Override public void onAttach(Context context) { super.onAttach(context); final boolean nearbyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.BT_NEAR_BY_SUGGESTION_ENABLED, true); use(AvailableMediaDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this); use(PreviouslyConnectedDevicePreferenceController.class).init(this); use(SlicePreferenceController.class).setSliceUri(nearbyEnabled ? Uri.parse(getString(R.string.config_nearby_devices_slice_uri)) : null); } /** * For Search. */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.connected_devices){ @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } }; }
3.屏蔽网络和互联网:
源码路径:package/apps/settings/src/com/android/settings/network/NetworkDashboardFragment
关键修改方法如下:
在getNonIndexableKeysFromProvider()方法添加过滤
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.network_and_internet) { @Override public List createPreferenceControllers(Context context) { return buildPreferenceControllers(context, null /* lifecycle */, null /* metricsFeatureProvider */, null /* fragment */, null /* mobilePlanHost */); } @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } };
/* * 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.network; import static com.android.settings.network.MobilePlanPreferenceController.MANAGE_MOBILE_PLAN_DIALOG_ID; import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.wifi.WifiMasterSwitchPreferenceController; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; import java.util.ArrayList; import java.util.List; @SearchIndexable public class NetworkDashboardFragment extends DashboardFragment implements MobilePlanPreferenceHost { private static final String TAG = "NetworkDashboardFrag"; @Override public int getMetricsCategory() { return SettingsEnums.SETTINGS_NETWORK_CATEGORY; } @Override protected String getLogTag() { return TAG; } @Override protected int getPreferenceScreenResId() { return R.xml.network_and_internet; } @Override public void onAttach(Context context) { super.onAttach(context); use(MultiNetworkHeaderController.class).init(getSettingsLifecycle()); use(AirplaneModePreferenceController.class).setFragment(this); getSettingsLifecycle().addObserver(use(AllInOneTetherPreferenceController.class)); } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); use(AllInOneTetherPreferenceController.class).initEnabler(getSettingsLifecycle()); } @Override public int getHelpResource() { return R.string.help_url_network_dashboard; } @Override protected List createPreferenceControllers(Context context) { return buildPreferenceControllers(context, getSettingsLifecycle(), mMetricsFeatureProvider, this /* fragment */, this /* mobilePlanHost */); } @Override protected boolean isParalleledControllers() { return true; } private static List buildPreferenceControllers(Context context, Lifecycle lifecycle, MetricsFeatureProvider metricsFeatureProvider, Fragment fragment, MobilePlanPreferenceHost mobilePlanHost) { final MobilePlanPreferenceController mobilePlanPreferenceController = new MobilePlanPreferenceController(context, mobilePlanHost); final WifiMasterSwitchPreferenceController wifiPreferenceController = new WifiMasterSwitchPreferenceController(context, metricsFeatureProvider); final VpnPreferenceController vpnPreferenceController = new VpnPreferenceController(context); final PrivateDnsPreferenceController privateDnsPreferenceController = new PrivateDnsPreferenceController(context); if (lifecycle != null) { lifecycle.addObserver(mobilePlanPreferenceController); lifecycle.addObserver(wifiPreferenceController); lifecycle.addObserver(vpnPreferenceController); lifecycle.addObserver(privateDnsPreferenceController); } final List controllers = new ArrayList(); controllers.add(new MobileNetworkSummaryController(context, lifecycle)); controllers.add(new TetherPreferenceController(context, lifecycle)); controllers.add(vpnPreferenceController); controllers.add(new ProxyPreferenceController(context)); controllers.add(mobilePlanPreferenceController); controllers.add(wifiPreferenceController); controllers.add(privateDnsPreferenceController); return controllers; } @Override public void showMobilePlanMessageDialog() { showDialog(MANAGE_MOBILE_PLAN_DIALOG_ID); } @Override public Dialog onCreateDialog(int dialogId) { Log.d(TAG, "onCreateDialog: dialogId=" + dialogId); switch (dialogId) { case MANAGE_MOBILE_PLAN_DIALOG_ID: final MobilePlanPreferenceController controller = use(MobilePlanPreferenceController.class); return new AlertDialog.Builder(getActivity()) .setMessage(controller.getMobilePlanDialogMessage()) .setCancelable(false) .setPositiveButton(com.android.internal.R.string.ok, (dialog, id) -> controller.setMobilePlanDialogMessage(null)) .create(); } return super.onCreateDialog(dialogId); } @Override public int getDialogMetricsCategory(int dialogId) { if (MANAGE_MOBILE_PLAN_DIALOG_ID == dialogId) { return SettingsEnums.DIALOG_MANAGE_MOBILE_PLAN; } return 0; } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.network_and_internet) { @Override public List createPreferenceControllers(Context context) { return buildPreferenceControllers(context, null /* lifecycle */, null /* metricsFeatureProvider */, null /* fragment */, null /* mobilePlanHost */); } @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } }; }
4.屏蔽电池:
源码路径:package/apps/settings/src/com/android/settings/fuelgauge/PowerUsageSummary
关键修改方法:
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.power_usage_summary){ @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } };
/* * Copyright (C) 2009 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.fuelgauge; import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; import android.app.settings.SettingsEnums; import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.Settings.Global; import android.text.format.Formatter; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnLongClickListener; import android.widget.TextView; import androidx.annotation.VisibleForTesting; import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager.LoaderCallbacks; import androidx.loader.content.Loader; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.fuelgauge.EstimateKt; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.utils.PowerUtil; import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.LayoutPreference; import java.util.List; /** * Displays a list of apps and subsystems that consume power, ordered by how much power was consumed * since the last time it was unplugged. */ @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class PowerUsageSummary extends PowerUsageBase implements OnLongClickListener, BatteryTipPreferenceController.BatteryTipListener { static final String TAG = "PowerUsageSummary"; private static final String KEY_BATTERY_HEADER = "battery_header"; private static final String KEY_SCREEN_USAGE = "screen_usage"; private static final String KEY_TIME_SINCE_LAST_FULL_CHARGE = "last_full_charge"; @VisibleForTesting static final int BATTERY_INFO_LOADER = 1; @VisibleForTesting static final int BATTERY_TIP_LOADER = 2; @VisibleForTesting static final int MENU_ADVANCED_BATTERY = Menu.FIRST + 1; public static final int DEBUG_INFO_LOADER = 3; @VisibleForTesting PowerGaugePreference mScreenUsagePref; @VisibleForTesting PowerGaugePreference mLastFullChargePref; @VisibleForTesting PowerUsageFeatureProvider mPowerFeatureProvider; @VisibleForTesting BatteryUtils mBatteryUtils; @VisibleForTesting LayoutPreference mBatteryLayoutPref; @VisibleForTesting BatteryInfo mBatteryInfo; @VisibleForTesting BatteryHeaderPreferenceController mBatteryHeaderPreferenceController; @VisibleForTesting boolean mNeedUpdateBatteryTip; @VisibleForTesting BatteryTipPreferenceController mBatteryTipPreferenceController; @VisibleForTesting final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange, Uri uri) { restartBatteryInfoLoader(); } }; @VisibleForTesting LoaderManager.LoaderCallbacks mBatteryInfoLoaderCallbacks = new LoaderManager.LoaderCallbacks() { @Override public Loader onCreateLoader(int i, Bundle bundle) { return new BatteryInfoLoader(getContext(), mStatsHelper); } @Override public void onLoadFinished(Loader loader, BatteryInfo batteryInfo) { mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo); mBatteryInfo = batteryInfo; updateLastFullChargePreference(); } @Override public void onLoaderReset(Loader loader) { // do nothing } }; LoaderManager.LoaderCallbacks mBatteryInfoDebugLoaderCallbacks = new LoaderCallbacks() { @Override public Loader onCreateLoader(int i, Bundle bundle) { return new DebugEstimatesLoader(getContext(), mStatsHelper); } @Override public void onLoadFinished(Loader loader, List batteryInfos) { updateViews(batteryInfos); } @Override public void onLoaderReset(Loader loader) { } }; protected void updateViews(List batteryInfos) { final BatteryMeterView batteryView = mBatteryLayoutPref .findViewById(R.id.battery_header_icon); final TextView percentRemaining = mBatteryLayoutPref.findViewById(R.id.battery_percent); final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1); BatteryInfo oldInfo = batteryInfos.get(0); BatteryInfo newInfo = batteryInfos.get(1); percentRemaining.setText(Utils.formatPercentage(oldInfo.batteryLevel)); // set the text to the old estimate (copied from battery info). Note that this // can sometimes say 0 time remaining because battery stats requires the phone // be unplugged for a period of time before being willing ot make an estimate. final String OldEstimateString = mPowerFeatureProvider.getOldEstimateDebugString( Formatter.formatShortElapsedTime(getContext(), PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))); final String NewEstimateString = mPowerFeatureProvider.getEnhancedEstimateDebugString( Formatter.formatShortElapsedTime(getContext(), PowerUtil.convertUsToMs(newInfo.remainingTimeUs))); summary1.setText(OldEstimateString + "\n" + NewEstimateString); batteryView.setBatteryLevel(oldInfo.batteryLevel); batteryView.setCharging(!oldInfo.discharging); } private LoaderManager.LoaderCallbacks mBatteryTipsCallbacks = new LoaderManager.LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { return new BatteryTipLoader(getContext(), mStatsHelper); } @Override public void onLoadFinished(Loader loader, List data) { mBatteryTipPreferenceController.updateBatteryTips(data); } @Override public void onLoaderReset(Loader loader) { } }; @Override public void onAttach(Context context) { super.onAttach(context); final SettingsActivity activity = (SettingsActivity) getActivity(); mBatteryHeaderPreferenceController = use(BatteryHeaderPreferenceController.class); mBatteryHeaderPreferenceController.setActivity(activity); mBatteryHeaderPreferenceController.setFragment(this); mBatteryHeaderPreferenceController.setLifecycle(getSettingsLifecycle()); mBatteryTipPreferenceController = use(BatteryTipPreferenceController.class); mBatteryTipPreferenceController.setActivity(activity); mBatteryTipPreferenceController.setFragment(this); mBatteryTipPreferenceController.setBatteryTipListener(this::onBatteryTipHandled); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setAnimationAllowed(true); initFeatureProvider(); mBatteryLayoutPref = (LayoutPreference) findPreference(KEY_BATTERY_HEADER); mScreenUsagePref = (PowerGaugePreference) findPreference(KEY_SCREEN_USAGE); mLastFullChargePref = (PowerGaugePreference) findPreference( KEY_TIME_SINCE_LAST_FULL_CHARGE); mBatteryUtils = BatteryUtils.getInstance(getContext()); if (Utils.isBatteryPresent(getContext())) { restartBatteryInfoLoader(); } mBatteryTipPreferenceController.restoreInstanceState(icicle); updateBatteryTipFlag(icicle); } @Override public void onResume() { super.onResume(); getContentResolver().registerContentObserver( Global.getUriFor(Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), false, mSettingsObserver); } @Override public void onPause() { getContentResolver().unregisterContentObserver(mSettingsObserver); super.onPause(); } @Override public int getMetricsCategory() { return SettingsEnums.FUELGAUGE_POWER_USAGE_SUMMARY_V2; } @Override protected String getLogTag() { return TAG; } @Override protected int getPreferenceScreenResId() { return R.xml.power_usage_summary; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.add(Menu.NONE, MENU_ADVANCED_BATTERY, Menu.NONE, R.string.advanced_battery_title); super.onCreateOptionsMenu(menu, inflater); } @Override public int getHelpResource() { return R.string.help_url_battery; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ADVANCED_BATTERY: new SubSettingLauncher(getContext()) .setDestination(PowerUsageAdvanced.class.getName()) .setSourceMetricsCategory(getMetricsCategory()) .setTitleRes(R.string.advanced_battery_title) .launch(); return true; default: return super.onOptionsItemSelected(item); } } protected void refreshUi(@BatteryUpdateType int refreshType) { final Context context = getContext(); if (context == null) { return; } // Skip refreshing UI if battery is not present. if (!mIsBatteryPresent) { return; } // Skip BatteryTipLoader if device is rotated or only battery level change if (mNeedUpdateBatteryTip && refreshType != BatteryUpdateType.BATTERY_LEVEL) { restartBatteryTipLoader(); } else { mNeedUpdateBatteryTip = true; } // reload BatteryInfo and updateUI restartBatteryInfoLoader(); updateLastFullChargePreference(); mScreenUsagePref.setSubtitle(StringUtil.formatElapsedTime(getContext(), mBatteryUtils.calculateScreenUsageTime(mStatsHelper), false)); } @VisibleForTesting void restartBatteryTipLoader() { getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks); } @VisibleForTesting void setBatteryLayoutPreference(LayoutPreference layoutPreference) { mBatteryLayoutPref = layoutPreference; } @VisibleForTesting void updateLastFullChargePreference() { if (mBatteryInfo != null && mBatteryInfo.averageTimeToDischarge != EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN) { mLastFullChargePref.setTitle(R.string.battery_full_charge_last); mLastFullChargePref.setSubtitle( StringUtil.formatElapsedTime(getContext(), mBatteryInfo.averageTimeToDischarge, false /* withSeconds */)); } else { final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper, System.currentTimeMillis()); mLastFullChargePref.setTitle(R.string.battery_last_full_charge); mLastFullChargePref.setSubtitle( StringUtil.formatRelativeTime(getContext(), lastFullChargeTime, false /* withSeconds */)); } } @VisibleForTesting void showBothEstimates() { final Context context = getContext(); if (context == null || !mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(context)) { return; } getLoaderManager().restartLoader(DEBUG_INFO_LOADER, Bundle.EMPTY, mBatteryInfoDebugLoaderCallbacks); } @VisibleForTesting void initFeatureProvider() { final Context context = getContext(); mPowerFeatureProvider = FeatureFactory.getFactory(context) .getPowerUsageFeatureProvider(context); } @VisibleForTesting void restartBatteryInfoLoader() { if (getContext() == null) { return; } // Skip restartBatteryInfoLoader if battery is not present. if (!mIsBatteryPresent) { return; } getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY, mBatteryInfoLoaderCallbacks); if (mPowerFeatureProvider.isEstimateDebugEnabled()) { // Set long click action for summary to show debug info View header = mBatteryLayoutPref.findViewById(R.id.summary1); header.setOnLongClickListener(this); } } @VisibleForTesting void updateBatteryTipFlag(Bundle icicle) { mNeedUpdateBatteryTip = icicle == null || mBatteryTipPreferenceController.needUpdate(); } @Override public boolean onLongClick(View view) { showBothEstimates(); view.setOnLongClickListener(null); return true; } @Override protected void restartBatteryStatsLoader(@BatteryUpdateType int refreshType) { super.restartBatteryStatsLoader(refreshType); // Update battery header if battery is present. if (mIsBatteryPresent) { mBatteryHeaderPreferenceController.quickUpdateHeaderPreference(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mBatteryTipPreferenceController.saveInstanceState(outState); } @Override public void onBatteryTipHandled(BatteryTip batteryTip) { restartBatteryTipLoader(); } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.power_usage_summary){ @Override public boolean isPageSearchEnabled(Context context) { return false; // 禁用搜索 } }; }
5.屏蔽入口:
源码路径:package/apps/settings/src/com/android/settings/DashboardFragmentRegistry
核心修改方法:注销以上几个App的入口:
PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap(); PARENT_TO_CATEGORY_KEY_MAP.put(TopLevelSettings.class.getName(), CategoryKey.CATEGORY_HOMEPAGE); /* PARENT_TO_CATEGORY_KEY_MAP.put( NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK); PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_CONNECT); PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_DEVICE);*/ PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(), CategoryKey.CATEGORY_APPS); /* PARENT_TO_CATEGORY_KEY_MAP.put(PowerUsageSummary.class.getName(), CategoryKey.CATEGORY_BATTERY);*/ PARENT_TO_CATEGORY_KEY_MAP.put(DisplaySettings.class.getName(), CategoryKey.CATEGORY_DISPLAY); PARENT_TO_CATEGORY_KEY_MAP.put(SoundSettings.class.getName(), CategoryKey.CATEGORY_SOUND); /* PARENT_TO_CATEGORY_KEY_MAP.put(StorageDashboardFragment.class.getName(), CategoryKey.CATEGORY_STORAGE);*/
/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.dashboard; import android.util.ArrayMap; import com.android.settings.DisplaySettings; import com.android.settings.LegalSettings; import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.accounts.AccountDetailDashboardFragment; import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.development.DevelopmentSettingsDashboardFragment; import com.android.settings.deviceinfo.StorageDashboardFragment; import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.display.NightDisplaySettings; import com.android.settings.enterprise.EnterprisePrivacySettings; import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.fuelgauge.SmartBatterySettings; import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings; import com.android.settings.gestures.GestureSettings; import com.android.settings.homepage.TopLevelSettings; import com.android.settings.language.LanguageAndInputSettings; import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.SoundSettings; import com.android.settings.notification.zen.ZenModeSettings; import com.android.settings.privacy.PrivacyDashboardFragment; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.SecuritySettings; import com.android.settings.system.SystemDashboardFragment; import com.android.settingslib.drawer.CategoryKey; import java.util.Map; /** * A registry to keep track of which page hosts which category. */ public class DashboardFragmentRegistry { /** * Map from parent fragment to category key. The parent fragment hosts child with * category_key. */ public static final Map PARENT_TO_CATEGORY_KEY_MAP; /** * Map from category_key to parent. This is a helper to look up which fragment hosts the * category_key. */ public static final Map CATEGORY_KEY_TO_PARENT_MAP; static { PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap(); PARENT_TO_CATEGORY_KEY_MAP.put(TopLevelSettings.class.getName(), CategoryKey.CATEGORY_HOMEPAGE); PARENT_TO_CATEGORY_KEY_MAP.put( NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK); PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_CONNECT); PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_DEVICE); PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(), CategoryKey.CATEGORY_APPS); PARENT_TO_CATEGORY_KEY_MAP.put(PowerUsageSummary.class.getName(), CategoryKey.CATEGORY_BATTERY); PARENT_TO_CATEGORY_KEY_MAP.put(DisplaySettings.class.getName(), CategoryKey.CATEGORY_DISPLAY); PARENT_TO_CATEGORY_KEY_MAP.put(SoundSettings.class.getName(), CategoryKey.CATEGORY_SOUND); PARENT_TO_CATEGORY_KEY_MAP.put(StorageDashboardFragment.class.getName(), CategoryKey.CATEGORY_STORAGE); PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettings.class.getName(), CategoryKey.CATEGORY_SECURITY); PARENT_TO_CATEGORY_KEY_MAP.put(AccountDetailDashboardFragment.class.getName(), CategoryKey.CATEGORY_ACCOUNT_DETAIL); PARENT_TO_CATEGORY_KEY_MAP.put(AccountDashboardFragment.class.getName(), CategoryKey.CATEGORY_ACCOUNT); PARENT_TO_CATEGORY_KEY_MAP.put( SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM); PARENT_TO_CATEGORY_KEY_MAP.put(LanguageAndInputSettings.class.getName(), CategoryKey.CATEGORY_SYSTEM_LANGUAGE); PARENT_TO_CATEGORY_KEY_MAP.put(DevelopmentSettingsDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT); PARENT_TO_CATEGORY_KEY_MAP.put(ConfigureNotificationSettings.class.getName(), CategoryKey.CATEGORY_NOTIFICATIONS); PARENT_TO_CATEGORY_KEY_MAP.put(LockscreenDashboardFragment.class.getName(), CategoryKey.CATEGORY_SECURITY_LOCKSCREEN); PARENT_TO_CATEGORY_KEY_MAP.put(ZenModeSettings.class.getName(), CategoryKey.CATEGORY_DO_NOT_DISTURB); PARENT_TO_CATEGORY_KEY_MAP.put(GestureSettings.class.getName(), CategoryKey.CATEGORY_GESTURES); PARENT_TO_CATEGORY_KEY_MAP.put(NightDisplaySettings.class.getName(), CategoryKey.CATEGORY_NIGHT_DISPLAY); PARENT_TO_CATEGORY_KEY_MAP.put(PrivacyDashboardFragment.class.getName(), CategoryKey.CATEGORY_PRIVACY); PARENT_TO_CATEGORY_KEY_MAP.put(EnterprisePrivacySettings.class.getName(), CategoryKey.CATEGORY_ENTERPRISE_PRIVACY); PARENT_TO_CATEGORY_KEY_MAP.put(LegalSettings.class.getName(), CategoryKey.CATEGORY_ABOUT_LEGAL); PARENT_TO_CATEGORY_KEY_MAP.put(MyDeviceInfoFragment.class.getName(), CategoryKey.CATEGORY_MY_DEVICE_INFO); PARENT_TO_CATEGORY_KEY_MAP.put(BatterySaverSettings.class.getName(), CategoryKey.CATEGORY_BATTERY_SAVER_SETTINGS); PARENT_TO_CATEGORY_KEY_MAP.put(SmartBatterySettings.class.getName(), CategoryKey.CATEGORY_SMART_BATTERY_SETTINGS); CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap(PARENT_TO_CATEGORY_KEY_MAP.size()); for (Map.Entry parentToKey : PARENT_TO_CATEGORY_KEY_MAP.entrySet()) { CATEGORY_KEY_TO_PARENT_MAP.put(parentToKey.getValue(), parentToKey.getKey()); } // For injection index, redirect CATEGORY_ACCOUNT_DETAIL to AccountDashboardFragment. CATEGORY_KEY_TO_PARENT_MAP.put(CategoryKey.CATEGORY_ACCOUNT_DETAIL, AccountDashboardFragment.class.getName()); } }
6.修改搜索Provider:
源码路径:package/apps/settings/src/com/android/settings/SettingsSearchIndexablesProvider
关键修改如下:
在getNonIndexableKeysFromProvider()方法添加如下过滤:
nonIndexableKeys.add(CategoryKey.CATEGORY_NETWORK); nonIndexableKeys.add(CategoryKey.CATEGORY_CONNECT); nonIndexableKeys.add(CategoryKey.CATEGORY_DEVICE); nonIndexableKeys.add(CategoryKey.CATEGORY_BATTERY); nonIndexableKeys.add(CategoryKey.CATEGORY_STORAGE);
/* * 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 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_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_RANK; import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID; import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS; import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS; import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS; import static android.provider.SearchIndexablesContract.SITE_MAP_COLUMNS; import static android.provider.SearchIndexablesContract.SLICE_URI_PAIRS_COLUMNS; import static com.android.settings.dashboard.DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.provider.SearchIndexableResource; import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesProvider; import android.provider.SettingsSlicesContract; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import androidx.annotation.Nullable; import androidx.slice.SliceViewManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.SettingsSliceProvider; import com.android.settingslib.drawer.ActivityTile; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.SearchIndexableData; import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.drawer.CategoryKey; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { public static final boolean DEBUG = false; /** * Flag for a system property which checks if we should crash if there are issues in the * indexing pipeline. */ public static final String SYSPROP_CRASH_ON_ERROR = "debug.com.android.settings.search.crash_on_error"; private static final String TAG = "SettingsSearchProvider"; private static final Collection INVALID_KEYS; static { INVALID_KEYS = new ArraySet(); INVALID_KEYS.add(null); INVALID_KEYS.add(""); } @Override public boolean onCreate() { return true; } @Override public Cursor queryXmlResources(String[] projection) { final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS); final List resources = getSearchIndexableResourcesFromProvider(getContext()); for (SearchIndexableResource val : resources) { final Object[] ref = new Object[INDEXABLES_XML_RES_COLUMNS.length]; ref[COLUMN_INDEX_XML_RES_RANK] = val.rank; ref[COLUMN_INDEX_XML_RES_RESID] = val.xmlResId; ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = val.className; ref[COLUMN_INDEX_XML_RES_ICON_RESID] = val.iconResId; ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = val.intentAction; ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = val.intentTargetPackage; ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = null; // intent target class cursor.addRow(ref); } return cursor; } /** * Gets a Cursor of RawData. We use those data in search indexing time */ @Override public Cursor queryRawData(String[] projection) { final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); final List raws = getSearchIndexableRawFromProvider(getContext()); for (SearchIndexableRaw val : raws) { cursor.addRow(createIndexableRawColumnObjects(val)); } return cursor; } /** * Gets a combined list non-indexable keys that come from providers inside of settings. * The non-indexable keys are used in Settings search at both index and update time to verify * the validity of results in the database. */ @Override public Cursor queryNonIndexableKeys(String[] projection) { final MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS); final List nonIndexableKeys = getNonIndexableKeysFromProvider(getContext()); for (String nik : nonIndexableKeys) { final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length]; ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik; cursor.addRow(ref); } return cursor; } /** * Gets a Cursor of dynamic Raw data similar to queryRawData. We use those data in search query * time */ @Nullable @Override public Cursor queryDynamicRawData(String[] projection) { final Context context = getContext(); final List rawList = new ArrayList(); rawList.addAll(getDynamicSearchIndexableRawFromProvider(context)); rawList.addAll(getInjectionIndexableRawData(context)); final MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS); for (SearchIndexableRaw raw : rawList) { cursor.addRow(createIndexableRawColumnObjects(raw)); } return cursor; } @Override public Cursor querySiteMapPairs() { final MatrixCursor cursor = new MatrixCursor(SITE_MAP_COLUMNS); final Context context = getContext(); // Loop through all IA categories and pages and build additional SiteMapPairs final List categories = FeatureFactory.getFactory(context) .getDashboardFeatureProvider(context).getAllCategories(); for (DashboardCategory category : categories) { // Use the category key to look up parent (which page hosts this key) final String parentClass = CATEGORY_KEY_TO_PARENT_MAP.get(category.key); if (parentClass == null) { continue; } // Build parent-child class pairs for all children listed under this key. for (Tile tile : category.getTiles()) { String childClass = null; CharSequence childTitle = ""; if (tile.getMetaData() != null) { childClass = tile.getMetaData().getString( SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); } if (childClass == null) { childClass = tile.getComponentName(); childTitle = tile.getTitle(getContext()); } if (childClass == null) { continue; } cursor.newRow() .add(SearchIndexablesContract.SiteMapColumns.PARENT_CLASS, parentClass) .add(SearchIndexablesContract.SiteMapColumns.CHILD_CLASS, childClass) .add(SearchIndexablesContract.SiteMapColumns.CHILD_TITLE, childTitle); } } // Loop through custom site map registry to build additional SiteMapPairs for (String childClass : CustomSiteMapRegistry.CUSTOM_SITE_MAP.keySet()) { final String parentClass = CustomSiteMapRegistry.CUSTOM_SITE_MAP.get(childClass); cursor.newRow() .add(SearchIndexablesContract.SiteMapColumns.PARENT_CLASS, parentClass) .add(SearchIndexablesContract.SiteMapColumns.CHILD_CLASS, childClass); } // Done. return cursor; } @Override public Cursor querySliceUriPairs() { final SliceViewManager manager = SliceViewManager.getInstance(getContext()); final MatrixCursor cursor = new MatrixCursor(SLICE_URI_PAIRS_COLUMNS); final String queryUri = getContext().getString(R.string.config_non_public_slice_query_uri); final Uri baseUri = !TextUtils.isEmpty(queryUri) ? Uri.parse(queryUri) : new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .build(); final Uri platformBaseUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .build(); final Collection sliceUris = manager.getSliceDescendants(baseUri); sliceUris.addAll(manager.getSliceDescendants(platformBaseUri)); for (Uri uri : sliceUris) { cursor.newRow() .add(SearchIndexablesContract.SliceUriPairColumns.KEY, uri.getLastPathSegment()) .add(SearchIndexablesContract.SliceUriPairColumns.SLICE_URI, uri); } return cursor; } private List getNonIndexableKeysFromProvider(Context context) { final Collection bundles = FeatureFactory.getFactory(context) .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); final List nonIndexableKeys = new ArrayList(); nonIndexableKeys.add(CategoryKey.CATEGORY_NETWORK); nonIndexableKeys.add(CategoryKey.CATEGORY_CONNECT); nonIndexableKeys.add(CategoryKey.CATEGORY_DEVICE); nonIndexableKeys.add(CategoryKey.CATEGORY_BATTERY); nonIndexableKeys.add(CategoryKey.CATEGORY_STORAGE); for (SearchIndexableData bundle : bundles) { final long startTime = System.currentTimeMillis(); Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); List providerNonIndexableKeys; try { providerNonIndexableKeys = provider.getNonIndexableKeys(context); } catch (Exception e) { // Catch a generic crash. In the absence of the catch, the background thread will // silently fail anyway, so we aren't losing information by catching the exception. // We crash when the system property exists so that we can test if crashes need to // be fixed. // The gain is that if there is a crash in a specific controller, we don't lose all // non-indexable keys, but we can still find specific crashes in development. if (System.getProperty(SYSPROP_CRASH_ON_ERROR) != null) { throw new RuntimeException(e); } Log.e(TAG, "Error trying to get non-indexable keys from: " + bundle.getTargetClass().getName(), e); continue; } if (providerNonIndexableKeys == null || providerNonIndexableKeys.isEmpty()) { if (DEBUG) { final long totalTime = System.currentTimeMillis() - startTime; Log.d(TAG, "No indexable, total time " + totalTime); } continue; } if (providerNonIndexableKeys.removeAll(INVALID_KEYS)) { Log.v(TAG, provider + " tried to add an empty non-indexable key"); } if (DEBUG) { final long totalTime = System.currentTimeMillis() - startTime; Log.d(TAG, "Non-indexables " + providerNonIndexableKeys.size() + ", total time " + totalTime); } nonIndexableKeys.addAll(providerNonIndexableKeys); } return nonIndexableKeys; } private List getSearchIndexableResourcesFromProvider(Context context) { final Collection bundles = FeatureFactory.getFactory(context) .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); List resourceList = new ArrayList(); for (SearchIndexableData bundle : bundles) { Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final List resList = provider.getXmlResourcesToIndex(context, true); if (resList == null) { continue; } for (SearchIndexableResource item : resList) { item.className = TextUtils.isEmpty(item.className) ? bundle.getTargetClass().getName() : item.className; } resourceList.addAll(resList); } return resourceList; } private List getSearchIndexableRawFromProvider(Context context) { final Collection bundles = FeatureFactory.getFactory(context) .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); final List rawList = new ArrayList(); for (SearchIndexableData bundle : bundles) { Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final List providerRaws = provider.getRawDataToIndex(context, true /* enabled */); if (providerRaws == null) { continue; } for (SearchIndexableRaw raw : providerRaws) { // The classname and intent information comes from the PreIndexData // This will be more clear when provider conversion is done at PreIndex time. raw.className = bundle.getTargetClass().getName(); } rawList.addAll(providerRaws); } return rawList; } private List getDynamicSearchIndexableRawFromProvider(Context context) { final Collection bundles = FeatureFactory.getFactory(context) .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues(); final List rawList = new ArrayList(); for (SearchIndexableData bundle : bundles) { final Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider(); final List providerRaws = provider.getDynamicRawDataToIndex(context, true /* enabled */); if (providerRaws == null) { continue; } for (SearchIndexableRaw raw : providerRaws) { // The classname and intent information comes from the PreIndexData // This will be more clear when provider conversion is done at PreIndex time. raw.className = bundle.getTargetClass().getName(); } rawList.addAll(providerRaws); } return rawList; } private List getInjectionIndexableRawData(Context context) { final DashboardFeatureProvider dashboardFeatureProvider = FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); final List rawList = new ArrayList(); final String currentPackageName = context.getPackageName(); for (DashboardCategory category : dashboardFeatureProvider.getAllCategories()) { // add start 屏蔽某些App if (category.key.equals(CategoryKey.CATEGORY_NETWORK) || category.key.equals(CategoryKey.CATEGORY_CONNECT) || category.key.equals(CategoryKey.CATEGORY_DEVICE) || category.key.equals(CategoryKey.CATEGORY_BATTERY) || category.key.equals(CategoryKey.CATEGORY_STORAGE)) { continue; } //add end for (Tile tile : category.getTiles()) { if (!isEligibleForIndexing(currentPackageName, tile)) { continue; } final SearchIndexableRaw raw = new SearchIndexableRaw(context); final CharSequence title = tile.getTitle(context); raw.title = TextUtils.isEmpty(title) ? null : title.toString(); if (TextUtils.isEmpty(raw.title)) { continue; } raw.key = dashboardFeatureProvider.getDashboardKeyForTile(tile); final CharSequence summary = tile.getSummary(context); raw.summaryOn = TextUtils.isEmpty(summary) ? null : summary.toString(); raw.summaryOff = raw.summaryOn; raw.className = CATEGORY_KEY_TO_PARENT_MAP.get(tile.getCategory()); rawList.add(raw); } } return rawList; } @VisibleForTesting boolean isEligibleForIndexing(String packageName, Tile tile) { // 屏蔽特定 Tile if (tile.getCategory().equals(CategoryKey.CATEGORY_NETWORK) || tile.getCategory().equals(CategoryKey.CATEGORY_CONNECT) || tile.getCategory().equals(CategoryKey.CATEGORY_DEVICE) || tile.getCategory().equals(CategoryKey.CATEGORY_BATTERY) || tile.getCategory().equals(CategoryKey.CATEGORY_STORAGE)) { return false; } if (TextUtils.equals(packageName, tile.getPackageName()) && tile instanceof ActivityTile) { // Skip Settings injected items because they should be indexed in the sub-pages. return false; } if (TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { // Skip homepage injected items since we would like to index their target activity. return false; } return true; } private static Object[] createIndexableRawColumnObjects(SearchIndexableRaw raw) { final Object[] ref = new Object[INDEXABLES_RAW_COLUMNS.length]; ref[COLUMN_INDEX_RAW_TITLE] = raw.title; ref[COLUMN_INDEX_RAW_SUMMARY_ON] = raw.summaryOn; ref[COLUMN_INDEX_RAW_SUMMARY_OFF] = raw.summaryOff; ref[COLUMN_INDEX_RAW_ENTRIES] = raw.entries; ref[COLUMN_INDEX_RAW_KEYWORDS] = raw.keywords; ref[COLUMN_INDEX_RAW_SCREEN_TITLE] = raw.screenTitle; ref[COLUMN_INDEX_RAW_CLASS_NAME] = raw.className; ref[COLUMN_INDEX_RAW_ICON_RESID] = raw.iconResId; ref[COLUMN_INDEX_RAW_INTENT_ACTION] = raw.intentAction; ref[COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE] = raw.intentTargetPackage; ref[COLUMN_INDEX_RAW_INTENT_TARGET_CLASS] = raw.intentTargetClass; ref[COLUMN_INDEX_RAW_KEY] = raw.key; ref[COLUMN_INDEX_RAW_USER_ID] = raw.userId; return ref; } }
7.修改getInjectionIndexableRawData()方法:
private List getInjectionIndexableRawData(Context context) { final DashboardFeatureProvider dashboardFeatureProvider = FeatureFactory.getFactory(context).getDashboardFeatureProvider(context); final List rawList = new ArrayList(); final String currentPackageName = context.getPackageName(); for (DashboardCategory category : dashboardFeatureProvider.getAllCategories()) { // add start 屏蔽某些App if (category.key.equals(CategoryKey.CATEGORY_NETWORK) || category.key.equals(CategoryKey.CATEGORY_CONNECT) || category.key.equals(CategoryKey.CATEGORY_DEVICE) || category.key.equals(CategoryKey.CATEGORY_BATTERY) || category.key.equals(CategoryKey.CATEGORY_STORAGE)) { continue; } //add end for (Tile tile : category.getTiles()) { if (!isEligibleForIndexing(currentPackageName, tile)) { continue; } final SearchIndexableRaw raw = new SearchIndexableRaw(context); final CharSequence title = tile.getTitle(context); raw.title = TextUtils.isEmpty(title) ? null : title.toString(); if (TextUtils.isEmpty(raw.title)) { continue; } raw.key = dashboardFeatureProvider.getDashboardKeyForTile(tile); final CharSequence summary = tile.getSummary(context); raw.summaryOn = TextUtils.isEmpty(summary) ? null : summary.toString(); raw.summaryOff = raw.summaryOn; raw.className = CATEGORY_KEY_TO_PARENT_MAP.get(tile.getCategory()); rawList.add(raw); } } return rawList; }
8.修改isEligibleForIndexing方法:
@VisibleForTesting boolean isEligibleForIndexing(String packageName, Tile tile) { // 屏蔽特定 Tile if (tile.getCategory().equals(CategoryKey.CATEGORY_NETWORK) || tile.getCategory().equals(CategoryKey.CATEGORY_CONNECT) || tile.getCategory().equals(CategoryKey.CATEGORY_DEVICE) || tile.getCategory().equals(CategoryKey.CATEGORY_BATTERY) || tile.getCategory().equals(CategoryKey.CATEGORY_STORAGE)) { return false; } if (TextUtils.equals(packageName, tile.getPackageName()) && tile instanceof ActivityTile) { // Skip Settings injected items because they should be indexed in the sub-pages. return false; } if (TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { // Skip homepage injected items since we would like to index their target activity. return false; } return true; }
9.实现效果如下:
10.总结:
从上面的截图可以看到不管是搜索关键字还是具体的App,都没有出现网络和互联网、已连接的设备、存储、电池四个App的入口,基本上这几个App不会在Setting是搜索中出现,至此上面的问题得到解决。
- 找到问题原因和提出解决方案
- 编码实施,打包镜像进行验证
- 在Setting中搜索前面几个App,基本上都不会出现
- 这些要屏蔽的App可以根据需求来实现,但是如果关键字搜索出来 太多App入口,没必要全都屏蔽,这样修改的话后期如果不需要屏蔽改动太多,所以建议修改几个主要的App搜索入口即可.