Copy file SystemUi.apk vào thư mục place-apk-here-for-modding 4. Chỉnh sửa: Chạy file Script.bat để bắt đầu, Enter để vào menu Chọn 9 để Decompile file SystemUi.apk. Nó hỏi thì nhấn y và Enter để vào ngay thư mục SystemUi.apk Chuẩn bị 1 ảnh dạng png. dạng như icon ấy nhé. Copy vào res/drawable-xhdpi Ta bắt đầu chỉnh sửa từ layout nhé: Vào res/layout/ Mở status_bar.xml bằng notepad++ Mình sẽ hướng dẫn làm shortcut của app qSlide (App riêng trên Snake 1.4 - Rom mình sử dụng để viết tut) vào bên trái của thanh Status Bar nhé (Các app khác làm tương tự) Tại status_bar.xml tìm dòng này Code: Mã: <com.android.systemui.statusbar.StatusBarIconView Thêm vào bên dưới dòng đấy code này Code: Mã: <ImageView android:paddingLeft="4.0dip" android:paddingRight="4.0dip" android:id="@id/qslide_button" android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/ic_notify_qslide" android:layout_toRightOf="@id/moreIcon" systemui:glowBackground="@drawable/ic_sysbar_highlight" /> Lưu ý những phần sau nhé: + android:id="@id/qslide_button": qslide_button các bạn có thể đặt tùy ý, nhưng phải nhớ + android:src="@drawable/ic_notify_qslide": đây là đường dẫn ảnh. Tức là cái ảnh ban nãy ta copy vào res/drawable-xhdpi. ic_notify_qslide đây là tên ảnh, phải giống nhé. + android:layout_toRightOf="@id/moreIcon": Cái này là căn bên trái phần có id là moreIcon, thêm vào chỗ nào thì lấy đổi phần moreIcon thành id của thẻ ngay phía trước chỗ các bạn thêm code. Save file status_bar.xml sau khi đã chỉnh sửa Tiếp theo vào res/values mở file ids.xml thêm vào dưới cùng trước </resources> đoạn code sau Code: Mã: <item type="id" name="qslide_button">false</item> Phần này name="qslide_button": qslide_button là tên id các bạn đã đặt ở trên nhé. Lưu file lại Quay ra màn hình Script.bat, chọn 11 để compile file apk lại Chờ một lát, đến lúc gặp thông báo này thì nhấn y rồi enter để tiếp tục nhé Lại chờ tiếp, đến khi gặp thông báo này thì cứ để đó Ta trở ra thư mục chính của APK-Multi-Tool-Experimental-RELEASE sẽ thấy có một thư mục keep xuất hiện Vào thư mục keep xoá file resources.arsc, vào tiếp keep/res/layout xoá file status_bar.xml Sau đó quay trở lại màn hình Script.bat nhấn Enter để tiếp tục. Đợi một lúc nó sẽ compile song. Tiếp theo, ta xoá thư mục SystemUI.apk trong thư mục projects và xoá file SystemUI.apk trong thư mục place-apk-here-for-modding đi. Vào thư mục place-apk-here-for-signing sẽ thấy có 1 file systemSystemUI.apk, đổi tên nó thành SystemUI.apk rồi copy nó vào thư mục place-apk-here-for-modding Ta quay trở lại màn hình Script.bat nhấn 9 để nó Decompile cái file SystemUI.apk mới Đợi nó decompile ra. Vào projects/SystemUI.apk/res/layout mở file status_bar.xml Ta để ý phần Code: Mã: <ImageView android:id="@id/qslide_button" android:paddingLeft="4.0dip" android:paddingRight="4.0dip" android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/ic_notify_qslide" android:layout_toRightOf="@id/moreIcon" systemui:glowBackground="@drawable/ic_sysbar_highlight" /> mới thêm bên trên. Nhớ lấy cái qslide_button nhé. Ta vào projects/SystemUI.apk/res/values mở file public.xml bằn Notepad++, tìm kiếm với từ khóa qslide_button. Ta thấy có thêm dòng này Code: Mã: <public type="id" name="qslide_button" id="0x7f0d0115" /> Để ý phần 0x7f0d0115. Nhớ lấy vì tiếp theo sẽ cần dùng. Ta vào theo đường dẫn sau (Tùy từng thiết bị, từng bản rom nó có thể ở đường dẫn khác) : projects/SystemUI.apk/smali/com/android/systemui/statusbar/phone mở file PhoneStatusBar.smali ( Hoặc StatusBarService.smali , cái này là tùy vào rom và thiết bị, các bạn phải tự tìm) Công việc ở đây là thêm 1 method xử lý rồi hook nó vào makeStatusBarView Bước 1: Tạo method xử lý vào PhoneStatusBar.smali. Method này là kiểu direct , nên cứ add nó vào bên dưới method cùng kiểu là đc, ví dụ là ngay dưới method createDebugButton Tìm kiếm đoạn sau Mã: .method private createDebugButton()V Nó có thể khác ở file của các bạn, nên các bạn có thể search với từ khóa Mã: .method private Ta kéo xuống đến khi gặp đoạn này Mã: return-void .end method Thì dừng lại. Thêm đoạn code sau xuống ngay bên dưới .end method Code: Mã: .method private myShortcut()V .locals 2 .prologue .line 29 sget-object v0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mExpandedView:Lcom/android/systemui/statusbar/phone/ExpandedView; const v1, 0x7f0d0115 invoke-virtual {v0, v1}, Lcom/android/systemui/statusbar/phone/ExpandedView;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/view/View; new-instance v1, Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55; invoke-direct {v1, p0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55;-><init>(Lcom/android/systemui/statusbar/phone/PhoneStatusBar;)V invoke-virtual {v0, v1}, Landroid/view/View;->setOnClickListener(Landroid/view/View$OnClickListener;)V .line 142 return-void .end method khi dex2jar ra trong java sẽ có như sau Mã: private void myShortcut() { ((View)mExpandedView.findViewById(2131558677)).setOnClickListener(new View.OnClickListener() { public void onClick(View paramAnonymousView) { PhoneStatusBar.this.clickToShortcut(); } }); } Ta phân tích code trên Mã: myShortcut Tên method, cái này tuỳ theo ý các bạn nhé Mã: 0x7f0d0115 đây chính là id ban nãy mình bảo các bạn nhớ lấy. Các các bạn thay vào nhé. Mã: Lcom/android/systemui/statusbar/phone/PhoneStatusBar Code: Mã: Lcom/android/systemui/statusbar/phone/ExpandedView Đây là đường dẫn 2 file PhoneStatusBar và file ExpandedView (File này giống tên ở các bản rom) các bạn tự tìm và thay vào nhé. Mã: Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55 Cần để ý kỹ phần này nhé. PhoneStatus$55 là một file smali. Tạm hiểu thế này Để ý sẽ thấy trong method này có 1 cái phần mở rộng ra trong smali gọi là InnerClass. Toàn bộ phần bên trong OnClickListener nó sẽ tách thành 1 cái file khác mình đặt tên nó là 55 và tên file của nó sẽ là PhoneStatus$55 (Hoặc StatusBarService$55) $55 ở đây là số thứ tự nhé, các bạn xem trong thư mục chứa PhoneStatusBar.smali (StatusBarService.smali) nó gọi đến StatusBarService$ bao nhiêu thì thêm vào. File này mình có để bên dưới nhé. Copy vào thư mục cùng với PhoneStatusBar.smali (StatusBarService.smali). Ta có code trong file PhoneStatusBar$55.smali như sau Code: Mã: .class Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55; .super Ljava/lang/Object; .source "PhoneStatusBar.java" # interfaces .implements Landroid/view/View$OnClickListener; # annotations .annotation system Ldalvik/annotation/EnclosingMethod; value = Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->myShortcut()V .end annotation .annotation system Ldalvik/annotation/InnerClass; accessFlags = 0x0 name = null .end annotation # instance fields .field final synthetic this$0:Lcom/android/systemui/statusbar/phone/PhoneStatusBar; # direct methods .method constructor <init>(Lcom/android/systemui/statusbar/phone/PhoneStatusBar;)V .locals 0 .parameter .prologue .line 3288 iput-object p1, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55;->this$0:Lcom/android/systemui/statusbar/phone/PhoneStatusBar; invoke-direct/range {p0 .. p0}, Ljava/lang/Object;-><init>()V return-void .end method # virtual methods .method public onClick(Landroid/view/View;)V .locals 1 .parameter "v" .prologue .line 2210 iget-object v0, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar$55;->this$0:Lcom/android/systemui/statusbar/phone/PhoneStatusBar; invoke-virtual {v0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->clickToShortcut()V .line 2216 return-void .end method Ta phân tích tiếp code này + Code: Mã: PhoneStatusBar.java nếu là StatusBarService thì đặt là StatusBarService.java + Code: Mã: myShortcut : Tên method bên trên. + Code: Mã: clickToShortcut : Tên method xử lý khi click vào shortcut. Ta sẽ đề cập ở phần sau. Các dòng khác thì mình đã giải thích ở trên, tự thay vào nhé. Bước 2: Tạo method xử lý khi click vào shortcut. Thêm vào bên dưới method myShortcut đoạn code sau Code: Mã: .method clickToShortcut()V .locals 5 .prologue .line 2257 invoke-virtual {p0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->animateCollapse()V const-string v2, "com.sphinxvn.snakeqslide" .line 27 .local v2, packageName:Ljava/lang/String; const-string v0, "com.sphinxvn.snakeqslide.MainActivity" .line 29 .local v0, activityName:Ljava/lang/String; new-instance v3, Landroid/content/ComponentName; invoke-direct {v3, v2, v0}, Landroid/content/ComponentName;-><init>(Ljava/lang/String;Ljava/lang/String;)V .line 31 .local v3, toLaunch:Landroid/content/ComponentName; new-instance v1, Landroid/content/Intent; const-string v4, "android.intent.action.MAIN" invoke-direct {v1, v4}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V .line 33 .local v1, intent:Landroid/content/Intent; const-string v4, "android.intent.category.LAUNCHER" invoke-virtual {v1, v4}, Landroid/content/Intent;->addCategory(Ljava/lang/String;)Landroid/content/Intent; .line 35 invoke-virtual {v1, v3}, Landroid/content/Intent;->setComponent(Landroid/content/ComponentName;)Landroid/content/Intent; .line 37 const/high16 v4, 0x1000 invoke-virtual {v1, v4}, Landroid/content/Intent;->setFlags(I)Landroid/content/Intent; .line 39 iget-object v0, p0, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->mContext:Landroid/content/Context; invoke-virtual {v0, v1}, Landroid/content/Context;->startActivity(Landroid/content/Intent;)V .line 2269 return-void .end method Khi dex2jar trong java sẽ có như sau Code: Mã: void clickToShortcut() { animateCollapse(); ComponentName localComponentName = new ComponentName("com.sphinxvn.snakeqslide", "com.sphinxvn.snakeqslide.MainActivity"); Intent localIntent = new Intent("android.intent.action.MAIN"); localIntent.addCategory("android.intent.category.LAUNCHER"); localIntent.setComponent(localComponentName); localIntent.setFlags(268435456); this.mContext.startActivity(localIntent); } Phân tích code: + Code: Mã: clickToShortcut Tên cái method xử lý khi click ta đề cập ban nãy.[/COLOR] + Code: Mã: com.sphinxvn.snakeqslide Code: Mã: com.sphinxvn.snakeqslide.MainActivity Để ý kỹ cái này. Làm sao để có nó? các bạn decompile app mà các bạn muốn đưa lên status ra. Sẽ có 1 file AndroidManifest.xml Ví dụ: Của mình là app SnakeQslide.apk có file AndroidManifest.xml như sau Code: Mã: <?xml version="1.0" encoding="utf-8"?> <manifest android:sharedUserId="android.uid.system" android:versionCode="1" package="com.sphinxvn.snakeqslide" android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:debuggable="true" > <activity android:label="@string/app_name_1" android:name="com.sphinxvn.snakeqslide.MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="SnakeQslideWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_INTERNET" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_VIDEO" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_MEMO" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_CALENDAR" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_CALCULATOR" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/snake_qslide_widget_info" /> </receiver> </application> </manifest> Để ý phần này Code: Mã: <manifest android:sharedUserId="android.uid.system" android:versionCode="1" package="com.sphinxvn.snakeqslide" android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android" > ta lấy đoạn Code: Mã: com.sphinxvn.snakeqslide thay cho Code: Mã: com.sphinxvn.snakeqslide ở trên method Tiếp đến là activity (hành động), trong một ứng dụng có rất nhiều activity, những activity này được khai báo ở file AndroidManifest.xml Ví dụ Code: Mã: <activity android:label="@string/app_name_1" android:name="com.sphinxvn.snakeqslide.MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="SnakeQslideWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_INTERNET" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_VIDEO" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_MEMO" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_CALENDAR" /> <action android:name="com.sphinxvn.snakeqslide.ACTION_WIDGET_CALCULATOR" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/snake_qslide_widget_info" /> </receiver> Ở đây có rất nhiều activity các bạn có thể gọi bất kỳ cái nào cũng đc, mình gọi app thì lấy đoạn này Code: Mã: com.sphinxvn.snakeqslide.MainActivity thay cho Code: Mã: com.sphinxvn.snakeqslide.MainActivity ở method trên. Cái này tùy vào file nhé. Thay vào những phần mình đã nói. Tiếp theo ta hook method vào makeStatusBarView Trong PhoneStatusBar.smali ta tìm dòng này Code: Mã: invoke-direct {p0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->createDebugButton()V Thêm vào bên trên đoạn hook myShortcut() như sau Code: Mã: invoke-direct {p0}, Lcom/android/systemui/statusbar/phone/PhoneStatusBar;->myShortcut()V Khi dex2jar trong java ta sẽ thấy thế này Code: Mã: myShortcut(); createDebugButton(); File PhoneStatusBar$55.smali:https://docs.google.com/file/d/0B1E9XrtUknzbSmwxRWVZUFYwR2c/edit?usp=sharing Ok đến đây ta save file lại. Tiếp theo là Compile project file apk. Tại màn hình Script.bat ta chọn 11 để bắt đầu compile. Như phần hướng dẫn ở trên đến đoạn hỏi y/n thì chọn y, đợi 1 lúc sẽ có 1 thông báo. Để đấy, ta quay ra thư mục keep (đã nói ở phần trên) xoá file classes.dex sau đó quay lại Script.bat nhấn enter để tiếp tục. Xong ta sẽ có file systemSystemUI.apk trong place-apk-here-for-signing Đổi tên thành SystemUI.apk copy vào system/app set 644 reboot và tận hưởng thôi. Lưu ý: sau khi chỉnh sửa xong, nên dex2jar file apk ra file jar để so sánh code java Tut được viết bởi @Kmasc.Team đến từ Tinhte.vn