>>> a = 1
>>> b = str(1)
>>> c = float(1)
>>> a
>>> b
'1'
>>> c
.0
Если проверить тип переменных, то у «a» будет «int», у «b» будет «str», а у «c» будет «float»
>>> print type(a)
<type 'int'>
>>> print type(b)
<type 'str'>
>>> print type(c)
<type 'float'>
· Строгая типизация. Python принято относить к строго типизированным объектным языкам.
· Функциональное программирование. В python можно использовать рекурсии, ленивые вычисления и функции высших порядков
· Императивное программирование. Python поддерживает процедурный метод программирования, в python можно использовать модули.
Python считается достаточно простым языком, он является самым популярным языком для изучения в колледжах США [38].
Код на python выполняется построчно, поэтому часто ошибку в коде можно заметить только после выполнения этой строчки. Программы, созданные с помощью python for android, запускаются достаточно долго.
Для запуска такого приложения, техническим средством должно быть устройство связи со следующими характеристиками:
· На устройстве во внутренней памяти должно быть 10мб свободной памяти для установки приложения и хранения его данных.
Требования к внутренней памяти обусловлены тем, что установленное приложение будет в себе содержать python for android и kivy. Для работы python for android необходим OpenGL ES 2.0, который есть в Android, начиная с версии 2.2.
Java является объектно-ориентированным языком программирования. С помощью компилятора исходный код на Java превращается в байт код, который содержит в себе набор инструкция для Java машины. Такой подход даёт независимость от платформы. В случае разработки под Android Java машиной является Dalvik. Использование такой машины может сильно снижать производительность.
Концепция Java в плане объектной ориентации схожа с python: «В Java есть специальный суперкласс Object и все классы являются его подклассами. Поэтому ссылочная переменная класса Object может ссылаться на объект любого другого класса» [39].
Java
имеет гибкую систему разграничения доступа, которая задаётся модификаторами
класса private, public, protected или отсутствием модификатора:
Таблица 19. Модификаторы и доступ в Java
|
|
private |
|
protected |
public |
|
тот же класс |
да |
да |
да |
да |
|
подкласс в том же пакете |
нет |
да |
да |
да |
|
независимый класс в том же пакете |
нет |
да |
да |
да |
|
подкласс в другом пакете |
нёт |
нет |
да |
да |
|
независимый класс в другом пакете |
нет |
нет |
нет |
да |
Наиболее простым интерфейсом для пользователя является стандартный интерфейс его системы. Алгоритм звонка при использовании функции Callback не должен отличаться от обычного алгоритма инициализации звонка.
Интерфейс такой программы должен помогать реализовать следующие функции:
1. Callback
o Запуск приложения при инициализации звонка из контактной книги(Contacts)
o Инициализация звонка на сервер телефонии
o Приём звонка от сервера телефонии
o Определение того, что установлен канал связи
o Анализ DTMF сигналов от сервера
o Передача DTMF сигнала во время звонка
2. Работа с историей
o Возможность удалять информацию из системного журнала истории вызовов
o Возможность добавлять информацию в системный журнал истории вызовов
3. Настройки
o Включить/выключить профиль
o Возможность выбрать профиль
o Возможность настроить профиль
o Возможность добавить профиль
o Возможность удалить профиль
4. Профили
o Возможность изменять номер сервера
o Возможность задать белый список номеров сервера
o Возможность указать время ожидания обратного звонка от сервера
o Возможность указать интервал между отправляемым сигналом DTMF
Алгоритм приложения с такими функциями следующий:
Пользователь первый раз открывает приложение и создаёт профиль. В профиле пользователь указывает номер сервера телефонии. В белый список пользователь заносит те номера, с которых ему будет перезванивать сервер телефонии. Время ожидания пользователь указывает в настройках. В случае отсутствия перезвона от сервера, пользователь сможет, не выключая приложения вручную, дальше пользоваться телефонией.
После настройки приложения пользователь может вызвать абонента из контактной книги. В это время появится меню выбора приложения, с помощью которого можно звонить. Если пользователь выберет DTMF Callback, то номер контакта будет сохранён приложением, а само приложение инициализирует вызов с сервером. Когда сервер разорвёт связь и перезвонит, приложение ответит на звонок и наберёт в тональном наборе сохранённый номер, после этого пользователю нужно будет дождаться соединения с вызываемым абонентом.
После окончания разговора в журнале вызовов должен остаться номер абонента, которому звонил пользователь. Подсчёт времени разговора должен начинаться с момента дозвона.
Исходя их реальных возможностей и нулевого опыта разработки под Android, были разработаны минимальные требования к прототипу:
. Прототип должен запускаться на всех современных устройствах под Android начиная от Android 2.1 и заканчивая Android 5.1
. Прототип должен упросить набор номера абонента, когда перезвонит сервер телефонии
. При звонке на номер абонента через прототип звонок должен инициироваться на номер сервера телефонии и одновременно запоминать номер, куда звонил абонент
Первым этапом разработки стало написание приложения, которое может осуществлять вызов на прописанный в коде приложения номер. Данный метод, когда значения переменных жёстко задаются в коде, а не берутся из внешних источников, называется hard coding. Такой метод применяется специально для быстрого тестирования приложения, чтобы каждый раз не набирать номер.
Было принято решение писать на языке программирования python, так как у меня имеется опыт написания на этом языке [40]. Для реализации понадобилось подключить Java класс android.intent.action.CALL из API Android. Целью данного приложения является тестирование возможности вызова любого абонента приложением. Данная функция нужна, чтобы после вызова абонентом «A» на номер абонента «B» начался звонок на номер сервера телефонии. После реализации этой функции стало ясно, что, несмотря на мой опыт, написание приложений под python всплывает множество неочевидных проблем, а в результате готовое приложение слишком долго загружается, что достаточно критично для телефонии. Также стало очевидно, что понимать API без знания языка программирования Java будет очень тяжело. Так как всё равно требовалось понимание языка программирования Java, а итоговый результат на Java давал преимущества, было принято решение переписать функцию под Java, используя Android Studio. Вот код итоговой функции под Java:
public void Call(View view) {
mNumberTextView.setText("Вызов на " + tel.getText() + " Инициализрован");
String toDial = "tel:" + tel.getText().toString();(new Intent(Intent.ACTION_CALL, Uri.parse(toDial)));
}
}
Для того чтобы android-приложение было вызвано из другого приложения можно использовать явные и неявные Намерения(Intent). В явном Намерении указывается, какой класс оно должно вызвать:
Intent intent_about = new Intent(MainActivity.this, AboutActivity.class);
startActivity(intent_about);
Активность AboutActivity.class прописана в Android.Manifest.xml, поэтому система знает какую активность надо запустить.
В неявном Намерении вместо класса, который надо запустить указывается действие, на которое должна среагировать система. В стандартной контактной книге(Contacts) в android, при вызове из неё происходит действие ACTION_CALL_PRIVELEGED. В это действие передаётся номер «tel:». Например, мы можем с помощью adb позвонить этим действием, написав:
adb -e shell am start -a android.intent.action.CALL_PRIVILEGED -d tel:911
,где 100 - это номер, куда позвонит телефон. Если прописать командуshell am start -a android.intent.action.CALL -d tel:911
При этом звонка не будет, так как не будет привилегий позвонить на такой номер. В зависимости от надобности, разные приложения могут использовать различные действия. Если экстренных вызовов не предполагается, то будет использоваться именно ACTION_CALL. Это более частый случай для вызовов из браузера или приложения с контактным номером.
На некоторых прошивках в качестве контактной книги может использоваться альтернативное приложение. Сам исходный код данного приложения может быть закрытым. Если в таких приложениях звонок инициируется как-то иначе, то угадать, через какой Intent инициируется звонок, может быть тяжело. В таком случае можно поставить альтернативную контактную книгу из Google Play или других доверенных источников.
Чтобы программа перехватила неявное Намерение надо в AndroidManifest.xml добавить intent-filter:
<intent-filter>
<action android:name="android.intent.action.CALL_PRIVILEGED"/>
<action android:name="android.intent.action.CALL"/>
<data android:scheme="tel"/>
</intent-filter>
Так как из контактной книги нужно взять только номер в scheme указывается «tel».
Теперь операционная система Android будет предлагать каждый раз вызвать приложение, когда будет вызываться Намерение ACTION_CALL или ACTION_CALL_PRIVILEGED.
Чтобы приложение могло использовать номер, который был в «tel» надо в нужном нам классе воспользоваться методом getData():
Существует библиотека под названием StandOut с помощью, которой можно создать плавающее окно [41]. Библиотека имеем открытый исходный код и примеры [42]. Данная библиотека распространяется под свободной лицензией MIT [43]. Данная лицензия позволяет свободно распространять программное обеспечение, которое содержит эту библиотек. Библиотека поставляется как есть, ответственность за вред, который она может нанести, авторы не несут.
Особенности данной библиотеки:
· Предоставление своего собственного VIEW. Лёгкая интеграция.
· Декораторы плавающих окон:
. заголовок плавающего окна
. кнопка, которая сворачивает плавающее окно
. кнопка, которая закрывает плавающее окно
. кнопка для изменения размеров окна
· Свёрнутое окно можно восстановить
· Создание окон разных типов
· Окна можно перемещать
При тестировании примеров из данной библиотеки было обнаружено, что плавающие окна могут находиться поверх всех окон, в том числе и во время звонка. Данную особенность можно использовать, чтобы создать кнопку, которая будет набирать нужный номер в dialer во время звонка.
Для того чтобы создать окно надо написать класс, который будет расширением класса StandOutWindow:
public class FloatingButton extends StandOutWindow {
}
Далее следует внутрь этого класса добавить метод создания окна:
@Overridevoid createAndAttachView(int id, FrameLayout frame) {inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);view = inflater.inflate(R.layout.floating_button, frame, true);
А в res/layouts слой с описанием интерфейса этого окна floating_button.xml.
Для плавающего окна в StandOut можно создавать кнопки, также как это делается и для обычных Активити. Следующий код следует добавить, чтобы всё пространство Активити заполняла кнопка:
<Button:layout_width="match_parent":layout_height="match_parent":text="Набрать номер":id="@+id/button4"/>
В классе FloatingButton.java можно написать обработчик для нажатия на кнопку:
Button button = (Button) view.findViewById(R.id.button4);.setOnClickListener(new View.OnClickListener() {
@Overridevoid onClick(View v) {rescommand = "input text '" + tel + "'";{.getRuntime().exec(new String[]{"su", "-c", rescommand});
} catch (IOException e) {.printStackTrace();
}
}
});
Данный обработчик будет отрабатываться при нажатии кнопки под id button4.
Строка rescommand содержит в себе команду, которая будет выполнена с правами root из консоли. Команда input text вводит в любое окно указанный текст, будто бы он был набран с клавиатуры. В данном случае текст этот - телефон, который будет получен из телефонной книги.
Для того чтобы абонент мог понять направленность приложения помимо названия принято создавать иконку. Для создания иконки были привлечены выпускница МИЭМ НИУ ВШЭ по направлению дизайн Мария Григорьевна Флейтман и выпускник НИУ ВШЭ по направлению вэб-дизайн Решетько Андрей Владимирович.
В ходе составления задания для дизайнеров было выдвинуто два предположения:
. так как DTMF Callback в первую очередь является приложением для телефонии, то вполне логично использовать в иконке трубку, символизирующую звонок. Поэтому была идея поместить трубку в середину, а вокруг неё поместить волны в виде кругов.
. слово Callback состоит из двух слов call(звонок) и back(назад). Первые буквы этих слов будут символизировать слово CallBack. Волны вокруг DTMF сигнал.
В результате были получены следующие иконки:
Рисунок 16. Иконка с трубкой 1
Рисунок
17. Иконка с трубкой 2
Рисунок
18. Иконка с трубкой 3
Рисунок
19. Иконка CB 1
Рисунок
20. Иконка CB 2
Иконка с трубкой 1 и Иконка CB 1 сделаны в стиле старых приложений, где используется градиент. Из середины цвет плавно перетекает к краям. Остальные иконки сделаны в более современном плоском дизайне, где каждое кольцо залито своим одним цветом. По моему мнению, получаются толстые полоски, которые плохо отражают волны. В то время, на градиенте кольца расходятся, как рябь по воде, что ассоциируется с волной.
Трубка создаёт стойкую ассоциацию, что приложение создано для звонков, в то время, как буквы CB не создают такого впечатления. Было принято решение использовать Иконку с трубкой 1.
Результатом разработки стало готовое приложение под названием DTMF CallBack, которое упрощает использование
функции телефонии Callback и
отвечает минимальным требованиям к прототипу.
Экспериментальная часть
Тестирование приложения проводилось на трёх устройствах:
1. Samsung galaxy s2, Android 4.1.2
2. Sony xperia z1, Android 4.4.4
. Эмулятор x86, Android 5.1
. Эмулятор x86, Android 2.1
Тестирование приёма номера из контактной книги проводилось вручную. В интерфейсе телефона выбиралось приложение Контакты (Contacts) и в нём выполнялась попытка позвонить на номер одного из контактов. Первое устройство предлагало использовать DTMF Callback для вызова, остальные три не предлагали. Стороннее приложение Контакты + [44] всегда предлагало использовать DTMF Callback.
Тестирование плавающего окна проводилось путём его инициализации, закрытия, перетаскивания вручную. На всех устройствах плавающее окно работало одинаково.