Android 9.0 launcher3 removes the drawer display of all apps (detailed code)
design sketch
Modification ideas
1. Add the global control variable sys.launcher3.is_ full_ App for dynamic switching
2. Add two sets of layouts, corresponding to drawers and no drawers
3. Remove allappsbutton
4. Load the icon in allappscontainerview into workspace
5. Newly installed apps automatically add icons to workspace
6. Replace the workspace icon and long press the delete option to cancel
7. Mask pull-up display drawer page gesture
8. Change page indicator to dot
Upper code
1. Add the global control variable sys.launcher3.is_ full_ app
1) Add the static method isdisableallapps() in launcherappstate by modifying the custom value sys.launcher3.is in settings_ full_ app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.java
private static Context mContext; public static boolean isDisableAllApps() { if (mContext != null) { return Settings.System.getInt(mContext.getContentResolver(),"sys.launcher3.is_full_app",0) == 1; } return true; }
vendor\mediatek\proprietary\packages\apps\Launcher3\AndroidManifest-common.xml
2) Add permissions in androidmanifest-common.xml
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
3) Add switchpreference in settingsactivity to dynamically modify sys.launcher3.is_ full_ app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\SettingsActivity.java
Override onpreferencetreelick() in the inner class launchersettingsfragment to listen for switchpreference clicks
/** * This fragment shows the launcher preferences. */ public static class LauncherSettingsFragment extends PreferenceFragment { ..... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... //读取保存的值,初始化 SwitchPreference 的初始状态,是否选中 int isFull = Settings.System.getInt(getActivity().getContentResolver(),0); Log.d("Launcher3","sys.launcher3.is_full_app="+isFull); SwitchPreference fullSwitch = (SwitchPreference) findPreference("pref_is_full_app"); fullSwitch.setChecked(isFull==1); } //add for change is_full_app value @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,Preference preference) { boolean result = true; final String key = preference.getKey(); if ("pref_is_full_app".equals(key)) { boolean checked = ((SwitchPreference) preference).isChecked(); Settings.System.putInt(getActivity().getContentResolver(),checked ? 1 : 0); Log.e("Launcher3","SwitchPreference checked="+checked); // Value has changed ProgressDialog.show(getActivity(),null /* title */,getActivity().getString(R.string.full_app_override_progress),true /* indeterminate */,false /* cancelable */); new LooperExecutor(LauncherModel.getWorkerLooper()).execute( new OverrideApplyHandler(getActivity())); } return result; } }
After clicking switch preference, you need to save sys.launcher3.is_ full_ App, clear the cache of launcher3, delay the start and end the current process
The clear cache method clearapplicationuserdata compiles and reports an error in launcher3, so the real clear cache operation is carried out by sending a broadcast to setting
//add for change is_full_app value private static class OverrideApplyHandler implements Runnable { private final Context mContext; private OverrideApplyHandler(Context context) { mContext = context; } @Override public void run() { // Clear the icon cache. LauncherAppState.getInstance(mContext).getIconCache().clear(); // Wait for it try { Thread.sleep(1000); } catch (Exception e) { Log.e("Launcher3","Error waiting",e); } // Schedule an alarm before we kill ourself. Intent homeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setPackage(mContext.getPackageName()) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent pi = PendingIntent.getActivity(mContext,42,homeIntent,PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); mContext.getSystemService(AlarmManager.class).setExact( AlarmManager.ELAPSED_REALTIME,SystemClock.elapsedRealtime() + 50,pi); //clear data will kill process Intent intent = new Intent("com.android.action.CLEAR_APP_DATA"); intent.putExtra("pkgName","com.android.launcher3"); intent.addFlags(0x01000000); mContext.sendBroadcast(intent); Log.i("Launcher3","Clearing user data com.android.launcher3"); // Kill process android.os.Process.killProcess(android.os.Process.myPid()); } }
4) Modify the launcher from the XML file corresponding to settingsactivity_ preferences
vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\launcher_ preferences.xml
<SwitchPreference android:key="pref_is_full_app" android:title="@string/is_full_app_title" android:summary="@string/is_full_app_desc" android:defaultValue="false" android:persistent="true" />
The corresponding string file will not be pasted. Just add it yourself
2. Add two sets of layouts, corresponding to drawers and no drawers
The XML corresponding to loading the layout file is vendor \ MediaTek \ proprietary \ packages \ apps \ launcher3 \ res \ XML \ device_ profiles.xml
Launcher3 determines which profile to load by obtaining minwidthdps and minhightdps. The resolution of my tablet is 1280 * 800, and two profile nodes are added
<profile launcher:name="Tablet" launcher:minWidthDps="376" launcher:minHeightDps="586" launcher:numRows="4" launcher:numColumns="5" launcher:numFolderRows="4" launcher:numFolderColumns="5" launcher:iconSize="50" launcher:iconTextSize="11" launcher:numHotseatIcons="5" launcher:defaultLayoutId="@xml/default_workspace_tb_5x6" /> <profile launcher:name="Tablet_no_all_app" launcher:minWidthDps="380" launcher:minHeightDps="590" launcher:numRows="4" launcher:numColumns="5" launcher:numFolderRows="4" launcher:numFolderColumns="5" launcher:iconSize="50" launcher:iconTextSize="11" launcher:numHotseatIcons="4" launcher:defaultLayoutId="@xml/default_workspace_tb_5x6_no_all_app" />
Correspondingly, you need to add four files under the XML file, which are default_ workspace_ tb_ 5x6.xml dw_ hotseat_ tb.xml default_ workspace_ tb_ 5x6_ no_ all_ app.xml dw_ hotseat_ tb_ no_ all_ app.xml
The advantage of this is that you can customize the loading contents of different layout files. The above configuration meanings are: minimum width, minimum height, layout rows and columns, layout rows and columns in folders, icon size, icon text size, number of hotseat, and loaded layout files
Judge whether the tablet needs to be loaded in the invariantdeviceprofile()_ no_ all_ app profile
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\InvariantDeviceProfile.java
public InvariantDeviceProfile(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); display.getMetrics(dm); Point smallestSize = new Point(); Point largestSize = new Point(); display.getCurrentSizeRange(smallestSize,largestSize); // This guarantees that width < height minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x,smallestSize.y),dm); minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x,largestSize.y),dm); Log.i("Launcher3.profiles","orignalminWidthDps="+minWidthDps + " orignalminHeightDps="+minHeightDps); //add for load no_all_app xml if (LauncherAppState.isDisableAllApps()) { Log.e("Launcher3.profiles","load no all app profiles"); //对应 device_profiles.xml 中 Tablet_no_all_app 的值 minWidthDps = 380.0f; minHeightDps = 590.0f; } ..... }
3. Remove allappsbutton
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Hotseat.java
Set featureflags.no in resetlayout()_ ALL_ APPS_ Replace icon with launcherappstate. Isdisableallapps()
void resetLayout(boolean hasVerticalHotseat) { mContent.removeAllViewsInLayout(); mHasVerticalHotseat = hasVerticalHotseat; InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv; if (hasVerticalHotseat) { mContent.setGridSize(1,idp.numHotseatIcons); } else { mContent.setGridSize(idp.numHotseatIcons,1); } //if (!FeatureFlags.NO_ALL_APPS_ICON) { /// add for check is need allappbutton if (!LauncherAppState.isDisableAllApps()) { // Add the Apps button Context context = getContext(); DeviceProfile grid = mLauncher.getDeviceProfile(); ... }
4. Load the icon in allappscontainerview into workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java
Add judgment in run(), add verifyapplications(), and modify pendinginstallshortcutinfo in installshortcutreceiver to public
public void run() { synchronized (this) { // Skip fast if we are already stopped. if (mStopped) { return; } } .... // second step TraceHelper.partitionSection(TAG,"step 2.1: loading all apps"); loadAllApps(); //add for load all app on workspace if (LauncherAppState.isDisableAllApps()) { android.util.Log.e("Launcher3","verifyApplications()"); verifyApplications(); } .... } //add for load all app on workspace private void verifyApplications() { final Context context = mApp.getContext(); ArrayList<Pair<ItemInfo,Object>> installQueue = new ArrayList<>(); final List<UserHandle> profiles = mUserManager.getUserProfiles(); for (UserHandle user : profiles) { final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null,user); ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>(); synchronized (this) { for (LauncherActivityInfo app : apps) { InstallShortcutReceiver.PendingInstallShortcutInfo pendingInstallShortcutInfo = new InstallShortcutReceiver.PendingInstallShortcutInfo(app,context); added.add(pendingInstallShortcutInfo); installQueue.add(pendingInstallShortcutInfo.getItemInfo()); } } if (!added.isEmpty()) { mApp.getModel().addAndBindAddedWorkspaceItems(installQueue); } } }
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\BaseModelUpdateTask.java
Comment on return in run()
@Override public final void run() { if (!mModel.isModelLoaded()) { if (DEBUG_TASKS) { Log.d(TAG,"Ignoring model task since loader is pending=" + this); } // Loader has not yet run. //annotaion for load all app on workspace // return; } execute(mApp,mDataModel,mAllAppsList); }
5. Newly installed apps automatically add icons to workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java
Add judgment in execute() and updatetoworkspace()
public void execute(LauncherAppState app,BgDataModel dataModel,AllAppsList appsList) { .... final ArrayList<AppInfo> addedOrModified = new ArrayList<>(); addedOrModified.addAll(appsList.added); //add for load new install app on workspace if (LauncherAppState.isDisableAllApps()) { android.util.Log.e("cczLauncher3","updateToWorkSpace()"); updateToWorkSpace(context,app,appsList); } ... } //add for load new install app on workspace public void updateToWorkSpace(Context context,LauncherAppState app,AllAppsList appsList){ ArrayList<Pair<ItemInfo,Object>> installQueue = new ArrayList<>(); final List<UserHandle> profiles = UserManagerCompat.getInstance(context).getUserProfiles(); ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>(); for (UserHandle user : profiles) { final List<LauncherActivityInfo> apps = LauncherAppsCompat.getInstance(context).getActivityList(null,user); synchronized (this) { for (LauncherActivityInfo info : apps) { 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); } }
6. Replace the workspace icon and long press the delete option to cancel
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java
Add icons to settextbasedondragsource(), setcontroltypebasedondragsource(), onaccessibilitydrop(), respectively, to determine whether to delete icons
private void setTextBasedOnDragSource(ItemInfo item) { if (!TextUtils.isEmpty(mText)) { mText = getResources().getString(item.id != ItemInfo.NO_ID ? R.string.remove_drop_target_label : android.R.string.cancel); //add for hide deletedroptarget if (LauncherAppState.isDisableAllApps()) { android.util.Log.e("Launcher3","hide delete drop target"); mText = getResources().getString(isCanDrop(item) ? R.string.remove_drop_target_label : android.R.string.cancel); } requestLayout(); } } private void setControlTypeBasedOnDragSource(ItemInfo item) { mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET : ControlType.CANCEL_TARGET; //add for hide deletedroptarget [S] if (LauncherAppState.isDisableAllApps()) { mControlType = isCanDrop(item) ? ControlType.REMOVE_TARGET : ControlType.CANCEL_TARGET; } } public void onAccessibilityDrop(View view,ItemInfo item) { // Remove the item from launcher and the db,we can ignore the containerInfo in this call // because we already remove the drag view from the folder (if the drag originated from // a folder) in Folder.beginDrag() //add if juge is need remove item from workspace if (!LauncherAppState.isDisableAllApps() || isCanDrop(item)) { mLauncher.removeItem(view,item,true /* deleteFromDb */); mLauncher.getWorkspace().stripEmptyScreens(); mLauncher.getDragLayer() .announceForAccessibility(getContext().getString(R.string.item_removed)); } } private boolean isCanDrop(ItemInfo item){ return !(item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER); }
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragController.java
Add judgment in drop() to cancel the current drag operation
private void drop(DropTarget dropTarget,Runnable flingAnimation) { .... boolean accepted = false; if (dropTarget != null) { dropTarget.onDragExit(mDragObject); if (dropTarget.acceptDrop(mDragObject)) { if (flingAnimation != null) { flingAnimation.run(); } else { dropTarget.onDrop(mDragObject,mOptions); } accepted = true; //add for cancel canceldroptarget handle if (LauncherAppState.isDisableAllApps() && dropTarget instanceof DeleteDropTarget && isNeedCancelDrag(mDragObject.dragInfo)) { cancelDrag(); } } } ... } private boolean isNeedCancelDrag(ItemInfo item){ return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER); }
7. Mask pull-up display drawer page gesture
vendor\mediatek\proprietary\packages\apps\Launcher3\quickstep\src\com\android\launcher3
\uioverrides\OverviewToAllAppsTouchController.java
canInterceptTouch() 中增加判断是否直接拦截 @Override protected boolean canInterceptTouch(MotionEvent ev) { //add for forbidden workspace drag change GradientView alph if (LauncherAppState.isDisableAllApps()){ android.util.Log.e("Launcher3","canInterceptTouch()"); return false; } if (mCurrentAnimation != null) { // If we are already animating from a prevIoUs state,we can intercept. return true; } if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { return false; } if (mLauncher.isInState(ALL_APPS)) { // In all-apps only listen if the container cannot scroll itself return mLauncher.getAppsView().shouldContainerScroll(ev); } else if (mLauncher.isInState(NORMAL)) { return true; } else if (mLauncher.isInState(OVERVIEW)) { RecentsView rv = mLauncher.getOverviewPanel(); return ev.getY() > (rv.getBottom() - rv.getPaddingBottom()); } else { return false; } }
8. Change page indicator to dot
vendor\mediatek\proprietary\packages\apps\Launcher3\res\layout\launcher.xml
Change workspacepageindicator to pageindicatordots
<com.android.launcher3.pageindicators.PageIndicatorDots android:id="@+id/page_indicator" android:layout_width="match_parent" android:layout_height="4dp" android:layout_gravity="bottom|center_horizontal" android:theme="@style/HomeScreenElementTheme" /> vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3
\pageindicators\PageIndicatorDots.java
Add pageindicatordots, inherit insettable, duplicate setinsets(), and adjust the position of dots
public class PageIndicatorDots extends View implements PageIndicator,Insettable { // add for change WorkspacePageIndicator line to dot @Override public void setInsets(Rect insets) { DeviceProfile grid = mLauncher.getDeviceProfile(); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); if (grid.isVerticalBarLayout()) { Rect padding = grid.workspacePadding; lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx; lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx; lp.bottomMargin = padding.bottom; } else { lp.leftMargin = lp.rightMargin = 0; lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom; } setLayoutParams(lp); } @Override public void setScroll(int currentScroll,int totalScroll) { if (mNumPages > 1) { if (mIsRtl) { currentScroll = totalScroll - currentScroll; } int scrollPerPage = totalScroll / (mNumPages - 1); // add for change WorkspacePageIndicator line to dot if (scrollPerPage == 0) { return; } int pageToLeft = currentScroll / scrollPerPage; int pageToLeftScroll = pageToLeft * scrollPerPage; int pageToRightScroll = pageToLeftScroll + scrollPerPage; ... }
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3
\states\SpringLoadedState.java
Note setshouldautohide(), to avoid crash when pressing workspace for a long time
@Override public void onStateEnabled(Launcher launcher) { Workspace ws = launcher.getWorkspace(); ws.showPageIndicatorAtCurrentScroll(); //annotaion for WorkspacePageIndicator line to dot // ws.getPageIndicator().setShouldAutoHide(false); // Prevent any Un/InstallShortcutReceivers from updating the db while we are // in spring loaded mode InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP); launcher.getRotationHelper().setCurrentStateRequest(REQUEST_LOCK); } @Override public void onStateDisabled(final Launcher launcher) { //annotaion for WorkspacePageIndicator line to dot // launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true); // Re-enable any Un/InstallShortcutReceiver and Now process any queued items InstallShortcutReceiver.disableAndFlushInstallQueue( InstallShortcutReceiver.FLAG_DRAG_AND_DROP,launcher); }
summary
The above is what Xiaobian introduced to you. Android 9.0 launcher 3 removes the drawer display and explains all app codes in detail. I hope it will be helpful to you. If you have any questions, please leave me a message and Xiaobian will reply to you in time. Thank you very much for your support to our website! If you think this article is helpful to you, welcome to reprint, please indicate the source, thank you!