Support highlighting the menu entry for Search results

1. Add a receiver to monitor the search state
2. Shoe/hide the menu highlight in the listener
3. Highlight the menu entry in SearchResultTrampoline
4. Enable/disable the receiver in SettingsInitialize

Bug: 205781792
Test: manual, robotest
Change-Id: Ia04901f504172f4f0c7b4b2ea7eda5f3713f676d
This commit is contained in:
Jason Chiu
2021-11-11 14:24:37 +08:00
parent 9ae7fa254e
commit 3af73364ba
10 changed files with 155 additions and 47 deletions

View File

@@ -297,6 +297,15 @@
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:name=".search.SearchStateReceiver"
android:exported="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES">
<intent-filter>
<action android:name="com.android.settings.SEARCH_START"/>
<action android:name="com.android.settings.SEARCH_EXIT"/>
</intent-filter>
</receiver>
<activity <activity
android:name="Settings$WifiSettingsActivity" android:name="Settings$WifiSettingsActivity"
android:label="@string/wifi_settings" android:label="@string/wifi_settings"

View File

@@ -16,17 +16,17 @@
package com.android.settings; package com.android.settings;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.homepage.SettingsHomepageActivity;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
/** Settings application which sets up activity embedding rules for the large screen device. */ /** Settings application which sets up activity embedding rules for the large screen device. */
public class SettingsApplication extends Application { public class SettingsApplication extends Application {
private WeakReference<Activity> mHomeActivity = new WeakReference<>(null); private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
@Override @Override
public void onCreate() { public void onCreate() {
@@ -37,11 +37,11 @@ public class SettingsApplication extends Application {
controller.initRules(); controller.initRules();
} }
public void setHomeActivity(Activity homeActivity) { public void setHomeActivity(SettingsHomepageActivity homeActivity) {
mHomeActivity = new WeakReference<>(homeActivity); mHomeActivity = new WeakReference<>(homeActivity);
} }
public Activity getHomeActivity() { public SettingsHomepageActivity getHomeActivity() {
return mHomeActivity.get(); return mHomeActivity.get();
} }
} }

View File

@@ -41,6 +41,7 @@ import androidx.window.embedding.SplitController;
import com.android.settings.Settings.CreateShortcutActivity; import com.android.settings.Settings.CreateShortcutActivity;
import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.search.SearchStateReceiver;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList; import java.util.ArrayList;
@@ -67,7 +68,7 @@ public class SettingsInitialize extends BroadcastReceiver {
managedProfileSetup(context, pm, broadcast, userInfo); managedProfileSetup(context, pm, broadcast, userInfo);
webviewSettingSetup(context, pm, userInfo); webviewSettingSetup(context, pm, userInfo);
ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context)); ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context));
enableTwoPaneDeepLinkActivityIfNecessary(pm, broadcast); enableTwoPaneDeepLinkActivityIfNecessary(pm, context);
} }
private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast, private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast,
@@ -148,12 +149,16 @@ public class SettingsInitialize extends BroadcastReceiver {
shortcutManager.updateShortcuts(updates); shortcutManager.updateShortcuts(updates);
} }
private void enableTwoPaneDeepLinkActivityIfNecessary(PackageManager pm, Intent intent) { private void enableTwoPaneDeepLinkActivityIfNecessary(PackageManager pm, Context context) {
final ComponentName deepLinkHome = new ComponentName(Utils.SETTINGS_PACKAGE_NAME, final ComponentName deepLinkHome = new ComponentName(Utils.SETTINGS_PACKAGE_NAME,
SettingsHomepageActivity.ALIAS_DEEP_LINK); SettingsHomepageActivity.ALIAS_DEEP_LINK);
final ComponentName searchStateReceiver = new ComponentName(context,
SearchStateReceiver.class);
final int enableState = SplitController.getInstance().isSplitSupported() final int enableState = SplitController.getInstance().isSplitSupported()
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED; : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
pm.setComponentEnabledSetting(deepLinkHome, enableState, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(deepLinkHome, enableState, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(searchStateReceiver, enableState,
PackageManager.DONT_KILL_APP);
} }
} }

