Initial Commit v2.0.13 with MQTT Library adding.

This commit is contained in:
ritoseo 2025-07-25 12:19:29 +09:00
commit 07f68645f6
95 changed files with 19284 additions and 0 deletions

6
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

25
.idea/jarRepositories.xml generated Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>

23
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,23 @@
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="..\:/Workspace/Android/OsicManager/app/src/main/res/drawable/selector_button.xml" value="0.2708333333333333" />
<entry key="..\:/Workspace/Android/OsicManager/app/src/main/res/layout/activity_main.xml" value="0.1437389770723104" />
<entry key="..\:/Workspace/Android/OsicManager/app/src/main/res/layout/activity_setting.xml" value="0.164021164021164" />
<entry key="..\:/Workspace/Android/OsicManager/app/src/main/res/layout/fragment_setting.xml" value="0.25" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

155
app/build.gradle Normal file
View File

@ -0,0 +1,155 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
signingConfigs {
debug {
storeFile file('D:\\Android\\rito3399.jks')
storePassword 'ritoseo'
keyAlias = 'ritokey'
keyPassword 'ritoseo'
// storePassword 'android'
// keyAlias = 'platform'
// keyPassword 'android'
}
release {
storeFile file('D:\\Android\\rito3399.jks')
storePassword 'ritoseo'
keyAlias = 'ritokey'
keyPassword 'ritoseo'
}
}
defaultConfig {
applicationId "kr.co.rito.osicmanager"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
// For 119 Version
// versionName "1.0.18"
// For OSIC10
// 2.0.2 - for YELLOW, BLUE KEY active mode working.
// 2.0.3 - for active mode hsact:// working
// 2.0.4 - for encoder live audio drop retry
// 2.0.5 - for ,
// 2.0.6 - for VFD LongPress : , ShortPress :
// 2.0.7 - for , "신호가 약합니다." , stbpage/osic10.php . runChannelList -> lastPlayUrl
// 2.0.8 - for ShouldStopPlay, ShouldPlayUrl ,
// 2.0.9 - for - 2024-06-20
// 2.0.10 - for - 2024-07-25 [ logmanager ]
// 2.0.11 - for MQTT ebcast
// 2.0.12 - for emergency.wav
// 2.0.13 - for AudioFilePlayer에서 MediaPlayer를 ExoPlayer로 . mEbcastMqttIp MQTT
versionName "2.0.13"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//ndk.abiFilters 'armeabi-v7a', 'arm64-v8a'
ndk.abiFilters 'arm64-v8a'
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
debug {
//buildConfigField "String", "SPECIAL_APP_MODE", "\"119NOTI_DEMO\""
buildConfigField "String", "SPECIAL_APP_MODE", "\"\""
}
release {
//buildConfigField "String", "SPECIAL_APP_MODE", "\"119NOTI_DEMO\""
buildConfigField "String", "SPECIAL_APP_MODE", "\"\""
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
ndkVersion '21.0.6113669'
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "OsicManager_v${defaultConfig.versionName}.apk"
}
}
}
dependencies {
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
//compileOnly files('libs/ritocls.jar')
implementation fileTree(dir: 'libs', include: ['*.jar'])
api fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.aar'])
//implementation 'org.videolan.android:libvlc-all:3.3.0-eap10'
//implementation 'org.videolan.android:libvlc-all:3.4.0-eap4'
implementation 'org.videolan.android:libvlc-all:3.4.5'
implementation 'com.google.android.exoplayer:exoplayer:2.16.0'
// mqtt
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
//implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
// implementation 'com.mindorks.android:prdownloader:0.6.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
//preBuild {
// doLast {
// //def imlFile = file(project.name + ".iml")
// def imlFile = file("..\\.idea\\modules\\app\\" + project.parent.name + ".app.iml")
// println 'Change ' + project.name + '.iml order'
// try {
// def parsedXml = (new XmlParser()).parse(imlFile)
// def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
// parsedXml.component[1].remove(jdkNode)
// def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
// println 'what' + sdkString
// new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
// groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
// } catch (FileNotFoundException e) {
// // nop, iml not found
// println "no iml found"
// }
// }
//}
//preBuild {
// doLast {
// def imlFile = file(project.name + ".app.iml")
// println 'Change ' + project.name + '.iml order'
// try {
// def parsedXml = (new XmlParser()).parse(imlFile)
// def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
// parsedXml.component[1].remove(jdkNode)
// def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
// println 'what' + sdkString
// new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
// groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
// } catch (FileNotFoundException e) {
// // nop, iml not found
// println "no iml found"
// }
// }
//}

Binary file not shown.

BIN
app/libs/ritocls.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,27 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("kr.co.rito.osicmanager", appContext.getPackageName());
}
}

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="kr.co.rito.osicmanager">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:clearTaskOnLaunch="true"
android:launchMode="singleInstance"
android:theme="@style/AppTheme">
<activity
android:name=".SettingActivity"
android:screenOrientation="landscape"
android:label="@string/title_activity_setting"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity android:name=".MainActivity"
android:screenOrientation="landscape"
android:clearTaskOnLaunch="true"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="org.eclipse.paho.android.service.MqttService" />
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,44 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
osic-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp osic-manager.cpp sha1sum.cpp mixer.c pcm.c)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
osic-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )

628
app/src/main/cpp/mixer.c Normal file
View File

