Практические задания

0. Ведение Git-репозитория (требования)

  1. Зарегистрироваться на Github (или аналоги);

  2. Создать ОДИН репозиторий под Android-проект;

  3. НИКОГДА не менять или создавать новый репозиторий при возникших проблемах с commit, push;

  4. Репозиторий должен содержать 1 (ОДНУ) основную ветку, если не противоречит заданиюж;

  5. На Git-репозиторий загружать весь Android-проект, НЕ просто файлы с *.kt или *.xml;

  6. Сгенерировать SSH-ключ на вашем устройстве, привязать ключ к профилю в Github.com;

  7. Рекомендуется добавить проверочную фразу к ключу;

  8. Выполнить первый commit с обновленным README.MD, где будут указана информация о Вас (ФИО, № группы).

1. Основы ООП. “Ходячий”

  1. Создать проект в Intellij Idea с названием вашего репозитория на Github, либо создать проект внутри директории, если вы уже связали репозиторий на Github с локальным на вашей машине;

  2. Создвать новую ветку в вашем Git-проекте с названием практического задания;

  3. В созданном проекте, по умолчанию будет создан sample code, в котором и будет продолжаться дальнейшая работа;

  4. Создать Класс Human, с свойствами: ФИО, Возраст, Текущая скорость;

  5. Класс должен содержать методы: конструктор со всеми свойствами, метод move(), геттеры и сеттеры свойств класса;

  6. Метод move() должен реализовать один из методов моделирования движений (в Картезианской системе координат): Random Walk, Gauss-Markov Mobility Model;

  7. В функции main() создать массив из экземпляров (количество зависит от вашего номер в списке группы) класса Human(), задать время “симуляции” (на свое усмотрение, в секундах), где в основном цикле “времени” заствить каждого Human ходить;

  8. Сделать коммит (один или несколько) и обновить в удаленном репозитории (git push);

  9. Слить текущую ветку в “основную\стартовую” после проверки преподавателем;

  10. В файле Readme.md описать (с формулами) принцип работы модели движения, выбранной в пункте 6. Вопросы к защите

1. Что такое свойство(свойства) класса?
2. Что такое методы класса?
3. Что такое первичный и вторичный конструкторы?
4. В чем особенность создания вторичного конструктора в языке Kotlin?
5. Что такое init{} в классе?
6. Какие основные положения ООП существуют?

2. Наследование.

  1. Создать новую ветку Вашего проекта, в которой будет выполняться практическая работа;

  2. В качестве нового функционала добавить класс-наследник Driver(), который должен наследовать некоторые свойства (на ваше усмотрение) класса Human();

  3. Движение объектов (экземпляров) класса Driver должно быть прямолинейным (необходимо переопределить функцию move() родительского класса);

  4. В основной фукнции main() создать (2-4 объекта Human и 1 объект Dirve);

  5. В методе move() реализовать параллельное движение каждого из объектов, созданных ранее; Используем Thread;

  6. Сделать commit, push;

  7. Слить ветку в main.

Почитать дома:

Вопросы к защите

1. Что такое наследование?
2. В каком случае необходимо наследование?
3. Написать программы, реализующую основной класс и класс-наследник (на усмотрение преподавателя).

3. Интерфейсы.

  1. Создать новую ветку для реализации “интерфейса”;

  2. Создать интерфейс Movable с шаблонами свойств (координаты, скорость и т.д.) и методов (метод move()), необходимых для реализации движения объектов;

  3. Провести рефакторинг текущей кодовой базы, в частности:

    1. Разделить классы\интерфейсы на файлы (1 класс = 1 файл);

    2. Обновить описание проекта в README.md с информацией по каждому файлу.

  4. Обновить удаленный репозиторий.

Почитать дома:

1. Что такое интерфейсы?
2. Чем отличается наследование интерфейса от "обычного" наследования? В каком случае логичнее наследовать от интерфейса?
3. Написать простой интерфейс вывода информации об объекте.

Android

4. Разработка простейшего калькулятора

Разработать простую версию калькулятора, используя TextView, Button и обработчик нажатия (onClickListener).

