Fix bàn phím tiếng Hàn máy LG, bàn phím gọi tiếng Hàn, LGViet, hướng dẫn sửa bàn phím tiếng Hàn, bàn phím tiếng Hàn. Như đã biết ROM gốc của các dòng đt LG nội địa từ Hàn quốc, cái đầu tiên ta nhìn thấy là bàn phím gọi điện thoại toàn tiếng hàn, nhìn rất ghét. Thông thường mọi người, chờ ai đó fix, rồi đưa file contact.apk đã sửa lên. Hôm nay mình sẽ dành một chút thời gian để viết một tut hướng dẫn các bạn hiểu đầu đuôi ngọn ngành của việc fix giao diện bàn phím tiếng Hàn, 1 việc tưởng chừng như đơn giản, nhưng không phải ai cũng biết. Đặc biệt là hiểu tường tận, ngọn nguồn của các fix để các bạn nắm đc, qua đó có thêm 1 chút kiến thức để xử lý các vấn đề tương tự. Với những người có nhiều kinh nghiệm kỹ năng thì việc này khá đơn giản, thậm chí mình còn ko cần nhìn code cũng có thể sửa đc. Các công cụ cần biết: - Dex2jar - Notepad++ + plugin smali để đọc code cho dễ - Apktool - java decompiler Fix bàn phím tiếng Hàn máy LG, bàn phím gọi tiếng Hàn, LGViet, hướng dẫn sửa bàn phím tiếng Hàn, bàn phím tiếng Hàn. Bài viết được thực hiện bởi hoangnova từ lgviet.com Các công cụ này mọi người tự search nhé, cách dùng thì có thể tìm lại các tút cũ mình đã viết để nắm đc, tránh mất thời gian lan man. Đầu tiên, dùng apktool, decompile file contactsbin.apk ra xem tình hình thế nào đã, luôn luôn là vậy, phải decompile ra xem trước xem làm gì với nó. Mở thử res/drawable-xhdpi xem có gì Ta thấy rằng các phím có tiếng hàn đó thực chất là 1 cái hình thôi. Tới đây nếu lười ta ngồi đổi tên các hình cho nhau, sao cho nó mất tiếng Hàn và còn tiếng Anh thôi, thế thì dễ quá, nhưng mình thường làm cách sửa từ source để fix triệt để, tận gốc. Theo nhận định và kinh nghiệm thì thấy rằng nếu có cả tiếng anh và tiếng hàn thế kia thì hản là trong code nó check đâu đó để với quốc gia KR nó sẽ đổi thành bàn phím hàn, với ả rập nó sẽ ra bàn phím ả rập, với quốc gia khác nó sẽ ra bàn phím cuốc tế. Copy tên của 1 cái hình có tiếng hàn, ở đây mình thử copy phím số 2 có tiếng hàn có tên là "dial_num_2_wht__kr.png" Vào seảrch thử trong value để xem giá trị của nó Có được cái id là mã hex rồi ta lại thử search tiếp thử trong code smali coi có gì ko. Thử cái nhé ! Đây rồi, có luôn, vậy là mình đoán đúng: Nó nằm trong class ResourceConfig Giờ ta cần dex2jar file classes.dex của Contact để xem code java nó viết gì nhé. Tất nhiên là thấy code rồi, nhưng làm sao để tìm thấy cái số kia ở trong code java ?! Ta cần đổi nó sang dạng số Decimal, bằng cách dùng calculator, làm như trong hình hướng dẫn dưới đây: Ta được dãy số 2130837710 Ctrl + F để search thử xem sao. Ta thấy nó nằm trong 1 method để gọi phím số 2 ra như sau: Mã: public int getDialNum2() { int i; if (SystemConfig.getCountry().equals(SystemConfig.COUNTRY.IL)) i = 2130837709; while (true) { return checkedResourceId(i, 2130837708); if (SystemConfig.getCountry().equals(SystemConfig.COUNTRY.KR)) { i = 2130837710; continue; } if (SystemConfig.getOperator().equals(SystemConfig.OPERATOR.TMUS)) { i = 2130837711; continue; } i = 2130837708; } } Vậy là chắc chắn như mình nói, với nhà mạng Hàn quốc nó gọi ra 1 cái hình khác. Việc của ta làm gì bây giờ, tất nhiên cần biết 1 chút về code để quan sát và đọc hiểu code. Đoạn trên nó viết rằng SystemConfig.getCountry() = SystemConfig.COUNTRY.KR thì nó ra bàn phím số 2 bằng tiếng Hàn. Vậy ta thử lần theo SystemConfig.getCountry() để sửa nó thành 1 country khác xem sao nhé. trong class Mã: public static COUNTRY getCountry() { return mBuildCountry; } Nó viết, tức là trả về cái biến mBuildCountry, lần theo mBuildCountry nó viết mBuildCountry = getBuildCountry(); còn thằng getBuildCountry thì đây Mã: private static COUNTRY getBuildCountry() { String str = SystemProperties.get("ro.build.target_country"); Object localObject = COUNTRY.COM; try { COUNTRY localCOUNTRY = COUNTRY.valueOf(str); localObject = localCOUNTRY; Log.i("SystemConfig", "BUILD Country: " + localObject); return localObject; } catch (IllegalArgumentException localIllegalArgumentException) { while (true) Log.e("SystemConfig", "unknown country code=" + str); } } À, ra vậy, vậy là nó lấy cái country từ build.prop, vậy nếu ta sửa build.prop ro.build.target_country thì sao, thì cũng đc thôi, nhưng cái đó nằm ngoài phạm vi bài này, sẽ có 1 tút khác sau. Tiếp tục bài này: String str = SystemProperties.get("ro.build.target_country"); Hay là thử gán nó bằng cái gì đó đại loại như ESA ( quốc tế) chẳng hạn: Sửa thế nào ? Xem code smali đã: Mã: .method private static getBuildCountry()Lcom/lge/contacts/util/SystemConfig$COUNTRY; .locals 6 .prologue .line 580 const-string v3, "ro.build.target_country" invoke-static {v3}, Landroid/os/SystemProperties;->get(Ljava/lang/StringLjava/lang/String; move-result-object v0 .line 586 .local v0, code:Ljava/lang/String; sget-object v1, Lcom/lge/contacts/util/SystemConfig$COUNTRY;->COM:Lcom/lge/contacts/util/SystemConfig$COUNTRY; .line 588 .local v1, country:Lcom/lge/contacts/util/SystemConfig$COUNTRY; :try_start_0 invoke-static {v0}, Lcom/lge/contacts/util/SystemConfig$COUNTRY;->valueOf(Ljava/lang/StringLcom/lge/contacts/util/SystemConfig$COUNTRY; :try_end_0 .catch Ljava/lang/IllegalArgumentException; {:try_start_0 .. :try_end_0} :catch_0 move-result-object v1 .line 593 :goto_0 const-string v3, "SystemConfig" new-instance v4, Ljava/lang/StringBuilder; invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V const-string v5, "BUILD Country: " invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/StringLjava/lang/StringBuilder; move-result-object v4 invoke-virtual {v4, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/ObjectLjava/lang/StringBuilder; move-result-object v4 invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v4 invoke-static {v3, v4}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/StringI .line 594 return-object v1 .line 589 :catch_0 move-exception v2 .line 590 .local v2, e:Ljava/lang/IllegalArgumentException; const-string v3, "SystemConfig" new-instance v4, Ljava/lang/StringBuilder; invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V const-string v5, "unknown country code=" invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/StringLjava/lang/StringBuilder; move-result-object v4 invoke-virtual {v4, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/StringLjava/lang/StringBuilder; move-result-object v4 invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v4 invoke-static {v3, v4}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/StringI goto :goto_0 .end method Chú ý đoạn này Mã: const-string v3, "ro.build.target_country" invoke-static {v3}, Landroid/os/SystemProperties;->get(Ljava/lang/StringLjava/lang/String; move-result-object v0 Sẽ ra code java thành đoạn này: Mã: String str = SystemProperties.get("ro.build.target_country"); Vậy gán mẹ cái v0 kia thành 1 string gì đó ta thích: Mình ko xóa code cũ đi mà đè cái v0 lên thành code thế này: Mã: const-string v3, "ro.build.target_country" invoke-static {v3}, Landroid/os/SystemProperties;->get(Ljava/lang/StringLjava/lang/String; move-result-object v0 const-string v0, "EU" RỒi thử compile lại apk, và lại thử dex2jar lại ta sẽ thấy code java nó ra thế này: Mã: private static COUNTRY getBuildCountry() { SystemProperties.get("ro.build.target_country"); Object localObject = COUNTRY.COM; try { COUNTRY localCOUNTRY = COUNTRY.valueOf("EU"); localObject = localCOUNTRY; Log.i("SystemConfig", "BUILD Country: " + localObject); return localObject; } catch (IllegalArgumentException localIllegalArgumentException) { while (true) Log.e("SystemConfig", "unknown country code=" + "EU"); } } Làm tương tự với thằng getBuildOperator() Sao cho cuối cùng nó ra code java thế này: Đoạn này nghĩa là ta gán getBuildOperator thành OPEN (cuốc tế) cho đồng bộ cùng Country. Mã: private static OPERATOR getBuildOperator() { SystemProperties.get("ro.build.target_operator"); Object localObject = OPERATOR.OPEN; try { OPERATOR localOPERATOR = OPERATOR.valueOf("OPEN"); localObject = localOPERATOR; if ((localObject == OPERATOR.TMO) && (isCountry(COUNTRY.US))) localObject = OPERATOR.TMUS; if ((localObject == OPERATOR.USC) && (isCountry(COUNTRY.MX))) localObject = OPERATOR.MXUSC; Log.i("SystemConfig", "BUILD Operator: " + localObject); return localObject; } catch (IllegalArgumentException localIllegalArgumentException) { while (true) Log.e("SystemConfig", "unknown operator code=" + "OPEN"); } } Đến đây chỉ xong 1 phần thôi, còn 1 chỗ khác cần sửa để gán giá trị default: Ở trong: com/android/contacts/dialpad/DialpadFeature.smali Method .method public constructor <init>(Landroid/content/Context Thêm vào đoạn code : Mã: .line 253 const/4 v2, 0x0 sput v2, Lcom/android/contacts/dialpad/DialpadFeature;->mVTDevice:I sput-boolean v2, Lcom/android/contacts/dialpad/DialpadFeature;->isLGU:Z sput-boolean v2, Lcom/android/contacts/dialpad/DialpadFeature;->isKR:Z const/4 v2, 0x1 sput-boolean v2, Lcom/android/contacts/dialpad/DialpadFeature;->isEU:Z .line 56 const-string v2, "OPEN" sput-object v2, Lcom/android/contacts/dialpad/DialpadFeature;->OPERATOR:Ljava/lang/String; .line 56 const-string v2, "EU" sput-object v2, Lcom/android/contacts/dialpad/DialpadFeature;->COUNTRY:Ljava/lang/String; Vào ngay bên dưới Mã: .line 253 invoke-direct {p0}, Lcom/android/contacts/dialpad/DialpadFeature;->initVTDevice()V Sao cho khi ra code java nó thành thế này: Mã: public DialpadFeature(Context paramContext) { this.mContext = paramContext; this.mTelephony = ((TelephonyManager)paramContext.getSystemService("phone")); this.mAudioManager = ((AudioManager)paramContext.getSystemService("audio")); this.mCheckDeclaredClass = new CheckDeclaredClass("android.telephony.TelephonyManager"); if (OPERATOR.equals("")) { Log.i(TAG, "OPERATOR : << UNKNOWN >>"); OPERATOR = "OPEN"; } if (COUNTRY.equals("")) { Log.i(TAG, "COUNTRY : << UNKNOWN >>"); COUNTRY = "UNKNOWN"; } Log.i(TAG, "OPERATOR : " + OPERATOR); Log.i(TAG, "COUNTRY : " + COUNTRY); Log.i(TAG, "MODEL_NAME : " + MODEL_NAME); initVTDevice(); mVTDevice = 0; isLGU = false; isKR = false; isEU = true; OPERATOR = "OPEN"; COUNTRY = "EU"; Log.i(TAG, "VTDevice : " + mVTDevice); if (isLGU) initSupportLGUGlobalRoaming(paramContext); Log.i(TAG, "isLGUSupportGlobalRoaming : " + isLGUSupportGlobalRoaming); } Đoạn này nghĩa là gán đè toàn bộ những cái nó config trong DialpadFeature thành cái mình mong muốn, ở đây là Mã: mVTDevice = 0; isLGU = false; isKR = false; isEU = true; OPERATOR = "OPEN"; COUNTRY = "EU"; Hehe, xong rồi, compile lại và thay thế vào contact cũ, đảm bảo bây giờ mọi thứ thành cuốc tế hết. Xem kết quả đây (đẹp hơn bố của đẹp luôn) Download file đã sửa bàn phím tiếng Hàn cho LTE3 tại đây: Mình mod trên bản ROM của LTE3 mới nhất nhé: https://drive.google.com/file/d/0B3J7gOQH7ViEWUotRS1IYXpqT1E/edit?usp=sharing Nguồn: lgviet.com cám ơn anh @hoangnova
mình biết gì đâu àm mod. toàn làm theo hướng dẫn của các bác sửa mấy cái đơn giản. chứ tinh chỉnh trong phần mềm sao biết đc.
đoạn này "Giờ ta cần dex2jar file classes.dex của Contact để xem code java nó viết gì nhé" là làm sao. có thể hướng dẫn chi tiết được không, file Classes.dex ở đâu
nó nằm ngay ở bên trong file .apk bạn à. Bạn mở nó lên bằng 7zip sẽ thấy nhé. Mà file apk bạn phải deodex lại mới có nhé.
Vậy làm sao dex2jar cái file đó. Chỉ chi tiết cái đoạn đó dùm e với Sent from my LG-F220K using Tapatalk