@ -0,0 +1,628 @@
/* mixer.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#define __force
#define __bitwise
#define __user
#include <sound/asound.h>
#include "tinyalsa/asoundlib.h"
struct mixer_ctl {
struct mixer *mixer;
struct snd_ctl_elem_info *info;
char **ename;
};
struct mixer {
int fd;
struct snd_ctl_card_info card_info;
struct snd_ctl_elem_info *elem_info;
struct mixer_ctl *ctl;
unsigned int count;
};
void mixer_close(struct mixer *mixer)
{
unsigned int n,m;
if (!mixer)
return;
if (mixer->fd >= 0)
close(mixer->fd);
if (mixer->ctl) {
for (n = 0; n < mixer->count; n++) {
if (mixer->ctl[n].ename) {
unsigned int max = mixer->ctl[n].info->value.enumerated.items;
for (m = 0; m < max; m++)
free(mixer->ctl[n].ename[m]);
free(mixer->ctl[n].ename);
}
}
free(mixer->ctl);
}
if (mixer->elem_info)
free(mixer->elem_info);
free(mixer);
/* TODO: verify frees */
}
struct mixer *mixer_open(unsigned int card)
{
struct snd_ctl_elem_list elist;
struct snd_ctl_elem_info tmp;
struct snd_ctl_elem_id *eid = NULL;
struct mixer *mixer = NULL;
unsigned int n, m;
int fd;
char fn[256];
snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
fd = open(fn, O_RDWR);
if (fd < 0)
return 0;
memset(&elist, 0, sizeof(elist));
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
mixer = calloc(1, sizeof(*mixer));
if (!mixer)
goto fail;
mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
if (!mixer->ctl || !mixer->elem_info)
goto fail;
if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
goto fail;
eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
if (!eid)
goto fail;
mixer->count = elist.count;
mixer->fd = fd;
elist.space = mixer->count;
elist.pids = eid;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
for (n = 0; n < mixer->count; n++) {
struct snd_ctl_elem_info *ei = mixer->elem_info + n;
ei->id.numid = eid[n].numid;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
goto fail;
mixer->ctl[n].info = ei;
mixer->ctl[n].mixer = mixer;
if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
if (!enames)
goto fail;
mixer->ctl[n].ename = enames;
for (m = 0; m < ei->value.enumerated.items; m++) {
memset(&tmp, 0, sizeof(tmp));
tmp.id.numid = ei->id.numid;
tmp.value.enumerated.item = m;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
goto fail;
enames[m] = strdup(tmp.value.enumerated.name);
if (!enames[m])
goto fail;
}
}
}
free(eid);
return mixer;
fail:
/* TODO: verify frees in failure case */
if (eid)
free(eid);
if (mixer)
mixer_close(mixer);
else if (fd >= 0)
close(fd);
return 0;
}
const char *mixer_get_name(struct mixer *mixer)
{
return (const char *)mixer->card_info.name;
}
unsigned int mixer_get_num_ctls(struct mixer *mixer)
{
if (!mixer)
return 0;
return mixer->count;
}
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
{
if (mixer && (id < mixer->count))
return mixer->ctl + id;
return NULL;
}
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
{
unsigned int n;
if (!mixer)
return NULL;
for (n = 0; n < mixer->count; n++)
if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
return mixer->ctl + n;
return NULL;
}
void mixer_ctl_update(struct mixer_ctl *ctl)
{
ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
}
const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
{
if (!ctl)
return NULL;
return (const char *)ctl->info->id.name;
}
enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
{
if (!ctl)
return MIXER_CTL_TYPE_UNKNOWN;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
default: return MIXER_CTL_TYPE_UNKNOWN;
};
}
const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
{
if (!ctl)
return "";
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
default: return "Unknown";
};
}
unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
{
if (!ctl)
return 0;
return ctl->info->count;
}
static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
{
int range;
if (percent > 100)
percent = 100;
else if (percent < 0)
percent = 0;
range = (ei->value.integer.max - ei->value.integer.min);
return ei->value.integer.min + (range * percent) / 100;
}
static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
{
int range = (ei->value.integer.max - ei->value.integer.min);
if (range == 0)
return 0;
return ((value - ei->value.integer.min) / range) * 100;
}
int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id));
}
int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
}
int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
{
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (id >= ctl->info->count))
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
return !!ev.value.integer.value[id];
case SNDRV_CTL_ELEM_TYPE_INTEGER:
return ev.value.integer.value[id];
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
return ev.value.enumerated.item[id];
case SNDRV_CTL_ELEM_TYPE_BYTES:
return ev.value.bytes.data[id];
default:
return -EINVAL;
}
return 0;
}
int mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl)
{
return (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
}
int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
{
struct snd_ctl_elem_value ev;
int ret = 0;
size_t size;
void *source;
size_t total_count;
if ((!ctl) || !count || !array)
return -EINVAL;
total_count = ctl->info->count;
if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
mixer_ctl_is_access_tlv_rw(ctl)) {
/* Additional two words is for the TLV header */
total_count += TLV_HEADER_SIZE;
}
if (count > total_count)
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
size = sizeof(ev.value.integer.value[0]);
source = ev.value.integer.value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
/* check if this is new bytes TLV */
if (mixer_ctl_is_access_tlv_rw(ctl)) {
struct snd_ctl_tlv *tlv;
int ret;
if (count > SIZE_MAX - sizeof(*tlv))
return -EINVAL;
tlv = calloc(1, sizeof(*tlv) + count);
if (!tlv)
return -ENOMEM;
tlv->numid = ctl->info->id.numid;
tlv->length = count;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv);
source = tlv->tlv;
memcpy(array, source, count);
free(tlv);
return ret;
} else {
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
size = sizeof(ev.value.bytes.data[0]);
source = ev.value.bytes.data;
break;
}
case SNDRV_CTL_ELEM_TYPE_IEC958:
size = sizeof(ev.value.iec958);
source = &ev.value.iec958;
break;
default:
return -EINVAL;
}
memcpy(array, source, size * count);
return 0;
}
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
{
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (id >= ctl->info->count))
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
ev.value.integer.value[id] = !!value;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
ev.value.integer.value[id] = value;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
ev.value.enumerated.item[id] = value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
ev.value.bytes.data[id] = value;
break;
default:
return -EINVAL;
}
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
}
int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
{
struct snd_ctl_elem_value ev;
size_t size;
void *dest;
size_t total_count;
if ((!ctl) || !count || !array)
return -EINVAL;
total_count = ctl->info->count;
if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) &&
mixer_ctl_is_access_tlv_rw(ctl)) {
/* Additional two words is for the TLV header */
total_count += TLV_HEADER_SIZE;
}
if (count > total_count)
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
size = sizeof(ev.value.integer.value[0]);
dest = ev.value.integer.value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
/* check if this is new bytes TLV */
if (mixer_ctl_is_access_tlv_rw(ctl)) {
struct snd_ctl_tlv *tlv;
int ret = 0;
if (count > SIZE_MAX - sizeof(*tlv))
return -EINVAL;
tlv = calloc(1, sizeof(*tlv) + count);
if (!tlv)
return -ENOMEM;
tlv->numid = ctl->info->id.numid;
tlv->length = count;
memcpy(tlv->tlv, array, count);
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv);
free(tlv);
return ret;
} else {
size = sizeof(ev.value.bytes.data[0]);
dest = ev.value.bytes.data;
}
break;
case SNDRV_CTL_ELEM_TYPE_IEC958:
size = sizeof(ev.value.iec958);
dest = &ev.value.iec958;
break;
default:
return -EINVAL;
}
memcpy(dest, array, size * count);
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
}
int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return ctl->info->value.integer.min;
}
int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return ctl->info->value.integer.max;
}
unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
{
if (!ctl)
return 0;
return ctl->info->value.enumerated.items;
}
const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
unsigned int enum_id)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
(enum_id >= ctl->info->value.enumerated.items))
return NULL;
return (const char *)ctl->ename[enum_id];
}
int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
{
unsigned int i, num_enums;
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
return -EINVAL;
num_enums = ctl->info->value.enumerated.items;
for (i = 0; i < num_enums; i++) {
if (!strcmp(string, ctl->ename[i])) {
memset(&ev, 0, sizeof(ev));
ev.value.enumerated.item[0] = i;
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
if (ret < 0)
return ret;
return 0;
}
}
return -EINVAL;
}
/** Subscribes for the mixer events.
* @param mixer A mixer handle.
* @param subscribe value indicating subscribe or unsubscribe for events
* @returns On success, zero.
* On failure, non-zero.
* @ingroup libtinyalsa-mixer
*/
int mixer_subscribe_events(struct mixer *mixer, int subscribe)
{
if (ioctl(mixer->fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) {
return -1;
}
return 0;
}
/** Wait for mixer events.
* @param mixer A mixer handle.
* @param timeout timout value
* @returns On success, 1.
* On failure, -errno.
* On timeout, 0
* @ingroup libtinyalsa-mixer
*/
int mixer_wait_event(struct mixer *mixer, int timeout)
{
struct pollfd pfd;
pfd.fd = mixer->fd;
pfd.events = POLLIN | POLLOUT | POLLERR | POLLNVAL;
for (;;) {
int err;
err = poll(&pfd, 1, timeout);
if (err < 0)
return -errno;
if (!err)
return 0;
if (pfd.revents & (POLLERR | POLLNVAL))
return -EIO;
if (pfd.revents & (POLLIN | POLLOUT))
return 1;
}
}

View File

@ -0,0 +1,703 @@
#include <jni.h>
#include <string>
#include <linux/sockios.h>
#include <pthread.h>
#include <__locale>
#include "osic-manager.h"
#include <android/log.h>
#include <unistd.h>
#include "sha1sum.h"
#include "tinyalsa/asoundlib.h"
#define LOG_TAG "ManagerNative"
#define LOGUNK(...) __android_log_print(ANDROID_LOG_UNKNOWN,LOG_TAG,__VA_ARGS__)
#define LOGDEF(...) __android_log_print(ANDROID_LOG_DEFAULT,LOG_TAG,__VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_FATAL_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGS(...) __android_log_print(ANDROID_SILENT_ERROR,LOG_TAG,__VA_ARGS__)
static JavaVM* g_jvm;
static jobject g_clazz;
static jmethodID g_javafn_NotifyInfo;
#define ACQUIRE_JNIENV(vm, envptr) \
{ \
int getEnvStat = vm->GetEnv((void **)&envptr, JNI_VERSION_1_6); \
if (getEnvStat == JNI_EDETACHED) { \
if (vm->AttachCurrentThread(&envptr, NULL) != 0) { \
LOGE("Unable to acquire JNIENV"); \
} \
} else if (getEnvStat == JNI_OK) { \
} \
}
#define RELEASE_JNIENV(vm, envptr) \
{ \
int getEnvStat = vm->GetEnv((void **)&envptr, JNI_VERSION_1_6); \
if (getEnvStat != JNI_EDETACHED) { \
vm->DetachCurrentThread(); \
} \
}
int callNotifyInfo(int code, char* strValue) {
if(g_javafn_NotifyInfo != NULL) {
JNIEnv *env;
ACQUIRE_JNIENV(g_jvm, env);
jstring jstrResult = env->NewStringUTF(strValue);
env->CallVoidMethod(g_clazz, g_javafn_NotifyInfo, code, jstrResult);
env->DeleteLocalRef(jstrResult);
RELEASE_JNIENV(g_jvm, env);
}
return 0;
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
char strBuffer[512] = {0, };
pthread_t tid;
get_interface_info("eth0", SIOCGIFHWADDR, strBuffer);
pthread_create(&tid, NULL, osic_start_thread, NULL);
//std::string hello = "Hello from C++";
std::string hello = strBuffer;
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getIPAddress(
JNIEnv* env,
jobject /* this */) {
char strBuffer[512] = {0, };
get_interface_info("eth0", SIOCGIFADDR, strBuffer);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getNetmask(
JNIEnv* env,
jobject /* this */) {
char strBuffer[512] = {0, };
get_interface_info("eth0", SIOCGIFNETMASK, strBuffer);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getGateway(
JNIEnv* env,
jobject /* this */) {
char strBuffer[512] = {0, };
get_default_gw(strBuffer);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getServerAddress(
JNIEnv* env,
jobject /* this */) {
char strBuffer[512] = {0, };
get_server_addr(strBuffer);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getServerPort(
JNIEnv* env,
jobject /* this */) {
return get_server_port();
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getConfigValue(
JNIEnv* env,
jobject thiz,
jstring target) {
char strBuffer[512] = {0, };
const char *pType = env->GetStringUTFChars(target, 0);
getConfigValue((char *)pType, strBuffer);
env->ReleaseStringUTFChars(target, pType);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_MainActivity_nativeInit(
JNIEnv* env,
jobject thiz,
jstring version) {
char strBuffer[512] = {0, };
const char *pVersion = env->GetStringUTFChars(version, 0);
setVersionString(pVersion);
env->ReleaseStringUTFChars(version, pVersion);
jclass cls = env->GetObjectClass(thiz);
g_clazz = env->NewWeakGlobalRef(thiz);
g_javafn_NotifyInfo = env->GetMethodID(cls, "nativeNotify", "(ILjava/lang/String;)V");
env->GetJavaVM(&g_jvm);
pthread_t tid;
pthread_create(&tid, NULL, osic_start_thread, NULL);
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_MainActivity_terminateService(
JNIEnv* env,
jobject thiz) {
quit_osic9_mode();
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_MainActivity_doSync(
JNIEnv* env,
jobject thiz) {
::sync();
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_MainActivity_setState(
JNIEnv* env,
jobject thiz,
jstring target) {
const char *pTarget = env->GetStringUTFChars(target, 0);
//setVersionString(pTarget);
setStateTarget((char *)pTarget);
env->ReleaseStringUTFChars(target, pTarget);
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_getIPAddress(
JNIEnv* env,
jclass /* this */) {
char strBuffer[512] = {0, };
get_interface_info("eth0", SIOCGIFADDR, strBuffer);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_getConfigValue(
JNIEnv* env,
jclass thiz,
jstring target) {
char strBuffer[512] = {0, };
const char *pType = env->GetStringUTFChars(target, 0);
getConfigValue((char *)pType, strBuffer);
env->ReleaseStringUTFChars(target, pType);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_setConfigValue(
JNIEnv* env,
jclass thiz,
jstring target,
jstring value) {
char strBuffer[512] = {0, };
const char *pType = env->GetStringUTFChars(target, 0);
const char *pValue = env->GetStringUTFChars(value, 0);
sprintf(strBuffer, "ritosysc CONFIG-WRITE=[%s]%s", pType, pValue);
env->ReleaseStringUTFChars(target, pType);
env->ReleaseStringUTFChars(value, pValue);
system(strBuffer);
sprintf(strBuffer, "ritosysc CONFIG-SAVE");
system(strBuffer);
}
extern "C" JNIEXPORT jstring JNICALL
Java_kr_co_rito_osicmanager_MainActivity_getFileCksum(
JNIEnv* env,
jobject thiz,
jstring target) {
char strBuffer[512] = {0, };
const char *pPath = env->GetStringUTFChars(target, 0);
rito_cksum((char *)pPath, strBuffer);
env->ReleaseStringUTFChars(target, pPath);
std::string result = strBuffer;
return env->NewStringUTF(result.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_kr_co_rito_osicmanager_MainActivity_sendSocketMessage(
JNIEnv* env,
jobject thiz,
jstring target) {
const char *pTarget = env->GetStringUTFChars(target, 0);
sendSocketMessage((char *)pTarget);
env->ReleaseStringUTFChars(target, pTarget);
}
#include <unistd.h>
#include <fcntl.h>
#define GPIO_IN 0
#define GPIO_OUT 1
#define GPIO_LOW 0
#define GPIO_HIGH 1
static int GPIOExport(int pin)
{
#define BUFFER_MAX 5
char buffer[BUFFER_MAX];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/export", O_WRONLY);
if (-1 == fd) {
LOGW("Failed to open export for writing!");
return(-1);
}
bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
char target_order[256];
sprintf(target_order, "ritosysc SHELL-ORDER=chmod 666 /sys/class/gpio/gpio%d/direction", pin);
system(target_order);
sprintf(target_order, "ritosysc SHELL-ORDER=chmod 666 /sys/class/gpio/gpio%d/value", pin);
system(target_order);
return(0);
}
static int GPIOUnexport(int pin)
{
char buffer[BUFFER_MAX];
ssize_t bytes_written;
int fd;
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (-1 == fd) {
LOGW("Failed to open unexport for writing!");
return(-1);
}
bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
write(fd, buffer, bytes_written);
close(fd);
return(0);
}
static int GPIODirection(int pin, int dir)
{
static const char s_directions_str[] = "in\0out";
#define DIRECTION_MAX 64
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
fd = open(path, O_WRONLY);
if (-1 == fd) {
LOGW("Failed to open gpio direction for writing!");
return(-1);
}
if (-1 == write(fd, &s_directions_str[GPIO_IN == dir ? 0 : 3], GPIO_IN == dir ? 2 : 3)) {
LOGW("Failed to set direction!");
return(-1);
}
close(fd);
return(0);
}
#define VALUE_MAX 64
static int GPIORead(int pin)
{
char path[VALUE_MAX];
char value_str[3];
int fd;
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_RDONLY);
if (-1 == fd) {
LOGW("Failed to open gpio value for reading!");
return(-1);
}
if (-1 == read(fd, value_str, 3)) {
LOGW("Failed to read value!");
return(-1);
}
close(fd);
return(atoi(value_str));
}
static int GPIOWrite(int pin, int value)
{
static const char s_values_str[] = "01";
char path[VALUE_MAX];
int fd;
snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_WRONLY);
if (-1 == fd) {
LOGW("Failed to open gpio value for writing!\n");
return(-1);
}
if (1 != write(fd, &s_values_str[GPIO_LOW == value ? 0 : 1], 1)) {
LOGW("Failed to write value!\n");
return(-1);
}
close(fd);
return(0);
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_getPinValue(
JNIEnv* env,
jclass /* this */,
jint pinNo) {
int ret;
ret = GPIORead(pinNo);
return ret;
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_setPinValue(
JNIEnv* env,
jclass /* this */,
jint pinNo,
jint value) {
int ret;
ret = GPIOWrite(pinNo, value);
return ret;
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_pinSetup(
JNIEnv* env,
jclass /* this */,
jint pinNo,
jint pinDirection) {
int ret;
ret = GPIOExport(pinNo);
if(ret < 0)
return ret;
if(pinDirection == GPIO_IN) {
GPIODirection(pinNo, GPIO_OUT);
GPIOWrite(pinNo, GPIO_HIGH);
} else {
ret = GPIODirection(pinNo, pinDirection);
}
return ret;
}
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
struct riff_wave_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t wave_id;
};
struct chunk_header {
uint32_t id;
uint32_t sz;
};
struct chunk_fmt {
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
};
int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
char *param_name, char *param_unit)
{
unsigned int min;
unsigned int max;
int is_within_bounds = 1;
min = pcm_params_get_min(params, static_cast<pcm_param>(param));
if (value < min) {
fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
param_unit, min, param_unit);
is_within_bounds = 0;
}
max = pcm_params_get_max(params, static_cast<pcm_param>(param));
if (value > max) {
fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
param_unit, max, param_unit);
is_within_bounds = 0;
}
return is_within_bounds;
}
int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_params *params;
int can_play;
params = pcm_params_get(card, device, PCM_OUT);
if (params == NULL) {
fprintf(stderr, "Unable to open PCM device %u.\n", device);
return 0;
}
can_play = check_param(params, PCM_PARAM_RATE, rate, (char*)"Sample rate", (char*)"Hz");
can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, (char*)"Sample", (char*)" channels");
can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, (char*)"Bitrate", (char*)" bits");
can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, (char*)"Period size", (char*)" frames");
can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, (char*)"Period count", (char*)" periods");
pcm_params_free(params);
return can_play;
}
void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_config config;
struct pcm *pcm;
char *buffer;
int size;
int num_read;
memset(&config, 0, sizeof(config));
config.channels = channels;
config.rate = rate;
config.period_size = period_size;
config.period_count = period_count;
if (bits == 32)
config.format = PCM_FORMAT_S32_LE;
else if (bits == 24)
config.format = PCM_FORMAT_S24_3LE;
else if (bits == 16)
config.format = PCM_FORMAT_S16_LE;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
return;
}
pcm = pcm_open(card, device, PCM_OUT, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device %u (%s)\n",
device, pcm_get_error(pcm));
return;
}
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = (char *)malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %d bytes\n", size);
free(buffer);
pcm_close(pcm);
return;
}
printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
do {
num_read = fread(buffer, 1, size, file);
if (num_read > 0) {
if (pcm_write(pcm, buffer, num_read)) {
fprintf(stderr, "Error playing sample\n");
break;
}
}
} while (num_read > 0);
free(buffer);
pcm_close(pcm);
}
int do_tinyplay(char *filename, unsigned int device_id, unsigned int card_id)
{
FILE *file;
struct riff_wave_header riff_wave_header;
struct chunk_header chunk_header;
struct chunk_fmt chunk_fmt;
unsigned int device = 0;
unsigned int card = 0;
unsigned int period_size = 1024;
unsigned int period_count = 4;
int more_chunks = 1;
LOGW("RITO TRACE[%d]", __LINE__);
file = fopen(filename, "rb");
if (!file) {
LOGW("Unable to open file '%s'\n", filename);
return 1;
}
LOGW("RITO TRACE[%d]", __LINE__);
fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
if ((riff_wave_header.riff_id != ID_RIFF) ||
(riff_wave_header.wave_id != ID_WAVE)) {
LOGW("Error: '%s' is not a riff/wave file\n", filename);
fclose(file);
return 1;
}
LOGW("RITO TRACE[%d]", __LINE__);
do {
fread(&chunk_header, sizeof(chunk_header), 1, file);
switch (chunk_header.id) {
case ID_FMT:
fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
/* If the format header is larger, skip the rest */
if (chunk_header.sz > sizeof(chunk_fmt))
fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
break;
case ID_DATA:
/* Stop looking for chunks */
more_chunks = 0;
break;
default:
/* Unknown chunk, skip bytes */
fseek(file, chunk_header.sz, SEEK_CUR);
}
} while (more_chunks);
LOGW("RITO TRACE[%d]", __LINE__);
device = device_id;
card = card_id;
play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate,
chunk_fmt.bits_per_sample, period_size, period_count);
LOGW("RITO TRACE[%d]", __LINE__);
fclose(file);
return 0;
}
static struct pcm *gp_pcm = NULL;
int aout_setup(unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_config config;
struct pcm *pcm;
char *buffer;
int size;
int num_read;
memset(&config, 0, sizeof(config));
config.channels = channels;
config.rate = rate;
config.period_size = period_size;
config.period_count = period_count;
if (bits == 32)
config.format = PCM_FORMAT_S32_LE;
else if (bits == 24)
config.format = PCM_FORMAT_S24_3LE;
else if (bits == 16)
config.format = PCM_FORMAT_S16_LE;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
return -1;
}
pcm = pcm_open(card, device, PCM_OUT, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device %u (%s)\n",
device, pcm_get_error(pcm));
return -2;
}
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = (char *)malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %d bytes\n", size);
free(buffer);
pcm_close(pcm);
return -3;
}
printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
gp_pcm = pcm;
return 0;
}
void aout_close() {
if(gp_pcm) {
pcm_close(gp_pcm);
gp_pcm = NULL;
}
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_playWaveFile(
JNIEnv* env,
jclass /* this */,
jstring filePath,
jint device_id) {
int ret;
const char *pPath = env->GetStringUTFChars(filePath, 0);
ret = do_tinyplay((char*)pPath, device_id, 0);
env->ReleaseStringUTFChars(filePath, pPath);
return ret;
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_setupAudioOut(
JNIEnv* env,
jclass /* this */,
jint device_id) {
int ret = aout_setup(0, device_id, 2, 44100, 16, 1024, 4);
return ret;
}
extern "C" JNIEXPORT jint JNICALL
Java_kr_co_rito_osicmanager_SystemUtil_writeAudioOut(
JNIEnv* env,
jclass /* this */,
jbyteArray buffer,
jint size) {
jbyte *pBuffer;
pBuffer = env->GetByteArrayElements(buffer, NULL);
pcm_write(gp_pcm, pBuffer, size);
env->ReleaseByteArrayElements(buffer, pBuffer, 0);
return size;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
#ifndef OSIC_MANAGER_H
#define OSIC_MANAGER_H
static int MANAGER_NOTIFY_ORDER_START_PLAYBACK = 1;
static int MANAGER_NOTIFY_ORDER_STOP_PLAYBACK = 2;
static int MANAGER_NOTIFY_ORDER_START_TICKER = 3;
static int MANAGER_NOTIFY_ORDER_START_TTS = 4;
static int MANAGER_NOTIFY_ORDER_CEC_CONTROL = 5;
static int MANAGER_NOTIFY_ORDER_JSON_ORDER = 6;
static int MANAGER_NOTIFY_ORDER_NOTIFY_SCREEN_ORDER = 7;
static int MANAGER_NOTIFY_ORDER_EVENT_MESSAGE = 8;
static int MANAGER_NOTIFY_ORDER_START_AUDIO = 9;
static int MANAGER_NOTIFY_ORDER_STOP_AUDIO = 10;
int callNotifyInfo(int code, char* strValue);
int get_interface_info( const char *eth, int infotype, char *rtnval );
int get_default_gw(char *pBuffer);
int get_server_addr(char *pBuffer);
int get_server_port();
int getConfigValue(char *pType, char *pResult);
void quit_osic9_mode();
void *osic_start_thread(void *pArg);
void setVersionString(const char *pVersion);
void setStateTarget(char *pTarget);
void sendSocketMessage(char *pTarget);
#endif

1369
app/src/main/cpp/pcm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,365 @@
//
// Created by 서인석 on 2020-10-22.
//
/* sha1sum.c - print SHA-1 Message-Digest Algorithm
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
* Copyright (C) 2004 g10 Code GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* SHA-1 coden take from gnupg 1.3.92.
Note, that this is a simple tool to be used for MS Windows.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#undef BIG_ENDIAN_HOST
typedef unsigned int u32;
/****************
* Rotate a 32 bit integer by n bytes
*/
#if defined(__GNUC__) && defined(__i386__)
static inline u32
rol( u32 x, int n)
{
__asm__("roll %%cl,%0"
:"=r" (x)
:"0" (x),"c" (n));
return x;
}
#else
#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
#endif
typedef struct {
u32 h0,h1,h2,h3,h4;
u32 nblocks;
unsigned char buf[64];
int count;
} SHA1_CONTEXT;
void
sha1_init( SHA1_CONTEXT *hd )
{
hd->h0 = 0x67452301;
hd->h1 = 0xefcdab89;
hd->h2 = 0x98badcfe;
hd->h3 = 0x10325476;
hd->h4 = 0xc3d2e1f0;
hd->nblocks = 0;
hd->count = 0;
}
/****************
* Transform the message X which consists of 16 32-bit-words
*/
static void
transform( SHA1_CONTEXT *hd, unsigned char *data )
{
u32 a,b,c,d,e,tm;
u32 x[16];
/* get values from the chaining vars */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
#ifdef BIG_ENDIAN_HOST
memcpy( x, data, 64 );
#else
{ int i;
unsigned char *p2;
for(i=0, p2=(unsigned char*)x; i < 16; i++, p2 += 4 ) {
p2[3] = *data++;
p2[2] = *data++;
p2[1] = *data++;
p2[0] = *data++;
}
}
#endif
#define K1 0x5A827999L
#define K2 0x6ED9EBA1L
#define K3 0x8F1BBCDCL
#define K4 0xCA62C1D6L
#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) )
#define F2(x,y,z) ( x ^ y ^ z )
#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) )
#define F4(x,y,z) ( x ^ y ^ z )
#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \
^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
, (x[i&0x0f] = rol(tm,1)) )
#define R(a,b,c,d,e,f,k,m) do { e += rol( a, 5 ) \
+ f( b, c, d ) \
+ k \
+ m; \
b = rol( b, 30 ); \
} while(0)
R( a, b, c, d, e, F1, K1, x[ 0] );
R( e, a, b, c, d, F1, K1, x[ 1] );
R( d, e, a, b, c, F1, K1, x[ 2] );
R( c, d, e, a, b, F1, K1, x[ 3] );
R( b, c, d, e, a, F1, K1, x[ 4] );
R( a, b, c, d, e, F1, K1, x[ 5] );
R( e, a, b, c, d, F1, K1, x[ 6] );
R( d, e, a, b, c, F1, K1, x[ 7] );
R( c, d, e, a, b, F1, K1, x[ 8] );
R( b, c, d, e, a, F1, K1, x[ 9] );
R( a, b, c, d, e, F1, K1, x[10] );
R( e, a, b, c, d, F1, K1, x[11] );
R( d, e, a, b, c, F1, K1, x[12] );
R( c, d, e, a, b, F1, K1, x[13] );
R( b, c, d, e, a, F1, K1, x[14] );
R( a, b, c, d, e, F1, K1, x[15] );
R( e, a, b, c, d, F1, K1, M(16) );
R( d, e, a, b, c, F1, K1, M(17) );
R( c, d, e, a, b, F1, K1, M(18) );
R( b, c, d, e, a, F1, K1, M(19) );
R( a, b, c, d, e, F2, K2, M(20) );
R( e, a, b, c, d, F2, K2, M(21) );
R( d, e, a, b, c, F2, K2, M(22) );
R( c, d, e, a, b, F2, K2, M(23) );
R( b, c, d, e, a, F2, K2, M(24) );
R( a, b, c, d, e, F2, K2, M(25) );
R( e, a, b, c, d, F2, K2, M(26) );
R( d, e, a, b, c, F2, K2, M(27) );
R( c, d, e, a, b, F2, K2, M(28) );
R( b, c, d, e, a, F2, K2, M(29) );
R( a, b, c, d, e, F2, K2, M(30) );
R( e, a, b, c, d, F2, K2, M(31) );
R( d, e, a, b, c, F2, K2, M(32) );
R( c, d, e, a, b, F2, K2, M(33) );
R( b, c, d, e, a, F2, K2, M(34) );
R( a, b, c, d, e, F2, K2, M(35) );
R( e, a, b, c, d, F2, K2, M(36) );
R( d, e, a, b, c, F2, K2, M(37) );
R( c, d, e, a, b, F2, K2, M(38) );
R( b, c, d, e, a, F2, K2, M(39) );
R( a, b, c, d, e, F3, K3, M(40) );
R( e, a, b, c, d, F3, K3, M(41) );
R( d, e, a, b, c, F3, K3, M(42) );
R( c, d, e, a, b, F3, K3, M(43) );
R( b, c, d, e, a, F3, K3, M(44) );
R( a, b, c, d, e, F3, K3, M(45) );
R( e, a, b, c, d, F3, K3, M(46) );
R( d, e, a, b, c, F3, K3, M(47) );
R( c, d, e, a, b, F3, K3, M(48) );
R( b, c, d, e, a, F3, K3, M(49) );
R( a, b, c, d, e, F3, K3, M(50) );
R( e, a, b, c, d, F3, K3, M(51) );
R( d, e, a, b, c, F3, K3, M(52) );
R( c, d, e, a, b, F3, K3, M(53) );
R( b, c, d, e, a, F3, K3, M(54) );
R( a, b, c, d, e, F3, K3, M(55) );
R( e, a, b, c, d, F3, K3, M(56) );
R( d, e, a, b, c, F3, K3, M(57) );
R( c, d, e, a, b, F3, K3, M(58) );
R( b, c, d, e, a, F3, K3, M(59) );
R( a, b, c, d, e, F4, K4, M(60) );
R( e, a, b, c, d, F4, K4, M(61) );
R( d, e, a, b, c, F4, K4, M(62) );
R( c, d, e, a, b, F4, K4, M(63) );
R( b, c, d, e, a, F4, K4, M(64) );
R( a, b, c, d, e, F4, K4, M(65) );
R( e, a, b, c, d, F4, K4, M(66) );
R( d, e, a, b, c, F4, K4, M(67) );
R( c, d, e, a, b, F4, K4, M(68) );
R( b, c, d, e, a, F4, K4, M(69) );
R( a, b, c, d, e, F4, K4, M(70) );
R( e, a, b, c, d, F4, K4, M(71) );
R( d, e, a, b, c, F4, K4, M(72) );
R( c, d, e, a, b, F4, K4, M(73) );
R( b, c, d, e, a, F4, K4, M(74) );
R( a, b, c, d, e, F4, K4, M(75) );
R( e, a, b, c, d, F4, K4, M(76) );
R( d, e, a, b, c, F4, K4, M(77) );
R( c, d, e, a, b, F4, K4, M(78) );
R( b, c, d, e, a, F4, K4, M(79) );
/* Update chaining vars */
hd->h0 += a;
hd->h1 += b;
hd->h2 += c;
hd->h3 += d;
hd->h4 += e;
}
/* Update the message digest with the contents
* of INBUF with length INLEN.
*/
static void
sha1_write( SHA1_CONTEXT *hd, unsigned char *inbuf, size_t inlen)
{
if( hd->count == 64 ) { /* flush the buffer */
transform( hd, hd->buf );
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count ) {
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
sha1_write( hd, NULL, 0 );
if( !inlen )
return;
}
while( inlen >= 64 ) {
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/* The routine final terminates the computation and
* returns the digest.
* The handle is prepared for a new cycle, but adding bytes to the
* handle will the destroy the returned buffer.
* Returns: 20 bytes representing the digest.
*/
static void
sha1_final(SHA1_CONTEXT *hd)
{
u32 t, msb, lsb;
unsigned char *p;
sha1_write(hd, NULL, 0); /* flush */;
t = hd->nblocks;
/* multiply by 64 to make a byte count */
lsb = t << 6;
msb = t >> 26;
/* add the count */
t = lsb;
if( (lsb += hd->count) < t )
msb++;
/* multiply by 8 to make a bit count */
t = lsb;
lsb <<= 3;
msb <<= 3;
msb |= t >> 29;
if( hd->count < 56 ) { /* enough room */
hd->buf[hd->count++] = 0x80; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else { /* need one extra block */
hd->buf[hd->count++] = 0x80; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
sha1_write(hd, NULL, 0); /* flush */;
memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = msb >> 24;
hd->buf[57] = msb >> 16;
hd->buf[58] = msb >> 8;
hd->buf[59] = msb ;
hd->buf[60] = lsb >> 24;
hd->buf[61] = lsb >> 16;
hd->buf[62] = lsb >> 8;
hd->buf[63] = lsb ;
transform( hd, hd->buf );
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
#else /* little endian */
#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \
*p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
#endif
X(0);
X(1);
X(2);
X(3);
X(4);
#undef X
}
int rito_cksum (char *pFilePath, char *pResult)
{
FILE *fp;
char buffer[4096];
size_t n;
size_t file_size = 0;
size_t jump = 0;
SHA1_CONTEXT ctx;
int i;
fp = fopen(pFilePath, "rb");
if (!fp) {
fprintf(stderr, "can't open `%s': %s\n", pFilePath, strerror(errno));
return -1;
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
jump = file_size / (4 * 1024 * 1024) * sizeof(buffer);
fseek(fp, 0, SEEK_SET);
sha1_init(&ctx);
while ((n = fread(buffer, 1, sizeof buffer, fp))) {
sha1_write(&ctx, reinterpret_cast<unsigned char *>(buffer), n);
fseek(fp, jump, SEEK_CUR);
}
if (ferror(fp)) {
fprintf(stderr, "error reading `%s': %s\n", pFilePath, strerror(errno));
fclose(fp);
return -2;
}
sha1_final(&ctx);
fclose(fp);
if (pResult) {
for (i = 0; i < 20; i++)
sprintf(pResult + strlen(pResult), "%02x", ctx.buf[i]);
}
return 0;
}
/*
Local Variables:
compile-command: "cc -Wall -g -o sha1sum sha1sum.c"
End:
*/

View File

@ -0,0 +1,10 @@
//
// Created by 서인석 on 2020-10-22.
//
#ifndef OSICMANAGER_SHA1SUM_H
#define OSICMANAGER_SHA1SUM_H
int rito_cksum (char *pFilePath, char *pResult);
#endif //OSICMANAGER_SHA1SUM_H

View File

@ -0,0 +1,325 @@
/* asoundlib.h
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#ifndef ASOUNDLIB_H
#define ASOUNDLIB_H
#include <sys/time.h>
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
/*
* PCM API
*/
struct pcm;
#define PCM_OUT 0x00000000
#define PCM_IN 0x10000000
#define PCM_MMAP 0x00000001
#define PCM_NOIRQ 0x00000002
#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to
* pcm_write for a playback stream will not
* attempt to restart the stream in the case
* of an underflow, but will return -EPIPE
* instead. After the first -EPIPE error, the
* stream is considered to be stopped, and a
* second call to pcm_write will attempt to
* restart the stream.
*/
#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */
/* PCM runtime states */
#define PCM_STATE_OPEN 0
#define PCM_STATE_SETUP 1
#define PCM_STATE_PREPARED 2
#define PCM_STATE_RUNNING 3
#define PCM_STATE_XRUN 4
#define PCM_STATE_DRAINING 5
#define PCM_STATE_PAUSED 6
#define PCM_STATE_SUSPENDED 7
#define PCM_STATE_DISCONNECTED 8
/* TLV header size*/
#define TLV_HEADER_SIZE (2 * sizeof(unsigned int))
/* Bit formats */
enum pcm_format {
PCM_FORMAT_INVALID = -1,
PCM_FORMAT_S16_LE = 0, /* 16-bit signed */
PCM_FORMAT_S32_LE, /* 32-bit signed */
PCM_FORMAT_S8, /* 8-bit signed */
PCM_FORMAT_S24_LE, /* 24-bits in 4-bytes */
PCM_FORMAT_S24_3LE, /* 24-bits in 3-bytes */
PCM_FORMAT_MAX,
};
/* Bitmask has 256 bits (32 bytes) in asound.h */
struct pcm_mask {
unsigned int bits[32 / sizeof(unsigned int)];
};
/* Configuration for a stream */
struct pcm_config {
unsigned int channels;
unsigned int rate;
unsigned int period_size;
unsigned int period_count;
enum pcm_format format;
/* Values to use for the ALSA start, stop and silence thresholds, and
* silence size. Setting any one of these values to 0 will cause the
* default tinyalsa values to be used instead.
* Tinyalsa defaults are as follows.
*
* start_threshold : period_count * period_size
* stop_threshold : period_count * period_size
* silence_threshold : 0
* silence_size : 0
*/
unsigned int start_threshold;
unsigned int stop_threshold;
unsigned int silence_threshold;
unsigned int silence_size;
/* Minimum number of frames available before pcm_mmap_write() will actually
* write into the kernel buffer. Only used if the stream is opened in mmap mode
* (pcm_open() called with PCM_MMAP flag set). Use 0 for default.
*/
int avail_min;
int flag;
};
/* PCM parameters */
enum pcm_param
{
/* mask parameters */
PCM_PARAM_ACCESS,
PCM_PARAM_FORMAT,
PCM_PARAM_SUBFORMAT,
/* interval parameters */
PCM_PARAM_SAMPLE_BITS,
PCM_PARAM_FRAME_BITS,
PCM_PARAM_CHANNELS,
PCM_PARAM_RATE,
PCM_PARAM_PERIOD_TIME,
PCM_PARAM_PERIOD_SIZE,
PCM_PARAM_PERIOD_BYTES,
PCM_PARAM_PERIODS,
PCM_PARAM_BUFFER_TIME,
PCM_PARAM_BUFFER_SIZE,
PCM_PARAM_BUFFER_BYTES,
PCM_PARAM_TICK_TIME,
};
/* Mixer control types */
enum mixer_ctl_type {
MIXER_CTL_TYPE_BOOL,
MIXER_CTL_TYPE_INT,
MIXER_CTL_TYPE_ENUM,
MIXER_CTL_TYPE_BYTE,
MIXER_CTL_TYPE_IEC958,
MIXER_CTL_TYPE_INT64,
MIXER_CTL_TYPE_UNKNOWN,
MIXER_CTL_TYPE_MAX,
};
/* Open and close a stream */
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config);
int pcm_close(struct pcm *pcm);
int pcm_is_ready(struct pcm *pcm);
/* Obtain the parameters for a PCM */
struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
unsigned int flags);
void pcm_params_free(struct pcm_params *pcm_params);
struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
enum pcm_param param);
unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
enum pcm_param param);
void pcm_params_set_min(struct pcm_params *pcm_params,
enum pcm_param param, unsigned int val);
unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
enum pcm_param param);
void pcm_params_set_max(struct pcm_params *pcm_params,
enum pcm_param param, unsigned int val);
/* Converts the pcm parameters to a human readable string.
* The string parameter is a caller allocated buffer of size bytes,
* which is then filled up to size - 1 and null terminated,
* if size is greater than zero.
* The return value is the number of bytes copied to string
* (not including null termination) if less than size; otherwise,
* the number of bytes required for the buffer.
*/
int pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size);
/* Returns 1 if the pcm_format is present (format bit set) in
* the pcm_params structure; 0 otherwise, or upon unrecognized format.
*/
int pcm_params_format_test(struct pcm_params *params, enum pcm_format format);
/* Set and get config */
int pcm_get_config(struct pcm *pcm, struct pcm_config *config);
int pcm_set_config(struct pcm *pcm, struct pcm_config *config);
/* Returns a human readable reason for the last error */
const char *pcm_get_error(struct pcm *pcm);
/* Returns the sample size in bits for a PCM format.
* As with ALSA formats, this is the storage size for the format, whereas the
* format represents the number of significant bits. For example,
* PCM_FORMAT_S24_LE uses 32 bits of storage.
*/
unsigned int pcm_format_to_bits(enum pcm_format format);
/* Returns the buffer size (int frames) that should be used for pcm_write. */
unsigned int pcm_get_buffer_size(struct pcm *pcm);
unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames);
unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes);
/* Returns the pcm latency in ms */
unsigned int pcm_get_latency(struct pcm *pcm);
/* Returns available frames in pcm buffer and corresponding time stamp.
* The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open,
* otherwise the clock is CLOCK_REALTIME.
* For an input stream, frames available are frames ready for the
* application to read.
* For an output stream, frames available are the number of empty frames available
* for the application to write.
*/
int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
struct timespec *tstamp);
/* Returns the subdevice on which the pcm has been opened */
unsigned int pcm_get_subdevice(struct pcm *pcm);
/* Write data to the fifo.
* Will start playback on the first write or on a write that
* occurs after a fifo underrun.
*/
int pcm_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_read(struct pcm *pcm, void *data, unsigned int count);
/*
* mmap() support.
*/
int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count);
int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
unsigned int *frames);
int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
int pcm_mmap_avail(struct pcm *pcm);
/* Returns current read/write position in the mmap buffer with associated time stamp.
*/
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
/* Prepare the PCM substream to be triggerable */
int pcm_prepare(struct pcm *pcm);
/* Start and stop a PCM channel that doesn't transfer data */
int pcm_start(struct pcm *pcm);
int pcm_stop(struct pcm *pcm);
/* ioctl function for PCM driver */
int pcm_ioctl(struct pcm *pcm, int request, ...);
/* Interrupt driven API */
int pcm_wait(struct pcm *pcm, int timeout);
int pcm_get_poll_fd(struct pcm *pcm);
/* Change avail_min after the stream has been opened with no need to stop the stream.
* Only accepted if opened with PCM_MMAP and PCM_NOIRQ flags
*/
int pcm_set_avail_min(struct pcm *pcm, int avail_min);
/*
* MIXER API
*/
struct mixer;
struct mixer_ctl;
/* Open and close a mixer */
struct mixer *mixer_open(unsigned int card);
void mixer_close(struct mixer *mixer);
/* Get info about a mixer */
const char *mixer_get_name(struct mixer *mixer);
/* Obtain mixer controls */
unsigned int mixer_get_num_ctls(struct mixer *mixer);
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
/* Get info about mixer controls */
const char *mixer_ctl_get_name(struct mixer_ctl *ctl);
enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl);
const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl);
unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl);
unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl);
const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
unsigned int enum_id);
/* Some sound cards update their controls due to external events,
* such as HDMI EDID byte data changing when an HDMI cable is
* connected. This API allows the count of elements to be updated.
*/
void mixer_ctl_update(struct mixer_ctl *ctl);
/* Set and get mixer controls */
int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id);
int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
int mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl);
int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count);
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count);
int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string);
/* Determine range of integer mixer controls */
int mixer_ctl_get_range_min(struct mixer_ctl *ctl);
int mixer_ctl_get_range_max(struct mixer_ctl *ctl);
int mixer_subscribe_events(struct mixer *mixer, int subscribe);
int mixer_wait_event(struct mixer *mixer, int timeout);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