Требования к “калькулятору”:

  1. Калькулятор должен состояить из кнопок циферблата (от 0 до 9);

  2. Должен включать в состав Layout кнопки “действий” ( + , -, *, /, =);

  3. Должен включать в состав TextView для отображения результата нажатия на Button’s из пунктов 1 и 2.

  4. При нажатии на = необходимо обработать строку из TextView вручную и выполнить записанные в строку операции;

  5. Достаточно обработки одной операции, нет необходимости обработки нескольких операций.

  6. Результата отправить на Github (или аналоги) репозиторий;

    1. Android-проект будет основным в ветке main\master;

    2. Заменить весь Ваш проект файлами Android-studio, оставив директорию с исходным кодом (переместить по схеме ниже).

Репозиторий Git все файлы предыдущего репозитория должны лежать внутри кода Android.

app
├── manifests
│   └── AndroidManifets.xml
├── kotlin+java
|   ├── Movable/        # Ваш код с практик 1-3.
|   |   ├──Human.kt
|   |   └── и т.д.
|   └── MainActivity.kt
├── res
│   ├── drawable/
│   ├── layout/
│   ├── mipmap/
|   ├── values/
|   └── xml/
└── Gradle Scripts/

4.5. Рефакторинг. Разделение по Activities.

  1. Из MainActivity необходимо создать некий hub, в котором будут отображаться кнопки перехода на другие Activity;

  2. Функционал калькулятора из ПР4 перенести на новое (необходимо создать) новое Activity;

  3. Реализовать метод перехода из MainActivity в другие при помощи кнопок.

Пример перехода но другое Activity при нажатии на кнопку bGoToPlayerActivity:

bGoToPlayerActivity.setOnClickListener({
        // Создаем Intent для класса MediaPlayerActivity - это MediaPlayerActivity.kt
        val randomIntent = Intent(this, MediaPlayerActivity::class.java)
        // Переходим в в другое Activity
        startActivity(randomIntent)
    });

Пример MainActivity

1760687685394

5. Разработать MediaPlayer для воспроизведения музыки

Цель: Научиться работать с файлами внутренней (или внешней) памяти смартфона, в частности, со звуковыми “дорожками”. Исползование класса MediaPlayer поможет в создании “каркаса” для MP3-проигрователя.

  1. Создать новое Activity для работы с MediaPlayer;

  2. MediaPlayer должен поддерживать функции: воспроизведение текущего трека, пауза текущего трека, обработка перехода Activity в состояние onPause(), регулировка громкости, SeekBar для отображения текущей длительности трека и его движение, перемотка трека (при помощи SeekBar);

  3. Возможность вопроизводить музыку из хранилища телефона при помощи Permission, строки 41-53;

  4. Важно реализовать проверку текущего файла на директорию (isDirectory);

  5. Отображение списка треков на экране Activity.

6. Местоположение смартфона. Location

Цель: получить доступ к данным о местоположении Android-телефона и вывести на экран значения. За основу можно взять пример.

  1. Создать Activity Location, в основном окне MainActivity добавить кнопку перехода в новую ‘Activity’;

  2. Получить доступ к классу Location при помощи permissions: ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION;

  3. Вывести в Activity данные о текущем (или последнем известном) местоположении смартфона:

  4. Получить данные можно при помощи метода getLastLocation()

  5. При каждом обновлении местоположения записывать данные в файл (лучше в формате Json);

  6. ДОП. БАЛЛЫ. Обернуть получение местоположения смартфона в сервис с целью записывать данные о местоположении в backgroud-режиме (когда приложение закрыто, activity не видно пользователю).

  7. ДОП. БАЛЛЫ. Выполнить Refactoring кода. Необходимо разделить код на логические составляющие (директории и файлы):

Названия директорий могут отличаться от Ваших:

1. UI - все что связано с визуальной составляющей (Activity, Fragments, и т.д.);
2. Services - отдельно классы сервисов, если такие имеются;
3. Data-классы - классы-структуры, связанные с записью данных в файл, базу данных или при передаче по сокетам. Они состоят только из переменных\свойств класса, без методов;
4. Supp - вспомогательные фукнции, например, чтение из файла, запись в файл и т.д.

