Отправляет email-рассылки с помощью сервиса Sendsay

[prg] Как перехватывать обработку нажатия на ссылки с talkback?

Всех приветствую. Обычно если мы,к примеру,наводим курсор на http ссылку
и двойным табом кликаем на неё или активируем её из меню ссылок в
talkback,то по умолчанию открывается браузер. Также,к примеру,при
нажатии в talkback на e-mail ссылку,открывается почтовый клиент.
Подскажите пожалуйста,как изменить поведение в моей программе при клике
на ссылку,или при её выборе из меню ссылок в talkback,чтобы при этом
клик срабатывал в talkback,поскольку те решения,которые я находил,не
работали,покрайней мере с talkback,т.е поведение при клике на ссылку с
talkback оставалось стандартным. Заранее благодарю всех за помощь.

Ответить   Fri, 13 Jul 2018 00:58:13 +0300 (#3573268)

 

Ответы:

Приветствую всех.

Формулируйте конкретнее: что вы хотите получить при щелчке по ссылке в вашей
программе?
Какой View содержит ссылку? Это действительно ссылка или обычный текст,
который TalkBack распознает по шаблону как ссылку?
Это ссылка на какой-то один конкретный тип файлов или любой url?
От этого зависит, есть ли подходящий вариант или нет.
Успехов. Анатолий.

Ответить   "i_chay" Sat, 14 Jul 2018 07:35:06 +0300 (#3573386)

 

Здравствуйте Анатолий. Вы писали

Я хочу понять,на какую ссылку я нажал и выполнить свой код. В общем это
тоже самое,что обработка клика по view,только обрабатывать клик по view
я умею,а вот с обработкой клика по ссылкам в textView с html текстом я
очень долго мучаюсь и не знаю,возможно ли это. Ещё Вы пишете

Ссылку содержит textView,причём talkback определяет эту ссылку как
ссылка,при этом в тексте может быть несколько таких
ссылок,соответственно мне нужно обрабатывать клик по каждой из
ссылок,т.е когда я с помощью посимвольной навигации дохожу до конкретной
ссылки и делаю по ней двойной таб. Ещё,если это реально,меня устроит
вариант,чтобы когда я нахожу список ссылок в talkback и делаю двойной
таб по одной из сылок,выполнялся мой код,хотя это совсем не обязательно.
Главное,чтобы я мог обработать клик по конкретной ссылке в textView и
выполнить мой метод. Ещё Вы пишете

Это ссылка на любой url. Ещё Вы пишете

Подскажите мне пожалуйста все варианты обработки клика по ссылкам,даже
если они не подходят для моей ситуации,учитывая,что это html текст в
textView и что talkback распознаёт эти ссылки. Если подходящих вариантов
нет,напишите мне пожалуйста об этом,чтобы я знал,что это невозможно.
Заранее благодарю Вас за помощь.

Ответить   Sat, 14 Jul 2018 15:26:38 +0300 (#3573437)

 

Приветствую всех.

Клик всегда обрабатывается в обработчике onClick того View, по которому этот
клик осуществлен.
TalkBack перехватывает сенсорный и клавиатурный ввод и может сам выполнять
какие-то специфические действия (которые его разработчики считают
необходимыми) и тогда этот клик может не попасть в целевой View.
Так что для полного понимания происходящего вам необходимо исследовать
исходники TalkBack.

В итоге ситуация распадается на два варианта: клик обработан в TalkBack
(если он активен), либо в View (если у него есть обработчик onClick
дефолтный или ваш).
Поскольку оба варианта имеют доступ к текстовому содержимому, то выделить
ссылку в позиции курсора не будет сложной задачей (при помощи регулярных
выражений или иным способом). Затем полученная ссылка отправляется системе
при помощи intent с значением action равным VIEW, а уже сама система
подбирает подходящее приложение из тех, в манифесте которых указан
intent-filter для конкретного типа url.
В чистой системе, кроме браузера, на http-ссылки ничего не зарегистрировано,
поэтому сразу стартует браузер. Если будут другие кандидаты, то система
предложит пользователю список приложений для работы с такими ссылками.
Например, чтобы ваша активность появлялась в списке приложений для открытия
http-ссылок, добавьте к активности вашего приложения intent-filter примерно
такого вида:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE"

<data android:scheme="http" />
<data android:scheme="https" />
</intent-filter>

Другой вариант (который правильнее назвать "костыль") -- это
трансформировать внешний вид ссылок так, чтобы TalkBack не распознавал в них
url (опять же для успеха необходимо уточнить способ, каким TalkBack
распознает url в обычном тексте).
Есть класс Linkify, который используется для выделения ссылок в TextView, но
помимо этого он позволяет изменить их внешний вид.
http://developer.alexanderklimov.ru/android/theory/linkify.php

Это позволит избежать вмешательства со стороны TalkBack и реализовать ваш
собственный обработчик для щелчка.

Успехов. Анатолий.

Ответить   "i_chay" Sat, 14 Jul 2018 17:28:40 +0300 (#3573442)

 

Здравствуйте Анатолий. Вы писали

Я не совсем точно Вам объяснил,дело в том,что я адаптирую для незрячих
проект,который уже не развивается и который содержит ссылке,при клике на
которые меняется действие в квесте. Адрес проекта:
https://github.com/BOOMik/QuestPlayer
Дело в том,что клик по ссылкам там реализован в классе,который
наследуется от LimkMovementMethod в методе,который примерно называется
onTouchEvent (в общем в методе,которому на вход подаётся MotionEvent).
Но для незрячих недоступен клик по этой ссылке,т.е даже если я,используя
детализацию по символам,найду символ,с которого начинается ссылка и
сделаю по нему двойной таб,то к сожалению ничего не произойдёт,хотя
зрячие без проблем кликают по этим ссылкам. Ещё нужно учесть тот
факт,что ссылка обрабатывается в одной activity и может выглядеть
примерно так:
<a href="exec:GT ''bed''">кровать</a>
т.е при клике по этой ссылке пользователь переходит в локацию bed,а
текст этой ссылки - кровать и всё это происходит в одной
activity,поэтому Ваш вариант с intentFilter мне,к сожалению,не подходит.
Ещё Вы пишете

Этот вариант,к сожалению,мне тоже не подойдёт,поскольку пользователь
должен понимать,что определённый фрагмент текста эта ссылка,на которую
можно кликнуть. Ещё Вы пишете

В проекте этот класс не используется,зато используются методы класса
html,за счёт чего talkback без проблем распознаёт ссылки. Ещё Вы пишете

А вот это уже очень интересно. Объясните мне пожалуйста,как это сделать?
Дело в том,что в методе onclick мы не знаем,на каком символе сейчас
стоит курсор talkback и по каким координатам view мы кликнули. Если бы я
это знал то,как Вы писали,смог бы без проблем выделить ссылку и
выполнить соответствующий метод. Подскажите пожалуйста,как определить
символ,на который стоит курсор talkback,точнее индекс этого символа.
Заранее благодарю Вас за помощь.

Ответить   Sun, 15 Jul 2018 15:12:17 +0300 (#3573535)

 

Приветствую всех.

А как вам удается вычислить экранные координаты для двойного tap (точнее,
для двух быстрых tap), используя индекс символа в текстовом фрагменте?

И в чем проблема? У класса Activity есть метод onNewIntent(), который
вызывается системой, если новый интент приходит в уже работающую
активность. Соответственно, чтобы это работало, в манифесте для активности
нужно указать атрибут android:launchMode="singleTop".

Подходит, если вы разберетесь в способах запуска активности и использовании
метода onNewIntent(см. ранее)..
А в соответствующем intent-filter пропишите правильную атрибут
android:schemeтребуемой ссылки (то есть не http, а exec).
Тогда только активность игрового плеера будет получать интенты с такими
ссылками и вы сможете их обрабатывать без всяких эмуляций двойных tap.

Успехов. Анатолий.

Ответить   "i_chay" Sun, 15 Jul 2018 17:10:32 +0300 (#3573538)

 

Здравствуйте Анатолий. Вы писали

Там как раз наоборот,они вычисляют ссылку по координатам и это для нас
недоступно. Там,конечно,ещё обрабатывают клик по изображению,но
поскольку я не где этого в квестах не встречал,и всё равно клик по
картинке в html,к сожалению,не доступен для нас,я решил не
заморачиваться. Если честно,я не понял,как это работает,но они это
делают так (в прошлом сообщении я ошибся,поскольку наследник класса
qspLinkMovementMethod ScrollingMovementMethod):
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();

if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();

x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();

x += widget.getScrollX();
y += widget.getScrollY();

Layout layout = widget.getLayout();

//Если не попали точно в символ, относящийся к ссылке,
проверяем 8 соседних
int[] dy = {0, -1, 1, 0, 0, -1, 1, 1, -1};
int[] dx = {0, 0, 0, -1, 1, -1, 1, -1, 1};
int line;
int off;

URLSpan[] link = null;
ImageSpan[] images = null;
for (int i=0; i<9; i++)
{
line = layout.getLineForVertical(y) + dy[i];
if ((line < 0) || (line > layout.getLineCount() - 1))
continue;
off = layout.getOffsetForHorizontal(line, x) + dx[i];
link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) break;
images = buffer.getSpans(off, off, ImageSpan.class);
if (images.length != 0) break;
}

if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
urlCatcher.OnUrlClicked(link[0].getURL());
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}

return true;
} else if (images.length != 0) {
if (action == MotionEvent.ACTION_UP) {
urlCatcher.OnImageClicked(images[0].getSource());
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(images[0]),
buffer.getSpanEnd(images[0]));
}

return true;
} else {
Selection.removeSelection(buffer);
}
}

return super.onTouchEvent(widget, buffer, event);
}
Подробнее на этот проект можно посмотреть gпо ссылке,которую я давал в
прошлом письме. Ещё Вы пишете