View File

@ -0,0 +1,220 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class FileDownloader extends Thread {
private static String TAG = "FileDownloader";
int DOWNLOAD_STATUS_PROCESS = 0;
int DOWNLOAD_STATUS_SUCCESS = 1;
int DOWNLOAD_STATUS_FAILED = 2;
private int mDownloadStatus = DOWNLOAD_STATUS_PROCESS;
private String mJsonUrlPath;
private LinkedBlockingQueue<DownInfo> mDownList;
private Context mContext;
private boolean mIsAlive = false;
public class DownInfo {
public String mUrl;
public String mSaveDir;
public String mSaveName;
int mTryCount;
}
private class CallbackToDownloadFile implements Callback {
private File directory;
private File fileToBeDownloaded;
public CallbackToDownloadFile(String directory, String fileName) {
this.directory = new File(directory);
this.fileToBeDownloaded = new File(this.directory.getAbsolutePath() + "/" + fileName);
}
@Override
public void onFailure(Call call, IOException e) {
mDownloadStatus = DOWNLOAD_STATUS_FAILED;
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!this.directory.exists()) {
this.directory.mkdirs();
}
if (this.fileToBeDownloaded.exists()) {
this.fileToBeDownloaded.delete();
}
try {
this.fileToBeDownloaded.createNewFile();
} catch (IOException e) {
e.printStackTrace();
mDownloadStatus = DOWNLOAD_STATUS_FAILED;
return;
}
InputStream is = response.body().byteStream();
OutputStream os = new FileOutputStream(this.fileToBeDownloaded);
final int BUFFER_SIZE = 2048;
byte[] data = new byte[BUFFER_SIZE];
int count;
long total = 0;
while ((count = is.read(data)) != -1) {
total += count;
os.write(data, 0, count);
}
os.flush();
os.close();
is.close();
mDownloadStatus = DOWNLOAD_STATUS_SUCCESS;
}
}
public FileDownloader(Context context) {
mContext = context;
mDownList = new LinkedBlockingQueue<DownInfo>(10000);
}
public void addDownloadTarget(String url, String directory, String filename) {
DownInfo info = new DownInfo();
info.mUrl = url;
info.mSaveDir = directory;
info.mSaveName = filename;
info.mTryCount = 0;
mDownList.offer(info);
}
@Override
public void run() {
mIsAlive = true;
while (mIsAlive) {
if (mDownList.size() > 0) {
boolean trouble = false;
DownInfo info = mDownList.poll();
try {
File destDirectory = new File(info.mSaveDir);
if (!destDirectory.exists()) {
destDirectory.mkdir();
}
} catch(Exception e) {
trouble = true;
}
if(trouble)
continue;
boolean allowUntrusted = true;
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder clientBuilder = client.newBuilder().readTimeout(10, TimeUnit.SECONDS);
if (allowUntrusted) {
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}
@Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
@Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
}};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
clientBuilder.sslSocketFactory(sslContext.getSocketFactory());
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
Log.d(TAG, "Trust Host :" + hostname);
return true;
}
};
clientBuilder.hostnameVerifier(hostnameVerifier);
} catch (Exception e) {
e.printStackTrace();
}
}
OkHttpClient httpClient = clientBuilder.build();
FileDownloader.CallbackToDownloadFile cb = new FileDownloader.CallbackToDownloadFile(info.mSaveDir, info.mSaveName);
Request request = new Request.Builder()
.url(info.mUrl)
.build();
httpClient.newCall(request).enqueue(cb);
while (mDownloadStatus == DOWNLOAD_STATUS_PROCESS) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (mDownloadStatus == DOWNLOAD_STATUS_FAILED) {
info.mTryCount++;
if (info.mTryCount < 10) {
mDownList.offer(info);
}
}
MainActivity.INSTANCE.doSync();
}
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,386 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
class JsonManager extends Thread {
private static String TAG = "JsonManager";
int DOWNLOAD_STATUS_PROCESS = 0;
int DOWNLOAD_STATUS_SUCCESS = 1;
int DOWNLOAD_STATUS_FAILED = 2;
private int mDownloadStatus = DOWNLOAD_STATUS_PROCESS;
private String mJsonUrlPath;
private Context mContext;
private class CallbackToDownloadFile implements Callback {
private File directory;
private File fileToBeDownloaded;
public CallbackToDownloadFile(String directory, String fileName) {
this.directory = new File(directory);
this.fileToBeDownloaded = new File(this.directory.getAbsolutePath() + "/" + fileName);
}
@Override
public void onFailure(Call call, IOException e) {
mDownloadStatus = DOWNLOAD_STATUS_FAILED;
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!this.directory.exists()) {
this.directory.mkdirs();
}
if (this.fileToBeDownloaded.exists()) {
this.fileToBeDownloaded.delete();
}
try {
this.fileToBeDownloaded.createNewFile();
} catch (IOException e) {
e.printStackTrace();
mDownloadStatus = DOWNLOAD_STATUS_FAILED;
return;
}
InputStream is = response.body().byteStream();
OutputStream os = new FileOutputStream(this.fileToBeDownloaded);
final int BUFFER_SIZE = 2048;
byte[] data = new byte[BUFFER_SIZE];
int count;
long total = 0;
while ((count = is.read(data)) != -1) {
total += count;
os.write(data, 0, count);
}
os.flush();
os.close();
is.close();
mDownloadStatus = DOWNLOAD_STATUS_SUCCESS;
}
}
public JsonManager(Context context) {
mContext = context;
}
public void setDownloadPath(String jsonUrl) {
mJsonUrlPath = jsonUrl;
}
@Override
public void run() {
if(mJsonUrlPath == null)
return;
boolean allowUntrusted = true;
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder clientBuilder = client.newBuilder().readTimeout(10, TimeUnit.SECONDS);
if(allowUntrusted) {
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}
@Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
@Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType) throws CertificateException {
}
}};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
clientBuilder.sslSocketFactory(sslContext.getSocketFactory());
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
Log.d(TAG, "Trust Host :" + hostname);
return true;
}
};
clientBuilder.hostnameVerifier( hostnameVerifier);
} catch(Exception e) {
e.printStackTrace();
}
}
Request request;
OkHttpClient httpClient;
CallbackToDownloadFile cb;
int retry_count = 0;
do {
mDownloadStatus = DOWNLOAD_STATUS_PROCESS;
httpClient = clientBuilder.build();
cb = new CallbackToDownloadFile("/tmp", "schedule.json");
request = new Request.Builder()
.url(mJsonUrlPath)
.build();
httpClient.newCall(request).enqueue(cb);
while (mDownloadStatus == DOWNLOAD_STATUS_PROCESS) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (mDownloadStatus == DOWNLOAD_STATUS_FAILED) {
retry_count++;
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} while(retry_count < 10 && mDownloadStatus == DOWNLOAD_STATUS_FAILED);
if (mDownloadStatus == DOWNLOAD_STATUS_FAILED) {
Log.w(TAG, "Failed to download JSON [" + mJsonUrlPath + "]");
return;
} else if (mDownloadStatus == DOWNLOAD_STATUS_SUCCESS) {
Log.i(TAG, "Success to download JSON [" + mJsonUrlPath + "] at retry count : " + retry_count);
}
File sourceFile = new File("/tmp/schedule.json");
String destPath = MainActivity.INSTANCE.mSDSavePath;
try {
File destDirectory = new File(destPath);
if (!destDirectory.exists()) {
destDirectory.mkdir();
}
} catch(Exception e) {
MainActivity.INSTANCE.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.INSTANCE, "MicroSD 동작에 문제가 있습니다.", Toast.LENGTH_LONG).show();
}
});
mDownloadStatus = DOWNLOAD_STATUS_FAILED;
return;
}
SystemUtil.TraceLog("JsonManager Trace Before [File destFile = new File]");
File destFile = new File(destPath + "/schedule.json");
SystemUtil.copyFile(sourceFile, destFile);
MainActivity.INSTANCE.doSync();
SystemUtil.TraceLog("JsonManager Trace Before [File checkFile = new File]");
File checkFile = new File(destPath + "/schedule.json.check");
if(checkFile.exists()) {
checkFile.delete();
MainActivity.INSTANCE.doSync();
}
JsonResult jsonResult = loadJsonData();
if(jsonResult == null) {
Log.w(TAG, "Failed to download JSON!!!!. jsonResult is null");
return;
}
if(jsonResult.mType.equalsIgnoreCase(MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_CONTENTS)) { // Download Contents Files
for(int i = 0; i < jsonResult.mFileCount;i++) {
mDownloadStatus = DOWNLOAD_STATUS_PROCESS;
String cksum = MainActivity.INSTANCE.getFileCksum(MainActivity.INSTANCE.mSDSavePath + "/" + jsonResult.mFilePathList[i]);
if(cksum.equalsIgnoreCase(jsonResult.mFileCksumList[i])) {
Log.d(TAG, "Already downloaded file : " + jsonResult.mFilePathList[i]);
continue;
}
for(int retry = 0;retry < 3;retry++) {
cb = new CallbackToDownloadFile(MainActivity.INSTANCE.mSDSavePath, jsonResult.mFilePathList[i]);
request = new Request.Builder()
.url(jsonResult.mFileUrlList[i])
.build();
Log.d(TAG, "Start Download File : " + jsonResult.mFileUrlList[i]);
httpClient.newCall(request).enqueue(cb);
while (mDownloadStatus == DOWNLOAD_STATUS_PROCESS) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
MainActivity.INSTANCE.doSync();
cksum = MainActivity.INSTANCE.getFileCksum(MainActivity.INSTANCE.mSDSavePath + "/" + jsonResult.mFilePathList[i]);
if (cksum.equalsIgnoreCase(jsonResult.mFileCksumList[i])) {
Log.d(TAG, "다운로드 파일 정상 [" + jsonResult.mFilePathList[i] + "]");
break;
} else {
Log.d(TAG, "다운로드 파일 체크섬 불일치 [" + jsonResult.mFilePathList[i] + "]. 재시도 횟수 : " + (retry + 1));
}
}
}
Log.d(TAG, "Contents Download Complete...");
checkFile = new File(destPath + "/schedule.json.check");
if(!checkFile.exists()) {
try {
checkFile.createNewFile();
MainActivity.INSTANCE.doSync();
} catch(Exception e) {
}
}
File backupFile = new File(destPath + "/file-schedule.json");
SystemUtil.copyFile(sourceFile, backupFile);
MainActivity.INSTANCE.doSync();
Log.d(TAG, "Do updateJsonTargetResult as File-Schedule...");
MainActivity.INSTANCE.mJsonScheduler.updateJsonTargetResult("file", jsonResult);
}
MainActivity.INSTANCE.mJsonScheduler.updateJsonResult(jsonResult);
MainActivity.INSTANCE.mJsonScheduler.prepareJsonSchedule();
}
public JsonResult loadJsonData() {
return loadJsonData("schedule.json");
}
public static JsonResult loadJsonData(String jsonFileName) {
String destPath = MainActivity.INSTANCE.mSDSavePath;
File destFile = new File(destPath + "/" + jsonFileName);
try {
FileInputStream stream = new FileInputStream(destFile);
String jString = null;
try {
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
jString = Charset.defaultCharset().decode(bb).toString();
} finally {
stream.close();
}
return parseJson(jString);
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
static JsonResult parseJson(String jsonData) {
JsonResult res = new JsonResult();
try {
JSONObject topObject = new JSONObject(jsonData);
String jsonType = topObject.getString("type");
if(jsonType.equalsIgnoreCase(MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_IPCAST)) {
res.mType = MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_IPCAST;
JSONArray jsonArray = topObject.getJSONArray("data");
res.mIpCount = jsonArray.length();
res.mIpAddressList = new String[res.mIpCount];
res.mIpTitleList = new String[res.mIpCount];
res.mIpNumberList = new String[res.mIpCount];
res.mIpSelectedIndex = 0;
for (int i = 0; i < res.mIpCount; i++) {
JSONObject jo = jsonArray.getJSONObject(i);
res.mIpAddressList[i] = jo.getString("address");
if(res.mIpAddressList[i].startsWith("live://")) {
res.mIpAddressList[i] = res.mIpAddressList[i].replace("live://", "udp://");
if(!res.mIpAddressList[i].contains("@")) {
res.mIpAddressList[i] = res.mIpAddressList[i].replace("udp://", "udp://@");
}
}
res.mIpTitleList[i] = jo.getString("title");
res.mIpNumberList[i] = jo.getString("ch_no");
if(jo.getBoolean("selected"))
res.mIpSelectedIndex = i;
}
} else if(jsonType.equalsIgnoreCase(MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_CARCAST)) {
res.mType = MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_CARCAST;
JSONArray carList = topObject.getJSONArray("data");
JSONObject carData = carList.getJSONObject(0);
res.mCarAddress = carData.getString("url");
res.mCarCar = carData.getString("car");
res.mCarStation = carData.getString("station");
} else if(jsonType.equalsIgnoreCase(MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_CONTENTS)) {
res.mType = MainActivity.MANAGER_JSON_ORDER_TYPE_PLAY_CONTENTS;
JSONArray jsonArray = topObject.getJSONArray("data");
res.mFileCount = jsonArray.length();
res.mFileUrlList = new String[res.mFileCount];
res.mFilePathList = new String[res.mFileCount];
res.mFileTitleList = new String[res.mFileCount];
res.mFileDurationList = new int[res.mFileCount];
res.mFileCksumList = new String[res.mFileCount];
for (int i = 0; i < res.mFileCount; i++) {
JSONObject jo = jsonArray.getJSONObject(i);
res.mFileUrlList[i] = jo.getString("url");
res.mFilePathList[i] = res.mFileUrlList[i].substring(res.mFileUrlList[i].lastIndexOf('/') + 1);
res.mFileTitleList[i] = jo.getString("name");
res.mFileDurationList[i] = jo.getInt("duration");
res.mFileCksumList[i] = jo.getString("cksum");
}
}
} catch(Exception e) {
e.printStackTrace();
return null;
}
return res;
}
}

View File

@ -0,0 +1,25 @@
package kr.co.rito.osicmanager;
public class JsonResult {
public String mType;
// For IpCast
public int mIpCount;
public int mIpSelectedIndex;
public String[] mIpAddressList;
public String[] mIpTitleList;
public String[] mIpNumberList;
// For CarCast
public String mCarAddress;
public String mCarStation;
public String mCarCar;
// For FileCast
public int mFileCount;
public String[] mFileUrlList;
public String[] mFileTitleList;
public int[] mFileDurationList;
public String[] mFilePathList;
public String[] mFileCksumList;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import android.graphics.AvoidXfermode;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.webkit.WebView;
public class RWebView extends WebView {
public RWebView(Context context) {
super(context);
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
public RWebView(Context context, AttributeSet attrs) {
super(context, attrs);
Paint p = new Paint();
p.setARGB(255, 255, 0, 255);
int removeColor = p.getColor();
p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
setLayerType(LAYER_TYPE_SOFTWARE, p);
}
public RWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Paint p = new Paint();
p.setARGB(255, 255, 0, 255);
int removeColor = p.getColor();
p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
setLayerType(LAYER_TYPE_SOFTWARE, p);
}
public RWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
Paint p = new Paint();
p.setARGB(255, 255, 0, 255);
int removeColor = p.getColor();
p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
setLayerType(LAYER_TYPE_SOFTWARE, p);
}
@Override
protected void onDraw(android.graphics.Canvas canvas) {
Paint p = new Paint();
p.setARGB(255, 255, 0, 255);
int removeColor = p.getColor();
p.setAlpha(1); // if Alpha is 0 it doesn't work. I don't know why
p.setXfermode(new AvoidXfermode(removeColor, 0, AvoidXfermode.Mode.TARGET));
canvas.drawPaint(p);
super.onDraw(canvas);
}
}

View File

@ -0,0 +1,167 @@
package kr.co.rito.osicmanager;
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import kr.co.rito.osicmanager.ui.main.PlaceholderFragment;
import kr.co.rito.osicmanager.ui.main.SectionsPagerAdapter;
public class SettingActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener {
static int test = 0;
Instrumentation mInstrument;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_setting);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
// SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
// ViewPager viewPager = findViewById(R.id.view_pager);
// viewPager.setAdapter(sectionsPagerAdapter);
// TabLayout tabs = findViewById(R.id.tabs);
// tabs.setupWithViewPager(viewPager);
// tabs.addOnTabSelectedListener(this);
// FloatingActionButton fab = findViewById(R.id.fab);
//
// mInstrument = new Instrumentation();
//
// fab.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
// .setAction("Action", null).show();
// }
// });
}
@Override
public void onStart() {
super.onStart();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
tabs.addOnTabSelectedListener(this);
FloatingActionButton fab = findViewById(R.id.fab);
mInstrument = new Instrumentation();
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
String tabName = tab.getText().toString();
Log.w("RITO", "TabSelected : " + tabName);
tab.view.requestFocus();
/*ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setCurrentItem(tab.getPosition());*/
/*TextView view = findViewById(R.id.textViewVersionValue);
view.setText("" + test);
test++;*/
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
String tabName = tab.getText().toString();
if(tabName.equals("네트워크 설정")) {
} else if(tabName.equals("서버 설정")) {
} else if(tabName.equals("기기 정보")) {
}
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
private void makeKeyEvent(final int keycode) {
new Thread(new Runnable() {
@Override
public void run() {
try {
mInstrument.sendKeyDownUpSync(keycode);
} catch(Exception e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(event.getKeyCode() == 183) { // SETUP KEY
// ViewPager viewPager = findViewById(R.id.view_pager);
// SectionsPagerAdapter sectionsPagerAdapter = (SectionsPagerAdapter)viewPager.getAdapter();
// PlaceholderFragment fragment = (PlaceholderFragment)sectionsPagerAdapter.getItem(1);
// fragment.saveSettings();
// sectionsPagerAdapter.getItem(1).onStop();
// Intent intent = new Intent(this, MainActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// startActivity(intent);
//SystemUtil.shellCommand("ritosysc SHELL-ORDER=killall kr.co.rito.osicmanager");
SystemUtil.shellCommand("ritosysc SHELL-ORDER=am force-stop kr.co.rito.osicmanager");
/*finish();*/
return true;
} else if(event.getKeyCode() == 200) { // VFD LEFT
makeKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
return true;
} else if(event.getKeyCode() == 201) { // VFD RIGHT
makeKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
return true;
} else if(event.getKeyCode() == 202) { // VFD UP
makeKeyEvent(KeyEvent.KEYCODE_DPAD_UP);
return true;
} else if(event.getKeyCode() == 203) { // VFD DOWN
makeKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN);
return true;
} else if(event.getKeyCode() == 199) { // VFD OKAY
makeKeyEvent(KeyEvent.KEYCODE_ENTER);
return true;
}
return false;
}
}

View File

@ -0,0 +1,369 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.StringTokenizer;
public class SystemUtil {
public final static String TAG = "OsicUtil";
public static String APP_MODE = "passive";
public static void shellCommand(String order) {
try {
Process process = Runtime.getRuntime().exec(order);
process.waitFor();
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void logStart() {
String filePath = Environment.getExternalStorageDirectory() + "/logcat.txt";
try {
File logFile = new File(filePath);
if (logFile.exists()) {
Log.d(TAG, "logStart starTime=" + System.currentTimeMillis() + " fileLength=" + logFile.length());
}
if (logFile.exists() && logFile.length() > 100 * 1024 * 1024) {
logFile.delete();
}
Runtime.getRuntime().exec(new String[]{"logcat", "-c"});
Runtime.getRuntime().exec(new String[]{"logcat", "-f", filePath});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void shellCommand(String[] order) {
try {
Process process = Runtime.getRuntime().exec(order);
process.waitFor();
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void property_set(String key, String val) throws IllegalArgumentException {
try {
Class<?> SystemProperties = Class.forName("android.os.SystemProperties");
//Parameters Types
@SuppressWarnings("rawtypes")
Class[] paramTypes = { String.class, String.class };
Method set = SystemProperties.getMethod("set", paramTypes);
//Parameters
Object[] params = { key, val };
set.invoke(SystemProperties, params); }
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static String property_get(String key) {
String ret = "";
try {
Class<?> SystemProperties = Class.forName("android.os.SystemProperties");
//Parameters Types
@SuppressWarnings("rawtypes")
Class[] paramTypes = { String.class };
Method get = SystemProperties.getMethod("get", paramTypes);
//Parameters
Object[] params = { key };
ret = (String) get.invoke(SystemProperties, params);
}
catch (IllegalArgumentException e)
{
ret = "";
e.printStackTrace();
Log.e(TAG, "IllegalArgumentException e: "+ e.toString());
}
catch (Exception e)
{
ret = "";
e.printStackTrace();
Log.e(TAG, "Exception e: "+ e.toString());
}
return ret;
}
public static String getVersionInfo(Context context) {
String version = "Unknown";
PackageInfo packageInfo;
if (context == null) {
return version;
}
try {
packageInfo = context.getApplicationContext()
.getPackageManager()
.getPackageInfo(context.getApplicationContext().getPackageName(), 0 );
version = packageInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "getVersionInfo :" + e.getMessage());
}
return version;
}
public static void copyFile(File sourceFile, File destFile) {
if (!destFile.getParentFile().exists())
destFile.getParentFile().mkdirs();
if (!destFile.exists()) {
try {
destFile.createNewFile();
} catch(Exception e) {
e.printStackTrace();
return;
}
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} catch(Exception e) {
e.printStackTrace();
}
if (source != null) {
try {
source.close();
} catch (Exception e) {
}
}
if (destination != null) {
try {
destination.close();
} catch (Exception e) {
}
}
}
public static final String TRACE_LOG_LEVEL_1 = "1";
public static final String TRACE_LOG_LEVEL_2 = "2";
public static final String TRACE_LOG_LEVEL_3 = "3";
public static final String TRACE_LOG_LEVEL_4 = "4";
public static final String TRACE_LOG_LEVEL_5 = "5";
public static void TraceLineLog(String message) {
StackTraceElement element = Thread.currentThread().getStackTrace()[3]; // 호출한 메서드의 스택 정보
String fullMessage = String.format("%s (%s:%d)", message, element.getFileName(), element.getLineNumber());
Log.d(TAG, fullMessage);
}
public static void TraceLog(String log) {
TraceLog(TRACE_LOG_LEVEL_1, log);
}
public static void TraceLog(String level, String log) {
String traceMode = property_get("sys.rito.trace");
if(traceMode.equals(level)) {
Log.d("OsicTrace", log);
}
}
public static class StorageInfo {
public final String path;
public final boolean readonly;
public final boolean removable;
public final boolean usb;
public final boolean mmc;
public final int number;
StorageInfo(String path, boolean readonly, boolean removable, int number, boolean usb, boolean mmc) {
this.path = path;
this.readonly = readonly;
this.removable = removable;
this.number = number;
this.usb = usb;
this.mmc = mmc;
}
public String getDisplayName() {
StringBuilder res = new StringBuilder();
if (!removable) {
res.append("Internal SD card");
} else if (number > 1) {
res.append("SD card " + number);
} else {
if(usb) {
res.append("USB disk");
} else {
res.append("SD card");
}
}
if (readonly) {
res.append(" (Read only)");
}
return res.toString();
}
}
public static String getSDCardPath() {
List<StorageInfo> list = getStorageList();
for(StorageInfo info : list) {
if(info.mmc)
return info.path;
}
return null;
}
public static void adjustDataVolume(byte[] data, int length, int volume) {
if(volume < 100) {
for(int j = 0;j < length && j < data.length - 1;j += 2) {
short vols = (short)((int)((data[j + 1] << 8) & 0x00FF00) + (int)(data[j] & 0x00FF));
double volf = vols;
volf *= (double)volume;
volf /= (double)100;
vols = (short)volf;
data[j + 1] = (byte)(((vols & 0x00FF00) >> 8) & 0x00FF);
data[j] = (byte)((vols & 0x00FF));
}
}
}
public static List<StorageInfo> getStorageList() {
List<StorageInfo> list = new ArrayList<StorageInfo>();
String def_path = Environment.getExternalStorageDirectory().getPath();
boolean def_path_removable = Environment.isExternalStorageRemovable();
String def_path_state = Environment.getExternalStorageState();
boolean def_path_available = def_path_state.equals(Environment.MEDIA_MOUNTED)
|| def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
boolean def_path_readonly = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
HashSet<String> paths = new HashSet<String>();
int cur_removable_number = 1;
if (def_path_available) {
paths.add(def_path);
list.add(0, new StorageInfo(def_path, def_path_readonly, def_path_removable, def_path_removable ? cur_removable_number++ : -1, false, false));
}
BufferedReader buf_reader = null;
try {
buf_reader = new BufferedReader(new FileReader("/proc/mounts"));
String line;
Log.d(TAG, "/proc/mounts");
while ((line = buf_reader.readLine()) != null) {
Log.d(TAG, line);
if (line.contains("vfat") || line.contains("/mnt")) {
StringTokenizer tokens = new StringTokenizer(line, " ");
String mount_device = tokens.nextToken(); //device
String mount_point = tokens.nextToken(); //mount point
if (paths.contains(mount_point)) {
continue;
}
String unused = tokens.nextToken(); //file system
List<String> flags = Arrays.asList(tokens.nextToken().split(",")); //flags
boolean readonly = flags.contains("ro");
if (line.contains("/dev/block/vold")) {
if (!line.contains("/mnt/secure")
&& !line.contains("/mnt/asec")
&& !line.contains("/mnt/obb")
&& !line.contains("/dev/mapper")
&& !line.contains("tmpfs")) {
boolean usb = false;
boolean mmc = false;
paths.add(mount_point);
if(mount_device.contains("/dev/block/vold/public:8"))
usb = true;
if(mount_device.contains("/dev/block/vold/public:179"))
mmc = true;
list.add(new StorageInfo(mount_point, readonly, true, cur_removable_number++, usb, mmc));
}
}
}
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (buf_reader != null) {
try {
buf_reader.close();
} catch (IOException ex) {}
}
}
return list;
}
public static boolean saveByteArrayToFile(String filePath, byte[] data, int length) {
if (filePath == null || data == null) {
return false;
}
FileOutputStream fos = null;
try {
File file = new File(filePath);
fos = new FileOutputStream(file, true);
fos.write(data, 0, length);
fos.flush();
//return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
public native static String getIPAddress();
public native static String getConfigValue(String target);
public native static void setConfigValue(String target, String value);
public static int GPIO_IN = 0;
public static int GPIO_OUT = 1;
public static int GPIO_LOW = 0;
public static int GPIO_HIGH = 1;
public native static int getPinValue(int pinNo);
public native static int setPinValue(int pinNo, int value);
public native static int pinSetup(int pinNo, int pinDirection);
public native static int playWaveFile(String filePath, int device);
public native static int setupAudioOut(int device);
public native static int writeAudioOut(byte[] buffer, int size);
}

View File

@ -0,0 +1,192 @@
package kr.co.rito.osicmanager;
import android.app.Activity;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.ConnectivityManager;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class TickerManager {
private final static String TAG = "TickerManager";
Activity mActivity;
TextView mTickerView;
String mTickerText;
Rect mPosition;
int mForeAlpha;
int mBackAlpha;
int mForeColor;
int mBackColor;
int mTickCount;
float mTickSpeed;
boolean mScriptActive;
Script mLastScript;
class Script extends Thread {
@Override
public void run() {
Log.i(TAG, "Script Start");
mScriptActive = true;
// mTickerView.setSelected(true);
// try {
// sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// mTickerView.setSelected(false);
// try {
// sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
MainActivity.INSTANCE.runOnUiThread(new Runnable() {
@Override
public void run() {
mTickerView.setSelected(true);
}
});
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//mTickerView.setSelected(true);
while(!mTickerView.isMarqueeActive()) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mTickerView.setAlpha(1);
mTickerView.setMarqueeSpeed(mTickSpeed);
while(!mTickerView.isMarqueeStopped()) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// mTickerView.setAlpha(0.01f);
// mTickerView.setSelected(false);
MainActivity.INSTANCE.runOnUiThread(new Runnable() {
@Override
public void run() {
mTickerView.setAlpha(0.01f);
mTickerView.setSelected(false);
}
});
Log.i(TAG, "Script End");
}
}
public TickerManager(Activity activity, TextView tickerView) {
mActivity = activity;
mTickerView = tickerView;
mForeAlpha = 0xFF000000;
mBackAlpha = 0xFE000000;
}
public void setupTicker(String text, Rect position, int foreColor, int backColor, int tickCount, float tickSpeed) {
mTickerText = text;
mPosition = position;
mForeColor = (mForeAlpha | foreColor);
mBackColor = (mBackAlpha | backColor);
mTickCount = tickCount;
mTickSpeed = tickSpeed * 50;
}
public void renderTicker() {
Paint paint = new Paint();
final float textSize = mPosition.height() * 0.5f;
paint.setTextSize(textSize);
float spaceWidth = paint.measureText(" ");
float width = mPosition.width();
int dupCount = (int)(width / spaceWidth) + 1;
Log.e(TAG, String.format("[Position] Width : %d, Height : %d, spaceWidth : %2.2f, width : %2.2f, dupCount : %d", mPosition.width(), mPosition.height(), spaceWidth, width, dupCount));
String curText = "";
for(int i = 0;i < dupCount;i++)
curText += " ";
curText += mTickerText;
final String _sendText = new String(curText);
mScriptActive = false;
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
// if(mLastScript != null) {
// try {
// mLastScript.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// try {
// Thread.sleep(150);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// mTickerView.setText("");
// mTickerView.setSelected(true);
// mTickerView.setSelected(false);
//mTickerView.setText(mTickerText);
// FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
// params.setMargins(mPosition.left, mPosition.top, mPosition.right, mPosition.bottom);
// mTickerView.setLayoutParams(params);
//mTickerView.layout(mPosition.left, mPosition.top, mPosition.right, mPosition.bottom);
mTickerView.setX(mPosition.left);
mTickerView.setY(mPosition.top);
mTickerView.getLayoutParams().width = (mPosition.right - mPosition.left);
mTickerView.getLayoutParams().height = (int)((mPosition.bottom - mPosition.top) * 1.0);
mTickerView.setGravity(Gravity.CENTER);
// mTickerView.setHeight((mPosition.bottom - mPosition.top));
// mTickerView.setWidth((mPosition.right - mPosition.left));
mTickerView.setTextSize(textSize);
mTickerView.setText(_sendText);
mTickerView.setHorizontallyScrolling(true);
mTickerView.setSingleLine(true);
mTickerView.setTextColor(mForeColor);
mTickerView.setBackgroundColor(mBackColor);
mTickerView.setMarqueeRepeatLimit(mTickCount);
//int curGravity = mTickerView.getGravity();
// mTickerView.setGravity(Gravity.AXIS_PULL_BEFORE);
// float spacing = mTickerView.getLetterSpacing();
// mTickerView.setLetterSpacing(spacing + 0.1f);
// mTickerView.setLetterSpacing(spacing);
// mTickerView.setGravity(Gravity.CENTER_VERTICAL);
// mTickerView.setAlpha(1);
// mTickerView.invalidate();
// mTickerView.bringToFront();
mLastScript = new Script();
mLastScript.start();
}
});
}
}

View File

@ -0,0 +1,128 @@
package kr.co.rito.osicmanager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.TextureView;
public class TickerView extends TextureView {
RenderScript mRenderer;
Rect mPosition;
String mTickerText;
int mForeColor;
int mBackColor;
public TickerView(Context context) {
super(context);
setOpaque(false);
}
public TickerView(Context context, AttributeSet attrs) {
super(context, attrs);
setOpaque(false);
}
public TickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOpaque(false);
}
public TickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setOpaque(false);
}
private static Bitmap getTextImageWithSizeDetail(String _txt, String _fontName, float _text_size, int _height,
int _colorCode, int _shadowColorCode, float _shadowOffsetX, float _shadowOffsetY, int align) {
Paint textPaint = new Paint();
textPaint.setTextSize(_text_size);
float _measureSize = textPaint.measureText(_txt);
int _width = (int)_measureSize + 1;
Bitmap textBitmap = Bitmap.createBitmap(_width, _height, Bitmap.Config.ARGB_8888);
// textBitmap.eraseColor(0x8844ff44);
Canvas canvas = new Canvas(textBitmap);
Typeface typeface = Typeface.create(_fontName, Typeface.NORMAL);
setAutoTextSize(_text_size, textPaint, _txt, _width);
textPaint.setAntiAlias(true);
textPaint.setColor(_colorCode);
textPaint.setShadowLayer(2f, _shadowOffsetX, _shadowOffsetY, _shadowColorCode);
textPaint.setTypeface(typeface);
Rect bounds = new Rect();
textPaint.getTextBounds(_txt, 0, _txt.length(), bounds);
float measureTxt = textPaint.measureText(_txt);
float w = 0f, h = Math.abs(bounds.top); // 상단정렬
// h = _height - Math.abs(bounds.bottom); //하단정렬
if (align == -1) {
h += (_height - h - Math.abs(bounds.bottom)) / 2;
} else if (align == 0) {
w = (_width - measureTxt) / 2;
h += (_height - h - Math.abs(bounds.bottom)) / 2;
} else if (align == 1) {
w = _width - measureTxt;
h += (_height - h - Math.abs(bounds.bottom)) / 2;
}
canvas.drawText(_txt, w, h, textPaint);
return textBitmap;
}
static void setAutoTextSize(float textSize, Paint paint, String text, int width) {
paint.setTextSize(textSize);
float _measureSize = paint.measureText(text);
if (_measureSize >= width) {
setAutoTextSize(--textSize, paint, text, width);
}
}
class RenderScript extends Thread {
@Override
public void run() {
int pos_x = mPosition.right;
//Bitmap textBitmap = getTextImageWithSizeDetail(mTickerText, "", );
while(true) {
Canvas canvas = lockCanvas();
if (canvas != null) {
Paint paint = new Paint();
paint.setTextSize(mPosition.height());
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawPaint(clearPaint);
canvas.drawRect(mPosition, paint);
canvas.drawColor(mForeColor);
canvas.drawText(mTickerText, pos_x, mPosition.top + 40, paint);
unlockCanvasAndPost(canvas);
}
try {
sleep(33);
} catch (InterruptedException e) {
e.printStackTrace();
}
pos_x -= 5;
}
}
}
public void setupTicker(String text, Rect position, int foreColor, int backColor) {
mTickerText = text;
mPosition = position;
mForeColor = foreColor;
mBackColor = backColor;
}
public void renderTicker() {
mRenderer = new RenderScript();
//mRenderer.start();
}
}

View File

@ -0,0 +1,30 @@
package kr.co.rito.osicmanager.ui.main;
import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
public class PageViewModel extends ViewModel {
private MutableLiveData<Integer> mIndex = new MutableLiveData<>();
private LiveData<String> mText = Transformations.map(mIndex, new Function<Integer, String>() {
@Override
public String apply(Integer input) {
return "Hello world from section: " + input;
}
});
public void setIndex(int index) {
mIndex.setValue(index);
}
public int getIndex() {
return mIndex.getValue();
}
public LiveData<String> getText() {
return mText;
}
}

View File

@ -0,0 +1,318 @@
package kr.co.rito.osicmanager.ui.main;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import kr.co.rito.osicmanager.MainActivity;
import kr.co.rito.osicmanager.R;
import kr.co.rito.osicmanager.SystemUtil;
/**
* A placeholder fragment containing a simple view.
*/
public class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private PageViewModel pageViewModel;
private boolean mIpReloadAlive = false;
public static PlaceholderFragment newInstance(int index) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putInt(ARG_SECTION_NUMBER, index);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
pageViewModel = ViewModelProviders.of(this).get(PageViewModel.class);
int index = 1;
if (getArguments() != null) {
index = getArguments().getInt(ARG_SECTION_NUMBER);
}
pageViewModel.setIndex(index);
}
private void infoUpdate(final View rootView) {
Log.w("RITO", "infoUpdate()");
TextView view = rootView.findViewById(R.id.textViewVersionValue);
//String value = SystemUtil.property_get("rito.system.version");
String value = SystemUtil.getVersionInfo(getContext());
if(value.length() == 0) {
value = "1";
}
view.setText(value);
view = rootView.findViewById(R.id.textViewInfoSerialValue);
value = SystemUtil.property_get("rito.board.serial");
view.setText(value);
view = rootView.findViewById(R.id.textViewInfoMacValue);
value = SystemUtil.property_get("rito.board.mac");
view.setText(value);
//SystemUtil _sysUtil = new SystemUtil();
if(!mIpReloadAlive) {
mIpReloadAlive = true;
new Thread("ipreload") {
@Override
public void run() {
while(mIpReloadAlive) {
final TextView _view = rootView.findViewById(R.id.textViewInfoIpValue);
final String _value = SystemUtil.getIPAddress();
MainActivity.INSTANCE.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.w("RITO", "Draw IP : " + _value);
_view.setText(_value);
}});
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
// view = rootView.findViewById(R.id.textViewInfoIpValue);
// value = SystemUtil.getIPAddress();
// view.setText(value);
}
private void netVisibility(View rootView, boolean visible) {
int visibility = View.INVISIBLE;
if(visible) {
visibility = View.VISIBLE;
}
TextView textView = rootView.findViewById(R.id.textViewNetIp);
textView.setVisibility(visibility);
textView = rootView.findViewById(R.id.textViewNetGateway);
textView.setVisibility(visibility);
textView = rootView.findViewById(R.id.textViewNetmask);
textView.setVisibility(visibility);
textView = rootView.findViewById(R.id.textViewNetDns);
textView.setVisibility(visibility);
EditText editText = rootView.findViewById(R.id.editTextNetIpValue);
editText.setVisibility(visibility);
editText = rootView.findViewById(R.id.editTextNetGatewayValue);
editText.setVisibility(visibility);
editText = rootView.findViewById(R.id.editTextNetmaskValue);
editText.setVisibility(visibility);
editText = rootView.findViewById(R.id.editTextNetDnsValue);
editText.setVisibility(visibility);
}
private void netUpdate(final View rootView) {
//SystemUtil _sysUtil = new SystemUtil();
String value = SystemUtil.getConfigValue("ipv4type");
RadioButton button = rootView.findViewById(R.id.radioButtonStatic);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.w("RITO", "STATIC CLICK");
netVisibility(rootView, true);
}
});
button = rootView.findViewById(R.id.radioButtonDhcp);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.w("RITO", "DHCP CLICK");
netVisibility(rootView, false);
}
});
if(value.equalsIgnoreCase("static")) {
RadioButton view = rootView.findViewById(R.id.radioButtonStatic);
view.performClick();
view.requestFocus();
EditText editText = rootView.findViewById(R.id.editTextNetIpValue);
value = SystemUtil.getConfigValue("ipaddr");
editText.setText(value);
editText = rootView.findViewById(R.id.editTextNetGatewayValue);
value = SystemUtil.getConfigValue("gateway");
editText.setText(value);
editText = rootView.findViewById(R.id.editTextNetmaskValue);
value = SystemUtil.getConfigValue("netmask");
editText.setText(value);
editText = rootView.findViewById(R.id.editTextNetDnsValue);
value = SystemUtil.getConfigValue("dns");
editText.setText(value);
} else {
RadioButton view = rootView.findViewById(R.id.radioButtonDhcp);
view.performClick();
view.requestFocus();
//netVisibility(rootView, false);
}
}
private void serverUpdate(final View rootView) {
//SystemUtil _sysUtil = new SystemUtil();
EditText editText = rootView.findViewById(R.id.editTextServerIpValue);
String value = SystemUtil.getConfigValue("svraddr");
editText.setText(value);
editText = rootView.findViewById(R.id.editTextServerPortValue);
value = SystemUtil.getConfigValue("svrport");
if(value.length() == 0)
value = "10000";
editText.setText(value);
}
private void updateSvrUpdate(final View rootView) {
//SystemUtil _sysUtil = new SystemUtil();
EditText editText = rootView.findViewById(R.id.editTextUpdateUrlValue);
String value = SystemUtil.getConfigValue("updatesvr");
editText.setText(value);
}
public void saveSettings(String target) {
EditText editText;
String value;
if(target.equals("server")) {
editText = getView().findViewById(R.id.editTextServerIpValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("svraddr", value);
}
editText = getView().findViewById(R.id.editTextServerPortValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("svrport", value);
}
editText = getView().findViewById(R.id.editTextUpdateUrlValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("updatesvr", value);
}
}
if(target.equals("network")) {
RadioButton _radio = getView().findViewById(R.id.radioButtonStatic);
if (_radio.isChecked()) {
editText = getView().findViewById(R.id.editTextNetIpValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("ipaddr", value);
}
editText = getView().findViewById(R.id.editTextNetGatewayValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("gateway", value);
}
editText = getView().findViewById(R.id.editTextNetmaskValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("netmask", value);
}
editText = getView().findViewById(R.id.editTextNetDnsValue);
value = editText.getText().toString();
if (value.length() > 0) {
SystemUtil.setConfigValue("dns", value);
}
SystemUtil.shellCommand("ritosysc NETAPPLY=STATIC");
} else {
SystemUtil.shellCommand("ritosysc NETAPPLY=DHCP");
}
}
}
@Override
public void onStop() {
mIpReloadAlive = false;
super.onStop();
}
@Override
public void onPause() {
//saveSettings();
super.onPause();
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_setting, container, false);
final TextView textView = root.findViewById(R.id.section_label);
Log.w("RITO", "onCreateView : " + pageViewModel.getIndex());
if(pageViewModel.getIndex() == 1) {
root.findViewById(R.id.layoutInfo).setVisibility(View.VISIBLE);
root.findViewById(R.id.layoutNetwork).setVisibility(View.INVISIBLE);
root.findViewById(R.id.layoutServer).setVisibility(View.INVISIBLE);
infoUpdate(root);
} else if(pageViewModel.getIndex() == 2) {
root.findViewById(R.id.layoutInfo).setVisibility(View.INVISIBLE);
root.findViewById(R.id.layoutNetwork).setVisibility(View.VISIBLE);
root.findViewById(R.id.layoutServer).setVisibility(View.INVISIBLE);
Button button = root.findViewById(R.id.buttonApplyNetwork);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
saveSettings("network");
}
});
netUpdate(root);
} else if(pageViewModel.getIndex() == 3) {
root.findViewById(R.id.layoutInfo).setVisibility(View.INVISIBLE);
root.findViewById(R.id.layoutNetwork).setVisibility(View.INVISIBLE);
root.findViewById(R.id.layoutServer).setVisibility(View.VISIBLE);
Button button = root.findViewById(R.id.buttonApplyServer);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
saveSettings("server");
}
});
serverUpdate(root);
updateSvrUpdate(root);
}
pageViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
return root;
}
}