View File

@@ -34,6 +34,7 @@ import com.android.settings.Settings;
import com.android.settings.SubSettings; import com.android.settings.SubSettings;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.homepage.SliceDeepLinkHomepageActivity;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -127,6 +128,15 @@ public class ActivityEmbeddingRulesController {
true /* finishPrimaryWithSecondary */, true /* finishPrimaryWithSecondary */,
true /* finishSecondaryWithPrimary */, true /* finishSecondaryWithPrimary */,
clearTop); clearTop);
registerTwoPanePairRule(
context,
getComponentName(context, SliceDeepLinkHomepageActivity.class),
secondaryComponent,
secondaryIntentAction,
true /* finishPrimaryWithSecondary */,
true /* finishSecondaryWithPrimary */,
clearTop);
} }
/** Register a SplitPairRule for SubSettings if the device supports 2-pane. */ /** Register a SplitPairRule for SubSettings if the device supports 2-pane. */

View File

@@ -78,6 +78,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
private static final int DEFAULT_HIGHLIGHT_MENU_KEY = R.string.menu_key_network; private static final int DEFAULT_HIGHLIGHT_MENU_KEY = R.string.menu_key_network;
private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300; private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300;
private TopLevelSettings mMainFragment;
private View mHomepageView; private View mHomepageView;
private View mSuggestionView; private View mSuggestionView;
private CategoryMixin mCategoryMixin; private CategoryMixin mCategoryMixin;
@@ -124,6 +125,11 @@ public class SettingsHomepageActivity extends FragmentActivity implements
homepageView.setVisibility(View.VISIBLE); homepageView.setVisibility(View.VISIBLE);
} }
/** Returns the main content fragment */
public TopLevelSettings getMainFragment() {
return mMainFragment;
}
@Override @Override
public CategoryMixin getCategoryMixin() { public CategoryMixin getCategoryMixin() {
return mCategoryMixin; return mCategoryMixin;
@@ -132,7 +138,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHomeActivity();
setContentView(R.layout.settings_homepage_container); setContentView(R.layout.settings_homepage_container);
final View appBar = findViewById(R.id.app_bar_container); final View appBar = findViewById(R.id.app_bar_container);
@@ -162,10 +167,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements
showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content); showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
} }
} }
final Fragment fragment = new TopLevelSettings(); mMainFragment = new TopLevelSettings();
fragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, mMainFragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
getHighlightMenuKey()); getHighlightMenuKey());
showFragment(fragment, R.id.main_content); showFragment(mMainFragment, R.id.main_content);
((FrameLayout) findViewById(R.id.main_content)) ((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); .getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
@@ -174,6 +179,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements
launchDeepLinkIntentToRight(); launchDeepLinkIntentToRight();
} }
@Override
protected void onStart() {
((SettingsApplication) getApplication()).setHomeActivity(this);
super.onStart();
}
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
@@ -189,10 +200,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
launchDeepLinkIntentToRight(); launchDeepLinkIntentToRight();
} }
protected void setHomeActivity() {
((SettingsApplication) getApplication()).setHomeActivity(this);
}
private void showSuggestionFragment() { private void showSuggestionFragment() {
final Class<? extends Fragment> fragment = FeatureFactory.getFactory(this) final Class<? extends Fragment> fragment = FeatureFactory.getFactory(this)
.getSuggestionFeatureProvider(this).getContextualSuggestionFragment(); .getSuggestionFeatureProvider(this).getContextualSuggestionFragment();
@@ -314,13 +321,9 @@ public class SettingsHomepageActivity extends FragmentActivity implements
} }
private void reloadHighlightMenuKey() { private void reloadHighlightMenuKey() {
final TopLevelSettings fragment = mMainFragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
(TopLevelSettings) getSupportFragmentManager().findFragmentById(R.id.main_content); getHighlightMenuKey());
if (fragment != null) { mMainFragment.reloadHighlightMenuKey();
fragment.getArguments().putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
getHighlightMenuKey());
fragment.reloadHighlightMenuKey();
}
} }
private void initHomepageContainer() { private void initHomepageContainer() {

View File

@@ -20,11 +20,6 @@ import android.content.ComponentName;
/** Activity for Slices to launch Settings deep link page */ /** Activity for Slices to launch Settings deep link page */
public class SliceDeepLinkHomepageActivity extends SettingsHomepageActivity { public class SliceDeepLinkHomepageActivity extends SettingsHomepageActivity {
@Override
protected void setHomeActivity() {
// do not overwrite homepage activity in SettingsApplication
}
@Override @Override
protected ComponentName getDeepLinkComponent() { protected ComponentName getDeepLinkComponent() {
return new ComponentName(getApplicationContext(), getClass()); return new ComponentName(getApplicationContext(), getClass());

View File

@@ -52,10 +52,12 @@ public class TopLevelSettings extends DashboardFragment implements
private static final String TAG = "TopLevelSettings"; private static final String TAG = "TopLevelSettings";
private static final String SAVED_HIGHLIGHTED_PREF = "highlighted_pref"; private static final String SAVED_HIGHLIGHTED_PREF = "highlighted_pref";
private static final String SAVED_CACHED_PREF = "cached_pref";
private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter; private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter;
private String mHighlightedPreferenceKey; private String mHighlightedPreferenceKey;
private String mCachedPreferenceKey;
public TopLevelSettings() { public TopLevelSettings() {
final Bundle args = new Bundle(); final Bundle args = new Bundle();
@@ -125,6 +127,7 @@ public class TopLevelSettings extends DashboardFragment implements
super.onCreate(icicle); super.onCreate(icicle);
if (icicle != null) { if (icicle != null) {
mHighlightedPreferenceKey = icicle.getString(SAVED_HIGHLIGHTED_PREF); mHighlightedPreferenceKey = icicle.getString(SAVED_HIGHLIGHTED_PREF);
mCachedPreferenceKey = icicle.getString(SAVED_CACHED_PREF);
} }
} }
@@ -132,6 +135,7 @@ public class TopLevelSettings extends DashboardFragment implements
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putString(SAVED_HIGHLIGHTED_PREF, mHighlightedPreferenceKey); outState.putString(SAVED_HIGHLIGHTED_PREF, mHighlightedPreferenceKey);
outState.putString(SAVED_CACHED_PREF, mCachedPreferenceKey);
} }
@Override @Override
@@ -169,9 +173,10 @@ public class TopLevelSettings extends DashboardFragment implements
} }
} }
/** Highlight a preference with specified key */ /** Highlight a preference with specified preference key */
public void setHighlightPreferenceKey(String prefKey) { public void setHighlightPreferenceKey(String prefKey) {
if (mTopLevelAdapter != null) { if (mTopLevelAdapter != null) {
mCachedPreferenceKey = null;
mHighlightedPreferenceKey = prefKey; mHighlightedPreferenceKey = prefKey;
mTopLevelAdapter.highlightPreference(prefKey, /* scrollNeeded= */ false); mTopLevelAdapter.highlightPreference(prefKey, /* scrollNeeded= */ false);
} }
@@ -184,13 +189,38 @@ public class TopLevelSettings extends DashboardFragment implements
} }
} }
/** Disable highlight on the menu entry */ /** Show/hide the highlight on the menu entry */
public void disableMenuHighlight() { public void setMenuHighlightShowed(boolean show) {
if (mTopLevelAdapter == null) { if (mTopLevelAdapter == null) {
return; return;
} }
mHighlightedPreferenceKey = null;
mTopLevelAdapter.highlightPreference(mHighlightedPreferenceKey, /* scrollNeeded= */ false); if (show) {
mHighlightedPreferenceKey = mCachedPreferenceKey;
mCachedPreferenceKey = null;
} else {
if (mCachedPreferenceKey == null) {
mCachedPreferenceKey = mHighlightedPreferenceKey;
}
mHighlightedPreferenceKey = null;
}
mTopLevelAdapter.highlightPreference(mHighlightedPreferenceKey, /* scrollNeeded= */ show);
}
/** Highlight and scroll to a preference with specified menu key */
public void setHighlightMenuKey(String menuKey) {
if (mTopLevelAdapter == null) {
return;
}
final String prefKey = HighlightableMenu.lookupPreferenceKey(menuKey);
if (TextUtils.isEmpty(prefKey)) {
Log.e(TAG, "Invalid highlight menu key: " + menuKey);
} else {
Log.d(TAG, "Menu key: " + menuKey);
mHighlightedPreferenceKey = prefKey;
mTopLevelAdapter.highlightPreference(prefKey, /* scrollNeeded= */ true);
}
} }
@Override @Override