Вопросы к защите

  1. Что такое Latitude, Longitude, Altitude? В чем измеряется? Если ли ограничение значений? Если да, от чего зависит?

  2. Что такое Unix Epoch Time?

  3. Как считается время в мобильных телефонах? Есть ли разница с вычислением времени на спутниках? Какая точность измерений?

7. Реализация клиент-серверного приложения (Python\clang)

  1. Создать новый репозиторий в профиле github (для backend-сервера);

  2. В созданный репозиторий добавить Ваш проект Android'a как submodule;

  3. В корне репозитория создать папку examples/, где будут находится примеры работы клиент-серверного приложения;

  4. Создать 2 файла: client.py, server.py;

  5. Реализовать передачу данных (можно просто “Hello World!”) от клиента к серверу и обратно;

  6. Посмотреть результат работы приложений в программе Wireshark, найти переданные сообщения;

  7. Добавить еще один файл в examples/: client.c или server.c;

  8. Реализовать соединение и передачу данных между примером на языке Python и примером на языке СИ;

  9. git commit && git push.

Вопросы к защите

  1. Что такое сокет (с точки зрения операционной системы)?

  2. Из чего состоит сокет (в сетевой части)?

  3. Для чего нужны функции accept(), listen(), bind()? Что выполняет каждая функция?

  4. Что такое файловый дескриптор? Как он связан с текущим процессом? Как он связан с операционной системой?

  5. Из чего состоит информация о файлах с точки зрения операционной системы?

  6. Расскажите что происходит при установлении TCP-соединения в вашей программе (анализируя Wireshark)?

8. Работа с сокетами (ZMQ). Передача данных от Android к PC

  1. На базе примера реализовать передачу данных внутри приложения Android (ваш предыдущий проект);

  2. Создать новое Activity, в котором будет реализованы функции клиента и сервера;

    1. Реализовать начало передачу данных между сервером и клиентом при нажатии на кнопку (создать новую кнопку);

    2. Новый функционал должен находится в отдельной (от основной) ветке (создаем новую ветку (branch));

  3. Наладить передачу данных от Вашего приложения (Android) на приложение-сервер на Вашем компьютере (или VPS, если имеется):

    1. Сервер (компьютер) - запустить серверную часть на базе языка Python + ZMQ;

    2. Android - выступает в роли клиента (на базе ZMQ), подключается к серверу;

    3. Ваш компьютер и телефон (Android) должны находится в одной сети (Wifi, USB, Internet (если есть белый ip-адрес));

    4. В роли данных со стороны Android-приложения выступает строка "Hello from Andorid!";

    5. Данные со стороны сервера - "Hello from Server!";

    6. Серверная часть ДОЛЖНА сохранить (в файл) каждый блок данных, пришедший со смартфона, и считать количество полученных пакетов.

    7. Серверная часть также должны иметь метод\функцию по выводу на экран (консоль) всех сохраненных данных;

  4. Git:

    1. Android - Сделать c merge request с новым функционалом;

    2. Server - добавить новый коммит, обновить удаленный репозиторий.

9. Backend-сервер на CXX

  1. Скоректировать backend-сервер в сторону работы на базе языка C++. Пример работы C++ и ZMQ.

  2. Реализовать передачу данных о местоположении смартфона (см. Задание №6) на CXX-сервер. Сервер должен:

    1. При получении данных от смартфона сохранять их в файл .json;

    2. Работа ZMQ-сокетов должна выполняться в отдельном (от int main()) потоке (thread). Простой пример;

    3. Приложение (Android) должно автоматически переподключаться к серверной части, в случае разрыва соединения (при помощи try и проверки на разрыв соединения);

  3. Реализовать графический интерфейс (ImGUI или Qt5\6), в котором (Здесь начинается ТВОРЧЕСТВО):

    1. Релизовать виджет (окно) с информацией о местоположении (которую мы получили в пункте 2.). В виде текстовой информации;

    2. Информация должна обновляться каждый раз, когда данные принимаются от Android-приложения;

    3. Обернуть реализацию визуального интерфейса в отдельный поток (см. по аналогии с пунктом 2.2).

  4. Связь между двумя потоками (пункты 2.2 и 3.3) осуществляется при помощи одной общей структуры (или класса), например:

struct location
{
    float latitude;
    float longitude;
    float altitude;
    // и т.д.
};