View File

@ -0,0 +1,46 @@
package kr.co.rito.osicmanager.ui.main;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import kr.co.rito.osicmanager.R;
/**
* A [FragmentPagerAdapter] that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
@StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public SectionsPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
@Override
public int getCount() {
// Show 2 total pages.
return 3;
}
}

View File

@ -0,0 +1,180 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttPingSender;
import org.eclipse.paho.client.mqttv3.internal.ClientComms;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**
* Default ping sender implementation on Android. It is based on AlarmManager.
*
* <p>This class implements the {@link MqttPingSender} pinger interface
* allowing applications to send ping packet to server every keep alive interval.
* </p>
*
* @see MqttPingSender
*/
class AlarmPingSender implements MqttPingSender {
// Identifier for Intents, log messages, etc..
private static final String TAG = "AlarmPingSender";
// TODO: Add log.
private ClientComms comms;
private MqttService service;
private BroadcastReceiver alarmReceiver;
private AlarmPingSender that;
private PendingIntent pendingIntent;
private volatile boolean hasStarted = false;
public AlarmPingSender(MqttService service) {
if (service == null) {
throw new IllegalArgumentException(
"Neither service nor client can be null.");
}
this.service = service;
that = this;
}
@Override
public void init(ClientComms comms) {
this.comms = comms;
this.alarmReceiver = new AlarmReceiver();
}
@Override
public void start() {
String action = MqttServiceConstants.PING_SENDER
+ comms.getClient().getClientId();
Log.d(TAG, "Register alarmreceiver to MqttService"+ action);
service.registerReceiver(alarmReceiver, new IntentFilter(action));
pendingIntent = PendingIntent.getBroadcast(service, 0, new Intent(
action), PendingIntent.FLAG_UPDATE_CURRENT);
schedule(comms.getKeepAlive());
hasStarted = true;
}
@Override
public void stop() {
Log.d(TAG, "Unregister alarmreceiver to MqttService"+comms.getClient().getClientId());
if(hasStarted){
if(pendingIntent != null){
// Cancel Alarm.
AlarmManager alarmManager = (AlarmManager) service.getSystemService(Service.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
hasStarted = false;
try{
service.unregisterReceiver(alarmReceiver);
}catch(IllegalArgumentException e){
//Ignore unregister errors.
}
}
}
@Override
public void schedule(long delayInMilliseconds) {
long nextAlarmInMilliseconds = System.currentTimeMillis()
+ delayInMilliseconds;
Log.d(TAG, "Schedule next alarm at " + nextAlarmInMilliseconds);
AlarmManager alarmManager = (AlarmManager) service
.getSystemService(Service.ALARM_SERVICE);
if(Build.VERSION.SDK_INT >= 23){
// In SDK 23 and above, dosing will prevent setExact, setExactAndAllowWhileIdle will force
// the device to run this task whilst dosing.
Log.d(TAG, "Alarm scheule using setExactAndAllowWhileIdle, next: " + delayInMilliseconds);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
Log.d(TAG, "Alarm scheule using setExact, delay: " + delayInMilliseconds);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, nextAlarmInMilliseconds,
pendingIntent);
}
}
/*
* This class sends PingReq packet to MQTT broker
*/
class AlarmReceiver extends BroadcastReceiver {
private WakeLock wakelock;
private final String wakeLockTag = MqttServiceConstants.PING_WAKELOCK
+ that.comms.getClient().getClientId();
@Override
@SuppressLint("Wakelock")
public void onReceive(Context context, Intent intent) {
// According to the docs, "Alarm Manager holds a CPU wake lock as
// long as the alarm receiver's onReceive() method is executing.
// This guarantees that the phone will not sleep until you have
// finished handling the broadcast.", but this class still get
// a wake lock to wait for ping finished.
Log.d(TAG, "Sending Ping at:" + System.currentTimeMillis());
PowerManager pm = (PowerManager) service
.getSystemService(Service.POWER_SERVICE);
wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
wakelock.acquire();
// Assign new callback to token to execute code after PingResq
// arrives. Get another wakelock even receiver already has one,
// release it until ping response returns.
IMqttToken token = comms.checkForActivity(new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "Success. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
wakelock.release();
}
@Override
public void onFailure(IMqttToken asyncActionToken,
Throwable exception) {
Log.d(TAG, "Failure. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
wakelock.release();
}
});
if (token == null && wakelock.isHeld()) {
wakelock.release();
}
}
}
}

