• 0
ENERGY

Поиск контакта по номеру

Вопросы

Никак не могу сделать поиск контакта по номеру.

 

Есть пример на Java, я все пытаюсь научиться переводить с java на Delphi, но не всегда получается. Вот пример (там же есть полный пример.): 

 

Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...

 

В нем используется Uri.withAppendedPath  (это Jnet_UriClass из Androidapi.JNI.Net) Я нигде не нашел пример работы с ним.

Попытался сделать сам : 

  vUriClass: Jnet_UriClass;
  vfilter : TJavaObjectArray<JString>;

wUri := vUriClass.withAppendedPath( TJContactsContract_PhoneLookup.JavaClass.CONTENT_FILTER_URI,
        vUriClass.encode( StringToJString('+11111111') ) );

   vfilter := TJavaObjectArray<JString>.Create(1);
   vfilter[0] := TJCommonDataKinds_StructuredName.JavaClass.DISPLAY_NAME;
                                                 

    with  SharedActivity.getContentResolver do
      wCursor :=query(wUri, vfilter, nil,nil, nil); // Query to get all contact sorted by displayname

Но ничего не получилось, вылетает ошибка сегментации в withAppendedPath.

 

Помогите пожалуйста, одна на вас надежда. Второй день пошел уже. Как этот ContactsContract.PhoneLookup provider использовать?

Вот полный код на Java :

