Фото Веб Камера

Веб Камера из Андроид смартфона

Веб Камера может понадобиться в самый неожиданный момент. Например, кто-то повадился посещать Вашу дачу без спроса. Можно провести Интернет на дачу, арендовать "белый" IP-адрес, поставить IP-видеокамеру ...

Или установить на смартфон какое-то приложение, которое превратит его в Веб Камеру, будет закачивать фото или видео на сервер разработчика, где Вы будете просматривать его в личном кабинете. Ну, и не только Вы. Опять же, не понятно, нет ли в этом приложении бэкдора...

Можно сделать иначе и бесплатно. Не проще, но программисты поймут выгоду. 

Курсовой Проект

Open Source


Веб Камера в исходных кодах на JAVA. Полностью весь проект для Android Studio - такой, как его сделал Разработчик. С комментариями.

Загружаем в Android Studio, подключаем смартфон по USB шнурку, компилируем, инсталлируем, пользуемся.

Теперь КАК?

В приложении используется стандартный Apache FTP Client. Соответствующие библиотеки включены в проект. Если есть сомнения, можете их скачать сами и заменить - проект полностью доступен - http://shmeleff.com/PhotoWebCamSHMELEFF.zip 


Все остальные части проекта доступны для ознакомления.


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



Макет приложения

Для упрощения проекта приложение работает только в вертикальной ориентации экрана. Для выполнения функций этого достаточно. В верхней части экрана отображается телеметрия - сообщения о работе приложения.

 Файл разметки activity_main.xml для главного экрана приложения - http://shmeleff.com/photocam/activity_main.xml

Верхний TextView используется для телеметрии - текстовых системных сообщений. Есть ротация и скроллинг.

TextureView расположенный в центре экрана предназначен для работы с изображением с фотокамеры.

В нижней части главного экрана приложения - блоки кнопок управления.

Веб Камера из Андроид смартфона

Курсовой проект

Java код главного класса - http://shmeleff.com/photocam/MainActivity.java 

Здесь выполняются все основные действия: запрашиваются разрешения (помимо файла Манифеста), создается и запускается таймер, используется фотокамера, вызывается FTP клиент, обрабатываются кнопки, читаются данные настроек (из ресурсов).

При смене версий OS Android иногда Google меняет правила получения разрешений для работы с фотокамерой и с записью и чтением данных  в память. Причем, менялись правила радикально.

http://oflameron.com Guide

Вообще-то надо было работу с фотокамерой вынести в отдельный класс.



Main Screen

Главный экран

Вверху - телеметрия - системные сообщения приложения.

Ниже - фото

Ещё ниже - кнопки управления

START/STOP - запуск и остановка процесса фото-регистрации

FRONT CAM/REAR CAM - переключение между фотокамерами

CAM LOCAL - сохранять фото в памяти смартфона

FTP SETUP - настройка подключения FTP  клиента

DARK - сделать темный экран

GUIDE - онлайн руководство


Icons

Использованные иконки

В приложении загружается некоторое количество иконок. Они иллюстрируют GUIDE, приложение и некоторые функции.

Структура проекта

Структура проекта

Всего 3 экрана, 4 java файла.


В AndroidManifest.xml даются разрешения и объявляются Activity

http://shmeleff.com/photocam/AndroidManifest.xml 

Скриншот файла ниже


Total Guide

Почему проект именно Фото Веб Камеры?


Apache FTP Client


Для загрузки фотографий на сервер используется известный Apache FTP Client

Просто взят стандартный код и подключены библиотеки.

Apache библиотеки надо разместить в папке

Вторая активити - для настройки параметров приложения. Содержит много элементов EditText для ввода параметров. Имеет табличную разметку

Описание полей ввода параметров

