ResolverActivity流程分析
ResolverActivity解析隐式Intent,其onCreate()方法如下
@Override
protected void onCreate(Bundle savedInstanceState) {
......
onCreate(savedInstanceState, intent, null, 0, null, null, true);
}
@UnsupportedAppUsage
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, Intent[] initialIntents,
List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
onCreate(savedInstanceState, intent, title, 0, initialIntents, rList,
supportsAlwaysUseOption);
}
调用ResolverActivity的5参数onCreate()方法,如下
- 获取ViewPager的适配器mMultiProfilePagerAdapter
- 通过configureContentView()设置布局
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, int defaultTitleRes, Intent[] initialIntents,
List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
setTheme(appliedThemeResId());
super.onCreate(savedInstanceState);
......
mMultiProfilePagerAdapter = createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
if (configureContentView()) {
return;
}
......
}
调用ResolverActivity的 configureContentView() 方法,如下
- 通过rebuildActiveTab()开始解析,需要注意这里传入的true即是下面的doPostProcessing
- 设置布局、ViewPager
private boolean configureContentView() {
......
boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true)
|| mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded();
.....
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
} else {
mLayoutId = getLayoutResource();
}
setContentView(mLayoutId);
mMultiProfilePagerAdapter.setupViewPager(findViewById(R.id.profile_pager));
boolean result = postRebuildList(rebuildCompleted);
.......
return result;
}
调用AbstractMultiProfilePagerAdapter的 rebuildActiveTab()、rebuildTab() 方法,如下
boolean rebuildActiveTab(boolean doPostProcessing) {
......
boolean result = rebuildTab(getActiveListAdapter(), doPostProcessing);
......
return result;
}
private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
......
return activeListAdapter.rebuildList(doPostProcessing);
}
调用ResolverListAdapter的 rebuildList() 方法,如下
- getInitialRebuiltResolveList()解析Intent,但还不知道怎么解析的,待定研究
- 解析到List<ResolvedComponentInfo> currentResolveList 中
protected boolean rebuildList(boolean doPostProcessing) {
......
List<ResolvedComponentInfo> currentResolveList = getInitialRebuiltResolveList();
......
boolean result =
finishRebuildingListWithFilteredResults(currentResolveList, doPostProcessing);
Trace.endSection();
return result;
}
调用ResolverListAdapter的 finishRebuildingListWithFilteredResults() 方法,如下
- 如果filteredResolveList只有一个则直接调用processSortedList()
- 如果filteredResolveList不止一个则调用postListReadyRunnable(),这里rebuildCompleted = false,说明数据未准备好,调用createSortingTask()异步排序,排完序调用processSortedList()
boolean finishRebuildingListWithFilteredResults(@Nullable List<ResolvedComponentInfo> filteredResolveList, boolean doPostProcessing) {
if (filteredResolveList == null || filteredResolveList.size() < 2) {
// No asynchronous work to do.
setPlaceholderCount(0);
processSortedList(filteredResolveList, doPostProcessing);
return true;
}
int placeholderCount = filteredResolveList.size();
if (mResolverListCommunicator.useLayoutWithDefault()) {
--placeholderCount;
}
setPlaceholderCount(placeholderCount);
// Send an "incomplete" list-ready while the async task is running.
postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ false);
createSortingTask(doPostProcessing).execute(filteredResolveList);
return false;
}
AsyncTask<List<ResolvedComponentInfo>,
Void,
List<ResolvedComponentInfo>> createSortingTask(boolean doPostProcessing)
return new AsyncTask<List<ResolvedComponentInfo>,
Void,
List<ResolvedComponentInfo>>() {
@Override
protected List<ResolvedComponentInfo> doInBackground(
List<ResolvedComponentInfo>... params) {
mResolverListController.sort(params[0]);
return params[0];
}
@Override
protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents
processSortedList(sortedComponents, doPostProcessing);
notifyDataSetChanged();
if (doPostProcessing) {
mResolverListCommunicator.updateProfileViewButton();
}
}
};
}
调用ResolverListAdapter的 processSortedList() 方法,如下
- 这里主要将信息封装成DisplayResolveInfo,添加到mDisplayList
- 封装好后调用postListReadyRunnable(),这里rebuildCompleted=true,说明数据已经准备好
protected void processSortedList(List<ResolvedComponentInfo> sortedComponents,
boolean doPostProcessing) {
final int n = sortedComponents != null ? sortedComponents.size() : 0;
......
if (n != 0) {
// First put the initial items at the top.
if (mInitialIntents != null) {
for (int i = 0; i < mInitialIntents.length; i++) {
......
addResolveInfo(new DisplayResolveInfo(ii, ri,
ri.loadLabel(mPm), null, ii, makePresentationGetter(ri)));
}
}
for (ResolvedComponentInfo rci : sortedComponents) {
final ResolveInfo ri = rci.getResolveInfoAt(0);
if (ri != null) {
addResolveInfoWithAlternates(rci);
}
}
}
......
postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ true);
......
}
调用ResolverListAdapter的 postListReadyRunnable() 方法,如下
- 这里通过主线程Handler回调onPostListReady()
void postListReadyRunnable(boolean doPostProcessing, boolean rebuildCompleted) {
if (mPostListReadyRunnable == null) {
mPostListReadyRunnable = new Runnable() {
@Override
public void run() {
mResolverListCommunicator.onPostListReady(ResolverListAdapter.this,
doPostProcessing, rebuildCompleted);
mPostListReadyRunnable = null;
}
};
mContext.getMainThreadHandler().post(mPostListReadyRunnable);
}
}
调用ResolverActivity的 onPostListReady() 方法,如下
- 当数据只有一个,maybeAutolaunchActivity()自动选择Launcher
- 当数据不止一个,先通过showEmptyResolverListEmptyState()显示一个空的View,等数据准备好后通过showListView()显示选择界面
@Override
public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing,
boolean rebuildCompleted) {
.......
if (mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(listAdapter)) {
mMultiProfilePagerAdapter.showEmptyResolverListEmptyState(listAdapter);
} else {
mMultiProfilePagerAdapter.showListView(listAdapter);
}
if (rebuildCompleted && maybeAutolaunchActivity()) {
return;
}
if (doPostProcessing) {
maybeCreateHeader(listAdapter);
resetButtonBar();
onListRebuilt(listAdapter, rebuildCompleted);
}
}
只有一个数据
ResolverActivity的 maybeAutolaunchActivity() 方法,如下
- 这里判断Profiles的个数
private boolean maybeAutolaunchActivity() {
int numberOfProfiles = mMultiProfilePagerAdapter.getItemCount();
if (numberOfProfiles == 1 && maybeAutolaunchIfSingleTarget()) {
return true;
} else if (numberOfProfiles == 2
&& mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded()
&& mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded()
&& (maybeAutolaunchIfNoAppsOnInactiveTab()
|| maybeAutolaunchIfCrossProfileSupported())) {
return true;
}
return false;
}
调用 ResolverActivity的 maybeAutolaunchIfSingleTarget() 方法,如下
- getUnfilteredCount()判断mDisplayList的个数是否为1,然后取出数据,通过safelyStartActivity()启动唯一的Activity
private boolean maybeAutolaunchIfSingleTarget() {
int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();
if (count != 1) {
return false;
}
if (mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null) {
return false;
}
// Only one target, so we're a candidate to auto-launch!
final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()
.targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
finish();
return true;
}
return false;
}
不止一个数据
当数据不止一个时,会弹窗提示,当用户选择会触发onButtonClick(),最终调用startSelected()
- 第一个参数为所选择的位置
- 第二个参数判断是否是Always按钮
- 第三个参数判断是否之前选择过
public void onButtonClick(View v) {
final int id = v.getId();
ListView listView = (ListView) mMultiProfilePagerAdapter.getActiveAdapterView();
ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();
int which = currentListAdapter.hasFilteredItem()
? currentListAdapter.getFilteredPosition()
: listView.getCheckedItemPosition();
boolean hasIndexBeenFiltered = !currentListAdapter.hasFilteredItem();
startSelected(which, id == R.id.button_always, hasIndexBeenFiltered);
}
设置默认Launcher(可直接看这里)
通过上面的分析,我们可以知道在 finishRebuildingListWithFilteredResults() 方法中判断Intent解析到的应用个数
故在ResolverListAdapter的finishRebuildingListWithFilteredResults()最前面添加修改
boolean finishRebuildingListWithFilteredResults(
@Nullable List<ResolvedComponentInfo> filteredResolveList, boolean doPostProcessing) {
filteredResolveList = changeDefaultLauncher(filteredResolveList)
......
}
具体的changeDefaultLauncher()方法如下
private List<ResolvedComponentInfo> changeDefaultLauncher(List<ResolvedComponentInfo> filteredResolveList) {
if (filteredResolveList != null) {
String defLauncher = "com.default.launcher";
for (ResolvedComponentInfo info : filteredResolveList) {
for (int i = 0; i < info.getCount(); i++) {
ResolveInfo resolveInfo = info.getResolveInfoAt(i);
if (defLauncher.equals(resolveInfo.activityInfo.packageName)) {
filteredResolveList = new ArrayList<>();
filteredResolveList.add(info);
Log.d(TAG, "changeDefaultLauncher:" + resolveInfo.activityInfo.packageName);
break;
}
}
}
}
return filteredResolveList;
}
但上面修改后,只有一个数据,会自动进入设置的Launcher,但按home键或者从第三方软件返回时,还是会返回到Launcher3
- 原因是只有一条数据时,调用的是maybeAutolaunchIfSingleTarget()中的safelyStartActivity()启动Acitivity,并未设置为Always(可在App-Default App-Home app中查看到并未设置)
- 我们更想要的效果是,设置Launcher为Always
故在ResolverActivity的maybeAutolaunchIfSingleTarget()的最前面添加修改
private boolean maybeAutolaunchActivity() {
setDefLauncher();
......
}
setDefLauncher()的具体实现如下
private void setDefLauncher() {
String defLauncher = "com.default.launcher";
int size = mMultiProfilePagerAdapter.getActiveListAdapter().getDisplayResolveInfoCount();
for (int i = 0; i < size; i++) {
DisplayResolveInfo info = mMultiProfilePagerAdapter.getActiveListAdapter().getDisplayResolveInfo(i);
if (info != null && defLauncher.equals(info.getResolveInfo().activityInfo.packageName)) {
Log.d(TAG, "setDefLauncher() = " + info.getResolveInfo().activityInfo.packageName);
startSelected(i, true, false);
finish();
}
}
}
参考文献
https://blog.csdn.net/yjz_0314/article/details/134704763