public String getContactDisplayNameByNumber(String number) {
    Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
    String name = "?";

    ContentResolver contentResolver = getContentResolver();
    Cursor contactLookup = contentResolver.query(uri, new String[] {BaseColumns._ID,
            ContactsContract.PhoneLookup.DISPLAY_NAME }, null, null, null);

    try {
        if (contactLookup != null && contactLookup.getCount() > 0) {
            contactLookup.moveToNext();
            name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
            //String contactId = contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID));
        }
    } finally {
        if (contactLookup != null) {
            contactLookup.close();
        }
    }

    return name;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 ответов на этот вопрос

  • 0

Есть компонент TAddressBook, он не подходит?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Большое Вам спасибо Ярослав, за то что вносите большой вклад в развитие Mobile Delphi. Очень мало примеров  и документации (причем на любом языке) по этому поводу, ваш сайт очень выручает.

Я попробовал демку c:\Program Files (x86)\Embarcadero\Studio\18.0\Samples\Object Pascal\Multi-Device Samples\Device Sensors and Services\Address Book\Contacts\Contacts_Delphi.dproj с  TAddressBook .

Delphi 10 upd 1

Запускал на телефоне HTC - ни один контакт не загрузился - просто пустой список.

UPD: Вместо  AddressBook1.AllContacts(Source, Contacts);

Нужно  AddressBook1.AllContacts(nil, Contacts);  тогда загружает все контакты.

Вся проблема в том, что он считывает сразу все контакты. А мне это не нужно.

Лучше использовать код для поиска конкретного номера, прекрасно находит работает (также работает и вставка нового контакта, здесь описал http://stackoverflow.com/questions/29782398/insert-contacts-in-android-with-delphi/41294891#41294891): 

function TCore.IsNumberInAddressBook(const aNumber: string): boolean;
var
  vCursor: JCursor;
  vQueryStr: string;
begin
  Result := false;
  // will be: data1 LIKE '%+380501960000%'   (with quotes)
  vQueryStr := JStringToString( TJCommonDataKinds_Phone.JavaClass.NORMALIZED_NUMBER) + ' LIKE ''%' + aNumber + '%''';

  vCursor := TAndroidHelper.Activity.getContentResolver.query(
    TJCommonDataKinds_Phone.JavaClass.CONTENT_URI,
    nil,   //projection String: A list of which columns to return. Passing null will return all columns, which is inefficient.
    StringToJString(vQueryStr), // String: A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.
    nil, nil);
   // Query help: https://developer.android.com/reference/android/content/ContentResolver.html#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String)

  if vCursor <> nil then
  try
    Result := vCursor.getCount > 0;
   finally
    vCursor.close;
  end;
end;

// а это может пригодится
 while (cursor.moveToNext) do  
 begin

   lbContactsList.Text := JStringToString(cursor.getString(
      cursor.getColumnIndex(StringToJString('DISPLAY_NAME'))));
   lbContactsList.Tag := cursor.getInt(cursor.getColumnIndex(StringToJString('_ID')));
   //  ListBox1.AddObject(ListBoxItem);
end;

 

Цитата

У меня вопрос к Вам. Вы не в курсе где находится исходный код процедуры

procedure AllContacts(const ASource: TAddressBookSource; var AContacts: TAddressBookContacts); (unit FMX.AddressBook)?

UPD: AllContacts находится в \source\fmx\FMX.AddressBook.Android.pas

 

 

А вообще для самообразования хотелось бы узнать как вызвать  ContactsContract.PhoneLookup.CONTENT_FILTER_URI

И что это за конструкция такая Uri.withAppendedPath, ведь в будущем наверняка с ней придется сталкиваться. Если вы в курсе, расскажите пожалуйста.

Изменено пользователем ENRGY

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 24.12.2016 в 01:35, Brovin Yaroslav сказал:

Есть компонент TAddressBook, он не подходит?

 

А как быть со службой? Если в USES есть FMX.AddressBook, то в службах это работать не будет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Всё-таки есть у кого-нибудь рабочий пример поиска имени по номеру телефона?

Буду премного благодарен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Есть такой пример поиска имени контакта по номеру телефона. Он компилируется, работает, но номер телефона не находит.

 

function TDMSrv.GetContactByPhoneNumber(const sTel: string): string;
var
  wJDislpayName,
  wJFirstName,
  wJLastName,
  wJQueryStr: JString;
  wJQueryParams: TJavaObjectArray<JString>;

  wSubCursor: JCursor;
  wfilter: TJavaObjectArray<JString>;
  wDataUri: JNet_URI;
begin
  if sTel.IsEmpty then
  begin
    log('GetContactByPhoneNumber. Phone number is empty!');
    exit;
  end;

  wDataUri := TJContactsContract_Data.JavaClass.CONTENT_URI;

  wfilter := TJavaObjectArray<JString>.Create(3);
  wfilter[0] := TJCommonDataKinds_StructuredName.JavaClass.DISPLAY_NAME;
  wfilter[1] := TJCommonDataKinds_StructuredName.JavaClass.FAMILY_NAME;
  wfilter[2] := TJCommonDataKinds_StructuredName.JavaClass.GIVEN_NAME;

  wJQueryStr := StringToJString('mimetype = ? AND lookup = ?');

  wJQueryParams := TJavaObjectArray<JString>.Create(2);
  wJQueryParams[0] := TJCommonDataKinds_Phone.JavaClass.NUMBER;
  wJQueryParams[1] := StringToJString(sTel);

  wSubCursor := TAndroidHelper.Context.getContentResolver.Query(wDataUri, wfilter, wJQueryStr, wJQueryParams, nil);

  try
    if wSubCursor.getCount > 0 then
    begin
      // Getting only first row, as we retrieving only names, a contact can have only one first name, one familyname,
      // for phone number for example, we need to loop on each row (while (wSubCursor.moveToNext) do) because a contact can have many phone number
      log('wSubCursor.getCount = ' + wSubCursor.getCount.ToString);
      wSubCursor.moveToNext;
      wJDislpayName := wSubCursor.getString(0);
      wJLastName    := wSubCursor.getString(1);
      wJFirstName   := wSubCursor.getString(2);
    end
    else
      log('wSubCursor.getCount = 0');

    Result := JStringToString(wJDislpayName);
  finally
    wSubCursor.close;
    FreeAndNil(wSubCursor);// := nil;
  end;
end;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
21 час назад, x11 сказал:

Всё-таки есть у кого-нибудь рабочий пример поиска имени по номеру телефона?

Буду премного благодарен.

Возьмите сорцы FMX.AddressBook.Android и заиспользуйте тот код. Единственная причина по которой адресная книга тянет за собой всю платформу в сервисах - это работа с TBitmapSurface. В теории, если уберете всю работу с BitmapSurface (он нужен только для загрузки фоток), то уберете зависимость от платформы. и в этом случае можно использовать эту реализацию напрямую в сервисах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Спасибо, конечно... но...

 

51 минуту назад, Brovin Yaroslav сказал:

В теории, если уберете всю работу с BitmapSurface (он нужен только для загрузки фоток), то уберете зависимость от платформы. и в этом случае можно использовать эту реализацию напрямую в сервисах.

 

На сколько я знаю, то FMX.AddressBook тянет за собой всю адресную книгу себе... зачем?

Ну и я не настолько в этом разбираюсь, чтобы правильно что-то "убрать".

Изменено пользователем x11

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Взял файл, удалил из uses все упоминания, начинающиеся с FMX, "прикрепил" к проекту, при попытке скомпилировать - 70+ ошибок.

Screenshot_1.png

Изменено пользователем x11

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
18 часов назад, x11 сказал:

Взял файл, удалил из uses все упоминания, начинающиеся с FMX, "прикрепил" к проекту, при попытке скомпилировать - 70+ ошибок.

Screenshot_1.png

Ну и правильно, удалить то удалили, а зависимости не разрешили. 

Из исходника в свой юнит или куда еще, надо перенести именно те методы, дергающие api, которые нужны для решения задачи.

Завтра конкретнее посмотрю

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Для решения задачи, по идее, мне нужна только одна маленькая процедура.

Т.е. получается за многолетнюю историю FMX я сейчас пока что единственный, кому понадобилось выполнить поиск контакта по номеру в сервисе? Ну или другой поиск в адресной книге Андроида.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

смотрите код на джава, примеров уйма на стаке.

сравните что в вашем коде выше не так, вот ссылочка для примера 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

В том-то и дело, что не получается. Вот пример (см там, где 79 оценок)

https://stackoverflow.com/questions/3712112/search-contact-by-phone-number

как его перевести в Delphi?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вот мне подсказали на sql.ru рабочий пример, который и у меня получилось использовать в службе.

Я так понимаю, что приходится в этом случае получать полностью всю адресную книгу и потом перебирать её у себя в коде циклом, что не совсем правильно.

Пример компилируется и работает на Delphi Tokyo:

function GetContactByNumbers(const aPhoneNumbers: TList<String>): string;
var
  wUri: JNet_URI;
  lookupID: String;
  wCursor,
  wSubCursor: JCursor;
  wLookup_Idx: Integer;
  wDisplayNameIdx: integer;
  wfilter,
  wJQueryParams: TJavaObjectArray<JString>;
  wDataUri: JNet_URI;
begin
  wUri :=  TJContactsContract_Contacts.JavaClass.CONTENT_URI;
  wCursor := TAndroidHelper.Context.getContentResolver.query(wUri, nil, nil, nil, StringToJString('display_name ASC'));
   try
     wLookup_Idx := wCursor.getColumnIndex(StringToJString('lookup'));
     wDisplayNameIdx := wCursor.getColumnIndex(StringToJString('display_name'));

     while wCursor.moveToNext do
     begin
       lookupID := JStringToString(wCursor.getString(wLookup_Idx));
       wfilter := TJavaObjectArray<JString>.Create(1);
       wfilter[0] := TJCommonDataKinds_Phone.JavaClass.NUMBER;

       // Qurey condition (Exrtact only data for specific ID)
       wJQueryParams := TJavaObjectArray<JString>.Create(2);
       wJQueryParams[0] := TJCommonDataKinds_Phone.JavaClass.CONTENT_ITEM_TYPE;
       wJQueryParams[1] := StringToJString(lookupID);

       wDataUri := TJContactsContract_Data.JavaClass.CONTENT_URI;  // Contacts data uri

       wSubCursor := TAndroidHelper.Context.getContentResolver.
         Query(wDataUri,wfilter,StringToJString('mimetype = ? AND lookup = ?') , wJQueryParams,nil); // Exec query

       try
         if wSubCursor.getCount > 0 then
         begin
           while (wSubCursor.moveToNext) do
           begin
             if aPhoneNumbers.Contains(JStringToString(wSubCursor.getString(0))) then
             begin
               Result := JStringToString(wCursor.getString(wDisplayNameIdx));
               Break;
             end;
           end;
         end;
       finally
         wSubCursor.close;
         wSubCursor := nil;
       end;
     end;
   finally
     wCursor.Close;
     wCursor := nil;
   end;
end;

 

 

К сожалению, в справке по Delphi нет описания TJContactsContract_Contacts, TJCommonDataKinds_Phone и TAndroidHelper.Context.getContentResolver.query. И примеров нет.

 

И пример использования:

// В USES нужно добавить System.Generics.Collections для TList.

VAR
 ListNumbers: TList<string>;
begin

  ListNumbers := TList<string>.Create;
  try
    ListNumbers.Add(sTel);// передаем полный номер: +380681234567
    ListNumbers.Add(RightStr(sTel, 10));// если в адресной книге записан номер без кода оператора - 0681234567
    ContactName := GetContactByNumbers(ListNumbers);
  finally
    FreeAndNil(ListNumbers);
  end;

 

Изменено пользователем x11

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

И ещё не понятно, как работает код, когда у контакта в адресной книге есть 2 номера телефона. Я проверил - оба функция находит, но где это, в каком месте кода, я не понял.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 23.12.2016 в 22:09, ENERGY сказал:

Есть пример на Java, я все пытаюсь научиться переводить с java на Delphi, но не всегда получается. Вот пример (там же есть полный пример.): 

 

function TContactsManager.GetContactByNumber(
  const aPhoneNumber: string): string;
var
  wUri: JNet_URI;
  wCursor: JCursor;
  wfilter,
  wJQueryParams: TJavaObjectArray<JString>;
begin
  Result := '';
  wUri := TJNet_URI.JavaClass.withAppendedPath
    (
     TJContactsContract_PhoneLookup.JavaClass.CONTENT_FILTER_URI,
     StringToJString(aPhoneNumber)
    );

  wfilter := TJavaObjectArray<JString>.Create(2);
  wfilter[0] := StringToJString('lookup');
  wfilter[1] := StringToJString('display_name');

  with SharedActivity.getContentResolver do
    wCursor := query(wUri, wfilter, nil, nil, nil);

  try
    if Assigned(wCursor) and
       (wCursor.getCount > 0) then
    begin
      wCursor.moveToNext;
      Result := JStringToString(wCursor.getString(
        wCursor.getColumnIndex(StringToJString('display_name'))));
    end;
  finally
    wCursor.Close;
    wCursor := nil;
  end;
end;

http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1183758&msg=21183983

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу