Модификация Android приложения от новичка и для новичков

в 8:07, , рубрики: android, Песочница, Разработка под android, метки: ,

Добрый день!
Хочу поделиться с вами историей как я модифицировал одно из системных приложений Adroid'а, точнее его модификации LeWa OS. С Андроидом я познакомился недавно, всего месяц назад, и постараюсь тут описать весь ход своих мыслей, что несомненно будет полезно всем тем кто хочет улучшить Андроид, но не знает с чего начать. Пост постараюсь сделать подробным, а потому длинным.

Для начало немного истории.

Как только я получил свой первый китайфон, решил попробовать разные прошивки и в результате остановился на Lewa. Но глаза постоянно мозолил один ее недочет — список контактов, а точнее быстрая навигация на английском.
Модификация Android приложения от новичка и для новичков

Информации о данной проблеме немного, поэтому начал копать сам.

Набор инструментов

Первое что нам надо — научиться распаковывать программы. Для этого нам понадобится:

  • установить Java
  • APKTOOLS для распаковки *.apk
  • Прочитать данный пост
  • Получить объект исследования. Если вы пользуетесь Lewa то надо из архива с прошивкой или прямо с телефона нужно вытянуть /system/app/PIM.apk и все apk из папки /system/framework/ обычно это framework-res.apk, lewa-res.apk и
    mediatek-res.apk. Если вы хотите просто потренироваться то могу дать свои

Приступим

Итак, первое что нам надо это разобрать наше приложение, для этого все apk надо скопировать в папку с apktools. Все apk которые лежали в /system/framework/ надо выделить, подцепить мышью и перенести на apktool-if.cmd тем самым открыв их с помощью этого bat'ника. PIM.apk таким же образом надо открыть с помощью apktool-d.cmd. В результате получаем папку с распакованным приложением.

Изучаем код

Первое что нам необходимо понять — что и где править. Так как мой список контактов изобилует русскими именами, а в быстротой навигации одни английские буквы резонно предположить, что буквы просто жестко забиты где то в коде, а не генерируются динамически исходя из того какие имена у вас в контактах. Обычно такие данные хранятся в папке res, а точнее в resvaluesarrays.xml но в нашем случае там ничего похожего нет.
Думаем дальше — раз нет там, значит есть где то в коде. Весь код находится в папе smali, по сути там не исходный код а так называемый Байт-код, и его там много. Так где же искать? Я поступил так, в папке reslayout хранятся все «окошки» нашего приложения, то что нам надо находится где-то в списке контактов, поэтому я наобум открыл contact_list_content.xml и начал изучать.

contact_list_content.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:orientation="vertical" android:id="@id/pinned_header_list_layout" android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <include android:id="@id/account_filter_header_container" layout="@layout/account_filter_header" />
    <include layout="@layout/wait_cursor" />
    <FrameLayout android:id="@id/contact_list_framelayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0">
        <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
            <view android:id="@android:id/list" android:fadingEdge="none" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" android:fastScrollEnabled="true" class="com.lewa.PIM.contacts.widget.PinnedHeaderListView" />
            <LinearLayout android:orientation="vertical" android:id="@id/import_layout" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="300.0dip" android:layout_marginBottom="@dimen/prompt_import_layout_bottom">
                <TextView android:textSize="16.0sp" android:gravity="center" android:layout_gravity="center_horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/prompt_no_contacts_pepole" />
                <Button android:textSize="14.0sp" android:gravity="center" android:layout_gravity="center_horizontal" android:id="@id/btn_login_lewa_account" android:layout_width="140.0dip" android:layout_height="wrap_content" android:layout_marginTop="18.0dip" android:text="@string/login_lewa_account" />
                <Button android:textSize="14.0sp" android:gravity="center" android:layout_gravity="center_horizontal" android:id="@id/btn_import_from_sim" android:layout_width="140.0dip" android:layout_height="wrap_content" android:layout_marginTop="18.0dip" android:text="@string/import_from_sim" />
                <Button android:textSize="14.0sp" android:gravity="center" android:layout_gravity="center_horizontal" android:id="@id/btn_import_from_sdcard" android:layout_width="140.0dip" android:layout_height="wrap_content" android:layout_marginTop="18.0dip" android:text="@string/import_from_sdcard" />
            </LinearLayout>
        </LinearLayout>
        <include layout="@layout/alphabet_fast_indexer" />
    </FrameLayout>
    <ViewStub android:id="@id/footer_stub" android:layout="@layout/footer_panel" android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>

Там меня заинтересовала строчка />. Что это за индексер такой?? Смотрим

alphabet_fast_indexer.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView android:textSize="32.0sp" android:textColor="?android:textColorPrimaryInverse" android:gravity="center" android:layout_gravity="right|center" android:id="@id/fast_indexer_pop_text_view" android:background="@android:color/holo_blue_light" android:visibility="gone" android:layout_width="48.0dip" android:layout_height="48.0dip" android:layout_marginRight="60.0dip" />
    <com.lewa.PIM.widget.AlphabetFastIndexer android:layout_gravity="right" android:id="@id/fast_indexer" android:layout_width="20.0dip" android:layout_height="fill_parent" />
</FrameLayout>

Тут ключевые стороки
<com.lewa.PIM.widget.AlphabetFastIndexer android:layout_gravity=«right» android:id="id/fast_indexer" android:layout_width=«20.0dip» android:layout_height=«fill_parent» />
Что это за элемент который прижимается к правой части экрана (android:layout_gravity=«right»), не то ли что мы ищем?
com.lewa.PIM.widget.AlphabetFastIndexer это ссылка на код PIMsmalicomlewaPIMwidgetAlphabetFastIndexer.smali, но изучать его неудобно, и тут на сцену выходит связка dex2jar-0.0.9.7 jd-gui-0.3.3.windows которые мы скачали из поста на форуме и так же научились ими пользоваться. Превращаем classes.dex в classes_dex2jar.jar и открываем через jd-gui.exe
Модификация Android приложения от новичка и для новичков