void run_gui(locaiton *loc){
    // здесь работает GUI поток
    // Выводит данные из ГЛОБАЛЬНОЙ структуры location
}

void run_server(locaiton *loc){
    // Здесь работает поток серверный
    // Записывает данные в ГЛОБАЛЬНУЮ структуру location
}

int main(){
    static location locationInfo;

    std::thread gui_thread(run_gui, &locationInfo);
    std::thread server_thread(run_server, &locationInfo);

    gui_thread.join();
    server_thread.join();

    return 0;
}

X. Android Cellinfo.

  1. Реализовать получение данных и передачу на backend-сервер след. данные о смартфоне:

    1. При помощи класса Telephony получаем информацию о сетях мобильной связи:

      1. CellInfoLte: CellIdentityLte, CellSignalStrengthLte;

        1. CellIdentityLte: Band, CellIdentity, EARFCN, MCC, MNC, PCI, TAC;

        2. CellSignalStrengthLte: ASU Level, CQI, RSRP, RSRQ, RSSI, RSSNR, Timing Advance;

      2. CellInfoGsm: CellIdentityGSM, CellSignalStrengthGsm;

        1. CellIdentityGSM: CellIdentity, BSIC, ARFCN, LAC, MCC, MNC, PSC;

        2. CellSignalStrengthGsm: Dbm, RSSI, Timing Advance;

      3. CellInfoNr: CellwIdentityNr, CellSignalStrengthNr

        1. CellIdentityNr: Band, NCI, PCI, Nrargcn, TAC, MCC, MNC;

        2. CellSignalStrengthNr: SS-RSRP, SS-RSRQ, SS-SINR, Timing Advance;

    2. Данные о местоположении смартфона (см. практику №6):

      1. Latitude;

      2. Longitude;

      3. Altitude;

      4. Current Time;

      5. Accuracy - точность вычисления местоположения;

    3. ОПЦИОНАЛЬНО Информацию о сетевом трафике смартфона:

      1. Информация об общем количестве переданных данных;

      2. Информация о ТОП приложений (входящих в 2-сигма по потреблению трафика), потребляющих интернет-трафик смартфона.

11. Android background service.

  1. Реализовать в приложении Android сервис работы в фоновом режиме. Пример здесь.

    1. Перенести функцию определения местоположения в Service;

    2. Перенести функцию получения данных о сети в Service;

    3. Перенести отправку посредством сокетов в Service.

  2. Реализовать отображение параметров мощности радиосигнала (CellSignalStrength) на графиках по мере получения данных с мобильного устройства.

    1. Для графиков использовать библиотеку ImPlot.

  3. Обновить git-репозиторий.

12. Драйв-тест.

  1. Провести драйв-тест в городской местности (например, г. Новосибирск);

    1. Пройтись по городу с телефоном, сохраняя статистику в json-файле (это у вас уже должно работать);

    2. Json-файл должен соответствовать формату из Практики №10;

    3. Собрать максимально возможное количество данных (за 1 неделю).

