מדריך | הפעלת המחווה לפתיחת מגירת האפליקציות במסך הבית!
-
אחרי הרבה עבודה...
המדריך באדיבות קלוד סונט 5
צילומי מסך:

@10110000 @שניאור-שמח @נוחעם-FM @שלום-כהן
מדריך: הוספת מחווה לפתיחת מגירת האפליקציות ב-Launcher3QuickStep
מדריך זה מתעד את השלבים המדויקים שביצעתי כדי לפתור בעיה נפוצה בבניות מבוססות
Launcher3QuickStep (AOSP) על מכשירים עם מסך ביחס ממדים חריג (כמו Qin F21 Pro)
כאשר החלקה למעלה במסך הבית לא פותחת את מגירת האפליקציות.
שורש הבעיה
ב-Launcher3QuickStep הסטנדרטי, המחווה של החלקה למעלה כדי לפתוח את המגירה
מיושמת דרך מחלקה בשםPortraitStatesTouchController, שנרשמת בתוך
QuickstepLauncher.createTouchControllers().הבעיה: הרישום הזה מותנה בבדיקה
DeviceProfile.isVerticalBarLayout().
במכשירים עם יחס ממדים חריג (מסכים קטנים/כמעט-מרובעים), הפונקציה הזו מחזירה
trueבטעות — מה שגורם לקוד לעבור לענף אחר (המיועד למכשירים עם hotseat
אנכי, כמו טאבלטים/מכשירים מתקפלים), שבוPortraitStatesTouchController
לא נרשם בכלל. התוצאה: אין שום דרך במגע לפתוח את המגירה.איך לזהות את זה בעצמכם ב-APK אחר
# אחרי פירוק עם apktool: grep -n "createTouchControllers" smali_classes2/com/android/launcher3/uioverrides/QuickstepLauncher.smaliחפשו בגוף המתודה הזו קריאה ל-
DeviceProfile;->isVerticalBarLayout()Z— אם
הענף שמוסיףPortraitStatesTouchControllerתלוי בבדיקה הזו, זו אותה בעיה.
הפתרון שבחרתי
במקום "לתקן" את
isVerticalBarLayout()(מסוכן — הוא משפיע על עוד המון
לוגיקת מסך), יצרתי controller עצמאי חדש שמזהה בעצמו החלקה למעלה על מסך
הבית ופותח את המגירה — בלי שום תלות בענף השבור. הוא נרשם תמיד, בלי תנאי,
כך שהוא עובד גם אםisVerticalBarLayout()ממשיך "לטעות".כלים נדרשים
מידע חשוב: המדריך דורש רוט עם הרשאות כתיבה
שלב 1 — פתיחת ה-APK לעריכה
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
ייפתח תפריט "פתח באמצעות". - בחרו הצג.
- תיפתח תצוגת עץ שמראה את מבנה ה-APK כולל
classes.dex,
classes2.dexוכו', כל אחד ניתן לניווט עד רמת חבילות ה-Smali. - נווטו לתוך
classes2.dex(שם נמצא כל קוד ה-launcher עצמו ברוב הבניות) →
com/android/launcher3/uioverrides/touchcontrollers/.
שלב 2 — יצירת המחלקה החדשה
בתוך התיקייה
touchcontrollers/שמצאתם, צרו קובץ Smali חדש (לחצו על הקובץ הראשון לחיצה ארוכה ובחרו "הוסף") בשם בדיוק:SimpleAppDrawerSwipeController.smali.class public Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; .super Ljava/lang/Object; .source "SimpleAppDrawerSwipeController.java" # interfaces .implements Lcom/android/launcher3/util/TouchController; # instance fields .field private mCanIntercept:Z .field private mDownX:F .field private mDownY:F .field private final mLauncher:Lcom/android/launcher3/Launcher; .field private final mSwipeSlop:F # direct methods .method public constructor <init>(Lcom/android/launcher3/Launcher;)V .locals 2 .param p1, "launcher" # Lcom/android/launcher3/Launcher; invoke-direct {p0}, Ljava/lang/Object;-><init>()V iput-object p1, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-static {p1}, Landroid/view/ViewConfiguration;->get(Landroid/content/Context;)Landroid/view/ViewConfiguration; move-result-object v0 invoke-virtual {v0}, Landroid/view/ViewConfiguration;->getScaledTouchSlop()I move-result v0 mul-int/lit8 v0, v0, 0x4 int-to-float v0, v0 iput v0, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F return-void .end method # virtual methods .method public onControllerInterceptTouchEvent(Landroid/view/MotionEvent;)Z .locals 6 .param p1, "ev" # Landroid/view/MotionEvent; invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I move-result v0 const/4 v1, 0x0 if-nez v0, :cond_1 iget-object v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; sget-object v3, Lcom/android/launcher3/LauncherState;->NORMAL:Lcom/android/launcher3/LauncherState; invoke-virtual {v2, v3}, Lcom/android/launcher3/Launcher;->isInState(Lcom/android/launcher3/statemanager/BaseState;)Z move-result v2 iput-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F return v1 :cond_1 iget-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z if-nez v2, :cond_2 return v1 :cond_2 const/4 v2, 0x2 if-eq v0, v2, :cond_3 return v1 :cond_3 invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I move-result v2 const/4 v3, 0x1 if-eq v2, v3, :cond_4 return v1 :cond_4 iget v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v4 sub-float/2addr v2, v4 invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F sub-float/2addr v4, v5 invoke-static {v4}, Ljava/lang/Math;->abs(F)F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F cmpl-float v5, v2, v5 if-lez v5, :cond_5 cmpl-float v5, v2, v4 if-lez v5, :cond_5 iget-object v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-virtual {v5}, Lcom/android/launcher3/Launcher;->getStateManager()Lcom/android/launcher3/statemanager/StateManager; move-result-object v5 sget-object v0, Lcom/android/launcher3/LauncherState;->ALL_APPS:Lcom/android/launcher3/LauncherState; invoke-virtual {v5, v0}, Lcom/android/launcher3/statemanager/StateManager;->goToState(Lcom/android/launcher3/statemanager/BaseState;)V const/4 v0, 0x1 return v0 :cond_5 return v1 .end method .method public onControllerTouchEvent(Landroid/view/MotionEvent;)Z .locals 1 .param p1, "ev" # Landroid/view/MotionEvent; const/4 v0, 0x1 return v0 .end methodאיך זה עובד, בקצרה:
onControllerInterceptTouchEventעוקב אחרי כל מגע: ב-ACTION_DOWNהוא בודק
שהמסך במצבNORMAL(מסך הבית, לא במגירה/overview כבר) ושומר את נקודת
ההתחלה.- ב-
ACTION_MOVE, אם התזוזה האנכית כלפי מעלה עוברת סף (4 × touch-slop של המערכת) והיא דומיננטית יותר מהתזוזה האופקית (כלומר מחווה אנכית ולא גרירה
בין מסכים) — הוא קורא ל-goToState(ALL_APPS)ומחזירtrue, מה שגורם
ל-DragLayer "לגנוב" את המגע משאר הרכיבים. onControllerTouchEventפשוט בולע את המשך המחווה כדי שלא יקרו תופעות לוואי
בזמן שהמעבר למגירה כבר קורה.
שלב 3 — רישום ה-controller
חזרו תיקייה אחת אחורה (
uioverrides/) ופתחו לעריכה את
QuickstepLauncher.smali. חפשו בתוך הקובץ (יש חיפוש טקסט בעורך) את המתודה:.method public createTouchControllers()[Lcom/android/launcher3/util/TouchController;בתוך המתודה הזו, מיד אחרי השורה הראשונה שמוסיפה פריט ל-
ArrayList(זו
שמוסיפה את ה-DragController— תזהו אותה לפיgetDragController()ממש
מעליה), הוסיפו את שלוש השורות הבאות:invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z new-instance v3, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; invoke-direct {v3, p0}, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;-><init>(Lcom/android/launcher3/Launcher;)V invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Zחשוב לפני שאתם מדביקים:
v2בקוד הזה הוא ה-register שמחזיק את
ה-ArrayList<TouchController>, ו-v3הוא register שחייב להיות פנוי
לשימוש חוזר באותה נקודה — בדקו בעצמכם בקובץ שלכם (חפשו למעלה איפהv3
משמש לאחרונה, ולמטה איפה הוא משמש הבא). אםv3לא פנוי שם, או אם.locals
בתחילת המתודה נמוך מדי בשביל ה-register שבחרתם — MT Manager יזרוק שגיאת קימפול Smali ברגע השמירה/יציאה מהעורך, ותצטרכו לבחור register אחר ואולי
להעלות את מספר ה-.locals.שלב 4 — שמירה וקימפול
צאו מעורך ה-Smali (בדרך כלל כפתור "שמור" או חץ אחורה) (לא לסמן את "חתימה אוטומטית"!)
— MT Manager יקמפל
אוטומטית את השינויים בחזרה ל-dex ברגע הזה. אם יש שגיאת תחביר Smali היא
תופיע כאן; אם לא, ה-APK בתיקייה שערכתם כבר מעודכן.
בהצלחה!
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
-
מ מחנה ידידים מחק נושא זה
-
מ מחנה ידידים שחזר נושא זה
-
אחרי הרבה עבודה...
המדריך באדיבות קלוד סונט 5
צילומי מסך:

@10110000 @שניאור-שמח @נוחעם-FM @שלום-כהן
מדריך: הוספת מחווה לפתיחת מגירת האפליקציות ב-Launcher3QuickStep
מדריך זה מתעד את השלבים המדויקים שביצעתי כדי לפתור בעיה נפוצה בבניות מבוססות
Launcher3QuickStep (AOSP) על מכשירים עם מסך ביחס ממדים חריג (כמו Qin F21 Pro)
כאשר החלקה למעלה במסך הבית לא פותחת את מגירת האפליקציות.
שורש הבעיה
ב-Launcher3QuickStep הסטנדרטי, המחווה של החלקה למעלה כדי לפתוח את המגירה
מיושמת דרך מחלקה בשםPortraitStatesTouchController, שנרשמת בתוך
QuickstepLauncher.createTouchControllers().הבעיה: הרישום הזה מותנה בבדיקה
DeviceProfile.isVerticalBarLayout().
במכשירים עם יחס ממדים חריג (מסכים קטנים/כמעט-מרובעים), הפונקציה הזו מחזירה
trueבטעות — מה שגורם לקוד לעבור לענף אחר (המיועד למכשירים עם hotseat
אנכי, כמו טאבלטים/מכשירים מתקפלים), שבוPortraitStatesTouchController
לא נרשם בכלל. התוצאה: אין שום דרך במגע לפתוח את המגירה.איך לזהות את זה בעצמכם ב-APK אחר
# אחרי פירוק עם apktool: grep -n "createTouchControllers" smali_classes2/com/android/launcher3/uioverrides/QuickstepLauncher.smaliחפשו בגוף המתודה הזו קריאה ל-
DeviceProfile;->isVerticalBarLayout()Z— אם
הענף שמוסיףPortraitStatesTouchControllerתלוי בבדיקה הזו, זו אותה בעיה.
הפתרון שבחרתי
במקום "לתקן" את
isVerticalBarLayout()(מסוכן — הוא משפיע על עוד המון
לוגיקת מסך), יצרתי controller עצמאי חדש שמזהה בעצמו החלקה למעלה על מסך
הבית ופותח את המגירה — בלי שום תלות בענף השבור. הוא נרשם תמיד, בלי תנאי,
כך שהוא עובד גם אםisVerticalBarLayout()ממשיך "לטעות".כלים נדרשים
מידע חשוב: המדריך דורש רוט עם הרשאות כתיבה
שלב 1 — פתיחת ה-APK לעריכה
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
ייפתח תפריט "פתח באמצעות". - בחרו הצג.
- תיפתח תצוגת עץ שמראה את מבנה ה-APK כולל
classes.dex,
classes2.dexוכו', כל אחד ניתן לניווט עד רמת חבילות ה-Smali. - נווטו לתוך
classes2.dex(שם נמצא כל קוד ה-launcher עצמו ברוב הבניות) →
com/android/launcher3/uioverrides/touchcontrollers/.
שלב 2 — יצירת המחלקה החדשה
בתוך התיקייה
touchcontrollers/שמצאתם, צרו קובץ Smali חדש (לחצו על הקובץ הראשון לחיצה ארוכה ובחרו "הוסף") בשם בדיוק:SimpleAppDrawerSwipeController.smali.class public Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; .super Ljava/lang/Object; .source "SimpleAppDrawerSwipeController.java" # interfaces .implements Lcom/android/launcher3/util/TouchController; # instance fields .field private mCanIntercept:Z .field private mDownX:F .field private mDownY:F .field private final mLauncher:Lcom/android/launcher3/Launcher; .field private final mSwipeSlop:F # direct methods .method public constructor <init>(Lcom/android/launcher3/Launcher;)V .locals 2 .param p1, "launcher" # Lcom/android/launcher3/Launcher; invoke-direct {p0}, Ljava/lang/Object;-><init>()V iput-object p1, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-static {p1}, Landroid/view/ViewConfiguration;->get(Landroid/content/Context;)Landroid/view/ViewConfiguration; move-result-object v0 invoke-virtual {v0}, Landroid/view/ViewConfiguration;->getScaledTouchSlop()I move-result v0 mul-int/lit8 v0, v0, 0x4 int-to-float v0, v0 iput v0, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F return-void .end method # virtual methods .method public onControllerInterceptTouchEvent(Landroid/view/MotionEvent;)Z .locals 6 .param p1, "ev" # Landroid/view/MotionEvent; invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I move-result v0 const/4 v1, 0x0 if-nez v0, :cond_1 iget-object v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; sget-object v3, Lcom/android/launcher3/LauncherState;->NORMAL:Lcom/android/launcher3/LauncherState; invoke-virtual {v2, v3}, Lcom/android/launcher3/Launcher;->isInState(Lcom/android/launcher3/statemanager/BaseState;)Z move-result v2 iput-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F return v1 :cond_1 iget-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z if-nez v2, :cond_2 return v1 :cond_2 const/4 v2, 0x2 if-eq v0, v2, :cond_3 return v1 :cond_3 invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I move-result v2 const/4 v3, 0x1 if-eq v2, v3, :cond_4 return v1 :cond_4 iget v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v4 sub-float/2addr v2, v4 invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F sub-float/2addr v4, v5 invoke-static {v4}, Ljava/lang/Math;->abs(F)F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F cmpl-float v5, v2, v5 if-lez v5, :cond_5 cmpl-float v5, v2, v4 if-lez v5, :cond_5 iget-object v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-virtual {v5}, Lcom/android/launcher3/Launcher;->getStateManager()Lcom/android/launcher3/statemanager/StateManager; move-result-object v5 sget-object v0, Lcom/android/launcher3/LauncherState;->ALL_APPS:Lcom/android/launcher3/LauncherState; invoke-virtual {v5, v0}, Lcom/android/launcher3/statemanager/StateManager;->goToState(Lcom/android/launcher3/statemanager/BaseState;)V const/4 v0, 0x1 return v0 :cond_5 return v1 .end method .method public onControllerTouchEvent(Landroid/view/MotionEvent;)Z .locals 1 .param p1, "ev" # Landroid/view/MotionEvent; const/4 v0, 0x1 return v0 .end methodאיך זה עובד, בקצרה:
onControllerInterceptTouchEventעוקב אחרי כל מגע: ב-ACTION_DOWNהוא בודק
שהמסך במצבNORMAL(מסך הבית, לא במגירה/overview כבר) ושומר את נקודת
ההתחלה.- ב-
ACTION_MOVE, אם התזוזה האנכית כלפי מעלה עוברת סף (4 × touch-slop של המערכת) והיא דומיננטית יותר מהתזוזה האופקית (כלומר מחווה אנכית ולא גרירה
בין מסכים) — הוא קורא ל-goToState(ALL_APPS)ומחזירtrue, מה שגורם
ל-DragLayer "לגנוב" את המגע משאר הרכיבים. onControllerTouchEventפשוט בולע את המשך המחווה כדי שלא יקרו תופעות לוואי
בזמן שהמעבר למגירה כבר קורה.
שלב 3 — רישום ה-controller
חזרו תיקייה אחת אחורה (
uioverrides/) ופתחו לעריכה את
QuickstepLauncher.smali. חפשו בתוך הקובץ (יש חיפוש טקסט בעורך) את המתודה:.method public createTouchControllers()[Lcom/android/launcher3/util/TouchController;בתוך המתודה הזו, מיד אחרי השורה הראשונה שמוסיפה פריט ל-
ArrayList(זו
שמוסיפה את ה-DragController— תזהו אותה לפיgetDragController()ממש
מעליה), הוסיפו את שלוש השורות הבאות:invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z new-instance v3, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; invoke-direct {v3, p0}, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;-><init>(Lcom/android/launcher3/Launcher;)V invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Zחשוב לפני שאתם מדביקים:
v2בקוד הזה הוא ה-register שמחזיק את
ה-ArrayList<TouchController>, ו-v3הוא register שחייב להיות פנוי
לשימוש חוזר באותה נקודה — בדקו בעצמכם בקובץ שלכם (חפשו למעלה איפהv3
משמש לאחרונה, ולמטה איפה הוא משמש הבא). אםv3לא פנוי שם, או אם.locals
בתחילת המתודה נמוך מדי בשביל ה-register שבחרתם — MT Manager יזרוק שגיאת קימפול Smali ברגע השמירה/יציאה מהעורך, ותצטרכו לבחור register אחר ואולי
להעלות את מספר ה-.locals.שלב 4 — שמירה וקימפול
צאו מעורך ה-Smali (בדרך כלל כפתור "שמור" או חץ אחורה) (לא לסמן את "חתימה אוטומטית"!)
— MT Manager יקמפל
אוטומטית את השינויים בחזרה ל-dex ברגע הזה. אם יש שגיאת תחביר Smali היא
תופיע כאן; אם לא, ה-APK בתיקייה שערכתם כבר מעודכן.
בהצלחה!
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
-
פוסט זה נמחק!
-
אחרי הרבה עבודה...
המדריך באדיבות קלוד סונט 5
צילומי מסך:

@10110000 @שניאור-שמח @נוחעם-FM @שלום-כהן
מדריך: הוספת מחווה לפתיחת מגירת האפליקציות ב-Launcher3QuickStep
מדריך זה מתעד את השלבים המדויקים שביצעתי כדי לפתור בעיה נפוצה בבניות מבוססות
Launcher3QuickStep (AOSP) על מכשירים עם מסך ביחס ממדים חריג (כמו Qin F21 Pro)
כאשר החלקה למעלה במסך הבית לא פותחת את מגירת האפליקציות.
שורש הבעיה
ב-Launcher3QuickStep הסטנדרטי, המחווה של החלקה למעלה כדי לפתוח את המגירה
מיושמת דרך מחלקה בשםPortraitStatesTouchController, שנרשמת בתוך
QuickstepLauncher.createTouchControllers().הבעיה: הרישום הזה מותנה בבדיקה
DeviceProfile.isVerticalBarLayout().
במכשירים עם יחס ממדים חריג (מסכים קטנים/כמעט-מרובעים), הפונקציה הזו מחזירה
trueבטעות — מה שגורם לקוד לעבור לענף אחר (המיועד למכשירים עם hotseat
אנכי, כמו טאבלטים/מכשירים מתקפלים), שבוPortraitStatesTouchController
לא נרשם בכלל. התוצאה: אין שום דרך במגע לפתוח את המגירה.איך לזהות את זה בעצמכם ב-APK אחר
# אחרי פירוק עם apktool: grep -n "createTouchControllers" smali_classes2/com/android/launcher3/uioverrides/QuickstepLauncher.smaliחפשו בגוף המתודה הזו קריאה ל-
DeviceProfile;->isVerticalBarLayout()Z— אם
הענף שמוסיףPortraitStatesTouchControllerתלוי בבדיקה הזו, זו אותה בעיה.
הפתרון שבחרתי
במקום "לתקן" את
isVerticalBarLayout()(מסוכן — הוא משפיע על עוד המון
לוגיקת מסך), יצרתי controller עצמאי חדש שמזהה בעצמו החלקה למעלה על מסך
הבית ופותח את המגירה — בלי שום תלות בענף השבור. הוא נרשם תמיד, בלי תנאי,
כך שהוא עובד גם אםisVerticalBarLayout()ממשיך "לטעות".כלים נדרשים
מידע חשוב: המדריך דורש רוט עם הרשאות כתיבה
שלב 1 — פתיחת ה-APK לעריכה
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
ייפתח תפריט "פתח באמצעות". - בחרו הצג.
- תיפתח תצוגת עץ שמראה את מבנה ה-APK כולל
classes.dex,
classes2.dexוכו', כל אחד ניתן לניווט עד רמת חבילות ה-Smali. - נווטו לתוך
classes2.dex(שם נמצא כל קוד ה-launcher עצמו ברוב הבניות) →
com/android/launcher3/uioverrides/touchcontrollers/.
שלב 2 — יצירת המחלקה החדשה
בתוך התיקייה
touchcontrollers/שמצאתם, צרו קובץ Smali חדש (לחצו על הקובץ הראשון לחיצה ארוכה ובחרו "הוסף") בשם בדיוק:SimpleAppDrawerSwipeController.smali.class public Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; .super Ljava/lang/Object; .source "SimpleAppDrawerSwipeController.java" # interfaces .implements Lcom/android/launcher3/util/TouchController; # instance fields .field private mCanIntercept:Z .field private mDownX:F .field private mDownY:F .field private final mLauncher:Lcom/android/launcher3/Launcher; .field private final mSwipeSlop:F # direct methods .method public constructor <init>(Lcom/android/launcher3/Launcher;)V .locals 2 .param p1, "launcher" # Lcom/android/launcher3/Launcher; invoke-direct {p0}, Ljava/lang/Object;-><init>()V iput-object p1, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-static {p1}, Landroid/view/ViewConfiguration;->get(Landroid/content/Context;)Landroid/view/ViewConfiguration; move-result-object v0 invoke-virtual {v0}, Landroid/view/ViewConfiguration;->getScaledTouchSlop()I move-result v0 mul-int/lit8 v0, v0, 0x4 int-to-float v0, v0 iput v0, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F return-void .end method # virtual methods .method public onControllerInterceptTouchEvent(Landroid/view/MotionEvent;)Z .locals 6 .param p1, "ev" # Landroid/view/MotionEvent; invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I move-result v0 const/4 v1, 0x0 if-nez v0, :cond_1 iget-object v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; sget-object v3, Lcom/android/launcher3/LauncherState;->NORMAL:Lcom/android/launcher3/LauncherState; invoke-virtual {v2, v3}, Lcom/android/launcher3/Launcher;->isInState(Lcom/android/launcher3/statemanager/BaseState;)Z move-result v2 iput-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v2 iput v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F return v1 :cond_1 iget-boolean v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mCanIntercept:Z if-nez v2, :cond_2 return v1 :cond_2 const/4 v2, 0x2 if-eq v0, v2, :cond_3 return v1 :cond_3 invoke-virtual {p1}, Landroid/view/MotionEvent;->getPointerCount()I move-result v2 const/4 v3, 0x1 if-eq v2, v3, :cond_4 return v1 :cond_4 iget v2, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownY:F invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F move-result v4 sub-float/2addr v2, v4 invoke-virtual {p1}, Landroid/view/MotionEvent;->getX()F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mDownX:F sub-float/2addr v4, v5 invoke-static {v4}, Ljava/lang/Math;->abs(F)F move-result v4 iget v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mSwipeSlop:F cmpl-float v5, v2, v5 if-lez v5, :cond_5 cmpl-float v5, v2, v4 if-lez v5, :cond_5 iget-object v5, p0, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;->mLauncher:Lcom/android/launcher3/Launcher; invoke-virtual {v5}, Lcom/android/launcher3/Launcher;->getStateManager()Lcom/android/launcher3/statemanager/StateManager; move-result-object v5 sget-object v0, Lcom/android/launcher3/LauncherState;->ALL_APPS:Lcom/android/launcher3/LauncherState; invoke-virtual {v5, v0}, Lcom/android/launcher3/statemanager/StateManager;->goToState(Lcom/android/launcher3/statemanager/BaseState;)V const/4 v0, 0x1 return v0 :cond_5 return v1 .end method .method public onControllerTouchEvent(Landroid/view/MotionEvent;)Z .locals 1 .param p1, "ev" # Landroid/view/MotionEvent; const/4 v0, 0x1 return v0 .end methodאיך זה עובד, בקצרה:
onControllerInterceptTouchEventעוקב אחרי כל מגע: ב-ACTION_DOWNהוא בודק
שהמסך במצבNORMAL(מסך הבית, לא במגירה/overview כבר) ושומר את נקודת
ההתחלה.- ב-
ACTION_MOVE, אם התזוזה האנכית כלפי מעלה עוברת סף (4 × touch-slop של המערכת) והיא דומיננטית יותר מהתזוזה האופקית (כלומר מחווה אנכית ולא גרירה
בין מסכים) — הוא קורא ל-goToState(ALL_APPS)ומחזירtrue, מה שגורם
ל-DragLayer "לגנוב" את המגע משאר הרכיבים. onControllerTouchEventפשוט בולע את המשך המחווה כדי שלא יקרו תופעות לוואי
בזמן שהמעבר למגירה כבר קורה.
שלב 3 — רישום ה-controller
חזרו תיקייה אחת אחורה (
uioverrides/) ופתחו לעריכה את
QuickstepLauncher.smali. חפשו בתוך הקובץ (יש חיפוש טקסט בעורך) את המתודה:.method public createTouchControllers()[Lcom/android/launcher3/util/TouchController;בתוך המתודה הזו, מיד אחרי השורה הראשונה שמוסיפה פריט ל-
ArrayList(זו
שמוסיפה את ה-DragController— תזהו אותה לפיgetDragController()ממש
מעליה), הוסיפו את שלוש השורות הבאות:invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z new-instance v3, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController; invoke-direct {v3, p0}, Lcom/android/launcher3/uioverrides/touchcontrollers/SimpleAppDrawerSwipeController;-><init>(Lcom/android/launcher3/Launcher;)V invoke-virtual {v2, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Zחשוב לפני שאתם מדביקים:
v2בקוד הזה הוא ה-register שמחזיק את
ה-ArrayList<TouchController>, ו-v3הוא register שחייב להיות פנוי
לשימוש חוזר באותה נקודה — בדקו בעצמכם בקובץ שלכם (חפשו למעלה איפהv3
משמש לאחרונה, ולמטה איפה הוא משמש הבא). אםv3לא פנוי שם, או אם.locals
בתחילת המתודה נמוך מדי בשביל ה-register שבחרתם — MT Manager יזרוק שגיאת קימפול Smali ברגע השמירה/יציאה מהעורך, ותצטרכו לבחור register אחר ואולי
להעלות את מספר ה-.locals.שלב 4 — שמירה וקימפול
צאו מעורך ה-Smali (בדרך כלל כפתור "שמור" או חץ אחורה) (לא לסמן את "חתימה אוטומטית"!)
— MT Manager יקמפל
אוטומטית את השינויים בחזרה ל-dex ברגע הזה. אם יש שגיאת תחביר Smali היא
תופיע כאן; אם לא, ה-APK בתיקייה שערכתם כבר מעודכן.
בהצלחה!
- במסך הקבצים של MT Manager, אתרו את ה-APK ולחצו עליו (לא לחיצה ארוכה) —
-
פוסט זה נמחק!
-
פוסט זה נמחק!
-
ש שניאור שמח העביר נושא זה מ-עזרה הדדית - שיאומי f21 pro ו +f21 pro
-
ע ע.1195 נעל נושא זה
שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.
נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.
בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗
הרשמה התחברות