View File

@ -0,0 +1,462 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* James Sutton - Removing SQL Injection vunerability (bug 467378)
*/
package org.eclipse.paho.android.service;
import java.util.Iterator;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Implementation of the {@link MessageStore} interface, using a SQLite database
*
*/
class DatabaseMessageStore implements MessageStore {
// TAG used for indentify trace data etc.
private static final String TAG = "DatabaseMessageStore";
// One "private" database column name
// The other database column names are defined in MqttServiceConstants
private static final String MTIMESTAMP = "mtimestamp";
// the name of the table in the database to which we will save messages
private static final String ARRIVED_MESSAGE_TABLE_NAME = "MqttArrivedMessageTable";
// the database
private SQLiteDatabase db = null;
// a SQLiteOpenHelper specific for this database
private MQTTDatabaseHelper mqttDb = null;
// a place to send trace data
private MqttTraceHandler traceHandler = null;
/**
* We need a SQLiteOpenHelper to handle database creation and updating
*
*/
private static class MQTTDatabaseHelper extends SQLiteOpenHelper {
// TAG used for indentify trace data etc.
private static final String TAG = "MQTTDatabaseHelper";
private static final String DATABASE_NAME = "mqttAndroidService.db";
// database version, used to recognise when we need to upgrade
// (delete and recreate)
private static final int DATABASE_VERSION = 1;
// a place to send trace data
private MqttTraceHandler traceHandler = null;
/**
* Constructor.
*
* @param traceHandler
* @param context
*/
public MQTTDatabaseHelper(MqttTraceHandler traceHandler, Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.traceHandler = traceHandler;
}
/**
* When the database is (re)created, create our table
*
* @param database
*/
@Override
public void onCreate(SQLiteDatabase database) {
String createArrivedTableStatement = "CREATE TABLE "
+ ARRIVED_MESSAGE_TABLE_NAME + "("
+ MqttServiceConstants.MESSAGE_ID + " TEXT PRIMARY KEY, "
+ MqttServiceConstants.CLIENT_HANDLE + " TEXT, "
+ MqttServiceConstants.DESTINATION_NAME + " TEXT, "
+ MqttServiceConstants.PAYLOAD + " BLOB, "
+ MqttServiceConstants.QOS + " INTEGER, "
+ MqttServiceConstants.RETAINED + " TEXT, "
+ MqttServiceConstants.DUPLICATE + " TEXT, " + MTIMESTAMP
+ " INTEGER" + ");";
traceHandler.traceDebug(TAG, "onCreate {"
+ createArrivedTableStatement + "}");
try {
database.execSQL(createArrivedTableStatement);
traceHandler.traceDebug(TAG, "created the table");
} catch (SQLException e) {
traceHandler.traceException(TAG, "onCreate", e);
throw e;
}
}
/**
* To upgrade the database, drop and recreate our table
*
* @param db
* the database
* @param oldVersion
* ignored
* @param newVersion
* ignored
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
traceHandler.traceDebug(TAG, "onUpgrade");
try {
db.execSQL("DROP TABLE IF EXISTS " + ARRIVED_MESSAGE_TABLE_NAME);
} catch (SQLException e) {
traceHandler.traceException(TAG, "onUpgrade", e);
throw e;
}
onCreate(db);
traceHandler.traceDebug(TAG, "onUpgrade complete");
}
}
/**
* Constructor - create a DatabaseMessageStore to store arrived MQTT message
*
* @param service
* our parent MqttService
* @param context
* a context to use for android calls
*/
public DatabaseMessageStore(MqttService service, Context context) {
this.traceHandler = service;
// Open message database
mqttDb = new MQTTDatabaseHelper(traceHandler, context);
// Android documentation suggests that this perhaps
// could/should be done in another thread, but as the
// database is only one table, I doubt it matters...
traceHandler.traceDebug(TAG, "DatabaseMessageStore<init> complete");
}
/**
* Store an MQTT message
*
* @param clientHandle
* identifier for the client storing the message
* @param topic
* The topic on which the message was published
* @param message
* the arrived MQTT message
* @return an identifier for the message, so that it can be removed when appropriate
*/
@Override
public String storeArrived(String clientHandle, String topic,
MqttMessage message) {
db = mqttDb.getWritableDatabase();
traceHandler.traceDebug(TAG, "storeArrived{" + clientHandle + "}, {"
+ message.toString() + "}");
byte[] payload = message.getPayload();
int qos = message.getQos();
boolean retained = message.isRetained();
boolean duplicate = message.isDuplicate();
ContentValues values = new ContentValues();
String id = java.util.UUID.randomUUID().toString();
values.put(MqttServiceConstants.MESSAGE_ID, id);
values.put(MqttServiceConstants.CLIENT_HANDLE, clientHandle);
values.put(MqttServiceConstants.DESTINATION_NAME, topic);
values.put(MqttServiceConstants.PAYLOAD, payload);
values.put(MqttServiceConstants.QOS, qos);
values.put(MqttServiceConstants.RETAINED, retained);
values.put(MqttServiceConstants.DUPLICATE, duplicate);
values.put(MTIMESTAMP, System.currentTimeMillis());
try {
db.insertOrThrow(ARRIVED_MESSAGE_TABLE_NAME, null, values);
} catch (SQLException e) {
traceHandler.traceException(TAG, "onUpgrade", e);
throw e;
}
int count = getArrivedRowCount(clientHandle);
traceHandler
.traceDebug(
TAG,
"storeArrived: inserted message with id of {"
+ id
+ "} - Number of messages in database for this clientHandle = "
+ count);
return id;
}
private int getArrivedRowCount(String clientHandle) {
int count = 0;
String[] projection = {
MqttServiceConstants.MESSAGE_ID,
};
String selection = MqttServiceConstants.CLIENT_HANDLE + "=?";
String[] selectionArgs = new String[1];
selectionArgs[0] = clientHandle;
Cursor c = db.query(
ARRIVED_MESSAGE_TABLE_NAME, // Table Name
projection, // The columns to return;
selection, // Columns for WHERE Clause
selectionArgs , // The values for the WHERE Cause
null, //Don't group the rows
null, // Don't filter by row groups
null // The sort order
);
if (c.moveToFirst()) {
count = c.getInt(0);
}
c.close();
return count;
}
/**
* Delete an MQTT message.
*
* @param clientHandle
* identifier for the client which stored the message
* @param id
* the identifying string returned when the message was stored
*
* @return true if the message was found and deleted
*/
@Override
public boolean discardArrived(String clientHandle, String id) {
db = mqttDb.getWritableDatabase();
traceHandler.traceDebug(TAG, "discardArrived{" + clientHandle + "}, {"
+ id + "}");
int rows;
String[] selectionArgs = new String[2];
selectionArgs[0] = id;
selectionArgs[1] = clientHandle;
try {
rows = db.delete(ARRIVED_MESSAGE_TABLE_NAME,
MqttServiceConstants.MESSAGE_ID + "=? AND "
+ MqttServiceConstants.CLIENT_HANDLE + "=?",
selectionArgs);
} catch (SQLException e) {
traceHandler.traceException(TAG, "discardArrived", e);
throw e;
}
if (rows != 1) {
traceHandler.traceError(TAG,
"discardArrived - Error deleting message {" + id
+ "} from database: Rows affected = " + rows);
return false;
}
int count = getArrivedRowCount(clientHandle);
traceHandler
.traceDebug(
TAG,
"discardArrived - Message deleted successfully. - messages in db for this clientHandle "
+ count);
return true;
}
/**
* Get an iterator over all messages stored (optionally for a specific client)
*
* @param clientHandle
* identifier for the client.<br>
* If null, all messages are retrieved
* @return iterator of all the arrived MQTT messages
*/
@Override
public Iterator<StoredMessage> getAllArrivedMessages(
final String clientHandle) {
return new Iterator<StoredMessage>() {
private Cursor c;
private boolean hasNext;
private final String[] selectionArgs = {
clientHandle,
};
{
db = mqttDb.getWritableDatabase();
// anonymous initialiser to start a suitable query
// and position at the first row, if one exists
if (clientHandle == null) {
c = db.query(ARRIVED_MESSAGE_TABLE_NAME,
null,
null,
null,
null,
null,
"mtimestamp ASC");
} else {
c = db.query(ARRIVED_MESSAGE_TABLE_NAME,
null,
MqttServiceConstants.CLIENT_HANDLE + "=?",
selectionArgs,
null,
null,
"mtimestamp ASC");
}
hasNext = c.moveToFirst();
}
@Override
public boolean hasNext() {
if (!hasNext){
c.close();
}
return hasNext;
}
@Override
public StoredMessage next() {
String messageId = c.getString(c
.getColumnIndex(MqttServiceConstants.MESSAGE_ID));
String clientHandle = c.getString(c
.getColumnIndex(MqttServiceConstants.CLIENT_HANDLE));
String topic = c.getString(c
.getColumnIndex(MqttServiceConstants.DESTINATION_NAME));
byte[] payload = c.getBlob(c
.getColumnIndex(MqttServiceConstants.PAYLOAD));
int qos = c.getInt(c.getColumnIndex(MqttServiceConstants.QOS));
boolean retained = Boolean.parseBoolean(c.getString(c
.getColumnIndex(MqttServiceConstants.RETAINED)));
boolean dup = Boolean.parseBoolean(c.getString(c
.getColumnIndex(MqttServiceConstants.DUPLICATE)));
// build the result
MqttMessageHack message = new MqttMessageHack(payload);
message.setQos(qos);
message.setRetained(retained);
message.setDuplicate(dup);
// move on
hasNext = c.moveToNext();
return new DbStoredData(messageId, clientHandle, topic, message);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
/* (non-Javadoc)
* @see java.lang.Object#finalize()
*/
@Override
protected void finalize() throws Throwable {
c.close();
super.finalize();
}
};
}
/**
* Delete all messages (optionally for a specific client)
*
* @param clientHandle
* identifier for the client.<br>
* If null, all messages are deleted
*/
@Override
public void clearArrivedMessages(String clientHandle) {
db = mqttDb.getWritableDatabase();
String[] selectionArgs = new String[1];
selectionArgs[0] = clientHandle;
int rows = 0;
if (clientHandle == null) {
traceHandler.traceDebug(TAG,
"clearArrivedMessages: clearing the table");
rows = db.delete(ARRIVED_MESSAGE_TABLE_NAME, null, null);
} else {
traceHandler.traceDebug(TAG,
"clearArrivedMessages: clearing the table of "
+ clientHandle + " messages");
rows = db.delete(ARRIVED_MESSAGE_TABLE_NAME,
MqttServiceConstants.CLIENT_HANDLE + "=?",
selectionArgs);
}
traceHandler.traceDebug(TAG, "clearArrivedMessages: rows affected = "
+ rows);
}
private class DbStoredData implements StoredMessage {
private String messageId;
private String clientHandle;
private String topic;
private MqttMessage message;
DbStoredData(String messageId, String clientHandle, String topic,
MqttMessage message) {
this.messageId = messageId;
this.topic = topic;
this.message = message;
}
@Override
public String getMessageId() {
return messageId;
}
@Override
public String getClientHandle() {
return clientHandle;
}
@Override
public String getTopic() {
return topic;
}
@Override
public MqttMessage getMessage() {
return message;
}
}
/**
* A way to get at the "setDuplicate" method of MqttMessage
*/
private class MqttMessageHack extends MqttMessage {
public MqttMessageHack(byte[] payload) {
super(payload);
}
@Override
protected void setDuplicate(boolean dup) {
super.setDuplicate(dup);
}
}
@Override
public void close() {
if (this.db!=null)
this.db.close();
}
}

View File

@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import java.util.Iterator;
import org.eclipse.paho.client.mqttv3.MqttMessage;
/**
* <p>
* Mechanism for persisting messages until we know they have been received
* </p>
* <ul>
* <li>A Service should store messages as they arrive via
* {@link #storeArrived(String, String, MqttMessage)}.
* <li>When a message has been passed to the consuming entity,
* {@link #discardArrived(String, String)} should be called.
* <li>To recover messages which have not been definitely passed to the
* consumer, {@link MessageStore#getAllArrivedMessages(String)} is used.
* <li>When a clean session is started {@link #clearArrivedMessages(String)} is
* used.
* </ul>
*/
interface MessageStore {
/**
* External representation of a stored message
*/
interface StoredMessage {
/**
* @return the identifier for the message within the store
*/
String getMessageId();
/**
* @return the identifier of the client which stored this message
*/
String getClientHandle();
/**
* @return the topic on which the message was received
*/
String getTopic();
/**
* @return the identifier of the client which stored this message
*/
MqttMessage getMessage();
}
/**
* Store a message and return an identifier for it
*
* @param clientHandle
* identifier for the client
* @param message
* message to be stored
* @return a unique identifier for it
*/
String storeArrived(String clientHandle, String Topic,
MqttMessage message);
/**
* Discard a message - called when we are certain that an arrived message
* has reached the application.
*
* @param clientHandle
* identifier for the client
* @param id
* id of message to be discarded
*/
boolean discardArrived(String clientHandle, String id);
/**
* Get all the stored messages, usually for a specific client
*
* @param clientHandle
* identifier for the client - if null, then messages for all
* clients are returned
*/
Iterator<StoredMessage> getAllArrivedMessages(String clientHandle);
/**
* Discard stored messages, usually for a specific client
*
* @param clientHandle
* identifier for the client - if null, then messages for all
* clients are discarded
*/
void clearArrivedMessages(String clientHandle);
void close();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
/**
* <p>
* Implementation of the IMqttDeliveryToken interface for use from within the
* MqttAndroidClient implementation
*/
class MqttDeliveryTokenAndroid extends MqttTokenAndroid
implements IMqttDeliveryToken {
// The message which is being tracked by this token
private MqttMessage message;
MqttDeliveryTokenAndroid(MqttAndroidClient client,
Object userContext, IMqttActionListener listener, MqttMessage message) {
super(client, userContext, listener);
this.message = message;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttDeliveryToken#getMessage()
*/
@Override
public MqttMessage getMessage() throws MqttException {
return message;
}
void setMessage(MqttMessage message) {
this.message = message;
}
void notifyDelivery(MqttMessage delivered) {
message = delivered;
super.notifyComplete();
}
}

View File

@ -0,0 +1,912 @@
/*******************************************************************************
* Copyright (c) 1999, 2016 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* James Sutton - isOnline Null Pointer (bug 473775)
*/
package org.eclipse.paho.android.service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* <p>
* The android service which interfaces with an MQTT client implementation
* </p>
* <p>
* The main API of MqttService is intended to pretty much mirror the
* IMqttAsyncClient with appropriate adjustments for the Android environment.<br>
* These adjustments usually consist of adding two parameters to each method :-
* </p>
* <ul>
* <li>invocationContext - a string passed from the application to identify the
* context of the operation (mainly included for support of the javascript API
* implementation)</li>
* <li>activityToken - a string passed from the Activity to relate back to a
* callback method or other context-specific data</li>
* </ul>
* <p>
* To support multiple client connections, the bulk of the MQTT work is
* delegated to MqttConnection objects. These are identified by "client
* handle" strings, which is how the Activity, and the higher-level APIs refer
* to them.
* </p>
* <p>
* Activities using this service are expected to start it and bind to it using
* the BIND_AUTO_CREATE flag. The life cycle of this service is based on this
* approach.
* </p>
* <p>
* Operations are highly asynchronous - in most cases results are returned to
* the Activity by broadcasting one (or occasionally more) appropriate Intents,
* which the Activity is expected to register a listener for.<br>
* The Intents have an Action of
* {@link MqttServiceConstants#CALLBACK_TO_ACTIVITY
* MqttServiceConstants.CALLBACK_TO_ACTIVITY} which allows the Activity to
* register a listener with an appropriate IntentFilter.<br>
* Further data is provided by "Extra Data" in the Intent, as follows :-
* </p>
* <table border="1" summary="">
* <tr>
* <th align="left">Name</th>
* <th align="left">Data Type</th>
* <th align="left">Value</th>
* <th align="left">Operations used for</th>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_CLIENT_HANDLE
* MqttServiceConstants.CALLBACK_CLIENT_HANDLE}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">The clientHandle identifying the client which
* initiated this operation</td>
* <td align="left" valign="top">All operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">{@link MqttServiceConstants#CALLBACK_STATUS
* MqttServiceConstants.CALLBACK_STATUS}</td>
* <td align="left" valign="top">Serializable</td>
* <td align="left" valign="top">An {@link Status} value indicating success or
* otherwise of the operation</td>
* <td align="left" valign="top">All operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_ACTIVITY_TOKEN
* MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">the activityToken passed into the operation</td>
* <td align="left" valign="top">All operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_INVOCATION_CONTEXT
* MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">the invocationContext passed into the operation
* </td>
* <td align="left" valign="top">All operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">{@link MqttServiceConstants#CALLBACK_ACTION
* MqttServiceConstants.CALLBACK_ACTION}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">one of
* <table summary="">
* <tr>
* <td align="left" valign="top"> {@link MqttServiceConstants#SEND_ACTION
* MqttServiceConstants.SEND_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#UNSUBSCRIBE_ACTION
* MqttServiceConstants.UNSUBSCRIBE_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top"> {@link MqttServiceConstants#SUBSCRIBE_ACTION
* MqttServiceConstants.SUBSCRIBE_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top"> {@link MqttServiceConstants#DISCONNECT_ACTION
* MqttServiceConstants.DISCONNECT_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top"> {@link MqttServiceConstants#CONNECT_ACTION
* MqttServiceConstants.CONNECT_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#MESSAGE_ARRIVED_ACTION
* MqttServiceConstants.MESSAGE_ARRIVED_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#MESSAGE_DELIVERED_ACTION
* MqttServiceConstants.MESSAGE_DELIVERED_ACTION}</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#ON_CONNECTION_LOST_ACTION
* MqttServiceConstants.ON_CONNECTION_LOST_ACTION}</td>
* </tr>
* </table>
* </td>
* <td align="left" valign="top">All operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_ERROR_MESSAGE
* MqttServiceConstants.CALLBACK_ERROR_MESSAGE}
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">A suitable error message (taken from the
* relevant exception where possible)</td>
* <td align="left" valign="top">All failing operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_ERROR_NUMBER
* MqttServiceConstants.CALLBACK_ERROR_NUMBER}
* <td align="left" valign="top">int</td>
* <td align="left" valign="top">A suitable error code (taken from the relevant
* exception where possible)</td>
* <td align="left" valign="top">All failing operations</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_EXCEPTION_STACK
* MqttServiceConstants.CALLBACK_EXCEPTION_STACK}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">The stacktrace of the failing call</td>
* <td align="left" valign="top">The Connection Lost event</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_MESSAGE_ID
* MqttServiceConstants.CALLBACK_MESSAGE_ID}</td>
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">The identifier for the message in the message
* store, used by the Activity to acknowledge the arrival of the message, so
* that the service may remove it from the store</td>
* <td align="left" valign="top">The Message Arrived event</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_DESTINATION_NAME
* MqttServiceConstants.CALLBACK_DESTINATION_NAME}
* <td align="left" valign="top">String</td>
* <td align="left" valign="top">The topic on which the message was received</td>
* <td align="left" valign="top">The Message Arrived event</td>
* </tr>
* <tr>
* <td align="left" valign="top">
* {@link MqttServiceConstants#CALLBACK_MESSAGE_PARCEL
* MqttServiceConstants.CALLBACK_MESSAGE_PARCEL}</td>
* <td align="left" valign="top">Parcelable</td>
* <td align="left" valign="top">The new message encapsulated in Android
* Parcelable format as a {@link ParcelableMqttMessage}</td>
* <td align="left" valign="top">The Message Arrived event</td>
* </tr>
* </table>
*/
@SuppressLint("Registered")
public class MqttService extends Service implements MqttTraceHandler {
// Identifier for Intents, log messages, etc..
static final String TAG = "MqttService";
// callback id for making trace callbacks to the Activity
// needs to be set by the activity as appropriate
private String traceCallbackId;
// state of tracing
private boolean traceEnabled = false;
// somewhere to persist received messages until we're sure
// that they've reached the application
MessageStore messageStore;
// An intent receiver to deal with changes in network connectivity
private NetworkConnectionIntentReceiver networkConnectionMonitor;
//a receiver to recognise when the user changes the "background data" preference
// and a flag to track that preference
// Only really relevant below android version ICE_CREAM_SANDWICH - see
// android docs
private BackgroundDataPreferenceReceiver backgroundDataPreferenceMonitor;
private volatile boolean backgroundDataEnabled = true;
// a way to pass ourself back to the activity
private MqttServiceBinder mqttServiceBinder;
// mapping from client handle strings to actual client connections.
private Map<String/* clientHandle */, MqttConnection/* client */> connections = new ConcurrentHashMap<>();
public MqttService() {
super();
}
/**
* pass data back to the Activity, by building a suitable Intent object and
* broadcasting it
*
* @param clientHandle
* source of the data
* @param status
* OK or Error
* @param dataBundle
* the data to be passed
*/
void callbackToActivity(String clientHandle, Status status,
Bundle dataBundle) {
// Don't call traceDebug, as it will try to callbackToActivity leading
// to recursion.
Intent callbackIntent = new Intent(
MqttServiceConstants.CALLBACK_TO_ACTIVITY);
if (clientHandle != null) {
callbackIntent.putExtra(
MqttServiceConstants.CALLBACK_CLIENT_HANDLE, clientHandle);
}
callbackIntent.putExtra(MqttServiceConstants.CALLBACK_STATUS, status);
if (dataBundle != null) {
callbackIntent.putExtras(dataBundle);
}
LocalBroadcastManager.getInstance(this).sendBroadcast(callbackIntent);
}
// The major API implementation follows :-
/**
* Get an MqttConnection object to represent a connection to a server
*
* @param serverURI specifies the protocol, host name and port to be used to connect to an MQTT server
* @param clientId specifies the name by which this connection should be identified to the server
* @param contextId specifies the app conext info to make a difference between apps
* @param persistence specifies the persistence layer to be used with this client
* @return a string to be used by the Activity as a "handle" for this
* MqttConnection
*/
public String getClient(String serverURI, String clientId, String contextId, MqttClientPersistence persistence) {
String clientHandle = serverURI + ":" + clientId+":"+contextId;
if (!connections.containsKey(clientHandle)) {
MqttConnection client = new MqttConnection(this, serverURI,
clientId, persistence, clientHandle);
connections.put(clientHandle, client);
}
return clientHandle;
}
/**
* Connect to the MQTT server specified by a particular client
*
* @param clientHandle
* identifies the MqttConnection to use
* @param connectOptions
* the MQTT connection options to be used
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
* @throws MqttSecurityException thrown if there is a security exception
* @throws MqttException thrown for all other MqttExceptions
*/
public void connect(String clientHandle, MqttConnectOptions connectOptions,
String invocationContext, String activityToken)
throws MqttSecurityException, MqttException {
MqttConnection client = getConnection(clientHandle);
client.connect(connectOptions, null, activityToken);
}
/**
* Request all clients to reconnect if appropriate
*/
void reconnect() {
traceDebug(TAG, "Reconnect to server, client size=" + connections.size());
for (MqttConnection client : connections.values()) {
traceDebug("Reconnect Client:",
client.getClientId() + '/' + client.getServerURI());
if(this.isOnline()){
client.reconnect();
}
}
}
/**
* Close connection from a particular client
*
* @param clientHandle
* identifies the MqttConnection to use
*/
public void close(String clientHandle) {
MqttConnection client = getConnection(clientHandle);
client.close();
}
/**
* Disconnect from the server
*
* @param clientHandle
* identifies the MqttConnection to use
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void disconnect(String clientHandle, String invocationContext,
String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.disconnect(invocationContext, activityToken);
connections.remove(clientHandle);
// the activity has finished using us, so we can stop the service
// the activities are bound with BIND_AUTO_CREATE, so the service will
// remain around until the last activity disconnects
stopSelf();
}
/**
* Disconnect from the server
*
* @param clientHandle
* identifies the MqttConnection to use
* @param quiesceTimeout
* in milliseconds
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void disconnect(String clientHandle, long quiesceTimeout,
String invocationContext, String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.disconnect(quiesceTimeout, invocationContext, activityToken);
connections.remove(clientHandle);
// the activity has finished using us, so we can stop the service
// the activities are bound with BIND_AUTO_CREATE, so the service will
// remain around until the last activity disconnects
stopSelf();
}
/**
* Get the status of a specific client
*
* @param clientHandle
* identifies the MqttConnection to use
* @return true if the specified client is connected to an MQTT server
*/
public boolean isConnected(String clientHandle) {
MqttConnection client = getConnection(clientHandle);
return client.isConnected();
}
/**
* Publish a message to a topic
*
* @param clientHandle
* identifies the MqttConnection to use
* @param topic
* the topic to which to publish
* @param payload
* the content of the message to publish
* @param qos
* the quality of service requested
* @param retained
* whether the MQTT server should retain this message
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
* @throws MqttPersistenceException when a problem occurs storing the message
* @throws MqttException if there was an error publishing the message
* @return token for tracking the operation
*/
public IMqttDeliveryToken publish(String clientHandle, String topic,
byte[] payload, int qos, boolean retained,
String invocationContext, String activityToken)
throws MqttPersistenceException, MqttException {
MqttConnection client = getConnection(clientHandle);
return client.publish(topic, payload, qos, retained, invocationContext,
activityToken);
}
/**
* Publish a message to a topic
*
* @param clientHandle
* identifies the MqttConnection to use
* @param topic
* the topic to which to publish
* @param message
* the message to publish
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
* @throws MqttPersistenceException when a problem occurs storing the message
* @throws MqttException if there was an error publishing the message
* @return token for tracking the operation
*/
public IMqttDeliveryToken publish(String clientHandle, String topic,
MqttMessage message, String invocationContext, String activityToken)
throws MqttPersistenceException, MqttException {
MqttConnection client = getConnection(clientHandle);
return client.publish(topic, message, invocationContext, activityToken);
}
/**
* Subscribe to a topic
*
* @param clientHandle
* identifies the MqttConnection to use
* @param topic
* a possibly wildcarded topic name
* @param qos
* requested quality of service for the topic
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void subscribe(String clientHandle, String topic, int qos,
String invocationContext, String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.subscribe(topic, qos, invocationContext, activityToken);
}
/**
* Subscribe to one or more topics
*
* @param clientHandle
* identifies the MqttConnection to use
* @param topic
* a list of possibly wildcarded topic names
* @param qos
* requested quality of service for each topic
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void subscribe(String clientHandle, String[] topic, int[] qos,
String invocationContext, String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.subscribe(topic, qos, invocationContext, activityToken);
}
/**
* Subscribe using topic filters
*
* @param clientHandle
* identifies the MqttConnection to use
* @param topicFilters
* a list of possibly wildcarded topicfilters
* @param qos
* requested quality of service for each topic
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
* @param messageListeners a callback to handle incoming messages
*/
public void subscribe(String clientHandle, String[] topicFilters, int[] qos, String invocationContext, String activityToken, IMqttMessageListener[] messageListeners){
MqttConnection client = getConnection(clientHandle);
client.subscribe(topicFilters, qos, invocationContext, activityToken, messageListeners);
}
/**
* Unsubscribe from a topic
*
* @param clientHandle
* identifies the MqttConnection
* @param topic
* a possibly wildcarded topic name
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void unsubscribe(String clientHandle, final String topic,
String invocationContext, String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.unsubscribe(topic, invocationContext, activityToken);
}
/**
* Unsubscribe from one or more topics
*
* @param clientHandle
* identifies the MqttConnection
* @param topic
* a list of possibly wildcarded topic names
* @param invocationContext
* arbitrary data to be passed back to the application
* @param activityToken
* arbitrary identifier to be passed back to the Activity
*/
public void unsubscribe(String clientHandle, final String[] topic,
String invocationContext, String activityToken) {
MqttConnection client = getConnection(clientHandle);
client.unsubscribe(topic, invocationContext, activityToken);
}
/**
* Get tokens for all outstanding deliveries for a client
*
* @param clientHandle
* identifies the MqttConnection
* @return an array (possibly empty) of tokens
*/
public IMqttDeliveryToken[] getPendingDeliveryTokens(String clientHandle) {
MqttConnection client = getConnection(clientHandle);
return client.getPendingDeliveryTokens();
}
/**
* Get the MqttConnection identified by this client handle
*
* @param clientHandle identifies the MqttConnection
* @return the MqttConnection identified by this handle
*/
private MqttConnection getConnection(String clientHandle) {
MqttConnection client = connections.get(clientHandle);
if (client == null) {
throw new IllegalArgumentException("Invalid ClientHandle");
}
return client;
}
/**
* Called by the Activity when a message has been passed back to the
* application
*
* @param clientHandle identifier for the client which received the message
* @param id identifier for the MQTT message
* @return {@link Status}
*/
public Status acknowledgeMessageArrival(String clientHandle, String id) {
if (messageStore.discardArrived(clientHandle, id)) {
return Status.OK;
}
else {
return Status.ERROR;
}
}
// Extend Service
/**
* @see android.app.Service#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
// create a binder that will let the Activity UI send
// commands to the Service
mqttServiceBinder = new MqttServiceBinder(this);
// create somewhere to buffer received messages until
// we know that they have been passed to the application
messageStore = new DatabaseMessageStore(this, this);
}
/**
* @see android.app.Service#onDestroy()
*/
@Override
public void onDestroy() {
// disconnect immediately
for (MqttConnection client : connections.values()) {
client.disconnect(null, null);
}
// clear down
if (mqttServiceBinder != null) {
mqttServiceBinder = null;
}
unregisterBroadcastReceivers();
if (this.messageStore !=null )
this.messageStore.close();
super.onDestroy();
}
/**
* @see android.app.Service#onBind(Intent)
*/
@Override
public IBinder onBind(Intent intent) {
// What we pass back to the Activity on binding -
// a reference to ourself, and the activityToken
// we were given when started
String activityToken = intent
.getStringExtra(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN);
mqttServiceBinder.setActivityToken(activityToken);
return mqttServiceBinder;
}
/**
* @see android.app.Service#onStartCommand(Intent,int,int)
*/
@Override
public int onStartCommand(final Intent intent, int flags, final int startId) {
// run till explicitly stopped, restart when
// process restarted
registerBroadcastReceivers();
return START_STICKY;
}
/**
* Identify the callbackId to be passed when making tracing calls back into
* the Activity
*
* @param traceCallbackId identifier to the callback into the Activity
*/
public void setTraceCallbackId(String traceCallbackId) {
this.traceCallbackId = traceCallbackId;
}
/**
* Turn tracing on and off
*
* @param traceEnabled set <code>true</code> to turn on tracing, <code>false</code> to turn off tracing
*/
public void setTraceEnabled(boolean traceEnabled) {
this.traceEnabled = traceEnabled;
}
/**
* Check whether trace is on or off.
*
* @return the state of trace
*/
public boolean isTraceEnabled(){
return this.traceEnabled;
}
/**
* Trace debugging information
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
*/
@Override
public void traceDebug(String tag, String message) {
traceCallback(MqttServiceConstants.TRACE_DEBUG, tag, message);
}
/**
* Trace error information
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
*/
@Override
public void traceError(String tag, String message) {
traceCallback(MqttServiceConstants.TRACE_ERROR, tag, message);
}
private void traceCallback(String severity, String tag, String message) {
if ((traceCallbackId != null) && (traceEnabled)) {
Bundle dataBundle = new Bundle();
dataBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.TRACE_ACTION);
dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_SEVERITY, severity);
dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_TAG, tag);
//dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_ID, traceCallbackId);
dataBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, message);
callbackToActivity(traceCallbackId, Status.ERROR, dataBundle);
}
}
/**
* trace exceptions
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
* @param e
* the exception
*/
@Override
public void traceException(String tag, String message, Exception e) {
if (traceCallbackId != null) {
Bundle dataBundle = new Bundle();
dataBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.TRACE_ACTION);
dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_SEVERITY, MqttServiceConstants.TRACE_EXCEPTION);
dataBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, message);
dataBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, e); //TODO: Check
dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_TAG, tag);
//dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_ID, traceCallbackId);
callbackToActivity(traceCallbackId, Status.ERROR, dataBundle);
}
}
@SuppressWarnings("deprecation")
private void registerBroadcastReceivers() {
if (networkConnectionMonitor == null) {
networkConnectionMonitor = new NetworkConnectionIntentReceiver();
registerReceiver(networkConnectionMonitor, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
}
if (Build.VERSION.SDK_INT < 14 /**Build.VERSION_CODES.ICE_CREAM_SANDWICH**/) {
// Support the old system for background data preferences
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
backgroundDataEnabled = cm.getBackgroundDataSetting();
if (backgroundDataPreferenceMonitor == null) {
backgroundDataPreferenceMonitor = new BackgroundDataPreferenceReceiver();
registerReceiver(
backgroundDataPreferenceMonitor,
new IntentFilter(
ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED));
}
}
}
private void unregisterBroadcastReceivers(){
if(networkConnectionMonitor != null){
unregisterReceiver(networkConnectionMonitor);
networkConnectionMonitor = null;
}
if (Build.VERSION.SDK_INT < 14 /**Build.VERSION_CODES.ICE_CREAM_SANDWICH**/) {
if(backgroundDataPreferenceMonitor != null){
unregisterReceiver(backgroundDataPreferenceMonitor);
}
}
}
/*
* Called in response to a change in network connection - after losing a
* connection to the server, this allows us to wait until we have a usable
* data connection again
*/
private class NetworkConnectionIntentReceiver extends BroadcastReceiver {
@Override
@SuppressLint("Wakelock")
public void onReceive(Context context, Intent intent) {
traceDebug(TAG, "Internal network status receive.");
// we protect against the phone switching off
// by requesting a wake lock - we request the minimum possible wake
// lock - just enough to keep the CPU running until we've finished
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wl = pm
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
wl.acquire();
traceDebug(TAG,"Reconnect for Network recovery.");
if (isOnline()) {
traceDebug(TAG,"Online,reconnect.");
// we have an internet connection - have another try at
// connecting
reconnect();
} else {
notifyClientsOffline();
}
wl.release();
}
}
/**
* @return whether the android service can be regarded as online
*/
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
//noinspection RedundantIfStatement
if (networkInfo != null
&& networkInfo.isAvailable()
&& networkInfo.isConnected()
&& backgroundDataEnabled) {
return true;
}
return false;
}
/**
* Notify clients we're offline
*/
private void notifyClientsOffline() {
for (MqttConnection connection : connections.values()) {
connection.offline();
}
}
/**
* Detect changes of the Allow Background Data setting - only used below
* ICE_CREAM_SANDWICH
*/
private class BackgroundDataPreferenceReceiver extends BroadcastReceiver {
@SuppressWarnings("deprecation")
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
traceDebug(TAG,"Reconnect since BroadcastReceiver.");
if (cm.getBackgroundDataSetting()) {
if (!backgroundDataEnabled) {
backgroundDataEnabled = true;
// we have the Internet connection - have another try at
// connecting
reconnect();
}
} else {
backgroundDataEnabled = false;
notifyClientsOffline();
}
}
}
/**
* Sets the DisconnectedBufferOptions for this client
* @param clientHandle identifier for the client
* @param bufferOpts the DisconnectedBufferOptions for this client
*/
public void setBufferOpts(String clientHandle, DisconnectedBufferOptions bufferOpts) {
MqttConnection client = getConnection(clientHandle);
client.setBufferOpts(bufferOpts);
}
public int getBufferedMessageCount(String clientHandle){
MqttConnection client = getConnection(clientHandle);
return client.getBufferedMessageCount();
}
public MqttMessage getBufferedMessage(String clientHandle, int bufferIndex){
MqttConnection client = getConnection(clientHandle);
return client.getBufferedMessage(bufferIndex);
}
public void deleteBufferedMessage(String clientHandle, int bufferIndex){
MqttConnection client = getConnection(clientHandle);
client.deleteBufferedMessage(bufferIndex);
}
}