EditText7 - "Per seconds 500+ Sample: 520" - Указывается время между фотоснимками. При использовании мобильного Интернета 4G рекомендуется не менее 500 секунд. Это время зависит от типа подключения к Интернету. WiFi или 5G позволяют делать снимки чаще. Следует учитывать, что в этом случае ротация фотоснимков на сервере будет происходить быстрее и надо буде либо чаще их просматривать, либо увеличивать количество снимков в серии (что увеличит необходимый размер дискового пространства).

EditText8 - Start Time HH. Sample: 7 - время начала фотосессии. Начало светлого времени суток в часах. Например, 7 утра.

EditText10 - End time HH. Sample: 20 - время окончания фотосессии. Окончание светлого времени суток. Например, 20 часов 

EditText1 - FTP Server. Sample: ftp.dtn.com - адрес веб сервера (веб хостинга или ftp сервера), на который будут загружаться фотографии. Может быть и IP адресом в некоторых случаях.

EditText14 - Filename. Sample: picture - шаблон имени файла изображения  на веб сервере, из которого будут создаваться имена фалов фотографий - picture1.jpg, picture2.jpg  и т.д. добавлением порядкового номера и расширения.

EditText15 - Images Number. Sample: 10 - количество фотографий в серии (сессии), после чего они будут перезаписываться на веб сервере.

EditText12 - Login. Sample: admin - login для подключения к хостингу (веб серверу)

EditText3 - Password. Sample: u54eU@ - пароль для подключения к хостингу.

EditText4 - Folder. Sample: public_html - имя папки на веб сервере (хостинге), в которую надо записывать фотографии, чтобы они были доступны для просмотра веб броузером. Дело в том, что у многих веб серверов папка, к которой подключается FTP  клиент, не совпадает с папкой, в которой лежат веб странички для просмотра вебброузером. Вот эту разницу и надо здесь указать, чтобы FTP клиент в неё перешел перед загрузкой файлов.