13. Работа с базой данных (PostgreSQL) из С/С++

  1. Доработать код backend-сервера для взаимодействия с базой данных PSQl.

    1. Создать собственную базу данных (пример);

    2. Создать таблицу на основе данных, которые вы собираете с Android-приложения (Практика X). Пример создания таблицы по ссылке выше;

    3. При каждом получении данных с Android-приложения, добавить данные в таблицу (пример на языке СИ);

  2. В GUI-потоке приложения отображать только текущее значение (пока НЕ загружаем из базы данных);

  3. Графики уровня сигнала (RSRP, RSSI, SINR) также отбражаем, кладя значения в массив по мере поступления данных.

    1. При получении данных о НЕСКОЛЬКИХ сотах, отображаем графики для каждого PCI. Например, пришли данные о двух сотах со значениями PCI_1 = 7 (RSRP = -100 [dBm]), PCI_2 = 13 (RSRP = -89 [dBm]), на графиках должно параллельно отобразиться 2 значения (разными цветами) по оси Y в одном значении оси `X;

    2. В легенде графика добавить значения для всех PCI.

  4. Обновить Github-репозиторий. Обновить README.md, описать возможности вашего приложения.

14. Отрисовка OpenStreetMap карты

Примеры всех этапов можно найти в лекции.

  1. Добработать backend-сервер для работы с OpenStreetMap картами:

    1. Реализовать пересчет текущих координат в номера тайлов;

    2. Получить .png-файл при помощи curl с сервера тайлов;

    3. Преобразовать изображение .png в пиксельную карту (RGBa массив);

    4. Отобразить карту на графике при помощи ImPlot в отдельном окне.

  2. Необходимо заргужать несколько тайлов (зависиот от текущего размера окна ImGui):

    1. Например, если размер окна равен 512x512, то вы должны загрузить и отобразить 4 тайла (256x256 [pix] каждый);

    2. Количество загружаемых тайлов должно динамически меняться в зависимости от изменения размера окна.

  3. Адаптировать вашу карту под изменения местоположения центра экрана и zoom’а:

    1. Т.е. имитировать перемещение карты “на лету”.

  4. Все, уже загруженные, тайлы сохранять в директориях build/zoom/x/y.png:

    • Заметьте, zoom это директория, x - это тоже директория, y - это конечный .png-файл.

    • Если тайл, который вы хотите отобразить уже был загружен, выводим на экран (из директории)

    • Иначе, загружаем через curl.

  5. Провести рефакторинг кода, разделить разные по смыслу сущности (функции) на разные файлы:

    • Например, функции по работе с curl сложить в файл curl_func.h/.cpp;

    • и т.д. ДЛЯ ВСЕХ функций (сокеты, БД, ImGui, и т.д.).

  6. Со звездочкой. Реализовать асинхронную загрузку изображений во время отправки запросов curl.

  7. Обновить github-репозиторий, дописать README.md.

    • В REAMDE.md должны быть описаны пункты: установка зависимостей, компиляция, запуск ПО, описание архитектуры ПО.

Примеры всех этапов можно найти в лекции.

XX. Двустороннее управление поверх сокетов (Android <-> Backend)

  1. В вашем приложении (backend gui) настроить фильтрацию передаваемых данных c со стороны Android-приложения:

    1. В backend-gui приложении реализовать вкладку с фильтрами (при помощи объектов Checkbox, у которого есть состояния true и false). Список переменных должен совпадать со списком из Практической работыXX. Android background service.

    2. При состоянии какого-либо Checkbox = false, передать команду на Android-приложение НЕ передавать (или передавать, если true) при помощи ZMQ-сокетов: 2. Это значит, что при получении или передачи пакетов между вашими приложениями необходимо добавить некоторые управляющие команды, которые Вы должны обработать вручную (if else или switch case и т.д.).

    3. Продолжение следует…

XX. PostgreSQL. База данных (на стороне backend)

XX. Тайлы. Работа с картами.

Вопросы к экзамену\зачету

  1. В чем разница между переменными val и var в языке Kotlin?

  2. Что такое свойство(свойства) класса?

  3. Что такое методы класса?

  4. Что такое первичный и вторичный конструкторы?

  5. В чем особенность создания вторичного конструктора в языке Kotlin?

  6. Что такое init{} в классе?

  7. Назовите основные положения ООП?

  8. Что такое наследование?

  9. В каком случае необходимо использовать наследование?

  10. Написать программы, реализующую основной класс и класс-наследник (на усмотрение преподавателя).

  11. Опишите основные методы жизненного цикла Activity в Android?

  12. Как приложение на смартфоне (Android) понимает какой из методов жизненного цикла выполнить?

  13. Что такое Latitude, Longitude, Altitude? В чем измеряется? Если ли ограничение значений? Если да, от чего зависит?

  14. Что такое Unix Epoch Time?

  15. Что такое сокет (с точки зрения операционной системы)?

  16. Что такое файловый дескриптор?

  17. Из чего состоит сокет (в сетевой части)?

  18. Для чего нужны функции accept(), listen(), bind()? Что выполняет каждая функция?

  19. Что такое файловый дескриптор? Как он связан с текущим процессом? Как он связан с операционной системой?

  20. Из чего состоит информация о файлах с точки зрения операционной системы?

  21. Расскажите что происходит при установлении TCP-соединения в вашей программе (анализируя Wireshark)?