View File

@ -0,0 +1,52 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import android.os.Binder;
/**
* What the Service passes to the Activity on binding:-
* <ul>
* <li>a reference to the Service
* <li>the activityToken provided when the Service was started
* </ul>
*
*/
class MqttServiceBinder extends Binder {
private MqttService mqttService;
private String activityToken;
MqttServiceBinder(MqttService mqttService) {
this.mqttService = mqttService;
}
/**
* @return a reference to the Service
*/
public MqttService getService() {
return mqttService;
}
void setActivityToken(String activityToken) {
this.activityToken = activityToken;
}
/**
* @return the activityToken provided when the Service was started
*/
public String getActivityToken() {
return activityToken;
}
}

View File

@ -0,0 +1,99 @@
/*******************************************************************************
* Copyright (c) 1999, 2016 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
/**
* Various strings used to identify operations or data in the Android MQTT
* service, mainly used in Intents passed between Activities and the Service.
*/
interface MqttServiceConstants {
/*
* Version information
*/
String VERSION = "v0";
/*
* Attributes of messages <p> Used for the column names in the database
*/
String DUPLICATE = "duplicate";
String RETAINED = "retained";
String QOS = "qos";
String PAYLOAD = "payload";
String DESTINATION_NAME = "destinationName";
String CLIENT_HANDLE = "clientHandle";
String MESSAGE_ID = "messageId";
/* Tags for actions passed between the Activity and the Service */
String SEND_ACTION = "send";
String UNSUBSCRIBE_ACTION = "unsubscribe";
String SUBSCRIBE_ACTION = "subscribe";
String DISCONNECT_ACTION = "disconnect";
String CONNECT_ACTION = "connect";
String CONNECT_EXTENDED_ACTION = "connectExtended";
String MESSAGE_ARRIVED_ACTION = "messageArrived";
String MESSAGE_DELIVERED_ACTION = "messageDelivered";
String ON_CONNECTION_LOST_ACTION = "onConnectionLost";
String TRACE_ACTION = "trace";
/* Identifies an Intent which calls back to the Activity */
String CALLBACK_TO_ACTIVITY = MqttService.TAG
+ ".callbackToActivity"+"."+VERSION;
/* Identifiers for extra data on Intents broadcast to the Activity */
String CALLBACK_ACTION = MqttService.TAG + ".callbackAction";
String CALLBACK_STATUS = MqttService.TAG + ".callbackStatus";
String CALLBACK_CLIENT_HANDLE = MqttService.TAG + "."
+ CLIENT_HANDLE;
String CALLBACK_ERROR_MESSAGE = MqttService.TAG
+ ".errorMessage";
String CALLBACK_EXCEPTION_STACK = MqttService.TAG
+ ".exceptionStack";
String CALLBACK_INVOCATION_CONTEXT = MqttService.TAG + "."
+ "invocationContext";
String CALLBACK_ACTIVITY_TOKEN = MqttService.TAG + "."
+ "activityToken";
String CALLBACK_DESTINATION_NAME = MqttService.TAG + '.'
+ DESTINATION_NAME;
String CALLBACK_MESSAGE_ID = MqttService.TAG + '.'
+ MESSAGE_ID;
String CALLBACK_RECONNECT = MqttService.TAG + ".reconnect";
String CALLBACK_SERVER_URI = MqttService.TAG + ".serverURI";
String CALLBACK_MESSAGE_PARCEL = MqttService.TAG + ".PARCEL";
String CALLBACK_TRACE_SEVERITY = MqttService.TAG
+ ".traceSeverity";
String CALLBACK_TRACE_TAG = MqttService.TAG + ".traceTag";
String CALLBACK_TRACE_ID = MqttService.TAG + ".traceId";
String CALLBACK_ERROR_NUMBER = MqttService.TAG
+ ".ERROR_NUMBER";
String CALLBACK_EXCEPTION = MqttService.TAG + ".exception";
//Intent prefix for Ping sender.
String PING_SENDER = MqttService.TAG + ".pingSender.";
//Constant for wakelock
String PING_WAKELOCK = MqttService.TAG + ".client.";
String WAKELOCK_NETWORK_INTENT = MqttService.TAG + "";
//Trace severity levels
String TRACE_ERROR = "error";
String TRACE_DEBUG = "debug";
String TRACE_EXCEPTION = "exception";
//exception code for non MqttExceptions
int NON_MQTT_EXCEPTION = -1;
}

