1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 package com.android.settings.search; 18 19 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; 20 21 import android.annotation.NonNull; 22 import android.app.ActivityOptions; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 import android.os.Bundle; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.Toolbar; 32 33 import androidx.fragment.app.FragmentActivity; 34 35 import com.android.settings.R; 36 import com.android.settings.Utils; 37 import com.android.settings.activityembedding.ActivityEmbeddingRulesController; 38 import com.android.settings.overlay.FeatureFactory; 39 import com.android.settingslib.search.SearchIndexableResources; 40 41 import com.google.android.setupcompat.util.WizardManagerHelper; 42 43 import java.util.List; 44 45 /** 46 * FeatureProvider for Settings Search 47 */ 48 public interface SearchFeatureProvider { 49 50 String KEY_HOMEPAGE_SEARCH_BAR = "homepage_search_bar"; 51 int REQUEST_CODE = 501; 52 53 /** 54 * Ensures the caller has necessary privilege to launch search result page. 55 * 56 * @throws IllegalArgumentException when caller is null 57 * @throws SecurityException when caller is not allowed to launch search result page 58 */ verifyLaunchSearchResultPageCaller(Context context, @NonNull ComponentName caller)59 void verifyLaunchSearchResultPageCaller(Context context, @NonNull ComponentName caller) 60 throws SecurityException, IllegalArgumentException; 61 62 /** 63 * @return a {@link SearchIndexableResources} to be used for indexing search results. 64 */ getSearchIndexableResources()65 SearchIndexableResources getSearchIndexableResources(); 66 67 /** 68 * @return a package name of settings intelligence. 69 */ getSettingsIntelligencePkgName(Context context)70 default String getSettingsIntelligencePkgName(Context context) { 71 return context.getString(R.string.config_settingsintelligence_package_name); 72 } 73 74 /** 75 * Initializes the search toolbar. 76 */ initSearchToolbar(FragmentActivity activity, Toolbar toolbar, int pageId)77 default void initSearchToolbar(FragmentActivity activity, Toolbar toolbar, int pageId) { 78 if (activity == null || toolbar == null) { 79 return; 80 } 81 82 if (!WizardManagerHelper.isDeviceProvisioned(activity) 83 || !Utils.isPackageEnabled(activity, getSettingsIntelligencePkgName(activity)) 84 || WizardManagerHelper.isAnySetupWizard(activity.getIntent())) { 85 final ViewGroup parent = (ViewGroup) toolbar.getParent(); 86 if (parent != null) { 87 parent.setVisibility(View.GONE); 88 } 89 return; 90 } 91 // Please forgive me for what I am about to do. 92 // 93 // Need to make the navigation icon non-clickable so that the entire card is clickable 94 // and goes to the search UI. Also set the background to null so there's no ripple. 95 final View navView = toolbar.getNavigationView(); 96 navView.setClickable(false); 97 navView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); 98 navView.setBackground(null); 99 100 final Context context = activity.getApplicationContext(); 101 final Intent intent = buildSearchIntent(context, pageId) 102 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 103 final List<ResolveInfo> resolveInfos = 104 activity.getPackageManager().queryIntentActivities(intent, 105 PackageManager.MATCH_DEFAULT_ONLY); 106 if (resolveInfos.isEmpty()) { 107 return; 108 } 109 110 final ComponentName searchComponentName = resolveInfos.get(0) 111 .getComponentInfo().getComponentName(); 112 // Set a component name since activity embedding requires a component name for 113 // registering a rule. 114 intent.setComponent(searchComponentName); 115 ActivityEmbeddingRulesController.registerTwoPanePairRuleForSettingsHome( 116 context, 117 searchComponentName, 118 intent.getAction(), 119 false /* finishPrimaryWithSecondary */, 120 true /* finishSecondaryWithPrimary */, 121 false /* clearTop */); 122 123 toolbar.setOnClickListener(tb -> { 124 FeatureFactory.getFactory(context).getSlicesFeatureProvider() 125 .indexSliceDataAsync(context); 126 127 FeatureFactory.getFactory(context).getMetricsFeatureProvider() 128 .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId); 129 130 final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle(); 131 activity.startActivity(intent, bundle); 132 }); 133 } 134 buildSearchIntent(Context context, int pageId)135 Intent buildSearchIntent(Context context, int pageId); 136 } 137