android 9.0 launcher3 去掉抽屜式顯示所有 app(代碼詳解)
效果圖
修改思路
1、增加全局控制變量 sys.launcher3.is_full_app,用來動態(tài)切換
2、增加兩套布局,對應(yīng)有抽屜和無抽屜
3、去除 allAppsButton
4、將 AllAppsContainerView 中的圖標(biāo)加載到 Workspace
5、新安裝的 app 自動添加圖標(biāo)到 Workspace
6、替換 Workspace 圖標(biāo)長按刪除選項(xiàng)為取消
7、屏蔽上拉顯示抽屜頁面手勢
8、修改頁面指示線為圓點(diǎn)
上代碼
1、增加全局控制變量 sys.launcher3.is_full_app
1) 在 LauncherAppState 中增加靜態(tài)方法 isDisableAllApps(), 通過修改 Settings 中自定義的值 sys.launcher3.is_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) AndroidManifest-common.xml 中增加權(quán)限
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
3) 在 SettingsActivity 中增加 SwitchPreference 用以動態(tài)修改 sys.launcher3.is_full_app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\SettingsActivity.java
在內(nèi)部類 LauncherSettingsFragment 中重寫 onPreferenceTreeClick() 用以監(jiān)聽 SwitchPreference 點(diǎn)擊
/** * This fragment shows the launcher preferences. */ public static class LauncherSettingsFragment extends PreferenceFragment { ..... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... //讀取保存的值,初始化 SwitchPreference 的初始狀態(tài),是否選中 int isFull = Settings.System.getInt(getActivity().getContentResolver(), "sys.launcher3.is_full_app", 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(), "sys.launcher3.is_full_app", 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; } }
點(diǎn)擊 SwitchPreference 后需要保存 sys.launcher3.is_full_app 新值,同時(shí)清除 Launcher3 的緩存,延時(shí)啟動并結(jié)束當(dāng)前進(jìn)程
清除緩存方法 clearApplicationUserData 在 Launcher3 中編譯報(bào)錯(cuò),所以通過發(fā)送廣播到 Setting 中進(jìn)行真正的清緩存操作
//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) SettingsActivity 對應(yīng)的 xml 文件修改 launcher_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" />
對應(yīng)的 string 文件就不貼了,自己增加下就行
2、增加兩套布局,對應(yīng)有抽屜和無抽屜
加載布局文件對應(yīng)的 xml 為 vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\device_profiles.xml
Launcher3 通過獲取 minWidthDps 和 minHeightDps 來確定加載哪一個(gè) profile,我的平板分辨率是 1280*800 的,增加兩個(gè) profile 節(jié)點(diǎn)
<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" />
對應(yīng)的你需要在 xml 文件下增加 4 個(gè)文件,分別是 default_workspace_tb_5x6.xml dw_hotseat_tb.xml default_workspace_tb_5x6_no_all_app.xml dw_hotseat_tb_no_all_app.xml
這樣的好處是你可以自定義不同的布局文件加載內(nèi)容,上面的配置含義簡單說一下,分別是最小寬度、最小高度、布局的行和列、文件夾中布局行和列、圖標(biāo)大小、圖標(biāo)文字大小、HotSeat 個(gè)數(shù),加載的布局文件
在 InvariantDeviceProfile() 判斷是否需要加載 Tablet_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"); //對應(yīng) device_profiles.xml 中 Tablet_no_all_app 的值 minWidthDps = 380.0f; minHeightDps = 590.0f; } ..... }
3、去除 allAppsButton
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Hotseat.java
將 resetLayout() 中 FeatureFlags.NO_ALL_APPS_ICON 替換為 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、將 AllAppsContainerView 中的圖標(biāo)加載到 Workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java
run() 中增加判斷,添加 verifyApplications(), 修改 InstallShortcutReceiver 中 PendingInstallShortcutInfo 為 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
注釋 run() 中的 return
@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、新安裝的 app 自動添加圖標(biāo)到 Workspace
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java
execute() 中增加判斷,添加 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、替換 Workspace 圖標(biāo)長按刪除選項(xiàng)為取消
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java
在 setTextBasedOnDragSource() 、setControlTypeBasedOnDragSource()、onAccessibilityDrop() 中分別增加判斷是否需要刪除圖標(biāo)
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
drop() 中增加判斷,取消當(dāng)前拖拽操作
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、屏蔽上拉顯示抽屜頁面手勢
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、修改頁面指示線為圓點(diǎn)
vendor\mediatek\proprietary\packages\apps\Launcher3\res\layout\launcher.xml
WorkspacePageIndicator 改為 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
增加 PageIndicatorDots 繼承 Insettable,復(fù)寫setInsets(), 調(diào)整圓點(diǎn)的位置
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
注釋 setShouldAutoHide(),避免長按 workSpace 時(shí)發(fā)生崩潰
@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); }
總結(jié)
以上所述是小編給大家介紹的android 9.0 launcher3 去掉抽屜式顯示所有 app代碼詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
Android Flutter實(shí)現(xiàn)視頻上滑翻頁效果的示例代碼
我們在短視頻應(yīng)用中經(jīng)常會看到不停上滑瀏覽下一條視頻的沉浸式交互效果,這種交互能夠讓用戶不停地翻頁,直到找到喜歡的視頻內(nèi)容。本文將通過Flutter中的PageView組件實(shí)現(xiàn),感興趣的可以了解一下2022-10-10Android recyclerview實(shí)現(xiàn)拖拽排序和側(cè)滑刪除
這篇文章主要為大家詳細(xì)介紹了Android recyclerview實(shí)現(xiàn)拖拽排序和側(cè)滑刪除,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02一文詳解Android IntentService的開發(fā)技巧
Android應(yīng)用開發(fā)中,執(zhí)行后臺任務(wù)是常見需求之一,其中,IntentService是一種強(qiáng)大的工具,可以輕松管理異步任務(wù),而無需擔(dān)心線程管理和生命周期問題,本文將深入探討 IntentService 的各個(gè)方面,需要的朋友可以參考下2023-11-11Android PC端用ADB抓取指定應(yīng)用日志實(shí)現(xiàn)步驟
這篇文章主要介紹了Android PC端用ADB抓取指定應(yīng)用日志實(shí)現(xiàn)步驟,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Android 三行代碼實(shí)現(xiàn)高斯模糊效果
這篇文章主要介紹了Android 三行代碼實(shí)現(xiàn)高斯模糊效果,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09android Activity線性布局和表格布局實(shí)例講解
在activity的布局中,線性布局和表格布局是最簡單的,這次分別從線性布局,表格布局以及線性布局和表格混合布局做了實(shí)驗(yàn)2013-11-11Android中WebView加載網(wǎng)頁設(shè)置進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android中WebView加載網(wǎng)頁設(shè)置進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05Android設(shè)置TextView樣式SpannableString教程
這篇文章主要為大家介紹了Android設(shè)置TextView樣式SpannableString教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02android 開發(fā)教程之日歷項(xiàng)目實(shí)踐(一)
決定開始學(xué)習(xí) Android 平臺下的軟件開發(fā),以日歷作為實(shí)踐項(xiàng)目,進(jìn)行一周后,基本完成,有需要的朋友可以參考下2013-01-01