View File

@ -0,0 +1,252 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttWireMessage;
/**
* <p>
* Implementation of the IMqttToken interface for use from within the
* MqttAndroidClient implementation
*/
class MqttTokenAndroid implements IMqttToken {
private IMqttActionListener listener;
private volatile boolean isComplete;
private volatile MqttException lastException;
private Object waitObject = new Object();
private MqttAndroidClient client;
private Object userContext;
private String[] topics;
private IMqttToken delegate; // specifically for getMessageId
private MqttException pendingException;
/**
* Standard constructor
*
* @param client used to pass MqttAndroidClient object
* @param userContext used to pass context
* @param listener optional listener that will be notified when the action completes. Use null if not required.
*/
MqttTokenAndroid(MqttAndroidClient client,
Object userContext, IMqttActionListener listener) {
this(client, userContext, listener, null);
}
/**
* Constructor for use with subscribe operations
*
* @param client used to pass MqttAndroidClient object
* @param userContext used to pass context
* @param listener optional listener that will be notified when the action completes. Use null if not required.
* @param topics topics to subscribe to, which can include wildcards.
*/
MqttTokenAndroid(MqttAndroidClient client,
Object userContext, IMqttActionListener listener, String[] topics) {
this.client = client;
this.userContext = userContext;
this.listener = listener;
this.topics = topics;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#waitForCompletion()
*/
@Override
public void waitForCompletion() throws MqttException, MqttSecurityException {
synchronized (waitObject) {
try {
waitObject.wait();
}
catch (InterruptedException e) {
// do nothing
}
}
if (pendingException != null) {
throw pendingException;
}
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#waitForCompletion(long)
*/
@Override
public void waitForCompletion(long timeout) throws MqttException,
MqttSecurityException {
synchronized (waitObject) {
try {
waitObject.wait(timeout);
}
catch (InterruptedException e) {
// do nothing
}
if (!isComplete) {
throw new MqttException(MqttException.REASON_CODE_CLIENT_TIMEOUT);
}
if (pendingException != null) {
throw pendingException;
}
}
}
/**
* notify successful completion of the operation
*/
void notifyComplete() {
synchronized (waitObject) {
isComplete = true;
waitObject.notifyAll();
if (listener != null) {
listener.onSuccess(this);
}
}
}
/**
* notify unsuccessful completion of the operation
*/
void notifyFailure(Throwable exception) {
synchronized (waitObject) {
isComplete = true;
if (exception instanceof MqttException) {
pendingException = (MqttException) exception;
}
else {
pendingException = new MqttException(exception);
}
waitObject.notifyAll();
if (exception instanceof MqttException) {
lastException = (MqttException) exception;
}
if (listener != null) {
listener.onFailure(this, exception);
}
}
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#isComplete()
*/
@Override
public boolean isComplete() {
return isComplete;
}
void setComplete(boolean complete) {
isComplete = complete;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getException()
*/
@Override
public MqttException getException() {
return lastException;
}
void setException(MqttException exception) {
lastException = exception;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getClient()
*/
@Override
public IMqttAsyncClient getClient() {
return client;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#setActionCallback(IMqttActionListener)
*/
@Override
public void setActionCallback(IMqttActionListener listener) {
this.listener = listener;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getActionCallback()
*/
@Override
public IMqttActionListener getActionCallback() {
return listener;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getTopics()
*/
@Override
public String[] getTopics() {
return topics;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#setUserContext(Object)
*/
@Override
public void setUserContext(Object userContext) {
this.userContext = userContext;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getUserContext()
*/
@Override
public Object getUserContext() {
return userContext;
}
void setDelegate(IMqttToken delegate) {
this.delegate = delegate;
}
/**
* @see org.eclipse.paho.client.mqttv3.IMqttToken#getMessageId()
*/
@Override
public int getMessageId() {
return (delegate != null) ? delegate.getMessageId() : 0;
}
@Override
public MqttWireMessage getResponse() {
return delegate.getResponse();
}
@Override
public boolean getSessionPresent() {
return delegate.getSessionPresent();
}
@Override
public int[] getGrantedQos() {
return delegate.getGrantedQos();
}
}

View File

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
/**
* Interface for simple trace handling, pass the trace message to trace
* callback.
*
*/
public interface MqttTraceHandler {
/**
* Trace debugging information
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
*/
void traceDebug(String tag, String message);
/**
* Trace error information
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
*/
void traceError(String tag, String message);
/**
* trace exceptions
*
* @param tag
* identifier for the source of the trace
* @param message
* the text to be traced
* @param e
* the exception
*/
void traceException(String tag, String message,
Exception e);
}

View File

@ -0,0 +1,119 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import android.os.Parcel;
import android.os.Parcelable;
/**
* <p>
* A way to flow MqttMessages via Bundles/Intents
* </p>
*
* <p>
* An application will probably use this only when receiving a message from a
* Service in a Bundle - the necessary code will be something like this :-
* </p>
* <pre>
* <code>
* private void messageArrivedAction(Bundle data) {
* ParcelableMqttMessage message = (ParcelableMqttMessage) data
* .getParcelable(MqttServiceConstants.CALLBACK_MESSAGE_PARCEL);
* <i>Use the normal {@link MqttMessage} methods on the the message object.</i>
* }
*
* </code>
* </pre>
*
* <p>
* It is unlikely that an application will directly use the methods which are
* specific to this class.
* </p>
*/
public class ParcelableMqttMessage extends MqttMessage implements Parcelable {
String messageId = null;
ParcelableMqttMessage(MqttMessage original) {
super(original.getPayload());
setQos(original.getQos());
setRetained(original.isRetained());
setDuplicate(original.isDuplicate());
}
ParcelableMqttMessage(Parcel parcel) {
super(parcel.createByteArray());
setQos(parcel.readInt());
boolean[] flags = parcel.createBooleanArray();
setRetained(flags[0]);
setDuplicate(flags[1]);
messageId = parcel.readString();
}
/**
* @return the messageId
*/
public String getMessageId() {
return messageId;
}
/**
* Describes the contents of this object
*/
@Override
public int describeContents() {
return 0;
}
/**
* Writes the contents of this object to a parcel
*
* @param parcel
* The parcel to write the data to.
* @param flags
* this parameter is ignored
*/
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeByteArray(getPayload());
parcel.writeInt(getQos());
parcel.writeBooleanArray(new boolean[]{isRetained(), isDuplicate()});
parcel.writeString(messageId);
}
/**
* A creator which creates the message object from a parcel
*/
public static final Parcelable.Creator<ParcelableMqttMessage> CREATOR = new Parcelable.Creator<ParcelableMqttMessage>() {
/**
* Creates a message from the parcel object
*/
@Override
public ParcelableMqttMessage createFromParcel(Parcel parcel) {
return new ParcelableMqttMessage(parcel);
}
/**
* creates an array of type {@link ParcelableMqttMessage}[]
*
*/
@Override
public ParcelableMqttMessage[] newArray(int size) {
return new ParcelableMqttMessage[size];
}
};
}

View File

@ -0,0 +1,55 @@
package org.eclipse.paho.android.service;
import org.eclipse.paho.client.mqttv3.MqttPingSender;
import org.eclipse.paho.client.mqttv3.internal.ClientComms;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class RitoPingSender implements MqttPingSender {
private ClientComms comms;
private ScheduledExecutorService scheduler;
private ScheduledFuture<?> pingFuture;
@Override
public void init(ClientComms comms) {
this.comms = comms;
this.scheduler = Executors.newSingleThreadScheduledExecutor();
}
@Override
public void start() {
schedule(comms.getKeepAlive());
}
private void schedule(int delayInSeconds) {
pingFuture = scheduler.scheduleAtFixedRate(() -> {
try {
comms.checkForActivity();
} catch (Exception e) {
e.printStackTrace();
}
}, delayInSeconds, delayInSeconds, TimeUnit.SECONDS);
}
@Override
public void stop() {
if (pingFuture != null) pingFuture.cancel(true);
scheduler.shutdownNow();
}
@Override
public void schedule(long delayInMilliseconds) {
if (pingFuture != null) pingFuture.cancel(true);
pingFuture = scheduler.schedule(() -> {
try {
comms.checkForActivity();
} catch (Exception e) {
e.printStackTrace();
}
}, delayInMilliseconds, TimeUnit.MILLISECONDS);
}
}

View File

@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 1999, 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.eclipse.paho.android.service;
/**
* Enumeration representing the success or failure of an operation
*/
enum Status {
/**
* Indicates that the operation succeeded
*/
OK,
/**
* Indicates that the operation failed
*/
ERROR,
/**
* Indicates that the operation's result may be returned asynchronously
*/
NO_RESULT
}

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 버튼이 눌렸을 때 -->
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#FF018786" />
<stroke android:width="4dp" android:color="#FF6200EE" />
</shape>
</item> <!-- 버튼이 안 눌렸을 때(디폴트) -->
<item android:state_focused="true">
<shape android:shape="rectangle">
<solid android:color="#FFA3AAA5" />
<stroke android:width="4dp" android:color="#FFAA0022" />
</shape>
</item> <!-- FOCUSSED -->
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="#FFA3AAA5" />
<stroke android:width="2dp" android:color="#000000" />
</shape>
</item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,203 @@
<?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:layout_x="300px"
android:layout_y="200px"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
</WebView>
<TextureView
android:id="@+id/texturePlayView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<ImageView
android:id="@+id/imageViewLoading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:contentDescription="@string/default_desc"
android:visibility="visible"
app:srcCompat="@drawable/webview_loading" />
<TextView
android:id="@+id/textViewCarcast"
android:layout_width="510px"
android:layout_height="70px"
android:layout_marginStart="0px"
android:layout_marginTop="0px"
android:background="#80F6F1F1"
android:gravity="center_vertical"
android:text="재난방송명"
android:textColor="#050505"
android:textSize="35px"
android:textStyle="bold"
android:visibility="invisible" />
<ImageView
android:id="@+id/imageViewWait"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/default_desc"
android:visibility="visible"
app:srcCompat="@drawable/wait_broadcast" />
<ImageView
android:id="@+id/imageViewDemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/default_desc"
android:visibility="invisible"
app:srcCompat="@drawable/demo_119" />
<ImageView
android:id="@+id/imageViewTts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:contentDescription="@string/default_desc"
android:visibility="visible"
app:srcCompat="@drawable/on_tts" />
<ImageView
android:id="@+id/imageViewBlack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:srcCompat="@drawable/blackground" />
<ImageView
android:id="@+id/imageViewChannelOsd"
android:layout_width="400px"
android:layout_height="90px"
android:layout_marginLeft="80px"
android:layout_marginTop="50px"
android:visibility="invisible"
app:srcCompat="@drawable/channel_osd" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="920px"
android:layout_marginTop="500px"
android:scaleX="2"
android:scaleY="2"
android:visibility="invisible" />
<SurfaceView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
<TextView
android:id="@+id/textViewChannelOsd"
android:layout_width="310px"
android:layout_height="90px"
android:layout_marginLeft="170px"
android:layout_marginTop="50px"
android:gravity="center"
android:text="채널명"
android:textAlignment="center"
android:textColor="#050505"
android:textSize="35px"
android:textStyle="bold"
android:visibility="invisible" />
<TextView
android:id="@+id/textViewTicker"
android:layout_width="1920px"
android:layout_height="wrap_content"
android:layout_marginLeft="0px"
android:alpha="0"
android:background="#80000000"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:gravity="center"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#ff4500"
android:textSize="140px" />
<!--<kr.co.rito.osicmanager.TickerView
android:id="@+id/tickerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />-->
</FrameLayout>
<FrameLayout
android:id="@+id/layoutCommand"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/imageViewCmdBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:srcCompat="@drawable/blackground" />
<SurfaceView
android:id="@+id/surfaceViewCmd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible" />
</FrameLayout>
<FrameLayout
android:id="@+id/layoutAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textViewAlert"
android:layout_width="700px"
android:layout_height="400px"
android:layout_marginLeft="600px"
android:layout_marginTop="300px"
android:background="#CC281F4E"
android:gravity="center"
android:text="TextView"
android:textColor="#FFFFFF"
android:textSize="34sp"
android:visibility="visible" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
tools:context=".SettingActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="?actionBarSize"
android:padding="@dimen/appbar_padding"
android:text="설 정"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textColor="#FFFFFF"
android:textSize="64px" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:tabGravity="fill"
app:tabMaxWidth="0dp"
app:tabMode="fixed"
app:tabTextAppearance="@style/MineCustomTabText" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:visibility="invisible"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,399 @@
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.PlaceholderFragment">
<FrameLayout
android:id="@+id/layoutServer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="800px"
android:layout_height="100px"
android:layout_marginLeft="100px"
android:layout_marginTop="20px"
android:gravity="left|center_vertical"
android:text="SERVER SETTING"
android:textColor="#000000"
android:textSize="90px" />
<EditText
android:id="@+id/editTextServerIpValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="150px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<EditText
android:id="@+id/editTextServerPortValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="260px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewServerIp"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="150px"
android:gravity="right|center_vertical"
android:text="IP"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewServerPort"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="260px"
android:gravity="right|center_vertical"
android:text="Port"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:layout_width="800px"
android:layout_height="100px"
android:layout_marginLeft="100px"
android:layout_marginTop="450px"
android:gravity="left|center_vertical"
android:text="UPDATE SETTING"
android:textColor="#000000"
android:textSize="90px" />
<TextView
android:id="@+id/textViewUpdateUrl"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="590px"
android:gravity="right|center_vertical"
android:text="ADDRESS"
android:textColor="#000000"
android:textSize="70px" />
<EditText
android:id="@+id/editTextUpdateUrlValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="590px"
android:background="#CDDC39"
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="textUri"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="60px" />
<Button
android:id="@+id/buttonApplyServer"
android:layout_width="300px"
android:layout_height="100px"
android:layout_marginLeft="1340px"
android:layout_marginTop="750px"
android:text="Apply"
android:textColor="#000000"
android:textSize="50px" />
</FrameLayout>
<FrameLayout
android:id="@+id/layoutNetwork"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/editTextNetDnsValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="490px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<EditText
android:id="@+id/editTextNetGatewayValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="380px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<EditText
android:id="@+id/editTextNetmaskValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="270px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<EditText
android:id="@+id/editTextNetIpValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="160px"
android:background="#CDDC39"
android:digits="0123456789."
android:gravity="left|center_vertical"
android:imeOptions="actionDone"
android:inputType="number"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<RadioGroup
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="50px"
android:background="#CDDC39"
android:gravity="center_vertical"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioButtonStatic"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="STATIC"
android:textSize="64px" />
<RadioButton
android:id="@+id/radioButtonDhcp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="DHCP"
android:textSize="64px" />
</RadioGroup>
<TextView
android:id="@+id/textViewNetDns"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="490px"
android:gravity="right|center_vertical"
android:text="DNS"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewNetGateway"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="380px"
android:gravity="right|center_vertical"
android:text="Gateway"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewNetmask"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="270px"
android:gravity="right|center_vertical"
android:text="Netmask"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewNetIp"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="160px"
android:gravity="right|center_vertical"
android:text="IP"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewNetIpType"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="50px"
android:gravity="right|center_vertical"
android:text="IPType"
android:textColor="#000000"
android:textSize="70px" />
<Button
android:id="@+id/buttonApplyNetwork"
android:layout_width="300px"
android:layout_height="100px"
android:layout_marginLeft="1340px"
android:layout_marginTop="600px"
android:text="Apply"
android:textColor="#000000"
android:textSize="50px"/>
</FrameLayout>
<FrameLayout
android:id="@+id/layoutInfo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textViewInfoMac"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="270px"
android:gravity="right|center_vertical"
android:text="Mac"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewInfoMacValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="270px"
android:background="#CDDC39"
android:gravity="left|center_vertical"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewInfoSerial"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="160px"
android:gravity="right|center_vertical"
android:text="Serial"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewInfoSerialValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="160px"
android:background="#CDDC39"
android:gravity="left|center_vertical"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewInfoIp"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="380px"
android:gravity="right|center_vertical"
android:text="IP"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewInfoIpValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="380px"
android:background="#CDDC39"
android:gravity="left|center_vertical"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewVersion"
android:layout_width="400px"
android:layout_height="100px"
android:layout_marginTop="50px"
android:gravity="right|center_vertical"
android:text="Version"
android:textColor="#000000"
android:textSize="70px" />
<TextView
android:id="@+id/textViewVersionValue"
android:layout_width="1200px"
android:layout_height="100px"
android:layout_marginLeft="440px"
android:layout_marginTop="50px"
android:background="#CDDC39"
android:gravity="left|center_vertical"
android:paddingStart="30px"
android:textColor="#000000"
android:textSize="70px" />
</FrameLayout>
<TextView
android:id="@+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:visibility="invisible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="appbar_padding">16dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="appbar_padding_top">8dp</dimen>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<string name="app_name">OsicManager</string>
<string name="default_desc">Image Desc</string>
<string name="title_activity_setting">SettingActivity</string>
<string name="tab_text_1">기기 정보</string>
<string name="tab_text_2">네트워크 설정</string>
<string name="tab_text_3">서버 설정</string>
</resources>

View File

@ -0,0 +1,34 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowNoTitle">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" >
<item name="windowNoTitle">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
<item name="windowNoTitle">true</item>
<item name="android:windowNoTitle">true</item>
</style>
<style name="MineCustomTabText" parent="TextAppearance.Design.Tab">
<item name="android:textSize">48px</item>
<item name="android:layout_marginHorizontal">100px</item>
</style>
</resources>

View File

@ -0,0 +1,17 @@
package kr.co.rito.osicmanager;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

53
build.gradle Normal file
View File

@ -0,0 +1,53 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
//classpath 'com.android.tools.build:gradle:4.0.1'
classpath "com.android.tools.build:gradle:7.0.2"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
// gradle.projectsEvaluated {
// tasks.withType(JavaCompile) {
// options.compilerArgs.add('-Xbootclasspath/p:app/libs/ritocls.jar')
// }
// }
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\ritocls.jar')
}
// After Android 4.2.x
tasks.withType(JavaCompile) {
Set<File> fileSet = options.bootstrapClasspath.getFiles()
List<File> newFileList = new ArrayList<>();
newFileList.add(new File("./app/libs/ritocls.jar"))
newFileList.addAll(fileSet)
options.bootstrapClasspath = files(
newFileList.toArray()
)
}
}
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

20
gradle.properties Normal file
View File

@ -0,0 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

2
settings.gradle Normal file
View File

@ -0,0 +1,2 @@
rootProject.name='OsicManager'
include ':app'