Да,Вы правы. Я забыл про эту возможность. Правда этот метод вызывается
по-моему только при режиме запуска activity singleInstance и singleTop.
Посоветуйте пожалуйста,какой из режимов запуска мне лучше
предпочесть,т.е какое значение лучше всего прописать в манифесте для
атрибута activity lounchMode (название атрибута может быть написана
неточно)? Ещё Вы пишете

Ну раз так сработает,то это хорошо. Просто я считал,что это не будет
работать без //. А ведь в проекте ссылки начинаются с exec: а не с
exec://. Ещё хотелось бы узнать как Вы предлагаете обрабатывать двойной
клик,ведь в обработчике onclick мы не знаем не индекса в строке,т.е
индекс символа в строке,под курсором которого находится talkback,не
координат view,по которому мы кликаем. Мы только знаем само view,по
которому мы кликаем. Заранее благодарю Вас за помощь.

Ответить   Sun, 15 Jul 2018 17:12:42 +0300 (#3573541)

 

Никак. Если вы будете использовать intent-filter и onNewIntent() в этом нет
необходимости.
Во-первых, вы сами говорили, что TalkBack находит эти ссылки и отображает их
в списке, из которого их можно активировать.
Во-вторых, если он этого не делает, то это можете сделать вы в своем
приложении, так как доступ к тексту в TextView у вас есть.
Выделите из него все необходимые ссылки и соберите их в список, который и
отобразите в контекстном меню данного TextView.

Ответить   "i_chay" Sun, 15 Jul 2018 18:53:00 +0300 (#3573549)

 

Здравствуйте Анатолий. Вы писали

Скорее всего я воспользуюсь фильтром и onNewIntent,но вопрос какой на
Ваш взгляд режим для запуска activity подойдёт лучше всего,я имею ввиду
из тех,при которых вызывается метод onNewIntent? Также хотелось бы
уточнить,обязательно ли использовать категорию browseble,просто,если
чесно,не очень бы хотелось,чтобы система воспринимала приложение как веб
браузер,когда оно таковым не является. Заранее благодарю Вас за ответы
на мои вопросы.

Ответить   Sun, 15 Jul 2018 20:56:31 +0300 (#3573562)

 

Зависит от того, как вы планируете взаимодействие вашей активности с
активностями из других пакетов. А также от того, нужны ли вам множественные
экземпляры вашей активности (может ли пользователь играть сразу в несколько
разных квестов) или нет. Если множественные экземпляры нужны, то SingleTop.
А вообще, в документации к элементу <activity> есть рекомендации по выбору
режима запуска.

Не обязательно.
Кстати, если вы сами будете извлекать ссылки из текста и собирать их в
список (а не полагаться на TalkBack), то вам и intent-filter не нужен.
Просто отправляйте явный интент своей активности непосредственно, поместив в
extras выбранную пользователем ссылку.

Ответить   "i_chay" Mon, 16 Jul 2018 00:14:54 +0300 (#3573577)

 

Приветствую всех.

Во-первых, у TalkBack нет никакого курсора. Курсор бывает лишь в полях
редактирования, да и то называется позицией выделения.
Во-вторых, в системе есть два фокуса: фокус ввода и фокус доступности.
TalkBack может управлять обоими.
В полях редактирования позиция курсора и позиция unit-навигации средствами
TalkBack синхронизируются, а в других элементах в этом нет
необходимости(например, в кнопках).
Так что если вы хотите отслеживать курсор, то используйте, например,
EditText в режиме readonly. Тогда вы будете иметь доступ к позиции курсора
средствами самого TextView / EditText.
Кроме того, класс Linkify позволяет вам подменить в TextView текст ссылки на
нужный вам. Самый примитивный вариант: добавить к тексту ссылки слова
"ссылка" или "по щелчку", если пользователь выбрал в настройках приложения
вариант с повышенной доступностью.
Успехов. Анатолий.

Ответить   "i_chay" Sun, 15 Jul 2018 18:23:28 +0300 (#3573545)