AlphabetFastIndexer.smali Декомпилированный

package com.lewa.PIM.widget;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;

public class AlphabetFastIndexer extends View
{
  public static String[] b = { "★", "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
  private int choose = 0;
  private int mChooseColor;
  private boolean mHasFav = true;
  private ArrayList<String> mLetters = new ArrayList();
  private int mPaddingBottom;
  private int mTextsize;
  OnTouchingLetterChangedListener onTouchingLetterChangedListener;
  private Paint paint = new Paint();
  private boolean showBkg = false;

  public AlphabetFastIndexer(Context paramContext)
  {
    super(paramContext);
    init(paramContext);
    setHasFavorite(false);
  }

  public AlphabetFastIndexer(Context paramContext, AttributeSet paramAttributeSet)
  {
    super(paramContext, paramAttributeSet);
    init(paramContext);
    setHasFavorite(false);
  }

  public AlphabetFastIndexer(Context paramContext, AttributeSet paramAttributeSet, int paramInt)
  {
    super(paramContext, paramAttributeSet, paramInt);
    init(paramContext);
    setHasFavorite(false);
  }

  private void init(Context paramContext)
  {
    this.mChooseColor = paramContext.getResources().getColor(17170450);
    this.mTextsize = paramContext.getResources().getDimensionPixelSize(2131361937);
    this.mPaddingBottom = paramContext.getResources().getDimensionPixelSize(2131361938);
  }

  public boolean dispatchTouchEvent(MotionEvent paramMotionEvent)
  {
    int i = paramMotionEvent.getAction();
    int j = (int)(paramMotionEvent.getY() / getHeight() * this.mLetters.size());
    switch (i)
    {
    default:
      return true;
    case 0:
      this.showBkg = true;
    case 2:
      drawThumb(j);
      return true;
    case 1:
    }
    this.showBkg = false;
    invalidate();
    return true;
  }

  public void drawThumb(int paramInt)
  {
    OnTouchingLetterChangedListener localOnTouchingLetterChangedListener = this.onTouchingLetterChangedListener;
    if ((this.choose != paramInt) && (localOnTouchingLetterChangedListener != null) && (paramInt >= 0) && (paramInt < this.mLetters.size()))
    {
      if (localOnTouchingLetterChangedListener != null)
        localOnTouchingLetterChangedListener.onTouchingLetterChanged((String)this.mLetters.get(paramInt));
      this.choose = paramInt;
      invalidate();
    }
  }

  public void drawThumb(String paramString)
  {
    if ((paramString != null) && (!paramString.equals(this.mLetters.get(this.choose))))
    {
      int i = this.mLetters.indexOf(paramString);
      if (i == -1)
        i = 0;
      if (this.choose != i)
      {
        this.choose = i;
        invalidate();
      }
    }
  }

  protected void onDraw(Canvas paramCanvas)
  {
    super.onDraw(paramCanvas);
    if (this.showBkg)
      paramCanvas.drawColor(Color.parseColor("#4C000000"));
    while (true)
    {
      int i = getHeight();
      int j = getWidth();
      int k = this.mLetters.size();
      int m = i / k;
      for (int n = 0; n < k; n++)
      {
        this.paint.setColor(-1);
        this.paint.setTypeface(Typeface.DEFAULT_BOLD);
        this.paint.setAntiAlias(true);
        this.paint.setTextSize(this.mTextsize);
        if (n == this.choose)
        {
          this.paint.setColor(this.mChooseColor);
          this.paint.setFakeBoldText(true);
        }
        String str = (String)this.mLetters.get(n);
        paramCanvas.drawText(str, j / 2 - this.paint.measureText(str) / 2.0F, m + m * n, this.paint);
        this.paint.reset();
      }
      paramCanvas.drawColor(Color.parseColor("#26000000"));
    }
  }

  protected void onMeasure(int paramInt1, int paramInt2)
  {
    if (this.mHasFav)
      paramInt2 -= this.mPaddingBottom;
    setMeasuredDimension(paramInt1, paramInt2);
  }

  public boolean onTouchEvent(MotionEvent paramMotionEvent)
  {
    return super.onTouchEvent(paramMotionEvent);
  }

  public void setHasFavorite(boolean paramBoolean)
  {
    int k;
    if (this.mHasFav != paramBoolean)
    {
      this.mHasFav = paramBoolean;
      this.mLetters.clear();
      String[] arrayOfString = b;
      int i = arrayOfString.length;
      int j = 0;
      if (j < i)
      {
        String str = arrayOfString[j];
        if ((!paramBoolean) && (str.equals("★")));
        while (true)
        {
          j++;
          break;
          this.mLetters.add(str);
        }
      }
      if (this.choose != 0)
      {
        if (!paramBoolean)
          break label117;
        k = 1 + this.choose;
        this.choose = k;
      }
      if (this.choose >= 0)
        break label128;
      this.choose = 0;
    }
    while (true)
    {
      requestLayout();
      return;
      label117: k = -1 + this.choose;
      break;
      label128: if (this.choose >= this.mLetters.size())
        this.choose = (-1 + this.mLetters.size());
    }
  }

  public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener paramOnTouchingLetterChangedListener)
  {
    this.onTouchingLetterChangedListener = paramOnTouchingLetterChangedListener;
  }

  public static abstract interface OnTouchingLetterChangedListener
  {
    public abstract void onTouchingLetterChanged(String paramString);
  }
}

