目录
1、设置首页SettingsHomepageActivity.java
2、ContextualCardsFragment.java
6、LegacySuggestionContextualCardController.java
8、SettingsIntelligence-SuggestionService.java
9、SuggestionFeatureProvider.java
一、概述
什么是建议(Suggestion)菜单,如下图。在设置首页的,第一个菜单上方,搜索框下方会弹出一些快捷菜单。提醒用户进行一些个性化设置,用户设置后或者关闭后则不再显示
二、Suggestion常见问题
1、如何打开原生Suggestion菜单
出现时机需要满足三个条件,1、设备不是 LowRam 设备 2、启用 settings_contextual_home 特性 3、在开机一定时间后(一般是几天,具体看 AndroidManifest.xml 中的有配置),为什么是这几个,后面的分析流程会详细解释。代码逻辑可以查看SettingsHomePageActivity-OnCreate
2、原生默认有哪些Suggestion菜单
在Settings AndroidManifest.xml中搜索以下cagegory
"com.android.settings.suggested.category.FIRST_IMPRESSION"
所有Suggestion都需要配置此category,其实其他应用配置该category应该也可以显示
原生默认共有七个:
ZenSuggestionActivity
WallpaperSuggestionActivity
StyleSuggestionActivity
Settings$NightDisplaySuggestionActivity
ScreenLockSuggestionActivity
FingerprintEnrollSuggestionActivity
WifiCallingSuggestionActivity
3、如何配置Suggestion菜单显示时机
所有Suggestion都有配置"com.android.settings.dismiss",如果第一个值为0,则显示直接显示。
非0时,则会根据取一个值,判断多少天后显示。逻辑在
DismissedChecker.java-parseAppearDay()中
<meta-data android:name="com.android.settings.dismiss" android:value="10,14,30" />
三、Suggestion菜单加载流程分析
整个加载过程涉及Settings、SettingsLib、SettingsIntelligence、framework。为何设计这么复杂,还是涉及到framework,我猜测google工程师初衷是为了在其他应用中也可以增加Suggestion菜单
1、设置首页SettingsHomepageActivity.java
判定显示Suggestion条件,条件满足时加载ContextualCardsFragment
SettingsHomepageActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
if (!getSystemService(ActivityManager.class).isLowRamDevice()) { //非LowRamDevice才会加载
initAvatarView();
final boolean scrollNeeded = mIsEmbeddingActivityEnabled
&& !TextUtils.equals(getString(DEFAULT_HIGHLIGHT_MENU_KEY), highlightMenuKey);
showSuggestionFragment(scrollNeeded);
//FeatureFlags.CONTEXTUAL_HOME = "settings_contextual_home" 该功能为true时才会显示Suggestion
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
//加载ContextualCardsFragment
showFragment(() -> new ContextualCardsFragment(), R.id.contextual_cards_content);
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
}
}
...
}
2、ContextualCardsFragment.java
Suggestion菜单显示在Fragment中,所有的Suggestion最终是用ContextualCardsFragment来加载和展示
ContextualCardsFragment.java
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = getContext();
if (savedInstanceState == null) {
FeatureFactory.getFactory(context).getSlicesFeatureProvider().newUiSession();
BluetoothUpdateWorker.initLocalBtManager(getContext());
}
//该Manager会管理Suggestion相关的Controller、Render
mContextualCardManager = new ContextualCardManager(context, getSettingsLifecycle(), //pri suggestion 2
savedInstanceState);
mKeyEventReceiver = new KeyEventReceiver();
}
@Override
public void onStart() {
super.onStart();
registerScreenOffReceiver();
registerKeyEventReceiver();
//loadCards,默认配置这里是不执行的
mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this), //pri suggestion 加载
sRestartLoaderNeeded);
sRestartLoaderNeeded = false;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, //pri suggestion 2
Bundle savedInstanceState) {
final Context context = getContext();
final View rootView = inflater.inflate(R.layout.settings_homepage, container, false);
mCardsContainer = rootView.findViewById(R.id.card_container);
mLayoutManager = new GridLayoutManager(getActivity(), SPAN_COUNT,
GridLayoutManager.VERTICAL, false /* reverseLayout */); //设为网格布局
mCardsContainer.setLayoutManager(mLayoutManager);
//Suggestion显示的布局未FocusRecyclerView,这个是对应的Adapter
mContextualCardsAdapter = new ContextualCardsAdapter(context, this /* lifecycleOwner */,
mContextualCardManager);
mCardsContainer.setItemAnimator(null);
mCardsContainer.setAdapter(mContextualCardsAdapter);
mContextualCardManager.setListener(mContextualCardsAdapter); //数据会通过回调从这里返回
mCardsContainer.setListener(this);
mItemTouchHelper = new ItemTouchHelper(new SwipeDismissalDelegate(mC