“Initializing LauncherAppState in the absence of LauncherProvider”);
}
Log.v(Launcher.TAG, “LauncherAppState initiated”);
Preconditions.assertUIThread();
mContext = context;
mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
//初始化接口
LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);
/**
*/
public void onTerminate() {
mContext.unregisterReceiver(mModel);
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
launcherApps.removeOnAppsChangedCallback(mModel);
PackageInstallerCompat.getInstance(mContext).onStop();
if (mNotificationBadgingObserver != null) {
mNotificationBadgingObserver.unregister();
}
}
public void enqueueModelUpdateTask(ModelUpdateTask task) {
task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
runOnWorkerThread(task);
}
/** Runs the specified runnable immediately if called from the worker thread, otherwise it is
private static void runOnWorkerThread(Runnable r) {
if (sWorkerThread.getThreadId() == Process.myTid()) {
r.run();
} else {
// If we are not on the worker thread, then post to the worker handler
sWorker.post®;
}
}
/**
*/
public interface ModelUpdateTask extends Runnable {
/**
*/
void init(LauncherAppState app, LauncherModel model,
BgDataModel dataModel, AllAppsList allAppsList, Executor uiExecutor);
}
public abstract class BaseModelUpdateTask implements ModelUpdateTask {
/**
Handles updates due to changes in package manager (app installed/updated/removed)
or when a user availability changes.
*/
public class PackageUpdatedTask extends BaseModelUpdateTask {
private static final boolean DEBUG = true;
private static final String TAG = “PackageUpdatedTask”;
public static final int OP_NONE = 0;
public static final int OP_ADD = 1;
public static final int OP_UPDATE = 2;
public static final int OP_REMOVE = 3; // uninstalled
public static final int OP_UNAVAILABLE = 4; // external media unmounted
public static final int OP_SUSPEND = 5; // package suspended
public static final int OP_UNSUSPEND = 6; // package unsuspended
public static final int OP_USER_AVAILABILITY_CHANGE = 7; // user available/unavailable
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
final Context context = app.getContext();
final IconCache iconCache = app.getIconCache();
final String[] packages = mPackages;
final int N = packages.length;
FlagOp flagOp = FlagOp.NO_OP;
final HashSet packageSet = new HashSet<>(Arrays.asList(packages));
ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, mUser);
switch (mOp) {
case OP_ADD: {
for (int i = 0; i < N; i++) {
if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
iconCache.updateIconsForPkg(packages[i], mUser);
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
appsList.removePackage(packages[i], Process.myUserHandle());
}
appsList.addPackage(context, packages[i], mUser);
// Automatically add homescreen icon for work profile apps for below O device.
if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) {//del by mjf for receive package changed msg
SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser);
}
}
flagOp = FlagOp.removeFlag(ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE);
break;
}
…
final ArrayList addedOrModified = new ArrayList<>();
addedOrModified.addAll(appsList.added);
//add for load new install app on workspace start by lhw
if(FeatureFlags.DISABLE_ALL_APP){
ArrayList
final List profiles = UserManagerCompat.getInstance(context).getUserProfiles();
ArrayList
for (UserHandle user : profiles) {
final List apps = LauncherAppsCompat.getInstance(context).getActivityList(null, user);
synchronized (this) {
for (LauncherActivityInfo info : apps) {
if(DmConfig.isHiddenPackage(info.getComponentName())){continue;}//hide app by lhw
for (AppInfo appInfo : appsList.added) {
if(info.getComponentName().equals(appInfo.componentName)){
InstallShortcutReceiver.PendingInstallShortcutInfo mPendingInstallShortcutInfo
= new InstallShortcutReceiver.PendingInstallShortcutInfo(info,context);
added.add(mPendingInstallShortcutInfo);
installQueue.add(mPendingInstallShortcutInfo.getItemInfo());
}
}
}
}
}
if (!added.isEmpty()) {
app.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
//add for load new install app on workspace end by lhw
appsList.added.clear();
addedOrModified.addAll(appsList.modified);
appsList.modified.clear();
final ArrayList removedApps = new ArrayList<>(appsList.removed);
appsList.removed.clear();
final ArrayMap
if (!addedOrModified.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
//TODO bindAppsAddedOrUpdated 通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新 LHW
callbacks.bindAppsAddedOrUpdated(addedOrModified);
}
});
for (AppInfo ai : addedOrModified) {
addedOrUpdatedApps.put(ai.componentName, ai);
}
}
/**
*/
public synchronized void updateIconsForPkg(String packageName, UserHandle user) {
removeIconsForPkg(packageName, user);
try {
PackageInfo info = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
long userSerial = mUserManager.getSerialNumberForUser(user);
for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {
addIconToDBAndMemCache(app, info, userSerial, false /replace existing/);
}
} catch (NameNotFoundException e) {
Log.d(TAG, “Package not found”, e);
}
}
/**
*/
public void addPackage(Context context, String packageName, UserHandle user) {
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
final List matches = launcherApps.getActivityList(packageName,
user);
for (LauncherActivityInfo info : matches) {
add(new AppInfo(context, info, user), info);
}
}
/**
Add the supplied ApplicationInfo objects to the list, and enqueue it into the
list to broadcast when notify() is called.
If the app is already in the list, doesn’t add it.
*/
public void add(AppInfo info, LauncherActivityInfo activityInfo) {
if (!mAppFilter.shouldShowApp(info.componentName)) {
return;
}
if (findAppInfo(info.componentName, info.user) != null) {
return;
}
mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */);
data.add(info);
added.add(info);
}
final ArrayMap
if (!addedOrModified.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {//TODO bindAppsAddedOrUpdated 通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新 LHW
callbacks.bindAppsAddedOrUpdated(addedOrModified);
}
});
for (AppInfo ai : addedOrModified) {
addedOrUpdatedApps.put(ai.componentName, ai);
}
}
4.Launcher.java 中通过AllAppsStore的addOrUpdateApps方法去通知AllApps界面刷新
/**
*/
public class Launcher extends BaseDraggingActivity implements LauncherExterns,
LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{
public static final String TAG = “Launcher”;
/**
*/
@Override
public void bindAppsAddedOrUpdated(ArrayList apps) {
mAppsView.getAppsStore().addOrUpdateApps(apps);
}
5.在AllAppsStore中更新App 列表
/**
*/
public class AllAppsStore {
/**
*/
public void addOrUpdateApps(List apps) {
for (AppInfo app : apps) {
Log.d(“LHW_L”,“addOrUpdateApps-==”+app.title+",=apps.size="+apps.size());
mComponentToAppMap.put(app.toComponentKey(), app);
}
notifyUpdate();
}
/**
*/
public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
Insettable, OnDeviceProfileChangeListener {
private final AllAppsStore mAllAppsStore = new AllAppsStore();
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
mLauncher.addOnDeviceProfileChangeListener(this);
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
mAH = new AdapterHolder[2];
mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
addSpringView(R.id.all_apps_header);
addSpringView(R.id.apps_list_view);
addSpringView(R.id.all_apps_tabs_view_pager);
}
/**
*/
public class AllAppsRecyclerView extends BaseRecyclerView implements LogContainerProvider {
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
final AlphabeticalAppsList appsList;
final Rect padding = new Rect();
AllAppsRecyclerView recyclerView;
boolean verticalFadingEdge;
AdapterHolder(boolean isWork) {
appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
adapter = new AllAppsGridAdapter(mLauncher, appsList);
appsList.setAdapter(adapter);
layoutManager = adapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
recyclerView.setApps(appsList, mUsingTabs);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
// No animations will occur when changes occur to the items in this RecyclerView.
recyclerView.setItemAnimator(null);
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
recyclerView.addItemDecoration(focusedItemDecorator);
adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
applyVerticalFadingEdgeEnabled(verticalFadingEdge);
applyPadding();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_ICON:
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.all_apps_icon, parent, false);
icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
icon.setOnFocusChangeListener(mIconFocusListener);
// Ensure the all apps icon height matches the workspace icons in portrait mode.
icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
return new ViewHolder(icon);
all_apps_icon.xml 中 BubbleTextView 显示桌面图标信息
xmlns:android=“http://schemas.android.com/apk/res/android” xmlns:launcher=“http://schemas.android.com/apk/res-auto” style="@style/BaseIcon" android:id="@+id/icon" android:layout_width=“match_parent” android:layout_height=“wrap_content” android:stateListAnimator="@animator/all_apps_fastscroll_icon_anim" launcher:iconDisplay=“all_apps” launcher:centerVertically=“true” android:paddingLeft="@dimen/dynamic_grid_cell_padding_x" android:paddingRight="@dimen/dynamic_grid_cell_padding_x" /> onBindViewHolder applyFromApplicationInfo 填充App信息数据 @Override public void onBindViewHolder(ViewHolder holder, int position) { switch (holder.getItemViewType()) { case VIEW_TYPE_ICON: AppInfo info = mApps.getAdapterItems().get(position).appInfo; BubbleTextView icon = (BubbleTextView) holder.itemView; icon.reset(); icon.applyFromApplicationInfo(info); break; Launcher 自定义 BubbleTextView 显示应用图标和信息 /** TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan because we want to make the bubble taller than the text and TextView’s clip is too aggressive. */ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback { public void applyFromApplicationInfo(AppInfo info) { applyIconAndLabel(info); // We don’t need to check the info since it’s not a ShortcutInfo super.setTag(info); // Verify high res immediately verifyHighRes(); if (info instanceof PromiseAppInfo) { PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info; applyProgressLevel(promiseAppInfo.level); } applyBadgeState(info, false /* animate */); } private void applyIconAndLabel(ItemInfoWithIcon info) { FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info); mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f); setIcon(iconDrawable); setText(info.title); if (info.contentDescription != null) { setContentDescription(info.isDisabled() } } /** */ private void setIcon(Drawable icon) { if (mIsIconVisible) { applyCompoundDrawables(icon); } mIcon = icon; } protected void applyCompoundDrawables(Drawable icon) { // If we had already set an icon before, disable relayout as the icon size is the // same as before. mDisableRelayout = mIcon != null; icon.setBounds(0, 0, mIconSize, mIconSize); if (mLayoutHorizontal) { setCompoundDrawablesRelative(icon, null, null, null); } else { setCompoundDrawables(null, icon, null, null); } mDisableRelayout = false; } Launcher.java文件 在onCreate 通过 LauncherModel 的 startLoader 函数进行数据的绑定加载和更新 /** */ public class Launcher extends BaseDraggingActivity implements LauncherExterns, LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{ public static final String TAG = “Launcher”; static final boolean LOGD = false; @Override protected void onCreate(Bundle savedInstanceState) { TraceHelper.beginSection(“Launcher-onCreate”); super.onCreate(savedInstanceState); TraceHelper.partitionSection(“Launcher-onCreate”, “super call”); LauncherAppState app = LauncherAppState.getInstance(this); mOldConfig = new Configuration(getResources().getConfiguration()); //获取初始化 LauncherModel 进行广播监听数据绑定和更新加载 mModel = app.setLauncher(this); initDeviceProfile(app.getInvariantDeviceProfile()); // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground int currentScreen = PagedView.INVALID_RESTORE_PAGE; if (savedInstanceState != null) { currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen); } // LauncherModel startLoader 开启线程进行数据加载 if (!mModel.startLoader(currentScreen)) { if (!internalStateHandled) { // If we are not binding synchronously, show a fade in animation when // the first page bind completes. mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0); } } else { // Pages bound synchronously. mWorkspace.setCurrentPage(currentScreen); setWorkspaceLoading(true); } // For handling default keys setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); setContentView(mLauncherView); startLoader() 绑定和加载所用应用信息、小组件、快捷方式等到Workspace /** Maintains in-memory state of the Launcher. It is expected that there should be only one LauncherModel object held in a static. Also provide APIs for updating the database state for the Launcher. */ public class LauncherModel extends BroadcastReceiver implements LauncherAppsCompat.OnAppsChangedCallbackCompat { private static final boolean DEBUG_RECEIVER = !com.android.launcher3.Log.IS_USER_VERSON;//true; /** Starts the loader. Tries to bind {@params synchronousBindPage} synchronously if possible. @return true if the page could be bound synchronously. */ public boolean startLoader(int synchronousBindPage) { // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING); synchronized (mLock) { // Don’t bother to start the thread if we know it’s not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { final Callbacks oldCallbacks = mCallbacks.get(); // Clear any pending bind-runnables from the synchronized load process. // begin modify by mjf for REQ006 //mUiExecutor.execute(oldCallbacks::clearPendingBinds); final Runnable runnable = new Runnable() { @Override public void run() { oldCallbacks.clearPendingBinds(); } }; mUiExecutor.execute(runnable); // end // If there is already one running, tell it to stop. stopLoader(); LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel, mBgAllAppsList, synchronousBindPage, mCallbacks); if (mModelLoaded && !mIsLoaderTaskRunning) { // Divide the set of loaded items into those that we are binding synchronously, // and everything else that is to be bound normally (asynchronously). loaderResults.bindWorkspace(); // For now, continue posting the binding of AllApps as there are other // issues that arise from that. loaderResults.bindAllApps(); loaderResults.bindDeepShortcuts(); loaderResults.bindWidgets(); return true; } else { startLoaderForResults(loaderResults); } } } return false; } public void startLoaderForResults(LoaderResults results) { synchronized (mLock) { stopLoader(); mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); runOnWorkerThread(mLoaderTask); //mUiExecutor.execute(oldCallbacks::clearPendingBinds); final Runnable runnable = new Runnable() { @Override public void run() { oldCallbacks.clearPendingBinds(); } }; mUiExecutor.execute(runnable); // end // If there is already one running, tell it to stop. stopLoader(); LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel, mBgAllAppsList, synchronousBindPage, mCallbacks); if (mModelLoaded && !mIsLoaderTaskRunning) { // Divide the set of loaded items into those that we are binding synchronously, // and everything else that is to be bound normally (asynchronously). loaderResults.bindWorkspace(); // For now, continue posting the binding of AllApps as there are other // issues that arise from that. loaderResults.bindAllApps(); loaderResults.bindDeepShortcuts(); loaderResults.bindWidgets(); return true; } else { startLoaderForResults(loaderResults); } } } return false; } public void startLoaderForResults(LoaderResults results) { synchronized (mLock) { stopLoader(); mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); runOnWorkerThread(mLoaderTask);
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
Launcher 初始加载所有应用信息
LauncherModel 广播监听Launcher数据处理和接口回调