Вот же оно public static String[] b = { "★", "#", «A», «B», «C», «D», «E», «F», «G», «H», «I», «J», «K», «L», «M», «N», «O», «P», «Q», «R», «S», «T», «U», «V», «W», «X», «Y», «Z» };!!! Но править прямо тут нельзя, декомпилированный код примерный, и врядли соберется обратно без ошибок, тем более у нас нет остальных частей программы. Так что правим байт код в PIMsmalicomlewaPIMwidgetAlphabetFastIndexer.smali

AlphabetFastIndexer.smali

.class public Lcom/lewa/PIM/widget/AlphabetFastIndexer;
.super Landroid/view/View;
.source "AlphabetFastIndexer.java"


# annotations
.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;
    }
.end annotation


# static fields
.field public static b:[Ljava/lang/String;


# instance fields
.field private choose:I

.field private mChooseColor:I

.field private mHasFav:Z

.field private mLetters:Ljava/util/ArrayList;
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "Ljava/util/ArrayList",
            "<",
            "Ljava/lang/String;",
            ">;"
        }
    .end annotation
.end field

.field private mPaddingBottom:I

.field private mTextsize:I

.field onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;

.field private paint:Landroid/graphics/Paint;

.field private showBkg:Z


# direct methods
.method static constructor <clinit>()V
    .locals 3

    .prologue
    .line 19
    const/16 v0, 0x1c

    new-array v0, v0, [Ljava/lang/String;

    const/4 v1, 0x0

    const-string v2, "u2605"

    aput-object v2, v0, v1

    const/4 v1, 0x1

    const-string v2, "#"

    aput-object v2, v0, v1

    const/4 v1, 0x2

    const-string v2, "A"

    aput-object v2, v0, v1

    const/4 v1, 0x3

    const-string v2, "B"

    aput-object v2, v0, v1

    const/4 v1, 0x4

    const-string v2, "C"

    aput-object v2, v0, v1

    const/4 v1, 0x5

    const-string v2, "D"

    aput-object v2, v0, v1

    const/4 v1, 0x6

    const-string v2, "E"

    aput-object v2, v0, v1

    const/4 v1, 0x7

    const-string v2, "F"

    aput-object v2, v0, v1

    const/16 v1, 0x8

    const-string v2, "G"

    aput-object v2, v0, v1

    const/16 v1, 0x9

    const-string v2, "H"

    aput-object v2, v0, v1

    const/16 v1, 0xa

    const-string v2, "I"

    aput-object v2, v0, v1

    const/16 v1, 0xb

    const-string v2, "J"

    aput-object v2, v0, v1

    const/16 v1, 0xc

    const-string v2, "K"

    aput-object v2, v0, v1

    const/16 v1, 0xd

    const-string v2, "L"

    aput-object v2, v0, v1

    const/16 v1, 0xe

    const-string v2, "M"

    aput-object v2, v0, v1

    const/16 v1, 0xf

    const-string v2, "N"

    aput-object v2, v0, v1

    const/16 v1, 0x10

    const-string v2, "O"

    aput-object v2, v0, v1

    const/16 v1, 0x11

    const-string v2, "P"

    aput-object v2, v0, v1

    const/16 v1, 0x12

    const-string v2, "Q"

    aput-object v2, v0, v1

    const/16 v1, 0x13

    const-string v2, "R"

    aput-object v2, v0, v1

    const/16 v1, 0x14

    const-string v2, "S"

    aput-object v2, v0, v1

    const/16 v1, 0x15

    const-string v2, "T"

    aput-object v2, v0, v1

    const/16 v1, 0x16

    const-string v2, "U"

    aput-object v2, v0, v1

    const/16 v1, 0x17

    const-string v2, "V"

    aput-object v2, v0, v1

    const/16 v1, 0x18

    const-string v2, "W"

    aput-object v2, v0, v1

    const/16 v1, 0x19

    const-string v2, "X"

    aput-object v2, v0, v1

    const/16 v1, 0x1a

    const-string v2, "Y"

    aput-object v2, v0, v1

    const/16 v1, 0x1b

    const-string v2, "Z"

    aput-object v2, v0, v1

    sput-object v0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->b:[Ljava/lang/String;

    return-void
.end method

.method public constructor <init>(Landroid/content/Context;)V
    .locals 2
    .parameter "context"

    .prologue
    const/4 v1, 0x0

    .line 44
    invoke-direct {p0, p1}, Landroid/view/View;-><init>(Landroid/content/Context;)V

    .line 22
    iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 23
    new-instance v0, Landroid/graphics/Paint;

    invoke-direct {v0}, Landroid/graphics/Paint;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    .line 27
    const/4 v0, 0x1

    iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    .line 29
    new-instance v0, Ljava/util/ArrayList;

    invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    .line 112
    iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    .line 45
    invoke-direct {p0, p1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V

    .line 46
    invoke-virtual {p0, v1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V

    .line 47
    return-void
.end method

.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
    .locals 2
    .parameter "context"
    .parameter "attrs"

    .prologue
    const/4 v1, 0x0

    .line 38
    invoke-direct {p0, p1, p2}, Landroid/view/View;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V

    .line 22
    iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 23
    new-instance v0, Landroid/graphics/Paint;

    invoke-direct {v0}, Landroid/graphics/Paint;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    .line 27
    const/4 v0, 0x1

    iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    .line 29
    new-instance v0, Ljava/util/ArrayList;

    invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    .line 112
    iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    .line 39
    invoke-direct {p0, p1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V

    .line 40
    invoke-virtual {p0, v1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V

    .line 41
    return-void
.end method

.method public constructor <init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
    .locals 2
    .parameter "context"
    .parameter "attrs"
    .parameter "defStyle"

    .prologue
    const/4 v1, 0x0

    .line 32
    invoke-direct {p0, p1, p2, p3}, Landroid/view/View;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V

    .line 22
    iput v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 23
    new-instance v0, Landroid/graphics/Paint;

    invoke-direct {v0}, Landroid/graphics/Paint;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    .line 27
    const/4 v0, 0x1

    iput-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    .line 29
    new-instance v0, Ljava/util/ArrayList;

    invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V

    iput-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    .line 112
    iput-boolean v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    .line 33
    invoke-direct {p0, p1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->init(Landroid/content/Context;)V

    .line 34
    invoke-virtual {p0, v1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setHasFavorite(Z)V

    .line 35
    return-void
.end method

.method private init(Landroid/content/Context;)V
    .locals 2
    .parameter "context"

    .prologue
    .line 50
    invoke-virtual {p1}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;

    move-result-object v0

    const v1, 0x1060012

    invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getColor(I)I

    move-result v0

    iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mChooseColor:I

    .line 51
    invoke-virtual {p1}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;

    move-result-object v0

    const v1, 0x7f0a0091

    invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getDimensionPixelSize(I)I

    move-result v0

    iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mTextsize:I

    .line 52
    invoke-virtual {p1}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;

    move-result-object v0

    const v1, 0x7f0a0092

    invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getDimensionPixelSize(I)I

    move-result v0

    iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mPaddingBottom:I

    .line 53
    return-void
.end method


# virtual methods
.method public dispatchTouchEvent(Landroid/view/MotionEvent;)Z
    .locals 6
    .parameter "event"

    .prologue
    const/4 v5, 0x1

    .line 116
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getAction()I

    move-result v0

    .line 117
    .local v0, action:I
    invoke-virtual {p1}, Landroid/view/MotionEvent;->getY()F

    move-result v2

    .line 118
    .local v2, y:F
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getHeight()I

    move-result v3

    int-to-float v3, v3

    div-float v3, v2, v3

    iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v4}, Ljava/util/ArrayList;->size()I

    move-result v4

    int-to-float v4, v4

    mul-float/2addr v3, v4

    float-to-int v1, v3

    .line 120
    .local v1, c:I
    packed-switch v0, :pswitch_data_0

    .line 143
    :goto_0
    return v5

    .line 122
    :pswitch_0
    iput-boolean v5, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    .line 135
    :pswitch_1
    invoke-virtual {p0, v1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->drawThumb(I)V

    goto :goto_0

    .line 138
    :pswitch_2
    const/4 v3, 0x0

    iput-boolean v3, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    .line 140
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V

    goto :goto_0

    .line 120
    :pswitch_data_0
    .packed-switch 0x0
        :pswitch_0
        :pswitch_2
        :pswitch_1
    .end packed-switch
.end method

.method public drawThumb(I)V
    .locals 2
    .parameter "position"

    .prologue
    .line 152
    iget-object v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;

    .line 153
    .local v0, listener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;
    iget v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    if-eq v1, p1, :cond_1

    if-eqz v0, :cond_1

    .line 154
    if-ltz p1, :cond_1

    iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v1}, Ljava/util/ArrayList;->size()I

    move-result v1

    if-ge p1, v1, :cond_1

    .line 155
    if-eqz v0, :cond_0

    .line 156
    iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v1, p1}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;

    move-result-object v1

    check-cast v1, Ljava/lang/String;

    invoke-interface {v0, v1}, Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;->onTouchingLetterChanged(Ljava/lang/String;)V

    .line 158
    :cond_0
    iput p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 159
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V

    .line 162
    :cond_1
    return-void
.end method

.method public drawThumb(Ljava/lang/String;)V
    .locals 3
    .parameter "letter"

    .prologue
    .line 165
    if-eqz p1, :cond_1

    iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    iget v2, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    invoke-virtual {v1, v2}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;

    move-result-object v1

    invoke-virtual {p1, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v1

    if-nez v1, :cond_1

    .line 166
    iget-object v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v1, p1}, Ljava/util/ArrayList;->indexOf(Ljava/lang/Object;)I

    move-result v0

    .line 167
    .local v0, i:I
    const/4 v1, -0x1

    if-ne v0, v1, :cond_0

    const/4 v0, 0x0

    .line 168
    :cond_0
    iget v1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    if-eq v1, v0, :cond_1

    .line 169
    iput v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 170
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->invalidate()V

    .line 173
    .end local v0           #i:I
    :cond_1
    return-void
.end method

.method protected onDraw(Landroid/graphics/Canvas;)V
    .locals 12
    .parameter "canvas"

    .prologue
    const/4 v11, 0x1

    .line 83
    invoke-super {p0, p1}, Landroid/view/View;->onDraw(Landroid/graphics/Canvas;)V

    .line 84
    iget-boolean v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->showBkg:Z

    if-eqz v8, :cond_1

    .line 85
    const-string v8, "#4C000000"

    invoke-static {v8}, Landroid/graphics/Color;->parseColor(Ljava/lang/String;)I

    move-result v8

    invoke-virtual {p1, v8}, Landroid/graphics/Canvas;->drawColor(I)V

    .line 90
    :goto_0
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getHeight()I

    move-result v0

    .line 91
    .local v0, height:I
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->getWidth()I

    move-result v5

    .line 92
    .local v5, width:I
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v8}, Ljava/util/ArrayList;->size()I

    move-result v4

    .line 93
    .local v4, size:I
    div-int v3, v0, v4

    .line 94
    .local v3, singleHeight:I
    const/4 v1, 0x0

    .local v1, i:I
    :goto_1
    if-ge v1, v4, :cond_2

    .line 95
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    const/4 v9, -0x1

    invoke-virtual {v8, v9}, Landroid/graphics/Paint;->setColor(I)V

    .line 96
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    sget-object v9, Landroid/graphics/Typeface;->DEFAULT_BOLD:Landroid/graphics/Typeface;

    invoke-virtual {v8, v9}, Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;

    .line 97
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    invoke-virtual {v8, v11}, Landroid/graphics/Paint;->setAntiAlias(Z)V

    .line 98
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    iget v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mTextsize:I

    int-to-float v9, v9

    invoke-virtual {v8, v9}, Landroid/graphics/Paint;->setTextSize(F)V

    .line 99
    iget v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    if-ne v1, v8, :cond_0

    .line 100
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    iget v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mChooseColor:I

    invoke-virtual {v8, v9}, Landroid/graphics/Paint;->setColor(I)V

    .line 101
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    invoke-virtual {v8, v11}, Landroid/graphics/Paint;->setFakeBoldText(Z)V

    .line 103
    :cond_0
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v8, v1}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;

    move-result-object v2

    check-cast v2, Ljava/lang/String;

    .line 104
    .local v2, letterStr:Ljava/lang/String;
    div-int/lit8 v8, v5, 0x2

    int-to-float v8, v8

    iget-object v9, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    invoke-virtual {v9, v2}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F

    move-result v9

    const/high16 v10, 0x4000

    div-float/2addr v9, v10

    sub-float v6, v8, v9

    .line 105
    .local v6, xPos:F
    mul-int v8, v3, v1

    add-int/2addr v8, v3

    int-to-float v7, v8

    .line 106
    .local v7, yPos:F
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    invoke-virtual {p1, v2, v6, v7, v8}, Landroid/graphics/Canvas;->drawText(Ljava/lang/String;FFLandroid/graphics/Paint;)V

    .line 107
    iget-object v8, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->paint:Landroid/graphics/Paint;

    invoke-virtual {v8}, Landroid/graphics/Paint;->reset()V

    .line 94
    add-int/lit8 v1, v1, 0x1

    goto :goto_1

    .line 87
    .end local v0           #height:I
    .end local v1           #i:I
    .end local v2           #letterStr:Ljava/lang/String;
    .end local v3           #singleHeight:I
    .end local v4           #size:I
    .end local v5           #width:I
    .end local v6           #xPos:F
    .end local v7           #yPos:F
    :cond_1
    const-string v8, "#26000000"

    invoke-static {v8}, Landroid/graphics/Color;->parseColor(Ljava/lang/String;)I

    move-result v8

    invoke-virtual {p1, v8}, Landroid/graphics/Canvas;->drawColor(I)V

    goto :goto_0

    .line 110
    .restart local v0       #height:I
    .restart local v1       #i:I
    .restart local v3       #singleHeight:I
    .restart local v4       #size:I
    .restart local v5       #width:I
    :cond_2
    return-void
.end method

.method protected onMeasure(II)V
    .locals 1
    .parameter "widthMeasureSpec"
    .parameter "heightMeasureSpec"

    .prologue
    .line 77
    iget-boolean v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    if-eqz v0, :cond_0

    iget v0, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mPaddingBottom:I

    sub-int/2addr p2, v0

    .end local p2
    :cond_0
    invoke-virtual {p0, p1, p2}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->setMeasuredDimension(II)V

    .line 78
    return-void
.end method

.method public onTouchEvent(Landroid/view/MotionEvent;)Z
    .locals 1
    .parameter "event"

    .prologue
    .line 148
    invoke-super {p0, p1}, Landroid/view/View;->onTouchEvent(Landroid/view/MotionEvent;)Z

    move-result v0

    return v0
.end method

.method public setHasFavorite(Z)V
    .locals 6
    .parameter "hasFav"

    .prologue
    .line 56
    iget-boolean v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    if-eq v4, p1, :cond_4

    .line 57
    iput-boolean p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mHasFav:Z

    .line 58
    iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v4}, Ljava/util/ArrayList;->clear()V

    .line 59
    sget-object v0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->b:[Ljava/lang/String;

    .local v0, arr$:[Ljava/lang/String;
    array-length v2, v0

    .local v2, len$:I
    const/4 v1, 0x0

    .local v1, i$:I
    :goto_0
    if-ge v1, v2, :cond_1

    aget-object v3, v0, v1

    .line 60
    .local v3, letter:Ljava/lang/String;
    if-nez p1, :cond_0

    const-string v4, "u2605"

    invoke-virtual {v3, v4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v4

    if-eqz v4, :cond_0

    .line 59
    :goto_1
    add-int/lit8 v1, v1, 0x1

    goto :goto_0

    .line 62
    :cond_0
    iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v4, v3}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z

    goto :goto_1

    .line 64
    .end local v3           #letter:Ljava/lang/String;
    :cond_1
    iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    if-eqz v4, :cond_2

    if-eqz p1, :cond_5

    iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    add-int/lit8 v4, v4, 0x1

    :goto_2
    iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 65
    :cond_2
    iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    if-gez v4, :cond_6

    const/4 v4, 0x0

    iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    .line 68
    :cond_3
    :goto_3
    invoke-virtual {p0}, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->requestLayout()V

    .line 70
    .end local v0           #arr$:[Ljava/lang/String;
    .end local v1           #i$:I
    .end local v2           #len$:I
    :cond_4
    return-void

    .line 64
    .restart local v0       #arr$:[Ljava/lang/String;
    .restart local v1       #i$:I
    .restart local v2       #len$:I
    :cond_5
    iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    add-int/lit8 v4, v4, -0x1

    goto :goto_2

    .line 66
    :cond_6
    iget v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    iget-object v5, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v5}, Ljava/util/ArrayList;->size()I

    move-result v5

    if-lt v4, v5, :cond_3

    iget-object v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->mLetters:Ljava/util/ArrayList;

    invoke-virtual {v4}, Ljava/util/ArrayList;->size()I

    move-result v4

    add-int/lit8 v4, v4, -0x1

    iput v4, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->choose:I

    goto :goto_3
.end method

.method public setOnTouchingLetterChangedListener(Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;)V
    .locals 0
    .parameter "onTouchingLetterChangedListener"

    .prologue
    .line 181
    iput-object p1, p0, Lcom/lewa/PIM/widget/AlphabetFastIndexer;->onTouchingLetterChangedListener:Lcom/lewa/PIM/widget/AlphabetFastIndexer$OnTouchingLetterChangedListener;

    .line 182
    return-void
.end method

Тут нас интересует следующий участок

AlphabetFastIndexer.smali
const/16 v0, 0x1c

    new-array v0, v0, [Ljava/lang/String;

    const/4 v1, 0x0

    const-string v2, "u2605"

    aput-object v2, v0, v1

    const/4 v1, 0x1

    const-string v2, "#"

    aput-object v2, v0, v1

    const/4 v1, 0x2

    const-string v2, "A"

    aput-object v2, v0, v1

    const/4 v1, 0x3

    const-string v2, "B"

    aput-object v2, v0, v1

    const/4 v1, 0x4

    const-string v2, "C"

    aput-object v2, v0, v1

    const/4 v1, 0x5

    const-string v2, "D"

    aput-object v2, v0, v1

    const/4 v1, 0x6

    const-string v2, "E"

    aput-object v2, v0, v1

    const/4 v1, 0x7

    const-string v2, "F"

    aput-object v2, v0, v1

    const/16 v1, 0x8

    const-string v2, "G"

    aput-object v2, v0, v1

    const/16 v1, 0x9

    const-string v2, "H"

    aput-object v2, v0, v1

    const/16 v1, 0xa

    const-string v2, "I"

    aput-object v2, v0, v1

    const/16 v1, 0xb

    const-string v2, "J"

    aput-object v2, v0, v1

    const/16 v1, 0xc

    const-string v2, "K"

    aput-object v2, v0, v1

    const/16 v1, 0xd

    const-string v2, "L"

    aput-object v2, v0, v1

    const/16 v1, 0xe

    const-string v2, "M"

    aput-object v2, v0, v1

    const/16 v1, 0xf

    const-string v2, "N"

    aput-object v2, v0, v1

    const/16 v1, 0x10

    const-string v2, "O"

    aput-object v2, v0, v1

    const/16 v1, 0x11

    const-string v2, "P"

    aput-object v2, v0, v1

    const/16 v1, 0x12

    const-string v2, "Q"

    aput-object v2, v0, v1

    const/16 v1, 0x13

    const-string v2, "R"

    aput-object v2, v0, v1

    const/16 v1, 0x14

    const-string v2, "S"

    aput-object v2, v0, v1

    const/16 v1, 0x15

    const-string v2, "T"

    aput-object v2, v0, v1

    const/16 v1, 0x16

    const-string v2, "U"

    aput-object v2, v0, v1

    const/16 v1, 0x17

    const-string v2, "V"

    aput-object v2, v0, v1

    const/16 v1, 0x18

    const-string v2, "W"

    aput-object v2, v0, v1

    const/16 v1, 0x19

    const-string v2, "X"

    aput-object v2, v0, v1

    const/16 v1, 0x1a

    const-string v2, "Y"

    aput-object v2, v0, v1

    const/16 v1, 0x1b

    const-string v2, "Z"

    aput-object v2, v0, v1

Тут и так все понятно, меняем буквы на русские, единсвенная оговорка, в начале есть такая строка
const/16 v0, 0x1c
Это размер массива, и т.к. русских букв больше на придется добавит несколько строк типа

const/16 v1, 0x1b

const-string v2, ""

aput-object v2, v0, v1
и помеять эту константу. const/16 v1, 0x1b это порядковый номер буквы он тоже будет с каждой буквой расти.

У меня получилось так:

AlphabetFastIndexer.smali Исправленный

const/16 v0, 0x1f

    new-array v0, v0, [Ljava/lang/String;

    const/4 v1, 0x0

    const-string v2, "u2605"

    aput-object v2, v0, v1

    const/4 v1, 0x1

    const-string v2, "#"

    aput-object v2, v0, v1

    const/4 v1, 0x2

    const-string v2, "u0410"

    aput-object v2, v0, v1

    const/4 v1, 0x3

    const-string v2, "u0411"

    aput-object v2, v0, v1

    const/4 v1, 0x4

    const-string v2, "u0412"

    aput-object v2, v0, v1

    const/4 v1, 0x5

    const-string v2, "u0413"

    aput-object v2, v0, v1

    const/4 v1, 0x6

    const-string v2, "u0414"

    aput-object v2, v0, v1

    const/4 v1, 0x7

    const-string v2, "u0415"

    aput-object v2, v0, v1

    const/16 v1, 0x8

    const-string v2, "u0416"

    aput-object v2, v0, v1

    const/16 v1, 0x9

    const-string v2, "u0417"

    aput-object v2, v0, v1

    const/16 v1, 0xa

    const-string v2, "u0418"

    aput-object v2, v0, v1

    const/16 v1, 0xb

    const-string v2, "u041a"

    aput-object v2, v0, v1

    const/16 v1, 0xc

    const-string v2, "u041b"

    aput-object v2, v0, v1

    const/16 v1, 0xd

    const-string v2, "u041c"

    aput-object v2, v0, v1

    const/16 v1, 0xe

    const-string v2, "u041d"

    aput-object v2, v0, v1

    const/16 v1, 0xf

    const-string v2, "u041e"

    aput-object v2, v0, v1

    const/16 v1, 0x10

    const-string v2, "u041f"

    aput-object v2, v0, v1

    const/16 v1, 0x11

    const-string v2, "u0420"

    aput-object v2, v0, v1

    const/16 v1, 0x12

    const-string v2, "u0421"

    aput-object v2, v0, v1

    const/16 v1, 0x13

    const-string v2, "u0422"

    aput-object v2, v0, v1

    const/16 v1, 0x14

    const-string v2, "u0423"

    aput-object v2, v0, v1

    const/16 v1, 0x15

    const-string v2, "u0424"

    aput-object v2, v0, v1

    const/16 v1, 0x16

    const-string v2, "u0425"

    aput-object v2, v0, v1

    const/16 v1, 0x17

    const-string v2, "u0426"

    aput-object v2, v0, v1

    const/16 v1, 0x18

    const-string v2, "u0427"

    aput-object v2, v0, v1

    const/16 v1, 0x19

    const-string v2, "u0428"

    aput-object v2, v0, v1

    const/16 v1, 0x1a

    const-string v2, "u0429"

    aput-object v2, v0, v1

    const/16 v1, 0x1b

    const-string v2, "u042b"

    aput-object v2, v0, v1

    const/16 v1, 0x1c

    const-string v2, "u042d"

    aput-object v2, v0, v1

    const/16 v1, 0x1d

    const-string v2, "u042e"

    aput-object v2, v0, v1

    const/16 v1, 0x1e

    const-string v2, "u042f"

    aput-object v2, v0, v1

"u042f" — это «юникоды» наших букв, так надежней)

После этого можно попробовать собрать риложение перетянув папку PIM на apktool-b.cmd, через некоторое время появится PIMdistPIM.apk

Теперь можно заменить им PIM.apk своего телефона, как это сделать выходит за рамки данной статьи. Могу лишь скзать что можно прошится моим патчем, предварительно заменив в нем PIM.apk на свой.

PROFIT?

Не совсем… Да, буквы русские но поиск то не работает!
Изучаем дальше декомпилированный AlphabetFastIndexer.smali
тут больше ничего интересного кроме
public static abstract interface OnTouchingLetterChangedListener
{
public abstract void onTouchingLetterChanged(String paramString);
}
Хотя по идее он к нашей проблеме не относится я все же решил посмотреть что это такое. public static abstract говорит о том, что этот интерфейс реализован где то в другом файле. Ищем поиском и находим пару файлов где встречается OnTouchingLetterChangedListener:
PIMsmalicomlewaPIMcontactslistContactEntryListFragment.smali
PIMsmalicomlewaPIMmmschoiceContactsMmsChoicePhoneNumbersContacts.smali

Они достаточно длинные поэтому приведу только то что нас интересует

ContactEntryListFragment.smali

Runnable FirstLettersRunnable = new Runnable()
  {
    public void run()
    {
      ContactEntryListFragment.this.marrFirstCharacters.clear();
      ContactEntryListFragment.this.marrFirstLetters.clear();
      Cursor localCursor = ContactEntryListFragment.this.mAdapter.getCursor(0);
      CharArrayBuffer localCharArrayBuffer1;
      CharArrayBuffer localCharArrayBuffer2;
      if ((localCursor != null) && (!localCursor.isClosed()) && (localCursor.getCount() > 0))
      {
        localCursor.moveToFirst();
        boolean bool = ContactEntryListFragment.this.mAdapter instanceof ContactEntryListAdapter;
        int i = 0;
        int j = 0;
        if (bool)
          j = ContactEntryListFragment.this.mAdapter.getStarredCount();
        do
        {
          localCharArrayBuffer1 = new CharArrayBuffer(128);
          localCharArrayBuffer2 = new CharArrayBuffer(128);
          if ((i >= j) || (localCursor.getInt(12) != 1))
            break;
          localCharArrayBuffer1.data[0] = '★';
          int k = 9733;
          i++;
          ContactEntryListFragment.this.marrFirstLetters.add(String.valueOf(k));
          ContactEntryListFragment.this.marrFirstCharacters.add(String.copyValueOf(localCharArrayBuffer1.data, 0, 1));
        }
        while (localCursor.moveToNext());
        if (ContactEntryListFragment.this.mAdapter != null)
          ContactEntryListFragment.this.mAdapter.notifyDataSetChanged();
      }
      ContactEntryListFragment.access$302(ContactEntryListFragment.this, true);
      return;
      localCursor.copyStringToBuffer(1, localCharArrayBuffer1);
      if ((localCharArrayBuffer1.data[0] >= 'a') && (localCharArrayBuffer1.data[0] <= 'z'))
      {
        char[] arrayOfChar = localCharArrayBuffer1.data;
        arrayOfChar[0] = ((char)('¢' + arrayOfChar[0]));
      }
      while (true)
      {
        localCursor.copyStringToBuffer(10, localCharArrayBuffer2);
        int m = Character.toUpperCase(localCharArrayBuffer2.data[0]);
        if ((m >= 65) && (m <= 90))
          break;
        m = 35;
        break;
        if ((localCharArrayBuffer1.data[0] < '€') && ((localCharArrayBuffer1.data[0] < 'A') || (localCharArrayBuffer1.data[0] > 'Z')))
          localCharArrayBuffer1.data[0] = '#';
      }
    }
  };

Как и откуда вызывается это функция я не понял но факт — она собирает первые буквы контактов и все что не относится к английским буквам приравневает к # И поэтому у нас ничего не работает… конкретно эта функция находится в «подфайле» PIMsmalicomlewaPIMcontactslistContactEntryListFragment$3.smali

Там нужно найти участок

.method public run()V
    .locals 13

    .prologue
    .local p0, this:Lcom/lewa/PIM/contacts/list/ContactEntryListFragment$3;,"Lcom/lewa/PIM/contacts/list/ContactEntryListFragment.3;"
    const/16 v12, 0x5a

    const/16 v11, 0x41

0x41 и 0x5a это буквы 'A' и 'Z' их надо поменять на русские:

.method public run()V
    .locals 13

    .prologue
    .local p0, this:Lcom/lewa/PIM/contacts/list/ContactEntryListFragment$3;,"Lcom/lewa/PIM/contacts/list/ContactEntryListFragment.3;"
    const/16 v12, 0x42f

    const/16 v11, 0x410

После чего найти


    aget-char v6, v6, v8

    const/16 v7, 0x61

    if-lt v6, v7, :cond_6

    iget-object v6, v3, Landroid/database/CharArrayBuffer;->data:[C

    aget-char v6, v6, v8

    const/16 v7, 0x7a

    if-gt v6, v7, :cond_6

0x61 — 'a'
0x7a — 'z'
Меняем


       aget-char v6, v6, v8

    const/16 v7, 0x430

    if-lt v6, v7, :cond_6

    iget-object v6, v3, Landroid/database/CharArrayBuffer;->data:[C

    aget-char v6, v6, v8

    const/16 v7, 0x44f

    if-gt v6, v7, :cond_6

В файле MmsChoicePhoneNumbersContacts.smali примерно такая же история

ContactEntryListFragment.smali

    protected void onQueryComplete(int paramInt, Object paramObject, Cursor paramCursor)
    {
      switch (paramInt)
      {
      default:
        return;
      case 0:
      }
      MmsChoicePhoneNumbersContacts.this.mAdapter.changeCursor(paramCursor);
      if (paramCursor.getCount() > 0)
      {
        MmsChoicePhoneNumbersContacts.this.marrFirstCharacters.clear();
        MmsChoicePhoneNumbersContacts.this.marrFirstLetters.clear();
        paramCursor.moveToPosition(-1);
        if (paramCursor.moveToNext())
        {
          CharArrayBuffer localCharArrayBuffer1 = new CharArrayBuffer(128);
          paramCursor.copyStringToBuffer(4, localCharArrayBuffer1);
          if ((localCharArrayBuffer1.data[0] >= 'a') && (localCharArrayBuffer1.data[0] <= 'z'))
          {
            char[] arrayOfChar = localCharArrayBuffer1.data;
            arrayOfChar[0] = ((char)('¢' + arrayOfChar[0]));
          }
          while (true)
          {
            CharArrayBuffer localCharArrayBuffer2 = new CharArrayBuffer(128);
            paramCursor.copyStringToBuffer(11, localCharArrayBuffer2);
            char c = Character.toUpperCase(localCharArrayBuffer2.data[0]);
            if ((c < 'A') || (c > 'Z'))
              c = '#';
            MmsChoicePhoneNumbersContacts.this.marrFirstLetters.add(String.valueOf(c));
            MmsChoicePhoneNumbersContacts.this.marrFirstCharacters.add(String.copyValueOf(localCharArrayBuffer1.data, 0, 1));
            break;
            if ((localCharArrayBuffer1.data[0] < '€') && ((localCharArrayBuffer1.data[0] < 'A') || (localCharArrayBuffer1.data[0] > 'Z')))
              localCharArrayBuffer1.data[0] = '#';
          }
        }
        MmsChoicePhoneNumbersContacts.access$502(MmsChoicePhoneNumbersContacts.this, true);
        paramCursor.moveToFirst();
        MmsChoicePhoneNumbersContacts.this.mEmptyTextView.setVisibility(8);
        return;
      }
      MmsChoicePhoneNumbersContacts.this.mEmptyTextView.setVisibility(0);
    }

# virtual methods
.method protected onQueryComplete(ILjava/lang/Object;Landroid/database/Cursor;)V
    .locals 10
    .parameter "token"
    .parameter "cookie"
    .parameter "cursor"

    .prologue
    const/16 v9, 0x5a

    const/16 v8, 0x41

Меняем на

# virtual methods
.method protected onQueryComplete(ILjava/lang/Object;Landroid/database/Cursor;)V
    .locals 10
    .parameter "token"
    .parameter "cookie"
    .parameter "cursor"

    .prologue
    const/16 v9, 0x42f

    const/16 v8, 0x410

и соответсвенно

    aget-char v3, v3, v5

    const/16 v4, 0x61

    if-lt v3, v4, :cond_3

    iget-object v3, v1, Landroid/database/CharArrayBuffer;->data:[C

    aget-char v3, v3, v5

    const/16 v4, 0x7a

    if-gt v3, v4, :cond_3

на

    aget-char v3, v3, v5

    const/16 v4, 0x430

    if-lt v3, v4, :cond_3

    iget-object v3, v1, Landroid/database/CharArrayBuffer;->data:[C

    aget-char v3, v3, v5

    const/16 v4, 0x44f

    if-gt v3, v4, :cond_3

Собираем это дело обратно и запихиваем а телефон. Вот теперь работает!
Модификация Android приложения от новичка и для новичков
Спасобо за внимание!

P.S. Надеюсь мой ход мыслей кому то поможет. В идеале бы наити как строятся группы в списке контактов и привинтить это дело сюда. Тогда бы в этом списке были толко те буквы, которые дейсвительно присутствуют в контактах, при том что на нескольких языках одновременно, но это мне пока не по зубам.

Автор: NioriX

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js