В   FTPActivity.java - настраиваются параметры, а используются в другой Активити. Как они сохраняются в приложении и передаются?

   //==========================================================

    //   Записать FTP настройки в ресурс

    //==========================================================

    public void onButton1Click(View view) {

        sPref = getSharedPreferences("MyPref", MODE_PRIVATE); //с помощью метода getPreferences получаем объект sPref класса SharedPreferences

        //Константа MODE_PRIVATE используется для настройки доступа и означает, что после

        //сохранения, данные будут видны только этому приложению

        EditText FTPeditText = (EditText)findViewById(R.id.editText1); //Текстовое поле для ввода FTP сервера

        host = FTPeditText.getText().toString();

        EditText LOGINeditText = (EditText)findViewById(R.id.editText2); //Текстовое поле для ввода FTP сервера

        username = LOGINeditText.getText().toString();

        Log.d(TAG, "==| FTP Username in Resources |==: " + username); // Логин FTP сервера

        EditText PASSWORDeditText = (EditText)findViewById(R.id.editText3); //Текстовое поле для ввода FTP сервера

        password = PASSWORDeditText.getText().toString();

        Log.d(TAG, "==| FTP Username in Resources |==: " + password); // Пароль FTP сервера

        EditText DESDIReditText = (EditText)findViewById(R.id.editText4); //Текстовое поле для ввода FTP сервера

        desDirectory = DESDIReditText.getText().toString();

        Log.d(TAG, "==| FTP Folder in Resources |==: " + desDirectory); // Папка FTP сервера

        EditText FTIMEeditText = (EditText)findViewById(R.id.editText7); //Текстовое поле для ввода перилда повтора

        ftime = FTIMEeditText.getText().toString();

        Log.d(TAG, "==| Ftime in Resources |==: " + ftime); // Время, через которое повторять снимок

        EditText STIMEeditText = (EditText)findViewById(R.id.editText8); //Текстовое поле для ввода времени начала сессии

        stime = STIMEeditText.getText().toString();

        Log.d(TAG, "==| Stime in Resources |==: " + stime); // Время старта сессии

        EditText ETIMEeditText = (EditText)findViewById(R.id.editText10); //Текстовое поле для ввода времени окончания сессии

        etime = ETIMEeditText.getText().toString();

        Log.d(TAG, "==| Etime in Resources |==: " + etime); // Время окончания сессии

        EditText FNAMEeditText = (EditText)findViewById(R.id.editText14); //Текстовое поле для ввода имени файла фотографии

        desFileName = FNAMEeditText.getText().toString();

        Log.d(TAG, "==| Image Fname in Resources |==: " + desFileName); // Имя файла фотограии без номера и расширения

        EditText INUMBEReditText = (EditText)findViewById(R.id.editText15); //Текстовое поле для ввода имени файла фотографии

        inumber = INUMBEReditText.getText().toString();

        Log.d(TAG, "==| Image Number in Resources |==: " + inumber); // Количество фотографий в сессию


        //==========================================

        //    Запись в Ресурс

        //==========================================

        //Создаем объект Editor для создания пар имя-значение:

        Editor ed = sPref.edit(); //чтобы редактировать данные, необходим объект Editor – получаем его из sPref

        ed.putString(FTP_TEXT, host); //В метод putString указываем наименование переменной – это константа FTP_TEXT, и значение

        Log.d(TAG, "==|| HOST ||==: " + host); // Адрес FTP сервера

        ed.putString(LOGIN_TEXT, username); //В метод putString указываем наименование переменной – это константа LOGIN_TEXT, и значение

        ed.putString(PASSWORD_TEXT, password); //В метод putString указываем наименование переменной – это константа PASSWORD_TEXT, и значение

        ed.putString(FOLDER_TEXT, desDirectory); //В метод putString указываем наименование переменной – это константа FOLDER_TEXT, и значение

        ed.putString(FTIME_TEXT, ftime); //В метод putString указываем наименование переменной – это константа FTIME_TEXT, и значение

        ed.putString(STIME_TEXT, stime); //В метод putString указываем наименование переменной – это константа STIME_TEXT, и значение

        ed.putString(ETIME_TEXT, etime); //В метод putString указываем наименование переменной – это константа ETIME_TEXT, и значение

        ed.putString(FNAME_TEXT, desFileName); //В метод putString указываем наименование переменной – это константа FNAME_TEXT, и значение

        ed.putString(INUMBER_TEXT, inumber); //В метод putString указываем наименование переменной – это константа INUMBER_TEXT, и значение

        ed.commit(); // Сохранение данных в ресурсах

        Log.d(TAG, "==| DAT Resources Parth |==: " + Environment.getDataDirectory()); // Каталог на устройстве, в который пишутся данные



        //==========================================

        //    Читать Ресурс

        //==========================================

        sPref = getSharedPreferences("MyPref",MODE_PRIVATE);

        String savedText = sPref.getString(FTP_TEXT, "");

        Log.d(TAG, "== FTP Server in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(LOGIN_TEXT, "");

        Log.d(TAG, "== LOGIN in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(PASSWORD_TEXT, "");

        Log.d(TAG, "== PASSWORD in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(FOLDER_TEXT, "");

        Log.d(TAG, "== FOLDER in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(FTIME_TEXT, "");

        Log.d(TAG, "== FTIME in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(STIME_TEXT, "");

        Log.d(TAG, "== STIME in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(ETIME_TEXT, "");

        Log.d(TAG, "== ETIME in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(FNAME_TEXT, "");

        Log.d(TAG, "== FNAME in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов

        savedText = sPref.getString(INUMBER_TEXT, "");

        Log.d(TAG, "== IMAGE NUMBER in Resources ==: " + savedText); // Пишем сохраненный текст из Ресурсов


    }

  Настройки сохраняются сразу. Пароль не шифруется и не маскируется звездочками.

Посмотреть данные можно через Resource Manager

  Через  Device Manager можно посмотреть, что записано в ресурсах на смартфоне. Для этого он должен быть подключен по USB и использоваться для отладки

Управление яркостью экрана

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


f.brightness2 = android.provider.Settings.System.getInt(getContentResolver(),android.provider.Settings.System.SCREEN_BRIGHTNESS);

f.brightness3 = android.provider.Settings.System.getInt(getContentResolver(),android.provider.Settings.System.SCREEN_BRIGHTNESS);

Сохранить текущее значение яркости.

Установить новое значение яркости экрана


context = getApplicationContext();

Intent brightnessIntent = this.getIntent();

float brightness = brightnessIntent.getFloatExtra("brightness value", f.brightness2);  //<-- 1-225

WindowManager.LayoutParams lp = getWindow().getAttributes();

lp.screenBrightness = brightness;

getWindow().setAttributes(lp);

 Методы класса MainActivity


public static void verifyStoragePermissions - получение разрешений на фотокамеру. Без этого ничего работать не будет. Вообще, правила получения и управления разрешениями много раз менялись. Это надо отслеживать.

public String ping - при старте программа Пингует некий IP-адрес и определяет доступность Интернета. Сообщение выдается в телеметрию. Такая проверка мобильного  Интернета проще.

 http://shmeleff.com/PhotoWebCamSHMELEFF.zip

public void onPause - выполняется, когда пауза в работе фотокамеры.  Пишет текст в телеметрию и вызывает stopBackgroundThread() 

public void onResume - возобновляет съемку. Вызывает startBackgroundThread()

public void handleMessage - написать телеметрию

public void handleMessage - написать сообщение

public void onButton4Click - перейти к Activity с настройками FTP клиента

public void onButtonGuide - перейти к Activity с кратким руководством

public void onButton4eClick - сделать темный экран / вернуть в исходное состояние. 

public void onButton5Click - выйти из приложения

public void onButtonClick - обработка нажатия кнопок

public void ifFTP - проверка доступности FTP подключения

public void onFTP - подключение к FTP серверу (WEB-серверу с  FTP загрузкой файлов)

public void TextViewImages - добавить имидж в TextView


 Методы класса FTPActivity

public void onButton1Click - Записать FTP настройки в ресурс

public void onButton3Click - Показать MAIN Activity

public void onButtonGuide - Показать Print Activity - встроенный GUIDE


Методы класса MyFTPClientFunctions

public boolean ftpConnect - подключение к FIP серверу

public boolean ftpDisconnect - отключение FTP сервера

 public boolean ftpUpload - загрузка изображений на хостинг (FTP сервер)


Класс PrintActivity

Показывает небольшое иллюстрированное руководство пользователя


Activity,  элементы, разметка

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

http://oflameron.com

Main Activity

Ничего особенного нет. 


<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    android:background="#fdf5e6"

    tools:context=".MainActivity">

    <!--  PhotoWebCamSHMELEFF - Valery Shmelev JAVA Application -->

    <!--  Полностью работоспособный проект (шаблон) Фото Веб Камеры с FTP загрузкой картинок -->


    <LinearLayout

        android:id="@+id/MainForm"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        android:gravity="bottom|center_horizontal"

        app:layout_constraintBottom_toBottomOf="parent">

        <TableLayout

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:stretchColumns="*"

            android:id="@+id/tableLayout1">

            <!--  Здесь пишем сообщения о работе приложения - Телеметрию -->

            <TableRow

                android:id="@+id/tableRow1h"

                android:layout_width="match_parent"

                android:layout_height="wrap_content">

                <TextView

                    android:id="@+id/TextView7e"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:scrollbars="vertical"

                    android:inputType="textMultiLine"

                    android:textSize="15dp"

                    android:autoLink="web"

                    android:textColorLink="#0066cc"

                    android:layout_span="3"

                    android:textColor="#005678"

                    android:maxLines="7"

                    android:lines="7"

                    android:gravity="bottom"

                    android:text="Telemetry:\n" />

            </TableRow>


            <!--  Здесь получаем картинку с фотокамеры -->

            <TableRow

                android:id="@+id/tableRow1"

                android:layout_width="match_parent"

                android:layout_height="wrap_content">

                <TextureView

                    android:id="@+id/textureView"

                    android:layout_width="348dp"

                    android:layout_height="348dp"

                    android:layout_marginTop="16dp"

                    android:layout_span="3"

                    android:rotation="0"

                    app:layout_constraintEnd_toEndOf="parent"

                    app:layout_constraintHorizontal_bias="0.49"

                    app:layout_constraintStart_toStartOf="parent"

                    app:layout_constraintTop_toTopOf="parent" />

            </TableRow>


            <!--  Кнопка начала сессии или паузы -->

            <TableRow

                android:id="@+id/tableRow1e"

                android:layout_width="match_parent"

                android:layout_height="match_parent">

                <Button

                    android:id="@+id/button1e"

                    android:layout_width="match_parent"

                    android:layout_height="match_parent"

                    android:layout_span="3"

                    android:onClick="onButtonClick"

                    android:text="START/STOP" />

            </TableRow>


            <!--  Выбрать FRONT фотокамеру -->

            <TableRow

                android:id="@+id/tableRow5"

                android:layout_width="match_parent"

                android:layout_height="wrap_content">

                <Button

                    android:id="@+id/button1"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content"

                    android:text="FRONT CAM" />


                <!--  Выбрать REAR фотокамеру -->

                <Button

                    android:id="@+id/button2"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content"

                    android:text="REAR CAM" />


                <!--  Записывать фото только в память смартфона -->

                <Button

                    android:id="@+id/button3"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content"

                    android:text="CAM LOCAL" />


            </TableRow>

            <!--  Перейти к настройкам FTP клиента (Apache FTP Client) -->

            <TableRow

                android:id="@+id/tableRow6"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content">

                <Button

                    android:id="@+id/button4"

                    android:layout_width="149dp"

                    android:layout_height="wrap_content"

                    android:onClick="onButton4Click"

                    android:text="FTP Setup" />


                <!--  Затемнить/Восстановить яркость экрана приложения -->

                <Button

                    android:id="@+id/button4e"

                    android:layout_width="149dp"

                    android:layout_height="wrap_content"

                    android:onClick="onButton4eClick"

                    android:text="Dark" />


                <!--  Выйти из приложения -->

                <Button

                    android:id="@+id/button5"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content"

                    android:onClick="onButton5Click"

                    android:text="Exit" />

            </TableRow>

            <!--  Показать подробное руководство -->

            <TableRow

                android:id="@+id/tableRow7e"

                android:layout_width="match_parent"

                android:layout_height="match_parent">

                <Button

                    android:id="@+id/buttonGuide"

                    android:layout_width="match_parent"

                    android:layout_height="match_parent"

                    android:layout_span="3"

                    android:onClick="onButtonGuide"

                    android:text="GUIDE" />

            </TableRow>


            <!--  Нижняя строка для сообщений -->

            <TableRow

                android:id="@+id/tableRow7"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content">

                <TextView

                    android:id="@+id/webGuide"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:textColorLink="#0066cc"

                    android:textStyle="bold"

                    android:layout_span="3"

                    android:lines="1"

                    android:textSize="18sp"

                    android:scrollbars = "vertical"

                    android:text="  Web GUIDE  " />

            </TableRow>

            <!--  Пустая строка -->

            <TableRow

                android:id="@+id/tableRow8"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content">

                <TextView

                    android:id="@+id/TextView7"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:layout_span="3"

                    android:lines="1"

                    android:text=" " />

            </TableRow>

        </TableLayout>

    </LinearLayout>

    <!--  PhotoWebCamSHMELEFF - Valery Shmelev JAVA Developer -->

    <!--  https://oflameron.imgbb.com/ -->

</androidx.constraintlayout.widget.ConstraintLayout>