View File

@@ -33,8 +33,6 @@ import androidx.fragment.app.FragmentActivity;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.search.SearchIndexableResources; import com.android.settingslib.search.SearchIndexableResources;
@@ -108,18 +106,8 @@ public interface SearchFeatureProvider {
FeatureFactory.getFactory(context).getMetricsFeatureProvider() FeatureFactory.getFactory(context).getMetricsFeatureProvider()
.logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId); .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) { final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
final TopLevelSettings fragment = (TopLevelSettings) activity activity.startActivity(intent, bundle);
.getSupportFragmentManager().findFragmentById(R.id.main_content);
if (fragment != null) {
fragment.disableMenuHighlight();
}
activity.startActivity(intent);
} else {
final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity)
.toBundle();
activity.startActivity(intent, bundle);
}
}); });
} }

View File

@@ -28,9 +28,11 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.SettingsApplication;
import com.android.settings.SubSettings; import com.android.settings.SubSettings;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -99,12 +101,20 @@ public class SearchResultTrampoline extends Activity {
// navigation behavior. // navigation behavior.
ActivityEmbeddingRulesController.registerSubSettingsPairRule(this, ActivityEmbeddingRulesController.registerSubSettingsPairRule(this,
false /* clearTop */); false /* clearTop */);
// TODO: pass menu key to homepage
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); startActivity(intent);
// Pass menu key to homepage
final SettingsHomepageActivity homeActivity =
((SettingsApplication) getApplicationContext()).getHomeActivity();
if (homeActivity != null) {
homeActivity.getMainFragment().setHighlightMenuKey(highlightMenuKey);
}
} else { } else {
// Two-pane case // Two-pane case
startActivity(SettingsActivity.getTrampolineIntent(intent, highlightMenuKey)); startActivity(SettingsActivity.getTrampolineIntent(intent, highlightMenuKey)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} }
// Done. // Done.

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import com.android.settings.SettingsApplication;
import com.android.settings.homepage.SettingsHomepageActivity;
/**
* A broadcast receiver that monitors the search state to show/hide the menu highlight
*/
public class SearchStateReceiver extends BroadcastReceiver {
private static final String TAG = "SearchStateReceiver";
private static final String ACTION_SEARCH_START = "com.android.settings.SEARCH_START";
private static final String ACTION_SEARCH_EXIT = "com.android.settings.SEARCH_EXIT";
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
Log.w(TAG, "Null intent");
return;
}
final SettingsHomepageActivity homeActivity =
((SettingsApplication) context.getApplicationContext()).getHomeActivity();
if (homeActivity == null) {
return;
}
final String action = intent.getAction();
Log.d(TAG, "action: " + action);
if (TextUtils.equals(ACTION_SEARCH_START, action)) {
homeActivity.getMainFragment().setMenuHighlightShowed(false);
} else if (TextUtils.equals(ACTION_SEARCH_EXIT, action)) {
homeActivity.getMainFragment().setMenuHighlightShowed(true);
}
}
}