first commit and add gitignore, README.md

This commit is contained in:
ChesterTseng 2016-06-04 19:09:35 +08:00
commit 760756ba2c
1861 changed files with 709236 additions and 0 deletions

Binary file not shown.

View file

@ -0,0 +1 @@
#Wed Aug 19 11:42:54 CST 2015

View file

@ -0,0 +1 @@
UartThrough_merge_ok_20150818

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View file

@ -0,0 +1,3 @@
<component name="CopyrightManager">
<settings default="" />
</component>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.7" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View file

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="support-v4-19.1.0">
<CLASSES>
<root url="jar://C:/adt-bundle-windows-x86-20130729/sdk/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://C:/adt-bundle-windows-x86-20130729/sdk/extras/android/m2repository/com/android/support/support-v4/19.1.0/support-v4-19.1.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.7</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/UartThrough.iml" filepath="$PROJECT_DIR$/UartThrough.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

View file

@ -0,0 +1,5 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="" />
</component>
</project>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="UartThrough" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="UartThrough" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-v4-19.1.0" level="project" />
</component>
</module>

View file

@ -0,0 +1,23 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 20
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.realtek.uartthrough"
minSdkVersion 8
targetSdkVersion 19
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile 'com.android.support:support-v4:20.0.0'
}

View file

@ -0,0 +1,13 @@
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.realtek.uartthrough.test;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.realtek.uartthrough.test";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = -1;
public static final String VERSION_NAME = "";
}

View file

@ -0,0 +1,13 @@
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.realtek.uartthrough;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.realtek.uartthrough";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "";
}

View file

@ -0,0 +1,92 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.realtek.uartthrough;
public final class R {
public static final class attr {
}
public static final class dimen {
public static final int activity_horizontal_margin=0x7f040000;
public static final int activity_vertical_margin=0x7f040001;
}
public static final class drawable {
public static final int add=0x7f020000;
public static final int ameba_group=0x7f020001;
public static final int back=0x7f020002;
public static final int bg_index01=0x7f020003;
public static final int bg_index1=0x7f020004;
public static final int device=0x7f020005;
public static final int ic_launcher=0x7f020006;
public static final int logo=0x7f020007;
public static final int logo1=0x7f020008;
public static final int search=0x7f020009;
public static final int setting=0x7f02000a;
}
public static final class id {
public static final int APPTitle=0x7f080003;
public static final int APPimageView=0x7f08000c;
public static final int action_settings=0x7f08001b;
public static final int btn_back=0x7f080002;
public static final int btn_scanDevices=0x7f08000d;
public static final int btn_send=0x7f080009;
public static final int btn_setting=0x7f08000e;
public static final int btn_setting_apply=0x7f08001a;
public static final int btn_setting_cancel=0x7f080014;
public static final int btn_setting_ungroup=0x7f080013;
public static final int chatDisplay=0x7f080006;
public static final int chat_ScrollView=0x7f080005;
public static final int debugLayout=0x7f08000a;
public static final int editTx_send=0x7f080008;
public static final int gridview_list=0x7f08000f;
public static final int item_image=0x7f080010;
public static final int item_text=0x7f080011;
public static final int item_text_info=0x7f080012;
public static final int layer1_linear0=0x7f080001;
public static final int layer1_linear2=0x7f080004;
public static final int layer1_linear3=0x7f080007;
public static final int mainlayout=0x7f080000;
public static final int spinner_baudrate=0x7f080015;
public static final int spinner_data=0x7f080016;
public static final int spinner_flowcontrol=0x7f080019;
public static final int spinner_parity=0x7f080017;
public static final int spinner_stopbit=0x7f080018;
public static final int text_test=0x7f08000b;
}
public static final class layout {
public static final int activity_chat=0x7f030000;
public static final int activity_main=0x7f030001;
public static final int layout_item=0x7f030002;
public static final int layout_item_setting=0x7f030003;
public static final int setting_group=0x7f030004;
public static final int setting_serialport=0x7f030005;
}
public static final class menu {
public static final int chat=0x7f070000;
public static final int main=0x7f070001;
}
public static final class string {
public static final int action_settings=0x7f060000;
public static final int app_name=0x7f060001;
public static final int hello_world=0x7f060002;
public static final int title_activity_chat=0x7f060003;
}
public static final class style {
/** API 11 theme customizations can go here.
API 14 theme customizations can go here.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
*/
public static final int AppBaseTheme=0x7f050000;
/** All customizations that are NOT specific to a particular API-level can go here.
*/
public static final int AppTheme=0x7f050001;
}
}

View file

@ -0,0 +1,18 @@
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.support.v4">
<uses-sdk android:minSdkVersion="4"/>
<application/>
</manifest>

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.support.v4.app;
import android.app.Notification;
/**
* Interface used for delivering notifications via a side channel that bypasses
* the NotificationManagerService.
*
* @hide
*/
oneway interface INotificationSideChannel {
/**
* Send an ambient notification to the service.
*/
void notify(String packageName, int id, String tag, in Notification notification);
/**
* Cancel an already-notified notification.
*/
void cancel(String packageName, int id, String tag);
/**
* Cancel all notifications for the given package.
*/
void cancelAll(String packageName);
}

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\androidTest\assets"/></dataSet></merger>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="20.0.0"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\intermediates\exploded-aar\com.android.support\support-v4\20.0.0\assets"/></dataSet><dataSet config="main"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\assets"/></dataSet><dataSet config="debug"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\debug\assets"/></dataSet></merger>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\androidTest\res"/><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\generated\res\rs\androidTest\debug"/><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\generated\res\generated\androidTest\debug"/></dataSet><mergedItems/></merger>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="20.0.0"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\intermediates\exploded-aar\com.android.support\support-v4\20.0.0\res"/></dataSet><dataSet config="main"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res"><file name="add" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\add.png" qualifiers="" type="drawable"/><file name="ameba_group" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\ameba_group.png" qualifiers="" type="drawable"/><file name="back" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\back.png" qualifiers="" type="drawable"/><file name="bg_index01" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\bg_index01.png" qualifiers="" type="drawable"/><file name="bg_index1" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\bg_index1.png" qualifiers="" type="drawable"/><file name="device" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\device.png" qualifiers="" type="drawable"/><file name="logo" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\logo.png" qualifiers="" type="drawable"/><file name="logo1" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\logo1.png" qualifiers="" type="drawable"/><file name="search" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\search.png" qualifiers="" type="drawable"/><file name="setting" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable\setting.png" qualifiers="" type="drawable"/><file name="ic_launcher" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable-hdpi\ic_launcher.png" qualifiers="hdpi" type="drawable"/><file name="ic_launcher" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable-mdpi\ic_launcher.png" qualifiers="mdpi" type="drawable"/><file name="ic_launcher" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable-xhdpi\ic_launcher.png" qualifiers="xhdpi" type="drawable"/><file name="ic_launcher" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\drawable-xxhdpi\ic_launcher.png" qualifiers="xxhdpi" type="drawable"/><file name="activity_chat" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\activity_chat.xml" qualifiers="" type="layout"/><file name="activity_main" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\activity_main.xml" qualifiers="" type="layout"/><file name="layout_item" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\layout_item.xml" qualifiers="" type="layout"/><file name="layout_item_setting" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\layout_item_setting.xml" qualifiers="" type="layout"/><file name="setting_group" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\setting_group.xml" qualifiers="" type="layout"/><file name="setting_serialport" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\layout\setting_serialport.xml" qualifiers="" type="layout"/><file name="chat" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\menu\chat.xml" qualifiers="" type="menu"/><file name="main" path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\menu\main.xml" qualifiers="" type="menu"/><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values\dimens.xml" qualifiers=""><dimen name="activity_horizontal_margin">16dp</dimen><dimen name="activity_vertical_margin">16dp</dimen></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values\strings.xml" qualifiers=""><string name="title_activity_chat">ChatActivity</string><string name="action_settings">Settings</string><string name="app_name">UartThrough</string><string name="hello_world">Hello world!</string></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values\styles.xml" qualifiers=""><style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style><style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values-sw720dp-land\dimens.xml" qualifiers="sw720dp-land"><dimen name="activity_horizontal_margin">128dp</dimen></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values-v11\styles.xml" qualifiers="v11"><style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values-v14\styles.xml" qualifiers="v14"><style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style></file><file path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\main\res\values-w820dp\dimens.xml" qualifiers="w820dp"><dimen name="activity_horizontal_margin">64dp</dimen></file></source><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\generated\res\rs\debug"/><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\build\generated\res\generated\debug"/></dataSet><dataSet config="debug"><source path="D:\branch\v3.3a\tools\uart_adapter\app\android\UartThrough\app\src\debug\res"/></dataSet><mergedItems/></merger>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.realtek.uartthrough.test">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" />
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.realtek.uartthrough"
android:handleProfiling="false"
android:functionalTest="false"
android:label="Tests for com.realtek.uartthrough"/>
</manifest>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.realtek.uartthrough"
android:versionCode="1"
android:versionName="1.0.1.20150408" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE"
android:required="true" />
<uses-permission
android:name="android.permission.CHANGE_WIFI_STATE"
android:required="true" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"
android:required="true" />
<uses-permission
android:name="android.permission.INTERNET"
android:required="true" />
<uses-permission
android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
android:required="true" />
<uses-permission
android:name="android.permission.CHANGE_NETWORK_STATE"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.realtek.uartthrough.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.realtek.uartthrough.ChatActivity"
android:label="@string/title_activity_chat" >
</activity>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/mainlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/layer1_linear0"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:background="@drawable/bg_index01"
android:layout_weight="1">
<ImageButton
android:id="@+id/btn_back"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="2dp"
android:src="@drawable/back"/>
<TextView
android:id="@+id/APPTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="1.75"
android:gravity="left"
android:paddingLeft="20dp"
android:text="Let us just chat"
android:textColor="@android:color/black"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layer1_linear2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:background="@drawable/bg_index1"
android:layout_weight="8">
<ScrollView
android:id="@+id/chat_ScrollView"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:background="#ffeeeeee"
android:fillViewport="false" >
<TextView
android:id="@+id/chatDisplay"
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dp"
android:background="#ffffffff"
android:focusable="true"
android:focusableInTouchMode="true"/>
</ScrollView>
</LinearLayout>
<LinearLayout
android:id="@+id/layer1_linear3"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<EditText
android:id="@+id/editTx_send"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="0.52"
android:clickable="true"
android:ems="10"
android:enabled="true"
android:text=""
android:textSize="14dp" />
<Button
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="Send" />
</LinearLayout>
<LinearLayout
android:id="@+id/debugLayout"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:background="#FFFFFF"
android:layout_weight="0">
<TextView
android:id="@+id/text_test"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=""
android:textSize="12sp"
android:maxLines = "9999999"
android:scrollbars = "vertical"/>
</LinearLayout>
</LinearLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/activity_chat.xml -->

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/mainlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/layer1_linear0"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:background="@drawable/bg_index01"
android:layout_weight="1">
<ImageView
android:id="@+id/APPimageView"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="2dp"
android:src="@drawable/logo"/>
<TextView
android:id="@+id/APPTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="3"
android:gravity="left"
android:paddingLeft="20dp"
android:text="Uart Through"
android:textColor="@android:color/black"
android:textSize="16sp" />
<ImageButton
android:id="@+id/btn_scanDevices"
android:contentDescription="@string/app_name"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="5dp"
android:layout_margin= "1dp"
android:src="@drawable/search"/>
<!--ImageButton
android:id="@+id/btn_addDevice"
android:contentDescription="@string/app_name"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="5dp"
android:layout_margin= "1dp"
android:src="@drawable/add"/-->
<ImageButton
android:id="@+id/btn_setting"
android:contentDescription="@string/app_name"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="5dp"
android:layout_margin= "1dp"
android:src="@drawable/setting"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layer1_linear2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:background="@drawable/bg_index1"
android:layout_weight="8">
<GridView
android:id="@+id/gridview_list"
android:listSelector="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:numColumns="2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="35dp"
android:gravity="center"
android:layout_gravity="center"
android:columnWidth="50pt"
android:stretchMode="columnWidth"
android:focusable="false"
android:focusableInTouchMode="false"/>
</LinearLayout>
</LinearLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/activity_main.xml -->

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent" >
<ImageView
android:id="@+id/item_image"
android:scaleType="centerCrop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" >
</ImageView>
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/item_image"
android:layout_centerHorizontal="true"
android:background="#22000000"
android:textSize="12sp"
android:ellipsize="middle"
android:singleLine="true"
android:maxEms="10"
>
</TextView>
<!-- com.realtek.myspeaker.SpeakerTextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/item_image"
android:layout_centerHorizontal="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever">
</com.realtek.myspeaker.SpeakerTextView-->
</RelativeLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/layout_item.xml -->

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent" >
<ImageView
android:id="@+id/item_image"
android:scaleType="centerCrop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" >
</ImageView>
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/item_image"
android:layout_centerHorizontal="true"
android:textSize="16sp"
>
</TextView>
<TextView
android:id="@+id/item_text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/item_text"
android:layout_centerHorizontal="true"
android:textSize="14sp"
>
</TextView>
<!-- com.realtek.myspeaker.SpeakerTextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/item_image"
android:layout_centerHorizontal="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever">
</com.realtek.myspeaker.SpeakerTextView-->
</RelativeLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/layout_item_setting.xml -->

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/background_light"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:layout_gravity="center"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<Button
android:id="@+id/btn_setting_ungroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Ungroup" />
<Button
android:id="@+id/btn_setting_cancel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Cancel" />"
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/setting_group.xml -->

View file

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/background_light"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="1dp"
android:layout_gravity="center"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<!-- ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical|center"
android:layout_weight="1"
android:src="@drawable/ic_launcher" /-->
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="3"
android:text="Serial Port Setup" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="3"
android:text="Baud Rate" />
<Spinner
android:id="@+id/spinner_baudrate"
android:spinnerMode="dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="3"
android:text="Data Bit" />
<Spinner
android:id="@+id/spinner_data"
android:spinnerMode="dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:text="Parity Bit" />
<Spinner
android:id="@+id/spinner_parity"
android:spinnerMode="dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_weight="3"
android:text="Stop Bit" />
<Spinner
android:id="@+id/spinner_stopbit"
android:spinnerMode="dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:text="Flow Control" />
<Spinner
android:id="@+id/spinner_flowcontrol"
android:spinnerMode="dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:layout_margin="1dp"
android:layout_gravity="center"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<Button
android:id="@+id/btn_setting_cancel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Cancel" />"
<Button
android:id="@+id/btn_setting_apply"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Apply" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout><!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/layout/setting_serialport.xml -->

View file

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/menu/chat.xml -->

View file

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/menu/main.xml -->

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/temp/android/mdis_discovery/UartThrough1/app/src/main/res/values-sw720dp-land/dimens.xml -->
<eat-comment/>
<dimen name="activity_horizontal_margin">128dp</dimen>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values-sw720dp-land/dimens.xml -->
<eat-comment/>
<dimen name="activity_horizontal_margin">128dp</dimen>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values-v11/styles.xml -->
<eat-comment/>
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/temp/android/mdis_discovery/UartThrough1/app/src/main/res/values-v11/styles.xml -->
<eat-comment/>
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values-v14/styles.xml -->
<eat-comment/>
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/temp/android/mdis_discovery/UartThrough1/app/src/main/res/values-v14/styles.xml -->
<eat-comment/>
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values-w820dp/dimens.xml -->
<eat-comment/>
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values/dimens.xml -->
<eat-comment/>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values/strings.xml -->
<eat-comment/>
<string name="action_settings">Settings</string>
<string name="app_name">UartThrough</string>
<string name="hello_world">Hello world!</string>
<string name="title_activity_chat">ChatActivity</string>
<!-- From: file:/D:/branch/v3.3a/tools/uart_adapter/app/android/UartThrough/app/src/main/res/values/styles.xml -->
<eat-comment/>
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View file

@ -0,0 +1,55 @@
int dimen activity_horizontal_margin 0x7f040000
int dimen activity_vertical_margin 0x7f040001
int drawable add 0x7f020000
int drawable ameba_group 0x7f020001
int drawable back 0x7f020002
int drawable bg_index01 0x7f020003
int drawable bg_index1 0x7f020004
int drawable device 0x7f020005
int drawable ic_launcher 0x7f020006
int drawable logo 0x7f020007
int drawable logo1 0x7f020008
int drawable search 0x7f020009
int drawable setting 0x7f02000a
int id APPTitle 0x7f080003
int id APPimageView 0x7f08000c
int id action_settings 0x7f08001b
int id btn_back 0x7f080002
int id btn_scanDevices 0x7f08000d
int id btn_send 0x7f080009
int id btn_setting 0x7f08000e
int id btn_setting_apply 0x7f08001a
int id btn_setting_cancel 0x7f080014
int id btn_setting_ungroup 0x7f080013
int id chatDisplay 0x7f080006
int id chat_ScrollView 0x7f080005
int id debugLayout 0x7f08000a
int id editTx_send 0x7f080008
int id gridview_list 0x7f08000f
int id item_image 0x7f080010
int id item_text 0x7f080011
int id item_text_info 0x7f080012
int id layer1_linear0 0x7f080001
int id layer1_linear2 0x7f080004
int id layer1_linear3 0x7f080007
int id mainlayout 0x7f080000
int id spinner_baudrate 0x7f080015
int id spinner_data 0x7f080016
int id spinner_flowcontrol 0x7f080019
int id spinner_parity 0x7f080017
int id spinner_stopbit 0x7f080018
int id text_test 0x7f08000b
int layout activity_chat 0x7f030000
int layout activity_main 0x7f030001
int layout layout_item 0x7f030002
int layout layout_item_setting 0x7f030003
int layout setting_group 0x7f030004
int layout setting_serialport 0x7f030005
int menu chat 0x7f070000
int menu main 0x7f070001
int string action_settings 0x7f060000
int string app_name 0x7f060001
int string hello_world 0x7f060002
int string title_activity_chat 0x7f060003
int style AppBaseTheme 0x7f050000
int style AppTheme 0x7f050001

View file

@ -0,0 +1,97 @@
-- Merging decision tree log ---
manifest
ADDED from AndroidManifest.xml:2:1
xmlns:tools
ADDED from AndroidManifest.xml:3:5
xmlns:android
ADDED from AndroidManifest.xml:2:11
package
ADDED from AndroidManifest.xml:4:5
INJECTED from AndroidManifest.xml:0:0
INJECTED from AndroidManifest.xml:0:0
android:versionName
ADDED from AndroidManifest.xml:6:5
android:versionCode
ADDED from AndroidManifest.xml:5:5
INJECTED from AndroidManifest.xml:0:0
INJECTED from AndroidManifest.xml:0:0
uses-sdk
ADDED from AndroidManifest.xml:8:5
MERGED from com.android.support:support-v4:20.0.0:16:5
android:targetSdkVersion
ADDED from AndroidManifest.xml:10:9
INJECTED from AndroidManifest.xml:0:0
INJECTED from AndroidManifest.xml:0:0
android:minSdkVersion
ADDED from AndroidManifest.xml:9:9
INJECTED from AndroidManifest.xml:0:0
INJECTED from AndroidManifest.xml:0:0
uses-permission#android.permission.ACCESS_WIFI_STATE
ADDED from AndroidManifest.xml:12:5
android:required
ADDED from AndroidManifest.xml:14:9
android:name
ADDED from AndroidManifest.xml:13:9
uses-permission#android.permission.CHANGE_WIFI_STATE
ADDED from AndroidManifest.xml:15:5
android:required
ADDED from AndroidManifest.xml:17:9
android:name
ADDED from AndroidManifest.xml:16:9
uses-permission#android.permission.ACCESS_NETWORK_STATE
ADDED from AndroidManifest.xml:18:5
android:required
ADDED from AndroidManifest.xml:19:9
android:name
ADDED from AndroidManifest.xml:20:9
uses-permission#android.permission.INTERNET
ADDED from AndroidManifest.xml:21:5
android:required
ADDED from AndroidManifest.xml:23:9
android:name
ADDED from AndroidManifest.xml:22:9
uses-permission#android.permission.CHANGE_WIFI_MULTICAST_STATE
ADDED from AndroidManifest.xml:24:5
android:required
ADDED from AndroidManifest.xml:25:9
android:name
ADDED from AndroidManifest.xml:26:9
uses-permission#android.permission.CHANGE_NETWORK_STATE
ADDED from AndroidManifest.xml:27:5
android:required
ADDED from AndroidManifest.xml:28:9
android:name
ADDED from AndroidManifest.xml:29:9
application
ADDED from AndroidManifest.xml:32:5
MERGED from com.android.support:support-v4:20.0.0:17:5
android:label
ADDED from AndroidManifest.xml:35:9
android:allowBackup
ADDED from AndroidManifest.xml:33:9
android:icon
ADDED from AndroidManifest.xml:34:9
android:theme
ADDED from AndroidManifest.xml:36:9
activity#com.realtek.uartthrough.MainActivity
ADDED from AndroidManifest.xml:38:9
android:label
ADDED from AndroidManifest.xml:40:13
android:name
ADDED from AndroidManifest.xml:39:13
intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER
ADDED from AndroidManifest.xml:41:13
action#android.intent.action.MAIN
ADDED from AndroidManifest.xml:42:17
android:name
ADDED from AndroidManifest.xml:42:25
category#android.intent.category.LAUNCHER
ADDED from AndroidManifest.xml:44:17
android:name
ADDED from AndroidManifest.xml:44:27
activity#com.realtek.uartthrough.ChatActivity
ADDED from AndroidManifest.xml:48:9
android:label
ADDED from AndroidManifest.xml:50:13
android:name
ADDED from AndroidManifest.xml:49:13

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<lint>
</lint>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.realtek.uartthrough"
android:versionCode="1"
android:versionName="1.0.1.20150408">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE"
android:required="true" />
<uses-permission
android:name="android.permission.CHANGE_WIFI_STATE"
android:required="true" />
<uses-permission
android:required="true"
android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission
android:name="android.permission.INTERNET"
android:required="true" />
<uses-permission
android:required="true"
android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission
android:required="true"
android:name="android.permission.CHANGE_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.realtek.uartthrough.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.realtek.uartthrough.ChatActivity"
android:label="@string/title_activity_chat" >
</activity>
</application>
</manifest>

View file

@ -0,0 +1,187 @@
package com.realtek.uartthrough;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
public class ChatActivity extends Activity {
//UI layout
private ImageButton btn_back;
private EditText editTx_send;
private Button btn_send;
private TextView text_chatDisplay;
private boolean rxThreadExit = false;
//Thread
private Thread rxThread = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_chat);
initData();
initComponent();
initComponentAction();
}
@Override
protected void onStart()
{
super.onStart();
rxThread = new Thread(){
@Override
public void run() {
//while(!isInterrupted()){
while(!rxThreadExit){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if(MainActivity.g_d.isReadable()) {
updateInfoDisplay(MainActivity.g_d.getInfo());
MainActivity.g_d.resetInfo();
MainActivity.g_d.setReadable(false);
}
}}
);
}
rxThreadExit = false;
Log.i("Sean debugging", "Chat rxThread exit");
}
};
rxThread.start();
}
@Override
protected void onStop() {
super.onStop();
if(rxThread != null){
//rxThread.interrupt();
rxThreadExit = true;
rxThread = null;
}
}
private void initData() {
// TODO Auto-generated method stub
}
private void initComponent() {
btn_back = (ImageButton) findViewById(R.id.btn_back);
editTx_send = (EditText) findViewById(R.id.editTx_send);
btn_send = (Button) findViewById(R.id.btn_send);
text_chatDisplay = (TextView) findViewById(R.id.chatDisplay);
SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
String date = df.format(Calendar.getInstance().getTime());
text_chatDisplay.append("========== "+date+" ==========\n");
editTx_send.setText("");
}
private void initComponentAction() {
btn_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.g_d.setCmd("stop");
MainActivity.g_d.resetInfo();
MainActivity.g_d.opStates().setOpState(MainActivity.g_d.opStates().stateAppStart());
Intent intent_Navigation = new Intent();
intent_Navigation.setClass(ChatActivity.this, MainActivity.class);
startActivity(intent_Navigation);
finish();
}
});
btn_send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(editTx_send.getText().toString().length()>0){
String text = editTx_send.getText().toString();
MainActivity.g_d.setTx(text);
MainActivity.g_d.setCmd("send");
//text_chatDisplay.setTextColor(Color.parseColor("#e54545"));
text_chatDisplay.append( Html.fromHtml(getCurrentTimeforHTML()) );
text_chatDisplay.append( Html.fromHtml( "<font color=\"#47a842\">[Me]" + text + "</font>" ) );
text_chatDisplay.append("\n");
editTx_send.setText("");
}
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
});
}
private void updateInfoDisplay(String recvStr) {
if(recvStr.length()>0){
String lines[] = recvStr.split("\\r?\\n");
for (int i = 0; i < lines.length; i++) {
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
//String date = df.format(Calendar.getInstance().getTime());
//text_chatDisplay.setTextColor(Color.parseColor("#8ebbeb"));
text_chatDisplay.append(Html.fromHtml(getCurrentTimeforHTML()));
text_chatDisplay.append(Html.fromHtml("<font color=\"#8ebbeb\">[Ameba]" + lines[i] + "</font>"));
text_chatDisplay.append("\n");
}
}
}
private String getCurrentTimeforHTML() {
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
String date = df.format(Calendar.getInstance().getTime());
String result = "<i><small><font color=\"#c5c5c5\">"+ date + "</font></small></i>";
return result;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.chat, menu);
return true;
}
}

View file

@ -0,0 +1,87 @@
package com.realtek.uartthrough;
//import java.io.Serializable;
public class DeviceManager {
public static enum CmdType {
/*SETUP,
CH_POS,
REMOVE,
TIP_G,
TIP,
RENAME,
TODO_FINISH,*/
DEFAULT
};
public static class DeviceInfo //implements Serializable
{
//private static final long serialVersionUID = 1L;
private int aliveFlag;
private String name;
private String name_small;
private String IP;
private int port;
private String macAdrress;
private int img;
public int getaliveFlag()
{
return this.aliveFlag;
}
public void setaliveFlag(int aliveFlag)
{
this.aliveFlag = aliveFlag;
}
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name= name;
}
public String getName_small()
{
return this.name_small;
}
public void setName_small(String name)
{
this.name_small= name;
}
public String getIP()
{
return this.IP;
}
public void setIP(String IP)
{
this.IP= IP;
}
public int getPort()
{
return this.port;
}
public void setPort(int port)
{
this.port= port;
}
public String getmacAdrress()
{
return this.macAdrress;
}
public void setmacAdrress(String macAdrress)
{
this.macAdrress= macAdrress;
}
public int getimg()
{
return this.img;
}
public void setimg(int speaker)
{
this.img= speaker;
}
}
}

View file

@ -0,0 +1,314 @@
package com.realtek.uartthrough;
import android.util.Log;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Objects;
import java.util.Vector;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.jmdns.ServiceInfo;
public class Globals_ctrl {
private static Globals_ctrl thisGlobal;
private static String infoDisplay = "";
private static final String mServiceName = "AMEBA";
private static final String TAG = "Globals_ctrl";
private static final String mServiceType = "_uart_control._tcp.local.";
private static boolean isResolveDone = false;
private static String successRec = "";
private static String sensorReadings = "";
private static Vector<ServiceInfo> deviceList = new Vector<ServiceInfo>();
private static InetAddress connIP = null;
private static int connPort=0;
private static String cmd="continue";
private static ByteBuffer tx = ByteBuffer.allocate(128);
private static byte[] recvBuffer = new byte[64];
private final Lock _mutex_recvBuf = new ReentrantLock(true);
private static OpStates os = OpStates.getInstance();
public Globals_ctrl(){}
public boolean isResolveFinish(){
return isResolveDone;
}
public void setResolveFinish(){
isResolveDone = true;
}
public void ResolveStatusReset(){
isResolveDone = false;
}
public void resetRecvBuffer(){
Arrays.fill( recvBuffer, (byte) 0 );
}
public boolean checkRecvBufUpdate(){
if(recvBuffer.length>0)
return true;
else
return false;
}
public void commitRecvBuffer(byte[] info, int len){
_mutex_recvBuf.lock();
resetRecvBuffer();
System.arraycopy(info, 0, recvBuffer, 0, len);
_mutex_recvBuf.unlock();
}
public String pullRecvBuffer(){
if(recvBuffer[0]<=0){
return "";
}else{
_mutex_recvBuf.lock();
byte [] res = new byte[recvBuffer.length];
System.arraycopy(recvBuffer, 0, res, 0, recvBuffer.length);
_mutex_recvBuf.unlock();
String controlInfo = parseRecvBuf(res);
return controlInfo;
}
}
private String parseRecvBuf(byte[] res) {
String result = "";
//check prefix
if(checkPrefix(res)){
int readbit = 10;
//-------- response for setting --------
if( convertirOctetEnEntier(res[readbit])==1 ){
result = "ok";
//-------- response for getting --------
}else if( convertirOctetEnEntier(res[readbit])==3 ){
readbit++;
int type = -1;
String str_len = "";
String str_HexValue = "";
do{
type = convertirOctetEnEntier(res[readbit]);
str_HexValue = Integer.toHexString(type);
if( type==1 ){//baudrate
result += "baudrate,";readbit++;
str_len = Integer.toHexString(convertirOctetEnEntier(res[readbit]));
int len = Integer.valueOf(str_len).intValue();
readbit++;
int bit = 0;
int v_rate = 0;
int tmp = 0;
for(int b=readbit;b<readbit+len;b++){
tmp = (res[b] & 0xFF) << (8*bit);
v_rate = v_rate + tmp ;
bit++;
}
result = result + String.valueOf(v_rate) + ";";readbit+=len;
}else if( type==2 ){//data
result += "data,";readbit++;
str_len = Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ",";
readbit++;
result = result + Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ";";readbit++;
}else if( type==4 ){//parity
result += "parity,";readbit++;
str_len = Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ",";
readbit++;
result = result + Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ";";readbit++;
}else if( type==8 ){//stopbit
result += "stopbit,";readbit++;
str_len = Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ",";
readbit++;
result = result + Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ";";readbit++;
}/*else if( type==16 ){//flowcontrol
result += "flowcontrol,";readbit++;
str_len = Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ",";
readbit++;
result = result + Integer.toHexString(convertirOctetEnEntier(res[readbit])) + ";";readbit++;
}*/else
readbit++;
}while(readbit<recvBuffer.length );
}
}else{
Log.e(TAG,"prefix error!!!");
}
return result;
}
private boolean checkPrefix(byte[] recvBuf) {
if("41".equals(String.format("0x%20x", recvBuf[0])) )
return false;
if("4D".equals(String.format("0x%20x", recvBuf[1])) )
return false;
if("45".equals(String.format("0x%20x", recvBuf[2])))
return false;
if("42".equals(String.format("0x%20x", recvBuf[3])))
return false;
if("41".equals(String.format("0x%20x", recvBuf[4])))
return false;
if("5F".equals(String.format("0x%20x", recvBuf[5])))
return false;
if("55".equals(String.format("0x%20x", recvBuf[6])))
return false;
if("41".equals(String.format("0x%20x", recvBuf[7])))
return false;
if("52".equals(String.format("0x%20x", recvBuf[8])))
return false;
if("54".equals(String.format("0x%20x", recvBuf[9])))
return false;
return true;
}
public String byte2bits(byte b) {
int z = b; z |= 256;
String str = Integer.toBinaryString(z);
int len = str.length();
return str.substring(len-8, len);
}
public int convertirOctetEnEntier(byte b){
int MASK = 0xFF;
int result = 0;
result = b & MASK;
return result;
}
public int byteArrayToInt(byte[] bytes) {
int value= 0;
for (int i = 0; i < 4; i++) {
int shift= (4 - 1 - i) * 8;
value +=(bytes[i] & 0x000000FF) << shift;
}
return value;
}
public void addInfo(String str){
infoDisplay+=(str+"\n");
}
public String getInfo(){
return infoDisplay;
}
public void resetInfo(){
infoDisplay="";
}
public String getServiceName(){
return mServiceName;
}
public String getServiceType(){
return mServiceType;
}
public String getSuccessRec(){
return successRec;
}
public void setSuccessRec(String str){
successRec=str;
}
public void setConnIP(InetAddress address){
connIP = address;
}
public InetAddress getConnIP(){
return connIP;
}
public void setConnPort(int p){
connPort=p;
}
public int getConnPort(){
return connPort;
}
public void setTx(byte bytes[]){
tx.put(bytes);
}
public byte[] getTx(){
return tx.array();
}
public void clearTx(){
tx.clear();
tx.put(new byte[128]);
tx.clear();
}
public void clearCmd(){
cmd="";
}
public void setCmd(String str){
cmd=str;
}
public String getCmd(){
return cmd;
}
public void clearDeviceList(){
deviceList.clear();
}
public Vector<ServiceInfo> getDeviceList(){
return deviceList;
}
public void addSensorReading(String reading){
sensorReadings = sensorReadings + reading;
}
public OpStates opStates(){
return os;
}
public static synchronized Globals_ctrl getInstance(){
if(thisGlobal==null){
thisGlobal = new Globals_ctrl();
}
return thisGlobal;
}
}

View file

@ -0,0 +1,152 @@
package com.realtek.uartthrough;
import java.net.InetAddress;
import java.util.Vector;
import javax.jmdns.ServiceInfo;
public class Globals_d {
private static Globals_d thisGlobal;
private static String infoDisplay_d = "";
private static boolean readable = false;
private static final String mServiceName = "AMEBA";
private static final String mServiceType = "_uart_data._tcp.local.";
private static boolean isResolveDone = false;
private static String successRec = "";
private static String sensorReadings = "";
private static Vector<ServiceInfo> deviceList = new Vector<ServiceInfo>();
private static InetAddress connIP = null;
private static int connPort=0;
private static String cmd="continue";
private static String tx="";
private static OpStates os = OpStates.getInstance();
public Globals_d(){}
public boolean isResolveFinish(){
return isResolveDone;
}
public void setResolveFinish(){
isResolveDone = true;
}
public void ResolveStatusReset(){
isResolveDone = false;
}
public boolean isReadable(){
return readable;
}
public void setReadable(boolean val){
readable = val;
}
public void addInfo(String str){
infoDisplay_d+=(str);
}
public String getInfo(){
return infoDisplay_d;
}
public void resetInfo(){
infoDisplay_d="";
}
public String getServiceName(){
return mServiceName;
}
public String getServiceType(){
return mServiceType;
}
public String getSuccessRec(){
return successRec;
}
public void setSuccessRec(String str){
successRec=str;
}
public void setConnIP(InetAddress address){
connIP = address;
}
public InetAddress getConnIP(){
return connIP;
}
public void setConnPort(int p){
connPort=p;
}
public int getConnPort(){
return connPort;
}
public void setTx(String str){
tx=str;
}
public String getTx(){
return tx;
}
public void clearTx(){
tx="";
}
public void clearCmd(){
cmd="";
}
public void setCmd(String str){
cmd=str;
}
public String getCmd(){
return cmd;
}
public void clearDeviceList(){
deviceList.clear();
}
public Vector<ServiceInfo> getDeviceList(){
return deviceList;
}
public void addSensorReading(String reading){
sensorReadings = sensorReadings + reading;
}
public OpStates opStates(){
return os;
}
public static synchronized Globals_d getInstance(){
if(thisGlobal==null){
thisGlobal = new Globals_d();
}
return thisGlobal;
}
}

View file

@ -0,0 +1,964 @@
package com.realtek.uartthrough;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.SimpleAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.realtek.uartthrough.DeviceManager.DeviceInfo;
import com.realtek.uartthrough.R;
public class MainActivity extends Activity {
//TAG
private final String TAG = "<uartthrough>";
private final String TAG_DISCOVER = "Discovery";
private final String TAG_UI_THREAD = "Update Ui thread";
//Number
public final int DEVICE_MAX_NUM = 32;
private boolean rcvThreadExit = false;
//UI Layout
//private TextView text_debug;
private ImageButton btn_scanDevices;
private ImageButton btn_setting;
private ProgressDialog pd;
private GridView gridView;
//UI Variable
private SimpleAdapter adapter_deviceInfo=null;
private SimpleAdapter adapter_deviceInfo_setting=null;
//Variable
public static DeviceInfo [] infoDevices;
public static Globals_d g_d = Globals_d.getInstance();
public int deviceNumberNow = 0;
private Globals_ctrl g_ctrl = Globals_ctrl.getInstance();
private boolean g_discoverEnable = false;
private List<HashMap<String, Object>> devInfoList = new ArrayList<HashMap<String, Object>>();
private NsdCore mNSD;
private String recvBuf = "";
//Thread
private UpdateUiThread uiThread;
private recvThread rcvThread=null;
private final Lock _gmutex_recvBuf = new ReentrantLock(true);
//TcpClient
private TcpClient dataClient;
private TcpClient ctrlClient;
//serial port Setting
byte[] cmdPrefix = new byte[]{0x41, 0x4D, 0x45, 0x42, 0x41, 0x5F, 0x55, 0x41, 0x52, 0x54};
String setting_rate = "";
String setting_data = "";
String setting_parity = "";
String setting_stopbit = "";
String setting_flowc = "";
String[] Setting_baudrate = {"1200", "9600", "14400"
, "19200", "28800", "38400", "57600"
, "76800", "115200", "128000", "153600"
, "230400", "460800", "500000", "921600"};
String[] Setting_data = {"7", "8"};
String[] Setting_parity = {"none", "odd", "even"};//0 , 1 , 2
String[] Setting_stopbit = {"none", "1 bit"};
String[] Setting_flowc = {"not support"};
Handler handler_pd = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 0:{
if(pd!=null)
pd.dismiss();
break;
}
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
@Override
protected void onStart()
{
super.onStart();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
initData();
initComponent();
initComponentAction();
if(rcvThread == null){
rcvThreadExit = false;
Log.i(TAG,"rcvThread create!!");
rcvThread = new recvThread();
rcvThread.start();
}
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "start onResume~~~");
if(g_d != null)
g_d.setCmd("stop");
}
@Override
protected void onStop() {
Log.i(TAG,"onStop!!");
rcvThreadExit = true;
if (mNSD!=null){
// mNSD.tearDown();
stopDiscover();
}
super.onStop();
}
@Override
protected void onDestroy() {
rcvThreadExit = true;
if (mNSD!=null){
// mNSD.tearDown();
stopDiscover();
}
super.onDestroy();
}
private void initData() {
if(infoDevices==null){
infoDevices = new DeviceInfo[DEVICE_MAX_NUM];
for(int i=0;i<DEVICE_MAX_NUM;i++)
{
infoDevices[i] = new DeviceInfo();
infoDevices[i].setaliveFlag(0);
infoDevices[i].setName("");
infoDevices[i].setName_small("");
infoDevices[i].setIP("");
infoDevices[i].setPort(0);
infoDevices[i].setmacAdrress("");
infoDevices[i].setimg(R.drawable.device);
}
}
}
private void initComponent() {
btn_scanDevices = null;
btn_setting = null;
pd = null;
//text_debug = (TextView) findViewById(R.id.text_debug);
btn_scanDevices = (ImageButton) findViewById(R.id.btn_scanDevices);
btn_setting = (ImageButton) findViewById(R.id.btn_setting);
gridView = (GridView)findViewById(R.id.gridview_list);
if(adapter_deviceInfo==null){
adapter_deviceInfo = new SimpleAdapter(this, devInfoList,
R.layout.layout_item, new String[] { "item_image", "item_text" },
new int[] { R.id.item_image, R.id.item_text });
}
if(adapter_deviceInfo_setting==null){
adapter_deviceInfo_setting = new SimpleAdapter(this, devInfoList,
R.layout.layout_item_setting, new String[] { "item_image", "item_text", "item_text_info" },
new int[] { R.id.item_image, R.id.item_text, R.id.item_text_info });
}
gridViewItemComponent();
for(int i=0;i<DEVICE_MAX_NUM;i++){
if(infoDevices[i].getaliveFlag()>0){
reloadDeviceInfo();
break;
}
}
}
private void device_config(int index) {
String listSelectedName = null;
g_ctrl.resetInfo();
//Log.d(TAG,"setting_builder: "+g_ctrl.getDeviceList().elementAt(index).getServiceName());
//Log.d(TAG,"setting_builder: "+g_ctrl.getDeviceList().elementAt(index).getHost());
//Log.d(TAG,"setting_builder: "+g_ctrl.getDeviceList().elementAt(index).getPort());
if( g_ctrl.getDeviceList().elementAt(index) == null )
return;
g_ctrl.setConnIP(g_ctrl.getDeviceList().elementAt(index).getInetAddress());
g_ctrl.setConnPort(g_ctrl.getDeviceList().elementAt(index).getPort());
//TODO
byte[] cmdGet_AllSetting = new byte[]{0x02, 0x00, 0x0f};
ByteBuffer tmp = ByteBuffer.allocate(cmdPrefix.length + cmdGet_AllSetting.length);
tmp.clear();
tmp.put(cmdPrefix);
tmp.put(cmdGet_AllSetting);
byte[] test = tmp.array();
//g_ctrl.setTx(test);
g_ctrl.clearTx();
g_ctrl.setTx(tmp.array());
g_ctrl.setCmd("Request");
ctrlClient = new TcpClient(g_ctrl);
ctrlClient.executeOnExecutor(TcpClient.THREAD_POOL_EXECUTOR);
pd = new ProgressDialog(MainActivity.this);
pd.setTitle("Serial port");
pd.setMessage("Please wait...");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
pd.show();
//Thread
Thread gettingThread = new Thread() {
@Override
public void run() {
int retry = 20;
do{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(retry-->0 && recvBuf.length()==0);
Message m = new Message();
m.what = 0;
handler_pd.sendMessage(m);
//show serial port setting
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,
recvBuf,
Toast.LENGTH_SHORT).show();
String[] type = recvBuf.split(";");
String[] info = {};
if(type.length!=4)
return;
for(int i=0;i<type.length;i++){
info = type[i].split(",");
if(i==0 ){//rate
setting_rate = info[1];
}else if(i==1){//data
setting_data = info[1];
}else if(i==2){//parity
setting_parity = info[1];
}else if(i==3){//stopbit
setting_stopbit = info[1];
}/*else if(index==4){//flowcontrol
setting_flowc = info[1];
}*/
}
recvBuf = "";
LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.setting_serialport,null);
final PopupWindow popupWindow = new PopupWindow(
popupView,
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
Button btnApply = (Button)popupView.findViewById(R.id.btn_setting_apply);
Button btnCancel = (Button)popupView.findViewById(R.id.btn_setting_cancel);
//====== baud rate =======
final Spinner spinner_baudrate = (Spinner)popupView.findViewById(R.id.spinner_baudrate);
ArrayAdapter<String> adapter_baudrate =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, Setting_baudrate);
adapter_baudrate.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_baudrate.setAdapter(adapter_baudrate);
int spinnerPosition = adapter_baudrate.getPosition(setting_rate);
spinner_baudrate.setSelection(spinnerPosition);
//====== data =======
final Spinner spinner_data = (Spinner)popupView.findViewById(R.id.spinner_data);
ArrayAdapter<String> adapter_data =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, Setting_data);
adapter_data.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_data.setAdapter(adapter_data);
spinnerPosition = adapter_data.getPosition(setting_data);
spinner_data.setSelection(spinnerPosition);
//====== parity =======
final Spinner spinner_parity = (Spinner)popupView.findViewById(R.id.spinner_parity);
ArrayAdapter<String> adapter_parity =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, Setting_parity);
adapter_parity.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_parity.setAdapter(adapter_parity);
spinnerPosition = Integer.valueOf(setting_parity).intValue();//adapter_parity.getPosition(parity);
spinner_parity.setSelection(spinnerPosition);
//====== stop bit =======
final Spinner spinner_stopbit = (Spinner)popupView.findViewById(R.id.spinner_stopbit);
ArrayAdapter<String> adapter_stopbit =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, Setting_stopbit);
adapter_stopbit.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_stopbit.setAdapter(adapter_stopbit);
spinnerPosition = Integer.valueOf(setting_stopbit).intValue();//adapter_stopbit.getPosition(stopbit);
spinner_stopbit.setSelection(spinnerPosition);
//====== flow control=======
final Spinner spinner_flowc = (Spinner)popupView.findViewById(R.id.spinner_flowcontrol);
ArrayAdapter<String> adapter_flowc =
new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_item, Setting_flowc);
adapter_flowc.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_flowc.setAdapter(adapter_flowc);
spinnerPosition = adapter_flowc.getPosition(setting_flowc);
spinner_flowc.setSelection(spinnerPosition);
btnApply.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
//TODO
setting_rate = spinner_baudrate.getSelectedItem().toString();
setting_data = spinner_data.getSelectedItem().toString();
setting_parity = spinner_parity.getSelectedItem().toString();
setting_stopbit = spinner_stopbit.getSelectedItem().toString();
//setting_flowc = spinner_flowc.getSelectedItem().toString();
g_ctrl.clearTx();
g_ctrl.setTx(combineReqCmd( setting_rate,
setting_data,
setting_parity,
setting_stopbit/*,
setting_flowc*/));
g_ctrl.setCmd("Request");
ctrlClient = new TcpClient(g_ctrl);
ctrlClient.executeOnExecutor(TcpClient.THREAD_POOL_EXECUTOR);
// Log.d(TAG,"requestCmd: " + requestCmd);
pd = new ProgressDialog(MainActivity.this);
pd.setTitle("Serial port");
pd.setMessage("Please wait...");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
pd.show();
//Thread
Thread settingThread = new Thread() {
@Override
public void run() {
int retry = 20;
do{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(retry-->0 && recvBuf.length()==0);
Message m = new Message();
m.what = 0;
handler_pd.sendMessage(m);
g_ctrl.setCmd("stop");
//show serial port setting
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,
recvBuf,
Toast.LENGTH_SHORT).show();
recvBuf = "";
};
});
}};
settingThread.start();
popupWindow.dismiss();
}
private byte[] combineReqCmd(String setting_rate, String setting_data, String setting_parity, String setting_stopbit/*, String setting_flowc*/) {
//<20150412> So far, flow control no support.
byte[] cmdSet_rate = null;
byte[] cmdSet_data = null;
byte[] cmdSet_parity = null;
byte[] cmdSet_stopbit = null;
//byte[] cmdSet_flowc = new byte[3];
if(setting_rate.equals("1200")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0xB0,(byte)0x04,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("9600")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte) 0x80,0x25,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("14400")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x40,(byte)0x38,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("19200")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x4B,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("28800")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x80,(byte)0x70,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("38400")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x96,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("57600")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0xE1,(byte)0x00,(byte)0x00};
}else if(setting_rate.equals("76800")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x2C,(byte)0x01,(byte)0x00};
}else if(setting_rate.equals("115200")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0xC2,(byte)0x01,(byte)0x00};
}else if(setting_rate.equals("128000")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0xF4,(byte)0x01,(byte)0x00};
}else if(setting_rate.equals("153600")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x58,(byte)0x02,(byte)0x00};
}else if(setting_rate.equals("230400")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x84,(byte)0x03,(byte)0x00};
}else if(setting_rate.equals("460800")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x08,(byte)0x07,(byte)0x00};
}else if(setting_rate.equals("500000")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x20,(byte)0xA1,(byte)0x07,(byte)0x00};
}else if(setting_rate.equals("921600")){
cmdSet_rate = new byte[]{ (byte)0x00,(byte)0x01,(byte)0x04,(byte)0x00,(byte)0x10,(byte)0x0E,(byte)0x00};
}
if(setting_data.equals("8")){
cmdSet_data = new byte[]{ 0x00,0x02,0x01, 0x08};
}else{
cmdSet_data = new byte[]{ 0x00,0x02,0x01, 0x07};
}
if(setting_parity.equals("none")){
cmdSet_parity = new byte[]{ 0x00,0x04,0x01, 0x00};
}else if(setting_parity.equals("odd")){
cmdSet_parity = new byte[]{ 0x00,0x04,0x01, 0x01};
}else if(setting_parity.equals("even")){
cmdSet_parity = new byte[]{ 0x00,0x04,0x01, 0x02};
}
if(setting_stopbit.equals("none")){
cmdSet_stopbit = new byte[]{ 0x00,0x08,0x01, 0x00};
}else if(setting_stopbit.equals("1 bit")){
cmdSet_stopbit = new byte[]{ 0x00,0x08,0x01, 0x01};
}
byte[] reqCmdByte = new byte[]{0x00};
//combine req cmd
ByteBuffer reqTmp = ByteBuffer.allocate(cmdPrefix.length +
reqCmdByte.length+
cmdSet_rate.length+
cmdSet_data.length+
cmdSet_parity.length+
cmdSet_stopbit.length);
reqTmp.clear();
reqTmp.put(cmdPrefix);
reqTmp.put(reqCmdByte);
reqTmp.put(cmdSet_rate);
reqTmp.put(cmdSet_data);
reqTmp.put(cmdSet_parity);
reqTmp.put(cmdSet_stopbit);
//byte[] test = reqTmp.array();
return reqTmp.array();
}
});
btnCancel.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
g_ctrl.setCmd("stop");
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
}
});
}
};
gettingThread.start();
}
private void initComponentAction() {
btn_scanDevices.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
pd = new ProgressDialog(MainActivity.this);
pd.setTitle("Searching...");
pd.setMessage("Please wait...");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
stopDiscover();
dialog.dismiss();
}
});
pd.show();
//Thread
Thread searchThread = new Thread() {
@SuppressLint("NewApi")
@Override
public void run() {
g_d.ResolveStatusReset();
devInfoList.clear();
g_ctrl.clearDeviceList();
infoDevices = null;
initData();
Log.i(TAG,"startDiscover");
int tmp = 0;
try {
startDiscover();
do{
if( g_ctrl.getDeviceList().size() > 0 )
{
Thread.sleep(2000);
break;
}
Thread.sleep(1000);
tmp++;
//Log.i(TAG,"startDiscover " + g_ctrl.getDeviceList().size() + " tmp " + tmp );
}while( tmp < 30 );
g_ctrl.ResolveStatusReset();
} catch (InterruptedException e) {
e.printStackTrace();
}
Message m = new Message();
m.what = 0;
handler_pd.sendMessage(m);
if(tmp >= 30 && ( g_ctrl.getDeviceList().size() == 0)){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,
"Devices search timeout!",
Toast.LENGTH_SHORT).show();
}
});
}
deviceNumberNow = g_ctrl.getDeviceList().size();
Log.i(TAG, "deviceNumberNow " + deviceNumberNow);
if (deviceNumberNow == 0) {
devInfoList.clear();
g_ctrl.clearDeviceList();
infoDevices = null;
initData();
}else{
for(int i=0;i<deviceNumberNow;i++){
/*Log.d(TAG_DISCOVER,"Name: " + g_d.getDeviceList().elementAt(i).getServiceName() );
Log.d(TAG_DISCOVER,"Type: " + g_d.getDeviceList().elementAt(i).getServiceType() );
Log.d(TAG_DISCOVER,"Host: " + g_d.getDeviceList().elementAt(i).getHost() );
Log.d(TAG_DISCOVER,"Port: " + g_d.getDeviceList().elementAt(i).getPort() );*/
infoDevices[i].setaliveFlag(1);
infoDevices[i].setName(g_ctrl.getDeviceList().elementAt(i).getName());
infoDevices[i].setName_small("");
infoDevices[i].setIP(g_ctrl.getDeviceList().elementAt(i).getHostAddress());
infoDevices[i].setPort(g_ctrl.getDeviceList().elementAt(i).getPort());
infoDevices[i].setmacAdrress("");
}
}
runOnUiThread(new Runnable() {
@Override
public void run() {
//show scan result
//text_debug.setText("");
/* for(int i=0;i<deviceNumberNow;i++){
text_debug.append("==== " +i+ " ====\n");
text_debug.append("name: "+infoDevices[i].getName()+"\n");
text_debug.append("host: "+infoDevices[i].getIP()+"\n");
text_debug.append("port: "+infoDevices[i].getPort()+"\n");
}
*/
Toast.makeText(MainActivity.this,
String.valueOf(deviceNumberNow) + " Ameba Found",
Toast.LENGTH_SHORT).show();
reloadDeviceInfo();
}
});
stopDiscover();
}
};
searchThread.start();
}
});
btn_setting.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//Log.d(TAG,"sean test " + adapter_deviceInfo_setting.getCount());
if (adapter_deviceInfo_setting.getCount() == 1) //only one device don't need setting_builder
device_config(0);
else{
AlertDialog.Builder setting_builder;
setting_builder=new AlertDialog.Builder(MainActivity.this);
//speaker_builder.setIcon(R.drawable.ic_dialog_question);
setting_builder.setTitle("Choose One Ameba");
setting_builder.setCancelable(false);
setting_builder.setSingleChoiceItems(adapter_deviceInfo_setting, -1, new DialogInterface.OnClickListener(){
@SuppressLint("NewApi")
@Override
public void onClick(DialogInterface dialog, final int index) {
device_config(index);
dialog.cancel();
}
} );
setting_builder.setPositiveButton("Cancel",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
setting_builder.create().show();
}
}
});
//======================= action ======================
//search devices when no device
boolean isSearchTrigger = true;
for(int i=0;i<DEVICE_MAX_NUM;i++){
if(infoDevices[i].getaliveFlag()>0){
isSearchTrigger = false;
break;
}
}
if(isSearchTrigger){
btn_scanDevices.performClick();
}
}
protected int parseInfo(String recvBuf) {
//TODO
return 1;
//-------- response for getting --------
}
private void gridViewItemComponent() {
gridView.setOnItemClickListener( new OnItemClickListener(){
@SuppressLint("NewApi")
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position,
long id) {
pd = new ProgressDialog(MainActivity.this);
pd.setTitle("Connecting...");
pd.setMessage("Please wait...");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
stopDiscover();
dialog.dismiss();
}
});
pd.show();
/*
try {
while(!g_d.isResolveFinish())
{
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
//TODO
Toast.makeText(MainActivity.this,"Connect to "+
infoDevices[position].getName(),
Toast.LENGTH_SHORT).show();
for (int i = 0; i < infoDevices.length; i++) {
if(g_ctrl.getDeviceList().elementAt(position).getInetAddress().equals(g_d.getDeviceList().elementAt(i).getInet4Address()) ) {
position = i;
break;
}
}
g_d.resetInfo();
g_d.setConnIP(g_d.getDeviceList().elementAt(position).getInetAddress()); //need check
g_d.setConnPort(g_d.getDeviceList().elementAt(position).getPort());
g_d.setCmd("Hello");
dataClient = new TcpClient(g_d);
dataClient.executeOnExecutor(TcpClient.THREAD_POOL_EXECUTOR);
g_d.opStates().setOpState(g_d.opStates().stateConnectedServer());
Intent intent_Navigation = new Intent();
intent_Navigation.setClass(MainActivity.this, ChatActivity.class);
startActivity(intent_Navigation);
finish();
}
});
}
private void startDiscover() {
Log.d(TAG_DISCOVER, "Start Service Button clicked");
g_d.resetInfo();
g_d.clearDeviceList();
g_ctrl.resetInfo();
g_ctrl.clearDeviceList();
g_discoverEnable = true;
if (mNSD!=null){
stopDiscover();
}
mNSD = new NsdCore(this);
mNSD.initializeNsd();
mNSD.discoverServices(g_d.getServiceType());
mNSD.discoverServices(g_ctrl.getServiceType());
if(uiThread==null){
uiThread = new UpdateUiThread();
uiThread.start();
}
g_d.opStates().setOpState(g_d.opStates().stateDiscoveringService());
g_ctrl.opStates().setOpState(g_d.opStates().stateDiscoveringService());
}
private void stopDiscover(){
g_discoverEnable = false;
Log.d(TAG_DISCOVER,"canceling discovering clicked");
if(mNSD != null)
mNSD.stopDiscovery();
//uiThread.interrupt();
g_d.opStates().setOpState(g_d.opStates().stateAppStart());
g_ctrl.opStates().setOpState(g_d.opStates().stateAppStart());
}
private void reloadDeviceInfo() {
devInfoList.clear();
if(infoDevices.length > 0) {
for (int i = 0; i < infoDevices.length; i++) {
if (infoDevices[i].getaliveFlag() == 1) {
HashMap<String, Object> reloadItemHashMap = new HashMap<String, Object>();
reloadItemHashMap.put("item_image", infoDevices[i].getimg());
reloadItemHashMap.put("item_text", infoDevices[i].getName());
reloadItemHashMap.put("item_text_info", infoDevices[i].getIP());
devInfoList.add(reloadItemHashMap);
}
}
gridView.setAdapter(adapter_deviceInfo);
}
}
public class recvThread extends Thread{
//======================= Thread ======================
@Override
public void run() {
//Log.d(TAG,"recvThread Run");
while(!rcvThreadExit){
if(g_ctrl.checkRecvBufUpdate() && g_ctrl.pullRecvBuffer().length()>0){
_gmutex_recvBuf.lock();
//Log.d(TAG,"recvBuf: lock " + recvBuf + " update? " + g_ctrl.checkRecvBufUpdate() + " length: "+g_ctrl.pullRecvBuffer().length());
recvBuf = g_ctrl.pullRecvBuffer();
g_ctrl.resetRecvBuffer();
_gmutex_recvBuf.unlock();
if(parseInfo(recvBuf)<0)
Log.e(TAG,"parseInfo(recvBuf) Fail!!!!!");
}
try {
// Log.d(TAG,"recvThread update " + g_ctrl.checkRecvBufUpdate() +" pullRecvBuffer length " + g_ctrl.pullRecvBuffer().length());
//Log.d(TAG,"isInterrupted() " + isInterrupted());
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Log.d(TAG,"recvThread exit");
}
//recvThread.start();
}
/*
* Class - UpdateUiThread
*/
public class UpdateUiThread extends Thread {
Globals_d g_d = Globals_d.getInstance();
private static final int DELAY = 200; // ms
@Override
public void run() {
Log.v(TAG_UI_THREAD, "Update Ui thread started");
while(g_discoverEnable){
//Log.d(TAG_UI_THREAD,"-----------");
//Log.d(TAG_UI_THREAD,g_d.getInfo());
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
Log.e(TAG_UI_THREAD,"Update Ui thread err");
return;
}
}
Log.v(TAG_UI_THREAD, "Update Ui thread close");
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

View file

@ -0,0 +1,95 @@
package com.realtek.uartthrough;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.content.Context;
import android.provider.Settings;
import android.text.format.Formatter;
import android.util.Log;
import java.lang.String;
import android.net.wifi.WifiInfo;
public class NsdCore {
private NsdHelper jnsdHelper=null;
private android.net.wifi.WifiManager.MulticastLock mMulticastLock;
private android.net.wifi.WifiManager wifi;
Globals_ctrl g_ctrl = Globals_ctrl.getInstance();
Globals_d g_d = Globals_d.getInstance();
Context mContext;
public static final String TAG = "NsdCore";
static WifiInfo wifiinfo=null;
public final String mServiceType_c = g_ctrl.getServiceType();
public final String mServiceType_d = g_d.getServiceType();
public String mServiceName_c = g_ctrl.getServiceName();
public String mServiceName_d = g_d.getServiceName();
String mIP ;
public NsdCore(Context context) {
mContext = context;
}
public void initializeNsd() {
wifi = (android.net.wifi.WifiManager)
mContext.getSystemService(android.content.Context.WIFI_SERVICE);
mIP = Formatter.formatIpAddress(wifi.getConnectionInfo().getIpAddress());
int intaddr = wifi.getConnectionInfo().getIpAddress();
if (wifi.getWifiState() == WifiManager.WIFI_STATE_DISABLED || intaddr == 0) {
mContext.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
} else {
stopDiscovery();
}
}
@SuppressLint("NewApi")
public void onDestroy() {
if (mMulticastLock != null) mMulticastLock.release();
}
@SuppressLint("NewApi")
public void discoverServices(String serviceType) {
wifiLock();
if ( serviceType.contains(mServiceType_c) ) {
Log.d(TAG, "discoverServices " +serviceType+ " start!!");
jnsdHelper = new NsdHelper(serviceType, g_ctrl, mIP);
jnsdHelper.executeOnExecutor(NsdHelper.THREAD_POOL_EXECUTOR);
}else if( serviceType.contains(mServiceType_d) ){
Log.d(TAG, "discoverServices " +serviceType+ " start!!");
NsdHelper jnsdHelper = new NsdHelper(serviceType, g_d, mIP);
jnsdHelper.executeOnExecutor(NsdHelper.THREAD_POOL_EXECUTOR);
}
}
private void wifiLock() {
mMulticastLock = wifi.createMulticastLock(getClass().getName());
mMulticastLock.setReferenceCounted(false);
mMulticastLock.acquire();
}
@SuppressLint("NewApi")
public void stopDiscovery() {
if (jnsdHelper != null) {
jnsdHelper.onCancelled();
}
if (mMulticastLock != null)
mMulticastLock.release();
}
}

View file

@ -0,0 +1,161 @@
package com.realtek.uartthrough;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.text.format.Formatter;
import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceInfo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by WUJINZHOU on 5/2/15.
*/
public class NsdHelper extends AsyncTask<Void, Void, Void> {
private final Lock _mutex = new ReentrantLock(true);
//private final String mServiceType = "_uart_data._tcp.local.";//"_uart_control._tcp.local.";
private final String tag = "@NsdHelper ";
private JmDNS jmdns = null;
private ServiceListener listener = null;
ServiceInfo mService;
Globals_ctrl mG_ctrl;
Globals_d mG_d;
private String mServiceType;
String mServiceType_c ;
String mServiceType_d ;
String mIP;
//ServiceEvent mServiceEvent;
public NsdHelper(String serviceType, Globals_ctrl g_ctrl, String ip){
mG_ctrl = g_ctrl;
mServiceType_c = mG_ctrl.getServiceType();
mServiceType = serviceType;
mIP = ip;
}
public NsdHelper(String serviceType, Globals_d g_d, String ip){
mG_d = g_d;
mServiceType_d = mG_d.getServiceType();
mServiceType = serviceType;
mIP = ip;
}
@Override
protected Void doInBackground(Void... params) {
startNSD();
return null;
}
@Override
protected void onCancelled() {
super.onCancelled();
stopNSD();
}
private void startNSD() {
Log.v(tag,"startNSD() " + mServiceType);
try {
jmdns = JmDNS.create(InetAddress.getByName(mIP));//JmDNS.create();
jmdns.addServiceListener(mServiceType, listener = new ServiceListener() {
@Override
public void serviceAdded(ServiceEvent event) {
jmdns.requestServiceInfo(event.getType(), event.getName(), true); //resolve service
Log.v(tag, "serviceAdded() "+event.getName());
}
@Override
public void serviceRemoved(ServiceEvent event) {
Log.v(tag,"serviceRemoved() " + event.getName());
}
@Override
public void serviceResolved(ServiceEvent event) {
boolean serviceDuplicate = false;
mService = event.getInfo();
//do someting with this service event
if( !(mServiceType_c == null) ){
_mutex.lock();
if ( mService.getType().contains(mServiceType_c)) {
for(int i=0;i< mG_ctrl.getDeviceList().size();i++){
if( mG_ctrl.getDeviceList().elementAt(i).getName().equalsIgnoreCase(mService.getName())){
serviceDuplicate = true;
break;
}
}
if (serviceDuplicate == false)
{
mG_ctrl.opStates().setOpState(mG_ctrl.opStates().stateResoledService());
mG_ctrl.addInfo(tag + "Resolve Succeeded.\n " + mService);
mG_ctrl.setSuccessRec(tag + "Resolve Succeeded. " + mService);
mG_ctrl.getDeviceList().add(mService); //TODO check ip before add to list
mG_ctrl.setResolveFinish();
//Log.i(tag,"nsdhelper: isResolveFinish " + mG_ctrl.isResolveFinish());
serviceDuplicate = false;
}
}
_mutex.unlock();
}
if( !(mServiceType_d == null) ){
if (!mServiceType_d.equals(null) && mService.getType().equals(mServiceType_d)) {
Log.e(tag, "G_D onServiceResolved");
mG_d.opStates().setOpState(mG_d.opStates().stateResoledService());
mG_d.setSuccessRec(tag + "Resolve Succeeded. " + mService);
mG_d.getDeviceList().add(mService);//TODO check ip before add to list
mG_d.setResolveFinish();
}
}
Log.w(tag, "onServiceResolved Succeeded. " + mService);
}
});
} catch (IOException e) {
Log.e(tag,"startNSD() IOException e:"+e);
e.printStackTrace();
}
}
private void stopNSD() {
if (jmdns != null) {
if (listener != null) {
jmdns.removeServiceListener(mServiceType, listener);
listener = null;
}
jmdns.unregisterAllServices();
try {
jmdns.close();
Log.v(tag,"stopNSD() ");
} catch (IOException e) {
Log.e(tag,"stopNSD() IOException e:"+e);
e.printStackTrace();
}
jmdns = null;
}
}
}

View file

@ -0,0 +1,64 @@
package com.realtek.uartthrough;
public class OpStates {
private static OpStates thisOpS;
///////////////////////operation states///////////////////////////////
private static String currState="";
private static String appStart ="application start";
private static String discoveringService="discovering service";
private static String discoveredService ="discovered service";
private static String resoledService ="resoled service";
private static String connectedServer="connected to server";
private static String stoppedConnection="stopped connection to server";
private static String appQuit="application quit";
public String getOpState(){
return currState;
}
public void setOpState(String state){
currState=state;
}
public String stateAppStart(){
return appStart;
}
public String stateDiscoveringService(){
return discoveringService;
}
public String stateDiscoveredService(){
return discoveredService;
}
public String stateResoledService(){
return resoledService;
}
public String stateConnectedServer(){
return connectedServer;
}
public String stateStoppedConnection(){
return stoppedConnection;
}
public String stateAppQuit(){
return appQuit;
}
public boolean onOpState(String state){
if(currState==state){
return true;
}
else {
return false;
}
}
////////////////////////operation states end//////////////////////////////
public OpStates(){}
public static synchronized OpStates getInstance(){
if(thisOpS==null){
thisOpS=new OpStates();
}
return thisOpS;
}
}

View file

@ -0,0 +1,231 @@
package com.realtek.uartthrough;
import android.os.AsyncTask;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
///////////////////////////////////////////////
public class TcpClient extends AsyncTask<Void, Void, Void> {
public static final String TAG = "TCP_Client";
public static final String TAG_CTRL = "TCP_Client(CTRL): ";
public static final String TAG_DATA = "TCP_Client(DATA): ";
int type;
Globals_ctrl g_ctrl ;
Globals_d g_d;
InetAddress ip;
int port ;
String cmd_ctrl_req = "null";
String cmd_ctrl_response = "null";
String cmd = "null";
ByteBuffer bf = ByteBuffer.allocate(1024);
CharBuffer cbuf = bf.asCharBuffer();
public TcpClient(Globals_ctrl gInstance) {
//Log.w("TcpClient Developing","G instructor control port");
g_ctrl = gInstance;
ip = g_ctrl.getConnIP();
port = g_ctrl.getConnPort();
type = 0;
}
public TcpClient(Globals_d gInstance) {
//Log.w("TcpClient Developing","G_d instructor data port");
g_d = gInstance;
ip = g_d.getConnIP();
port = g_d.getConnPort();
type = 1;
}
@Override
protected Void doInBackground(Void...params) {
// g_d.addInfo("TcpClient start");
try {
do{
Thread.sleep(1000);
final Socket s = new Socket(ip, port);
s.setTcpNoDelay(true);
final BufferedInputStream rx = new BufferedInputStream(s.getInputStream());
final PrintStream tx = new PrintStream(s.getOutputStream());
switch (type) {
case 0: // control port
g_ctrl.resetInfo();
/*==========================
* thread for control TX
* =========================
*/
new Thread(new Runnable() {
public void run() {
do {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Log.v(TAG_CTRL,"TX thread error");
break;
}
cmd_ctrl_req = g_ctrl.getCmd();
if(cmd_ctrl_req.equals("Request")) {
try {
tx.write(g_ctrl.getTx());
} catch (IOException e) {
Log.v(TAG_CTRL,"TX write error");
break;
}
tx.flush();
g_ctrl.clearTx();
g_ctrl.clearCmd();
}
}while ( !cmd_ctrl_req.equals("stop") );
if(!s.isClosed()) {
tx.close();
try {
s.close();
} catch (IOException e) {
Log.v(TAG_CTRL,"TX socket close error");
}
}
}
}).start();
/*==========================
* for control RX
* =========================
*/
int len;
byte [] recv_buf = new byte[64];
while (!cmd_ctrl_response.equals("stop")) {
cmd_ctrl_response = g_ctrl.getCmd();
if( rx.available() > 0 ) {
len = rx.read(recv_buf);
g_ctrl.commitRecvBuffer(recv_buf,len);
}else{
Thread.sleep(200);
}
}
break;
case 1: //data port
g_d.resetInfo();
/*==========================
* thread for data TX
* =========================
*/
new Thread(new Runnable() {
public void run() {
do {
try {
//Log.v(TAG_DATA,"DATA TX thread");
Thread.sleep(500);
} catch (InterruptedException e) {
Log.v(TAG_DATA,"TX thread error");
break;
}
cmd = g_d.getCmd();
if(cmd.equals("send")) {
Log.v(TAG_DATA,"DATA TX thread: " +g_d.getTx()+ " port: " +s.getLocalPort());
tx.println(g_d.getTx());
g_d.clearTx();
g_d.clearCmd();
}
}while ( !cmd.equals("stop") );
if(!s.isClosed()) {
tx.close();
Log.v(TAG_DATA, "DATA TX SOCKET CLOSE " );
try {
s.close();
} catch (IOException e) {
Log.v(TAG_CTRL,"TX socket close error");
}
}
}
}).start();
/*==========================
* for data RX
* =========================
*/
int b=0;
cmd = g_d.getCmd();
while (!cmd.equals("stop")) {
cmd = g_d.getCmd();
//Log.v(TAG_DATA,"DATA RX thread");
if( rx.available() > 0 ) {
while(rx.available() > 0) {
b = rx.read();
Log.v(TAG_DATA,"DATA RX thread: " + b + " port: " +s.getLocalPort());
cbuf.put((char) b);
cbuf.flip();
g_d.addInfo(cbuf.toString());
if(rx.available() == 0) {
g_d.setReadable(true);
}
}
}else{
Thread.sleep(200);
}
}
break;
default:
break;
}
if(!s.isClosed()) {
rx.close();
s.close();
}
}while ( !(!cmd_ctrl_response.equals("stop") || !cmd.equals("stop")) );
if(type == 0)
Log.w(TAG, "TCP Control RX Quit");
else
Log.w(TAG, "TCP data RX Quit");
}
catch (Exception err)
{
Log.e(TAG,""+err);
}
return null;
}
/*
@Override
protected void onPostExecute(Void result) {
//do something....
super.onPostExecute(result);
}
*/
}

View file

@ -0,0 +1,31 @@
package com.realtek.uartthrough;
public class UARTCmd {
//cmd_c : AMEBA_UART 0x02, 0x01
//public char cmd_c[] ={0x41, 0x4D, 0x45, 0x42, 0x41, 0x5F, 0x55, 0x41, 0x52, 0x54, 0x02, 0x01};
public char cmd_c[] ={0x41, 0x4D, 0x45, 0x42, 0x41, 0x5F, 0x55, 0x41, 0x52, 0x54};
public static enum UART_Setting_Type {
UART_BaudRate,
UART_Data,
UART_Parity,
UART_Stop,
UART_FlowControl,
DEFAULT
};
public char[] getReqSettingCmd(UART_Setting_Type uartType){
//char[] result = cmd_c;
switch(uartType){
case UART_BaudRate:{
break;
}
}
return cmd_c;
}
}

View file

@ -0,0 +1,433 @@
// /Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Collection;
import java.util.Map;
import javax.jmdns.impl.JmDNSImpl;
/**
* mDNS implementation in Java.
*
* @author Arthur van Hoff, Rick Blair, Jeff Sonstein, Werner Randelshofer, Pierre Frisch, Scott Lewis, Scott Cytacki
*/
public abstract class JmDNS implements Closeable {
/**
*
*/
public static interface Delegate {
/**
* This method is called if JmDNS cannot recover from an I/O error.
*
* @param dns
* target DNS
* @param infos
* service info registered with the DNS
*/
public void cannotRecoverFromIOError(JmDNS dns, Collection<ServiceInfo> infos);
}
/**
* The version of JmDNS.
*/
public static final String VERSION = "3.4.2";
/**
* <p>
* Create an instance of JmDNS.
* </p>
* <p>
* <b>Note:</b> This is a convenience method. The preferred constructor is {@link #create(InetAddress, String)}.<br/>
* Check that your platform correctly handle the default localhost IP address and the local hostname. In doubt use the explicit constructor.<br/>
* This call is equivalent to <code>create(null, null)</code>.
* </p>
*
* @see #create(InetAddress, String)
* @return jmDNS instance
* @exception IOException
* if an exception occurs during the socket creation
*/
public static JmDNS create() throws IOException {
return new JmDNSImpl(null, null);
}
/**
* <p>
* Create an instance of JmDNS and bind it to a specific network interface given its IP-address.
* </p>
* <p>
* <b>Note:</b> This is a convenience method. The preferred constructor is {@link #create(InetAddress, String)}.<br/>
* Check that your platform correctly handle the default localhost IP address and the local hostname. In doubt use the explicit constructor.<br/>
* This call is equivalent to <code>create(addr, null)</code>.
* </p>
*
* @see #create(InetAddress, String)
* @param addr
* IP address to bind to.
* @return jmDNS instance
* @exception IOException
* if an exception occurs during the socket creation
*/
public static JmDNS create(final InetAddress addr) throws IOException {
return new JmDNSImpl(addr, null);
}
/**
* <p>
* Create an instance of JmDNS.
* </p>
* <p>
* <b>Note:</b> This is a convenience method. The preferred constructor is {@link #create(InetAddress, String)}.<br/>
* Check that your platform correctly handle the default localhost IP address and the local hostname. In doubt use the explicit constructor.<br/>
* This call is equivalent to <code>create(null, name)</code>.
* </p>
*
* @see #create(InetAddress, String)
* @param name
* name of the newly created JmDNS
* @return jmDNS instance
* @exception IOException
* if an exception occurs during the socket creation
*/
public static JmDNS create(final String name) throws IOException {
return new JmDNSImpl(null, name);
}
/**
* <p>
* Create an instance of JmDNS and bind it to a specific network interface given its IP-address.
* </p>
* If <code>addr</code> parameter is null this method will try to resolve to a local IP address of the machine using a network discovery:
* <ol>
* <li>Check the system property <code>net.mdns.interface</code></li>
* <li>Check the JVM local host</li>
* <li>Use the {@link NetworkTopologyDiscovery} to find a valid network interface and IP.</li>
* <li>In the last resort bind to the loopback address. This is non functional in most cases.</li>
* </ol>
* If <code>name</code> parameter is null will use the hostname. The hostname is determined by the following algorithm:
* <ol>
* <li>Get the hostname from the InetAdress obtained before.</li>
* <li>If the hostname is a reverse lookup default to <code>JmDNS name</code> or <code>computer</code> if null.</li>
* <li>If the name contains <code>'.'</code> replace them by <code>'-'</code></li>
* <li>Add <code>.local.</code> at the end of the name.</li>
* </ol>
* <p>
* <b>Note:</b> If you need to use a custom {@link NetworkTopologyDiscovery} it must be setup before any call to this method. This is done by setting up a {@link NetworkTopologyDiscovery.Factory.ClassDelegate} and installing it using
* {@link NetworkTopologyDiscovery.Factory#setClassDelegate(NetworkTopologyDiscovery.Factory.ClassDelegate)}. This must be done before creating a {@link JmDNS} or {@link JmmDNS} instance.
* </p>
*
* @param addr
* IP address to bind to.
* @param name
* name of the newly created JmDNS
* @return jmDNS instance
* @exception IOException
* if an exception occurs during the socket creation
*/
public static JmDNS create(final InetAddress addr, final String name) throws IOException {
return new JmDNSImpl(addr, name);
}
/**
* Return the name of the JmDNS instance. This is an arbitrary string that is useful for distinguishing instances.
*
* @return name of the JmDNS
*/
public abstract String getName();
/**
* Return the HostName associated with this JmDNS instance. Note: May not be the same as what started. The host name is subject to negotiation.
*
* @return Host name
*/
public abstract String getHostName();
/**
* Return the address of the interface to which this instance of JmDNS is bound.
*
* @return Internet Address
* @exception IOException
* if there is an error in the underlying protocol, such as a TCP error.
*/
public abstract InetAddress getInetAddress() throws IOException;
/**
* Return the address of the interface to which this instance of JmDNS is bound.
*
* @return Internet Address
* @exception IOException
* if there is an error in the underlying protocol, such as a TCP error.
* @deprecated do not use this implementation yields unpredictable results use {@link #getInetAddress()}
*/
@Deprecated
public abstract InetAddress getInterface() throws IOException;
/**
* Get service information. If the information is not cached, the method will block until updated information is received.
* <p/>
* Usage note: Do not call this method from the AWT event dispatcher thread. You will make the user interface unresponsive.
*
* @param type
* fully qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @return null if the service information cannot be obtained
*/
public abstract ServiceInfo getServiceInfo(String type, String name);
/**
* Get service information. If the information is not cached, the method will block for the given timeout until updated information is received.
* <p/>
* Usage note: If you call this method from the AWT event dispatcher thread, use a small timeout, or you will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds. Typical timeout should be 5s.
* @return null if the service information cannot be obtained
*/
public abstract ServiceInfo getServiceInfo(String type, String name, long timeout);
/**
* Get service information. If the information is not cached, the method will block until updated information is received.
* <p/>
* Usage note: Do not call this method from the AWT event dispatcher thread. You will make the user interface unresponsive.
*
* @param type
* fully qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @return null if the service information cannot be obtained
*/
public abstract ServiceInfo getServiceInfo(String type, String name, boolean persistent);
/**
* Get service information. If the information is not cached, the method will block for the given timeout until updated information is received.
* <p/>
* Usage note: If you call this method from the AWT event dispatcher thread, use a small timeout, or you will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds. Typical timeout should be 5s.
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @return null if the service information cannot be obtained
*/
public abstract ServiceInfo getServiceInfo(String type, String name, boolean persistent, long timeout);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
* <p/>
* Usage note: Do not call this method from the AWT event dispatcher thread. You will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
*/
public abstract void requestServiceInfo(String type, String name);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
* <p/>
* Usage note: Do not call this method from the AWT event dispatcher thread. You will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
*/
public abstract void requestServiceInfo(String type, String name, boolean persistent);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds
*/
public abstract void requestServiceInfo(String type, String name, long timeout);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param timeout
* timeout in milliseconds
*/
public abstract void requestServiceInfo(String type, String name, boolean persistent, long timeout);
/**
* Listen for service types.
*
* @param listener
* listener for service types
* @exception IOException
* if there is an error in the underlying protocol, such as a TCP error.
*/
public abstract void addServiceTypeListener(ServiceTypeListener listener) throws IOException;
/**
* Remove listener for service types.
*
* @param listener
* listener for service types
*/
public abstract void removeServiceTypeListener(ServiceTypeListener listener);
/**
* Listen for services of a given type. The type has to be a fully qualified type name such as <code>_http._tcp.local.</code>.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @param listener
* listener for service updates
*/
public abstract void addServiceListener(String type, ServiceListener listener);
/**
* Remove listener for services of a given type.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @param listener
* listener for service updates
*/
public abstract void removeServiceListener(String type, ServiceListener listener);
/**
* Register a service. The service is registered for access by other jmdns clients. The name of the service may be changed to make it unique.<br>
* Note that the given {@code ServiceInfo} is bound to this {@code JmDNS} instance, and should not be reused for any other {@linkplain #registerService(ServiceInfo)}.
*
* @param info
* service info to register
* @exception IOException
* if there is an error in the underlying protocol, such as a TCP error.
*/
public abstract void registerService(ServiceInfo info) throws IOException;
/**
* Unregister a service. The service should have been registered.
* <p>
* <b>Note:</b> Unregistered services will not disappear form the list of services immediately. According to the specification, when unregistering services we send goodbye packets and then wait <b>1s</b> before purging the cache.<br/>
* This is support for shared records that can be rescued by some other cooperation DNS.
*
* <pre>
* Clients receiving a Multicast DNS Response with a TTL of zero SHOULD NOT immediately delete the record from the cache, but instead record a TTL of 1 and then delete the record one second later.
* </pre>
*
* </p>
*
* @param info
* service info to remove
*/
public abstract void unregisterService(ServiceInfo info);
/**
* Unregister all services.
*/
public abstract void unregisterAllServices();
/**
* Register a service type. If this service type was not already known, all service listeners will be notified of the new service type.
* <p>
* Service types are automatically registered as they are discovered.
* </p>
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @return <code>true</code> if the type or subtype was added, <code>false</code> if the type was already registered.
*/
public abstract boolean registerServiceType(String type);
/**
* List Services and serviceTypes. Debugging Only
*
* @deprecated since 3.2.2
*/
@Deprecated
public abstract void printServices();
/**
* Returns a list of service infos of the specified type.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @return An array of service instance.
*/
public abstract ServiceInfo[] list(String type);
/**
* Returns a list of service infos of the specified type.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @param timeout
* timeout in milliseconds. Typical timeout should be 6s.
* @return An array of service instance.
*/
public abstract ServiceInfo[] list(String type, long timeout);
/**
* Returns a list of service infos of the specified type sorted by subtype. Any service that do not register a subtype is listed in the empty subtype section.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @return A dictionary of service info by subtypes.
*/
public abstract Map<String, ServiceInfo[]> listBySubtype(String type);
/**
* Returns a list of service infos of the specified type sorted by subtype. Any service that do not register a subtype is listed in the empty subtype section.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @param timeout
* timeout in milliseconds. Typical timeout should be 6s.
* @return A dictionary of service info by subtypes.
*/
public abstract Map<String, ServiceInfo[]> listBySubtype(String type, long timeout);
/**
* Returns the instance delegate
*
* @return instance delegate
*/
public abstract Delegate getDelegate();
/**
* Sets the instance delegate
*
* @param value
* new instance delegate
* @return previous instance delegate
*/
public abstract Delegate setDelegate(Delegate value);
}

View file

@ -0,0 +1,426 @@
/**
*
*/
package javax.jmdns;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.jmdns.impl.JmmDNSImpl;
/**
* <p>
* Java Multihomed Multicast DNS
* </p>
* Uses an underlying {@link JmDNS} instance for each {@link InetAddress} found on this computer.<br/>
* This class will monitor network topology changes, and will create or destroy JmDNS instances as required. It is your responsibility to maintain services registration (hint: use a {@link NetworkTopologyListener}).<br/>
* Most of this class methods have no notion of transaction: if an Exception is raised in the middle of execution, you may be in an incoherent state.
* <p>
* <b>Note:</b> This API is experimental and may change in the future please let us know what work and what does not work in your application.
* </p>
*
* @author C&eacute;drik Lime, Pierre Frisch
*/
public interface JmmDNS extends Closeable {
/**
* JmmDNS.Factory enable the creation of new instance of JmmDNS.
*/
public static final class Factory {
private static volatile JmmDNS _instance;
/**
* This interface defines a delegate to the EOClassDescriptionRegister class to enable subclassing.
*/
public static interface ClassDelegate {
/**
* Allows the delegate the opportunity to construct and return a different JmmDNS.
*
* @return Should return a new JmmDNS.
* @see #classDelegate()
* @see #setClassDelegate(ClassDelegate anObject)
*/
public JmmDNS newJmmDNS();
}
private static final AtomicReference<ClassDelegate> _databaseClassDelegate = new AtomicReference<ClassDelegate>();
private Factory() {
super();
}
/**
* Assigns <code>delegate</code> as JmmDNS's class delegate. The class delegate is optional.
*
* @param delegate
* The object to set as JmmDNS's class delegate.
* @see #classDelegate()
* @see JmmDNS.Factory.ClassDelegate
*/
public static void setClassDelegate(ClassDelegate delegate) {
_databaseClassDelegate.set(delegate);
}
/**
* Returns JmmDNS's class delegate.
*
* @return JmmDNS's class delegate.
* @see #setClassDelegate(ClassDelegate anObject)
* @see JmmDNS.Factory.ClassDelegate
*/
public static ClassDelegate classDelegate() {
return _databaseClassDelegate.get();
}
/**
* Returns a new instance of JmmDNS using the class delegate if it exists.
*
* @return new instance of JmmDNS
*/
protected static JmmDNS newJmmDNS() {
JmmDNS dns = null;
ClassDelegate delegate = _databaseClassDelegate.get();
if (delegate != null) {
dns = delegate.newJmmDNS();
}
return (dns != null ? dns : new JmmDNSImpl());
}
/**
* Return the instance of the Multihomed Multicast DNS.
*
* @return the JmmDNS
*/
public static JmmDNS getInstance() {
if (_instance == null) {
synchronized (Factory.class) {
if (_instance == null) {
_instance = JmmDNS.Factory.newJmmDNS();
}
}
}
return _instance;
}
/**
* Closes the instance if still running and discard it.
*
* @throws IOException
*/
public static void close() throws IOException {
synchronized (Factory.class) {
_instance.close();
_instance = null;
}
}
}
/**
* Return the names of the JmDNS instances.
*
* @return list of name of the JmDNS
* @see javax.jmdns.JmDNS#getName()
*/
public abstract String[] getNames();
/**
* Return the list HostName associated with this JmmDNS instance.
*
* @return list of host names
* @see javax.jmdns.JmDNS#getHostName()
*/
public abstract String[] getHostNames();
/**
* Return the list of addresses of the interface to which this instance of JmmDNS is bound.
*
* @return list of Internet Address
* @exception IOException
* @see javax.jmdns.JmDNS#getInetAddress()
*/
public abstract InetAddress[] getInetAddresses() throws IOException;
/**
* Return the list of addresses of the interface to which this instance of JmmDNS is bound.
*
* @return list of Internet Address
* @exception IOException
* @see javax.jmdns.JmDNS#getInterface()
* @deprecated do not use this implementation yields unpredictable results use {@link #getInetAddresses()}
*/
@Deprecated
public abstract InetAddress[] getInterfaces() throws IOException;
/**
* Return a list of all the registered JmDNS instances
*
* @return list of JmDNS instances
*/
public abstract JmDNS[] getDNS();
/**
* Get service information. If the information is not cached, the method will block until updated information is received on all DNS.
* <p/>
* Usage note: Do not call this method from the AWT event dispatcher thread. You will make the user interface unresponsive.
*
* @param type
* fully qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @return list of service info. If no service info is found the list is empty.
* @see javax.jmdns.JmDNS#getServiceInfo(java.lang.String, java.lang.String)
*/
public abstract ServiceInfo[] getServiceInfos(String type, String name);
/**
* Get service information. If the information is not cached, the method will block until updated information is received on all DNS.
* <p/>
* Usage note: If you call this method from the AWT event dispatcher thread, use a small timeout, or you will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds. Typical timeout should be 5s.
* @return list of service info. If no service info is found the list is empty.
* @see javax.jmdns.JmDNS#getServiceInfo(java.lang.String, java.lang.String, long)
*/
public abstract ServiceInfo[] getServiceInfos(String type, String name, long timeout);
/**
* Get service information. If the information is not cached, the method will block until updated information is received on all DNS.
* <p/>
* Usage note: If you call this method from the AWT event dispatcher thread, use a small timeout, or you will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @return list of service info. If no service info is found the list is empty.
* @see javax.jmdns.JmDNS#getServiceInfo(java.lang.String, java.lang.String, boolean)
*/
public abstract ServiceInfo[] getServiceInfos(String type, String name, boolean persistent);
/**
* Get service information. If the information is not cached, the method will block until updated information is received on all DNS.
* <p/>
* Usage note: If you call this method from the AWT event dispatcher thread, use a small timeout, or you will make the user interface unresponsive.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds. Typical timeout should be 5s.
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @return list of service info. If no service info is found the list is empty.
* @see javax.jmdns.JmDNS#getServiceInfo(java.lang.String, java.lang.String, boolean, long)
*/
public abstract ServiceInfo[] getServiceInfos(String type, String name, boolean persistent, long timeout);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @see javax.jmdns.JmDNS#requestServiceInfo(java.lang.String, java.lang.String)
*/
public abstract void requestServiceInfo(String type, String name);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @see javax.jmdns.JmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean)
*/
public abstract void requestServiceInfo(String type, String name, boolean persistent);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param timeout
* timeout in milliseconds
* @see javax.jmdns.JmDNS#requestServiceInfo(java.lang.String, java.lang.String, long)
*/
public abstract void requestServiceInfo(String type, String name, long timeout);
/**
* Request service information. The information about the service is requested and the ServiceListener.resolveService method is called as soon as it is available.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code> .
* @param name
* unqualified service name, such as <code>foobar</code> .
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param timeout
* timeout in milliseconds
* @see javax.jmdns.JmDNS#requestServiceInfo(java.lang.String, java.lang.String, boolean, long)
*/
public abstract void requestServiceInfo(String type, String name, boolean persistent, long timeout);
/**
* Listen for service types.
*
* @param listener
* listener for service types
* @exception IOException
* @see javax.jmdns.JmDNS#addServiceTypeListener(javax.jmdns.ServiceTypeListener)
*/
public abstract void addServiceTypeListener(ServiceTypeListener listener) throws IOException;
/**
* Remove listener for service types.
*
* @param listener
* listener for service types
* @see javax.jmdns.JmDNS#removeServiceTypeListener(javax.jmdns.ServiceTypeListener)
*/
public abstract void removeServiceTypeListener(ServiceTypeListener listener);
/**
* Listen for services of a given type. The type has to be a fully qualified type name such as <code>_http._tcp.local.</code>.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @param listener
* listener for service updates
* @see javax.jmdns.JmDNS#addServiceListener(java.lang.String, javax.jmdns.ServiceListener)
*/
public abstract void addServiceListener(String type, ServiceListener listener);
/**
* Remove listener for services of a given type.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @param listener
* listener for service updates
* @see javax.jmdns.JmDNS#removeServiceListener(java.lang.String, javax.jmdns.ServiceListener)
*/
public abstract void removeServiceListener(String type, ServiceListener listener);
/**
* Register a service. The service is registered for access by other jmdns clients. The name of the service may be changed to make it unique.<br>
* <b>Note</b> the Service info is cloned for each network interface.
*
* @param info
* service info to register
* @exception IOException
* @see javax.jmdns.JmDNS#registerService(javax.jmdns.ServiceInfo)
*/
public abstract void registerService(ServiceInfo info) throws IOException;
/**
* Unregister a service. The service should have been registered.
*
* @param info
* service info to remove
* @see javax.jmdns.JmDNS#unregisterService(javax.jmdns.ServiceInfo)
*/
public abstract void unregisterService(ServiceInfo info);
/**
* Unregister all services.
*
* @see javax.jmdns.JmDNS#unregisterAllServices()
*/
public abstract void unregisterAllServices();
/**
* Register a service type. If this service type was not already known, all service listeners will be notified of the new service type. Service types are automatically registered as they are discovered.
*
* @param type
* full qualified service type, such as <code>_http._tcp.local.</code>.
* @see javax.jmdns.JmDNS#registerServiceType(java.lang.String)
*/
public abstract void registerServiceType(String type);
/**
* Returns a list of service infos of the specified type.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @return An array of service instance.
* @see javax.jmdns.JmDNS#list(java.lang.String)
*/
public abstract ServiceInfo[] list(String type);
/**
* Returns a list of service infos of the specified type.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @param timeout
* timeout in milliseconds. Typical timeout should be 6s.
* @return An array of service instance.
* @see javax.jmdns.JmDNS#list(java.lang.String, long)
*/
public abstract ServiceInfo[] list(String type, long timeout);
/**
* Returns a list of service infos of the specified type sorted by subtype. Any service that do not register a subtype is listed in the empty subtype section.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @return A dictionary of service info by subtypes.
* @see javax.jmdns.JmDNS#listBySubtype(java.lang.String)
*/
public abstract Map<String, ServiceInfo[]> listBySubtype(String type);
/**
* Returns a list of service infos of the specified type sorted by subtype. Any service that do not register a subtype is listed in the empty subtype section.
*
* @param type
* Service type name, such as <code>_http._tcp.local.</code>.
* @param timeout
* timeout in milliseconds. Typical timeout should be 6s.
* @return A dictionary of service info by subtypes.
* @see javax.jmdns.JmDNS#listBySubtype(java.lang.String, long)
*/
public abstract Map<String, ServiceInfo[]> listBySubtype(String type, long timeout);
/**
* Listen to network changes.
*
* @param listener
* listener for network changes
*/
public abstract void addNetworkTopologyListener(NetworkTopologyListener listener);
/**
* Remove listener for network changes.
*
* @param listener
* listener for network changes
*/
public abstract void removeNetworkTopologyListener(NetworkTopologyListener listener);
/**
* Returns list of network change listeners
*
* @return list of network change listeners
*/
public abstract NetworkTopologyListener[] networkListeners();
}

View file

@ -0,0 +1,164 @@
package javax.jmdns;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.atomic.AtomicReference;
import javax.jmdns.impl.NetworkTopologyDiscoveryImpl;
/**
* This class is used to resolve the list of Internet address to use when attaching JmDNS to the network.
* <p>
* To create you own filtering class for Internet Addresses you will need to implement the class and the factory delegate. These must be called before any other call to JmDNS.
*
* <pre>
* public static class MyNetworkTopologyDiscovery implements NetworkTopologyDiscovery {
*
* &#064;Override
* public InetAddress[] getInetAddresses() {
* // TODO Auto-generated method stub
* return null;
* }
*
* &#064;Override
* public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress) {
* // TODO Auto-generated method stub
* return false;
* }
*
* }
*
* public static class MyClass implements NetworkTopologyDiscovery.Factory.ClassDelegate {
* public MyClass() {
* super();
* NetworkTopologyDiscovery.Factory.setClassDelegate(this);
*
* // Access JmDNS or JmmDNS
* }
*
* &#064;Override
* public NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
* return new MyNetworkTopologyDiscovery();
* }
*
* }
* </pre>
*
* </p>
*
* @author Pierre Frisch
*/
public interface NetworkTopologyDiscovery {
/**
* NetworkTopologyDiscovery.Factory enable the creation of new instance of NetworkTopologyDiscovery.
*/
public static final class Factory {
private static volatile NetworkTopologyDiscovery _instance;
/**
* This interface defines a delegate to the NetworkTopologyDiscovery.Factory class to enable subclassing.
*/
public static interface ClassDelegate {
/**
* Allows the delegate the opportunity to construct and return a different NetworkTopologyDiscovery.
*
* @return Should return a new NetworkTopologyDiscovery Object.
* @see #classDelegate()
* @see #setClassDelegate(ClassDelegate anObject)
*/
public NetworkTopologyDiscovery newNetworkTopologyDiscovery();
}
private static final AtomicReference<Factory.ClassDelegate> _databaseClassDelegate = new AtomicReference<Factory.ClassDelegate>();
private Factory() {
super();
}
/**
* Assigns <code>delegate</code> as NetworkTopologyDiscovery's class delegate. The class delegate is optional.
*
* @param delegate
* The object to set as NetworkTopologyDiscovery's class delegate.
* @see #classDelegate()
* @see JmmDNS.Factory.ClassDelegate
*/
public static void setClassDelegate(Factory.ClassDelegate delegate) {
_databaseClassDelegate.set(delegate);
}
/**
* Returns NetworkTopologyDiscovery's class delegate.
*
* @return NetworkTopologyDiscovery's class delegate.
* @see #setClassDelegate(ClassDelegate anObject)
* @see JmmDNS.Factory.ClassDelegate
*/
public static Factory.ClassDelegate classDelegate() {
return _databaseClassDelegate.get();
}
/**
* Returns a new instance of NetworkTopologyDiscovery using the class delegate if it exists.
*
* @return new instance of NetworkTopologyDiscovery
*/
protected static NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
NetworkTopologyDiscovery instance = null;
Factory.ClassDelegate delegate = _databaseClassDelegate.get();
if (delegate != null) {
instance = delegate.newNetworkTopologyDiscovery();
}
return (instance != null ? instance : new NetworkTopologyDiscoveryImpl());
}
/**
* Return the instance of the Multihomed Multicast DNS.
*
* @return the JmmDNS
*/
public static NetworkTopologyDiscovery getInstance() {
if (_instance == null) {
synchronized (NetworkTopologyDiscovery.Factory.class) {
if (_instance == null) {
_instance = NetworkTopologyDiscovery.Factory.newNetworkTopologyDiscovery();
}
}
}
return _instance;
}
}
/**
* Get all local Internet Addresses for the machine.
*
* @return Set of InetAddress
*/
public abstract InetAddress[] getInetAddresses();
/**
* Check if a given InetAddress should be used for mDNS
*
* @param networkInterface
* @param interfaceAddress
* @return <code>true</code> is the address is to be used, <code>false</code> otherwise.
*/
public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress);
/**
* Locks the given InetAddress if the device requires it.
*
* @param interfaceAddress
*/
public void lockInetAddress(InetAddress interfaceAddress);
/**
* Locks the given InetAddress if the device requires it.
*
* @param interfaceAddress
*/
public void unlockInetAddress(InetAddress interfaceAddress);
}

View file

@ -0,0 +1,45 @@
/**
*
*/
package javax.jmdns;
import java.net.InetAddress;
import java.util.EventObject;
/**
* @author C&eacute;drik Lime, Pierre Frisch
*/
public abstract class NetworkTopologyEvent extends EventObject {
/**
*
*/
private static final long serialVersionUID = -8630033521752540987L;
/**
* Constructs a Service Event.
*
* @param eventSource
* The DNS on which the Event initially occurred.
* @exception IllegalArgumentException
* if source is null.
*/
protected NetworkTopologyEvent(final Object eventSource) {
super(eventSource);
}
/**
* Returns the JmDNS instance associated with the event or null if it is a generic event.
*
* @return JmDNS instance
*/
public abstract JmDNS getDNS();
/**
* The Internet address affected by this event.
*
* @return InetAddress
*/
public abstract InetAddress getInetAddress();
}

View file

@ -0,0 +1,30 @@
/**
*
*/
package javax.jmdns;
import java.util.EventListener;
/**
* Listener for network topology updates.
*
* @author C&eacute;drik Lime, Pierre Frisch
*/
public interface NetworkTopologyListener extends EventListener {
/**
* A network address has been added.<br/>
*
* @param event
* The NetworkTopologyEvent providing the name and fully qualified type of the service.
*/
void inetAddressAdded(NetworkTopologyEvent event);
/**
* A network address has been removed.
*
* @param event
* The NetworkTopologyEvent providing the name and fully qualified type of the service.
*/
void inetAddressRemoved(NetworkTopologyEvent event);
}

View file

@ -0,0 +1,74 @@
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns;
import java.util.EventObject;
/**
*
*/
public abstract class ServiceEvent extends EventObject implements Cloneable {
/**
*
*/
private static final long serialVersionUID = -8558445644541006271L;
/**
* Constructs a Service Event.
*
* @param eventSource
* The object on which the Event initially occurred.
* @exception IllegalArgumentException
* if source is null.
*/
public ServiceEvent(final Object eventSource) {
super(eventSource);
}
/**
* Returns the JmDNS instance which originated the event.
*
* @return JmDNS instance
*/
public abstract JmDNS getDNS();
/**
* Returns the fully qualified type of the service.
*
* @return type of the service.
*/
public abstract String getType();
/**
* Returns the instance name of the service. Always returns null, if the event is sent to a service type listener.
*
* @return name of the service
*/
public abstract String getName();
/**
* Returns the service info record, or null if the service could not be resolved. Always returns null, if the event is sent to a service type listener.
*
* @return service info record
* @see javax.jmdns.ServiceEvent#getInfo()
*/
public abstract ServiceInfo getInfo();
/*
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
public ServiceEvent clone() {
try {
return (ServiceEvent) super.clone();
} catch (CloneNotSupportedException exception) {
// clone is supported
return null;
}
}
}

View file

@ -0,0 +1,727 @@
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Enumeration;
import java.util.Map;
import javax.jmdns.impl.ServiceInfoImpl;
/**
* <p>
* The fully qualified service name is build using up to 5 components with the following structure:
*
* <pre>
* &lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.<br/>
* &lt;Instance&gt;.&lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.<br/>
* &lt;sub&gt;._sub.&lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.
* </pre>
*
* <ol>
* <li>&lt;servicedomain&gt;.&lt;parentdomain&gt;: This is the domain scope of the service typically "local.", but this can also be something similar to "in-addr.arpa." or "ip6.arpa."</li>
* <li>&lt;protocol&gt;: This is either "_tcp" or "_udp"</li>
* <li>&lt;app&gt;: This define the application protocol. Typical example are "_http", "_ftp", etc.</li>
* <li>&lt;Instance&gt;: This is the service name</li>
* <li>&lt;sub&gt;: This is the subtype for the application protocol</li>
* </ol>
* </p>
*/
public abstract class ServiceInfo implements Cloneable {
/**
* This is the no value text byte. According top the specification it is one byte with 0 value.
*/
public static final byte[] NO_VALUE = new byte[0];
/**
* Fields for the fully qualified map.
*/
public enum Fields {
/**
* Domain Field.
*/
Domain,
/**
* Protocol Field.
*/
Protocol,
/**
* Application Field.
*/
Application,
/**
* Instance Field.
*/
Instance,
/**
* Subtype Field.
*/
Subtype
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final String text) {
return new ServiceInfoImpl(type, name, "", port, 0, 0, false, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final String text) {
return new ServiceInfoImpl(type, name, subtype, port, 0, 0, false, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final String text) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, false, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final String text) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, false, text);
}
/**
* Construct a service description for registering with JmDNS. The properties hashtable must map property names to either Strings or byte arrays describing the property values.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param props
* properties describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final Map<String, ?> props) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, false, props);
}
/**
* Construct a service description for registering with JmDNS. The properties hashtable must map property names to either Strings or byte arrays describing the property values.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param props
* properties describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final Map<String, ?> props) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, false, props);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param text
* bytes describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final byte[] text) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, false, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param text
* bytes describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final byte[] text) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, false, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final boolean persistent, final String text) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, persistent, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param text
* string describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final boolean persistent, final String text) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, persistent, text);
}
/**
* Construct a service description for registering with JmDNS. The properties hashtable must map property names to either Strings or byte arrays describing the property values.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param props
* properties describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final boolean persistent, final Map<String, ?> props) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, persistent, props);
}
/**
* Construct a service description for registering with JmDNS. The properties hashtable must map property names to either Strings or byte arrays describing the property values.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param props
* properties describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final boolean persistent, final Map<String, ?> props) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, persistent, props);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param text
* bytes describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final int port, final int weight, final int priority, final boolean persistent, final byte[] text) {
return new ServiceInfoImpl(type, name, "", port, weight, priority, persistent, text);
}
/**
* Construct a service description for registering with JmDNS.
*
* @param type
* fully qualified service type name, such as <code>_http._tcp.local.</code>.
* @param name
* unqualified service instance name, such as <code>foobar</code>
* @param subtype
* service subtype see draft-cheshire-dnsext-dns-sd-06.txt chapter 7.1 Selective Instance Enumeration
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param text
* bytes describing the service
* @return new service info
*/
public static ServiceInfo create(final String type, final String name, final String subtype, final int port, final int weight, final int priority, final boolean persistent, final byte[] text) {
return new ServiceInfoImpl(type, name, subtype, port, weight, priority, persistent, text);
}
/**
* Construct a service description for registering with JmDNS. The properties hashtable must map property names to either Strings or byte arrays describing the property values.
*
* @param qualifiedNameMap
* dictionary of values to build the fully qualified service name. Mandatory keys are Application and Instance. The Domain default is local, the Protocol default is tcp and the subtype default is none.
* @param port
* the local port on which the service runs
* @param weight
* weight of the service
* @param priority
* priority of the service
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @param props
* properties describing the service
* @return new service info
*/
public static ServiceInfo create(final Map<Fields, String> qualifiedNameMap, final int port, final int weight, final int priority, final boolean persistent, final Map<String, ?> props) {
return new ServiceInfoImpl(qualifiedNameMap, port, weight, priority, persistent, props);
}
/**
* Returns true if the service info is filled with data.
*
* @return <code>true</code> if the service info has data, <code>false</code> otherwise.
*/
public abstract boolean hasData();
/**
* Fully qualified service type name, such as <code>_http._tcp.local.</code>
*
* @return service type name
*/
public abstract String getType();
/**
* Fully qualified service type name with the subtype if appropriate, such as <code>_printer._sub._http._tcp.local.</code>
*
* @return service type name
*/
public abstract String getTypeWithSubtype();
/**
* Unqualified service instance name, such as <code>foobar</code> .
*
* @return service name
*/
public abstract String getName();
/**
* The key is used to retrieve service info in hash tables.<br/>
* The key is the lower case qualified name.
*
* @return the key
*/
public abstract String getKey();
/**
* Fully qualified service name, such as <code>foobar._http._tcp.local.</code> .
*
* @return qualified service name
*/
public abstract String getQualifiedName();
/**
* Get the name of the server.
*
* @return server name
*/
public abstract String getServer();
/**
* Returns the host IP address string in textual presentation.<br/>
* <b>Note:</b> This can be either an IPv4 or an IPv6 representation.
*
* @return the host raw IP address in a string format.
* @deprecated since 3.2.3
* @see #getHostAddresses()
*/
@Deprecated
public abstract String getHostAddress();
/**
* Returns the host IP addresses string in textual presentation.
*
* @return list of host raw IP address in a string format.
*/
public abstract String[] getHostAddresses();
/**
* Get the host address of the service.<br/>
*
* @return host Internet address
* @deprecated since 3.1.8
* @see #getInetAddresses()
*/
@Deprecated
public abstract InetAddress getAddress();
/**
* Get the InetAddress of the service. This will return the IPv4 if it exist, otherwise it return the IPv6 if set.<br/>
* <b>Note:</b> This return null if the service IP address cannot be resolved.
*
* @return Internet address
* @deprecated since 3.2.3
* @see #getInetAddresses()
*/
@Deprecated
public abstract InetAddress getInetAddress();
/**
* Get the IPv4 InetAddress of the service.<br/>
* <b>Note:</b> This return null if the service IPv4 address cannot be resolved.
*
* @return Internet address
* @deprecated since 3.2.3
* @see #getInet4Addresses()
*/
@Deprecated
public abstract Inet4Address getInet4Address();
/**
* Get the IPv6 InetAddress of the service.<br/>
* <b>Note:</b> This return null if the service IPv6 address cannot be resolved.
*
* @return Internet address
* @deprecated since 3.2.3
* @see #getInet6Addresses()
*/
@Deprecated
public abstract Inet6Address getInet6Address();
/**
* Returns a list of all InetAddresses that can be used for this service.
* <p>
* In a multi-homed environment service info can be associated with more than one address.
* </p>
*
* @return list of InetAddress objects
*/
public abstract InetAddress[] getInetAddresses();
/**
* Returns a list of all IPv4 InetAddresses that can be used for this service.
* <p>
* In a multi-homed environment service info can be associated with more than one address.
* </p>
*
* @return list of InetAddress objects
*/
public abstract Inet4Address[] getInet4Addresses();
/**
* Returns a list of all IPv6 InetAddresses that can be used for this service.
* <p>
* In a multi-homed environment service info can be associated with more than one address.
* </p>
*
* @return list of InetAddress objects
*/
public abstract Inet6Address[] getInet6Addresses();
/**
* Get the port for the service.
*
* @return service port
*/
public abstract int getPort();
/**
* Get the priority of the service.
*
* @return service priority
*/
public abstract int getPriority();
/**
* Get the weight of the service.
*
* @return service weight
*/
public abstract int getWeight();
/**
* Get the text for the service as raw bytes.
*
* @return raw service text
*/
public abstract byte[] getTextBytes();
/**
* Get the text for the service. This will interpret the text bytes as a UTF8 encoded string. Will return null if the bytes are not a valid UTF8 encoded string.<br/>
* <b>Note:</b> Do not use. This method make the assumption that the TXT record is one string. This is false. The TXT record is a series of key value pairs.
*
* @return service text
* @see #getPropertyNames()
* @see #getPropertyBytes(String)
* @see #getPropertyString(String)
* @deprecated since 3.1.7
*/
@Deprecated
public abstract String getTextString();
/**
* Get the URL for this service. An http URL is created by combining the address, port, and path properties.
*
* @return service URL
* @deprecated since 3.2.3
* @see #getURLs()
*/
@Deprecated
public abstract String getURL();
/**
* Get the list of URL for this service. An http URL is created by combining the address, port, and path properties.
*
* @return list of service URL
*/
public abstract String[] getURLs();
/**
* Get the URL for this service. An URL is created by combining the protocol, address, port, and path properties.
*
* @param protocol
* requested protocol
* @return service URL
* @deprecated since 3.2.3
* @see #getURLs()
*/
@Deprecated
public abstract String getURL(String protocol);
/**
* Get the list of URL for this service. An URL is created by combining the protocol, address, port, and path properties.
*
* @param protocol
* requested protocol
* @return list of service URL
*/
public abstract String[] getURLs(String protocol);
/**
* Get a property of the service. This involves decoding the text bytes into a property list. Returns null if the property is not found or the text data could not be decoded correctly.
*
* @param name
* property name
* @return raw property text
*/
public abstract byte[] getPropertyBytes(final String name);
/**
* Get a property of the service. This involves decoding the text bytes into a property list. Returns null if the property is not found, the text data could not be decoded correctly, or the resulting bytes are not a valid UTF8 string.
*
* @param name
* property name
* @return property text
*/
public abstract String getPropertyString(final String name);
/**
* Enumeration of the property names.
*
* @return property name enumeration
*/
public abstract Enumeration<String> getPropertyNames();
/**
* Returns a description of the service info suitable for printing.
*
* @return service info description
*/
public abstract String getNiceTextString();
/**
* Set the text for the service. Setting the text will fore a re-announce of the service.
*
* @param text
* the raw byte representation of the text field.
* @exception IllegalStateException
* if attempting to set the text for a non persistent service info.
*/
public abstract void setText(final byte[] text) throws IllegalStateException;
/**
* Set the text for the service. Setting the text will fore a re-announce of the service.
*
* @param props
* a key=value map that will be encoded into raw bytes.
* @exception IllegalStateException
* if attempting to set the text for a non persistent service info.
*/
public abstract void setText(final Map<String, ?> props) throws IllegalStateException;
/**
* Returns <code>true</code> if ServiceListener.resolveService will be called whenever new new information is received.
*
* @return the persistent
*/
public abstract boolean isPersistent();
/**
* Returns the domain of the service info suitable for printing.
*
* @return service domain
*/
public abstract String getDomain();
/**
* Returns the protocol of the service info suitable for printing.
*
* @return service protocol
*/
public abstract String getProtocol();
/**
* Returns the application of the service info suitable for printing.
*
* @return service application
*/
public abstract String getApplication();
/**
* Returns the sub type of the service info suitable for printing.
*
* @return service sub type
*/
public abstract String getSubtype();
/**
* Returns a dictionary of the fully qualified name component of this service.
*
* @return dictionary of the fully qualified name components
*/
public abstract Map<Fields, String> getQualifiedNameMap();
/*
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
public ServiceInfo clone() {
try {
return (ServiceInfo) super.clone();
} catch (CloneNotSupportedException exception) {
// clone is supported
return null;
}
}
}

View file

@ -0,0 +1,49 @@
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns;
import java.util.EventListener;
/**
* Listener for service updates.
*
* @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch
*/
public interface ServiceListener extends EventListener {
/**
* A service has been added.<br/>
* <b>Note:</b>This event is only the service added event. The service info associated with this event does not include resolution information.<br/>
* To get the full resolved information you need to listen to {@link #serviceResolved(ServiceEvent)} or call {@link JmDNS#getServiceInfo(String, String, long)}
*
* <pre>
* ServiceInfo info = event.getDNS().getServiceInfo(event.getType(), event.getName())
* </pre>
* <p>
* Please note that service resolution may take a few second to resolve.
* </p>
*
* @param event
* The ServiceEvent providing the name and fully qualified type of the service.
*/
void serviceAdded(ServiceEvent event);
/**
* A service has been removed.
*
* @param event
* The ServiceEvent providing the name and fully qualified type of the service.
*/
void serviceRemoved(ServiceEvent event);
/**
* A service has been resolved. Its details are now available in the ServiceInfo record.<br/>
* <b>Note:</b>This call back will never be called if the service does not resolve.<br/>
*
* @param event
* The ServiceEvent providing the name, the fully qualified type of the service, and the service info record.
*/
void serviceResolved(ServiceEvent event);
}

View file

@ -0,0 +1,35 @@
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns;
import java.util.EventListener;
/**
* Listener for service types.
*
* @author Arthur van Hoff, Werner Randelshofer
*/
public interface ServiceTypeListener extends EventListener {
/**
* A new service type was discovered.
*
* @param event
* The service event providing the fully qualified type of the service.
*/
void serviceTypeAdded(ServiceEvent event);
/**
* A new subtype for the service type was discovered.
*
* <pre>
* &lt;sub&gt;._sub.&lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.
* </pre>
*
* @param event
* The service event providing the fully qualified type of the service with subtype.
* @since 3.2.0
*/
void subTypeForServiceTypeAdded(ServiceEvent event);
}

View file

@ -0,0 +1,293 @@
// Copyright 2003-2005 Arthur van Hoff Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
/**
* A table of DNS entries. This is a map table which can handle multiple entries with the same name.
* <p/>
* Storing multiple entries with the same name is implemented using a linked list. This is hidden from the user and can change in later implementation.
* <p/>
* Here's how to iterate over all entries:
*
* <pre>
* for (Iterator i=dnscache.allValues().iterator(); i.hasNext(); ) {
* DNSEntry entry = i.next();
* ...do something with entry...
* }
* </pre>
* <p/>
* And here's how to iterate over all entries having a given name:
*
* <pre>
* for (Iterator i=dnscache.getDNSEntryList(name).iterator(); i.hasNext(); ) {
* DNSEntry entry = i.next();
* ...do something with entry...
* }
* </pre>
*
* @author Arthur van Hoff, Werner Randelshofer, Rick Blair, Pierre Frisch
*/
public class DNSCache extends ConcurrentHashMap<String, List<DNSEntry>> {
// private static Logger logger = Logger.getLogger(DNSCache.class.getName());
private static final long serialVersionUID = 3024739453186759259L;
/**
*
*/
public DNSCache() {
this(1024);
}
/**
* @param map
*/
public DNSCache(DNSCache map) {
this(map != null ? map.size() : 1024);
if (map != null) {
this.putAll(map);
}
}
/**
* Create a table with a given initial size.
*
* @param initialCapacity
*/
public DNSCache(int initialCapacity) {
super(initialCapacity);
}
// ====================================================================
// Map
/**
* {@inheritDoc}
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return new DNSCache(this);
}
// ====================================================================
/**
* Returns all entries in the cache
*
* @return all entries in the cache
*/
public Collection<DNSEntry> allValues() {
List<DNSEntry> allValues = new ArrayList<DNSEntry>();
for (List<? extends DNSEntry> entry : this.values()) {
if (entry != null) {
allValues.addAll(entry);
}
}
return allValues;
}
/**
* Iterate only over items with matching name. Returns an list of DNSEntry or null. To retrieve all entries, one must iterate over this linked list.
*
* @param name
* @return list of DNSEntries
*/
public Collection<? extends DNSEntry> getDNSEntryList(String name) {
Collection<? extends DNSEntry> entryList = this._getDNSEntryList(name);
if (entryList != null) {
synchronized (entryList) {
entryList = new ArrayList<DNSEntry>(entryList);
}
} else {
entryList = Collections.emptyList();
}
return entryList;
}
private Collection<? extends DNSEntry> _getDNSEntryList(String name) {
return this.get(name != null ? name.toLowerCase() : null);
}
/**
* Get a matching DNS entry from the table (using isSameEntry). Returns the entry that was found.
*
* @param dnsEntry
* @return DNSEntry
*/
public DNSEntry getDNSEntry(DNSEntry dnsEntry) {
DNSEntry result = null;
if (dnsEntry != null) {
Collection<? extends DNSEntry> entryList = this._getDNSEntryList(dnsEntry.getKey());
if (entryList != null) {
synchronized (entryList) {
for (DNSEntry testDNSEntry : entryList) {
if (testDNSEntry.isSameEntry(dnsEntry)) {
result = testDNSEntry;
break;
}
}
}
}
}
return result;
}
/**
* Get a matching DNS entry from the table.
*
* @param name
* @param type
* @param recordClass
* @return DNSEntry
*/
public DNSEntry getDNSEntry(String name, DNSRecordType type, DNSRecordClass recordClass) {
DNSEntry result = null;
Collection<? extends DNSEntry> entryList = this._getDNSEntryList(name);
if (entryList != null) {
synchronized (entryList) {
for (DNSEntry testDNSEntry : entryList) {
if (testDNSEntry.matchRecordType(type) && testDNSEntry.matchRecordClass(recordClass)) {
result = testDNSEntry;
break;
}
}
}
}
return result;
}
/**
* Get all matching DNS entries from the table.
*
* @param name
* @param type
* @param recordClass
* @return list of entries
*/
public Collection<? extends DNSEntry> getDNSEntryList(String name, DNSRecordType type, DNSRecordClass recordClass) {
Collection<? extends DNSEntry> entryList = this._getDNSEntryList(name);
if (entryList != null) {
synchronized (entryList) {
entryList = new ArrayList<DNSEntry>(entryList);
for (Iterator<? extends DNSEntry> i = entryList.iterator(); i.hasNext();) {
DNSEntry testDNSEntry = i.next();
if (!testDNSEntry.matchRecordType(type) || (!testDNSEntry.matchRecordClass(recordClass))) {
i.remove();
}
}
}
} else {
entryList = Collections.emptyList();
}
return entryList;
}
/**
* Adds an entry to the table.
*
* @param dnsEntry
* @return true if the entry was added
*/
public boolean addDNSEntry(final DNSEntry dnsEntry) {
boolean result = false;
if (dnsEntry != null) {
List<DNSEntry> entryList = this.get(dnsEntry.getKey());
if (entryList == null) {
this.putIfAbsent(dnsEntry.getKey(), new ArrayList<DNSEntry>());
entryList = this.get(dnsEntry.getKey());
}
synchronized (entryList) {
entryList.add(dnsEntry);
}
// This is probably not very informative
result = true;
}
return result;
}
/**
* Removes a specific entry from the table. Returns true if the entry was found.
*
* @param dnsEntry
* @return true if the entry was removed
*/
public boolean removeDNSEntry(DNSEntry dnsEntry) {
boolean result = false;
if (dnsEntry != null) {
List<DNSEntry> entryList = this.get(dnsEntry.getKey());
if (entryList != null) {
synchronized (entryList) {
entryList.remove(dnsEntry);
}
}
}
return result;
}
/**
* Replace an existing entry by a new one.<br/>
* <b>Note:</b> the 2 entries must have the same key.
*
* @param newDNSEntry
* @param existingDNSEntry
* @return <code>true</code> if the entry has been replace, <code>false</code> otherwise.
*/
public boolean replaceDNSEntry(DNSEntry newDNSEntry, DNSEntry existingDNSEntry) {
boolean result = false;
if ((newDNSEntry != null) && (existingDNSEntry != null) && (newDNSEntry.getKey().equals(existingDNSEntry.getKey()))) {
List<DNSEntry> entryList = this.get(newDNSEntry.getKey());
if (entryList == null) {
this.putIfAbsent(newDNSEntry.getKey(), new ArrayList<DNSEntry>());
entryList = this.get(newDNSEntry.getKey());
}
synchronized (entryList) {
entryList.remove(existingDNSEntry);
entryList.add(newDNSEntry);
}
// This is probably not very informative
result = true;
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized String toString() {
StringBuffer aLog = new StringBuffer(2000);
aLog.append("\t---- cache ----");
for (String key : this.keySet()) {
aLog.append("\n\t\t");
aLog.append("\n\t\tname '");
aLog.append(key);
aLog.append("' ");
List<? extends DNSEntry> entryList = this.get(key);
if ((entryList != null) && (!entryList.isEmpty())) {
synchronized (entryList) {
for (DNSEntry entry : entryList) {
aLog.append("\n\t\t\t");
aLog.append(entry.toString());
}
}
} else {
aLog.append(" no entries");
}
}
return aLog.toString();
}
}

View file

@ -0,0 +1,316 @@
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns.impl;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import javax.jmdns.ServiceInfo.Fields;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
/**
* DNS entry with a name, type, and class. This is the base class for questions and records.
*
* @author Arthur van Hoff, Pierre Frisch, Rick Blair
*/
public abstract class DNSEntry {
// private static Logger logger = Logger.getLogger(DNSEntry.class.getName());
private final String _key;
private final String _name;
private final String _type;
private final DNSRecordType _recordType;
private final DNSRecordClass _dnsClass;
private final boolean _unique;
final Map<Fields, String> _qualifiedNameMap;
/**
* Create an entry.
*/
DNSEntry(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
_name = name;
// _key = (name != null ? name.trim().toLowerCase() : null);
_recordType = type;
_dnsClass = recordClass;
_unique = unique;
_qualifiedNameMap = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getName());
String domain = _qualifiedNameMap.get(Fields.Domain);
String protocol = _qualifiedNameMap.get(Fields.Protocol);
String application = _qualifiedNameMap.get(Fields.Application);
String instance = _qualifiedNameMap.get(Fields.Instance).toLowerCase();
_type = (application.length() > 0 ? "_" + application + "." : "") + (protocol.length() > 0 ? "_" + protocol + "." : "") + domain + ".";
_key = ((instance.length() > 0 ? instance + "." : "") + _type).toLowerCase();
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
boolean result = false;
if (obj instanceof DNSEntry) {
DNSEntry other = (DNSEntry) obj;
result = this.getKey().equals(other.getKey()) && this.getRecordType().equals(other.getRecordType()) && this.getRecordClass() == other.getRecordClass();
}
return result;
}
/**
* Check if two entries have exactly the same name, type, and class.
*
* @param entry
* @return <code>true</code> if the two entries have are for the same record, <code>false</code> otherwise
*/
public boolean isSameEntry(DNSEntry entry) {
return this.getKey().equals(entry.getKey()) && this.matchRecordType(entry.getRecordType()) && this.matchRecordClass(entry.getRecordClass());
}
/**
* Check if two entries have the same subtype.
*
* @param other
* @return <code>true</code> if the two entries have are for the same subtype, <code>false</code> otherwise
*/
public boolean sameSubtype(DNSEntry other) {
return this.getSubtype().equals(other.getSubtype());
}
/**
* Check if the requested record class match the current record class
*
* @param recordClass
* @return <code>true</code> if the two entries have compatible class, <code>false</code> otherwise
*/
public boolean matchRecordClass(DNSRecordClass recordClass) {
return (DNSRecordClass.CLASS_ANY == recordClass) || (DNSRecordClass.CLASS_ANY == this.getRecordClass()) || this.getRecordClass().equals(recordClass);
}
/**
* Check if the requested record tyep match the current record type
*
* @param recordType
* @return <code>true</code> if the two entries have compatible type, <code>false</code> otherwise
*/
public boolean matchRecordType(DNSRecordType recordType) {
return this.getRecordType().equals(recordType);
}
/**
* Returns the subtype of this entry
*
* @return subtype of this entry
*/
public String getSubtype() {
String subtype = this.getQualifiedNameMap().get(Fields.Subtype);
return (subtype != null ? subtype : "");
}
/**
* Returns the name of this entry
*
* @return name of this entry
*/
public String getName() {
return (_name != null ? _name : "");
}
/**
* @return the type
*/
public String getType() {
return (_type != null ? _type : "");
}
/**
* Returns the key for this entry. The key is the lower case name.
*
* @return key for this entry
*/
public String getKey() {
return (_key != null ? _key : "");
}
/**
* @return record type
*/
public DNSRecordType getRecordType() {
return (_recordType != null ? _recordType : DNSRecordType.TYPE_IGNORE);
}
/**
* @return record class
*/
public DNSRecordClass getRecordClass() {
return (_dnsClass != null ? _dnsClass : DNSRecordClass.CLASS_UNKNOWN);
}
/**
* @return true if unique
*/
public boolean isUnique() {
return _unique;
}
public Map<Fields, String> getQualifiedNameMap() {
return Collections.unmodifiableMap(_qualifiedNameMap);
}
public boolean isServicesDiscoveryMetaQuery() {
return _qualifiedNameMap.get(Fields.Application).equals("dns-sd") && _qualifiedNameMap.get(Fields.Instance).equals("_services");
}
public boolean isDomainDiscoveryQuery() {
// b._dns-sd._udp.<domain>.
// db._dns-sd._udp.<domain>.
// r._dns-sd._udp.<domain>.
// dr._dns-sd._udp.<domain>.
// lb._dns-sd._udp.<domain>.
if (_qualifiedNameMap.get(Fields.Application).equals("dns-sd")) {
String name = _qualifiedNameMap.get(Fields.Instance);
return "b".equals(name) || "db".equals(name) || "r".equals(name) || "dr".equals(name) || "lb".equals(name);
}
return false;
}
public boolean isReverseLookup() {
return this.isV4ReverseLookup() || this.isV6ReverseLookup();
}
public boolean isV4ReverseLookup() {
return _qualifiedNameMap.get(Fields.Domain).endsWith("in-addr.arpa");
}
public boolean isV6ReverseLookup() {
return _qualifiedNameMap.get(Fields.Domain).endsWith("ip6.arpa");
}
/**
* Check if the record is stale, i.e. it has outlived more than half of its TTL.
*
* @param now
* update date
* @return <code>true</code> is the record is stale, <code>false</code> otherwise.
*/
public abstract boolean isStale(long now);
/**
* Check if the record is expired.
*
* @param now
* update date
* @return <code>true</code> is the record is expired, <code>false</code> otherwise.
*/
public abstract boolean isExpired(long now);
/**
* Check that 2 entries are of the same class.
*
* @param entry
* @return <code>true</code> is the two class are the same, <code>false</code> otherwise.
*/
public boolean isSameRecordClass(DNSEntry entry) {
return (entry != null) && (entry.getRecordClass() == this.getRecordClass());
}
/**
* Check that 2 entries are of the same type.
*
* @param entry
* @return <code>true</code> is the two type are the same, <code>false</code> otherwise.
*/
public boolean isSameType(DNSEntry entry) {
return (entry != null) && (entry.getRecordType() == this.getRecordType());
}
/**
* @param dout
* @exception IOException
*/
protected void toByteArray(DataOutputStream dout) throws IOException {
dout.write(this.getName().getBytes("UTF8"));
dout.writeShort(this.getRecordType().indexValue());
dout.writeShort(this.getRecordClass().indexValue());
}
/**
* Creates a byte array representation of this record. This is needed for tie-break tests according to draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
*
* @return byte array representation
*/
protected byte[] toByteArray() {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
this.toByteArray(dout);
dout.close();
return bout.toByteArray();
} catch (IOException e) {
throw new InternalError();
}
}
/**
* Does a lexicographic comparison of the byte array representation of this record and that record. This is needed for tie-break tests according to draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
*
* @param that
* @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
*/
public int compareTo(DNSEntry that) {
byte[] thisBytes = this.toByteArray();
byte[] thatBytes = that.toByteArray();
for (int i = 0, n = Math.min(thisBytes.length, thatBytes.length); i < n; i++) {
if (thisBytes[i] > thatBytes[i]) {
return 1;
} else if (thisBytes[i] < thatBytes[i]) {
return -1;
}
}
return thisBytes.length - thatBytes.length;
}
/**
* Overriden, to return a value which is consistent with the value returned by equals(Object).
*/
@Override
public int hashCode() {
return this.getKey().hashCode() + this.getRecordType().indexValue() + this.getRecordClass().indexValue();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder aLog = new StringBuilder(200);
aLog.append("[" + this.getClass().getSimpleName() + "@" + System.identityHashCode(this));
aLog.append(" type: " + this.getRecordType());
aLog.append(", class: " + this.getRecordClass());
aLog.append((_unique ? "-unique," : ","));
aLog.append(" name: " + _name);
this.toString(aLog);
aLog.append("]");
return aLog.toString();
}
/**
* @param aLog
*/
protected void toString(StringBuilder aLog) {
// Stub
}
}

View file

@ -0,0 +1,604 @@
// /Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jmdns.impl.constants.DNSConstants;
import javax.jmdns.impl.constants.DNSLabel;
import javax.jmdns.impl.constants.DNSOptionCode;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
import javax.jmdns.impl.constants.DNSResultCode;
/**
* Parse an incoming DNS message into its components.
*
* @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch, Daniel Bobbert
*/
public final class DNSIncoming extends DNSMessage {
private static Logger logger = Logger.getLogger(DNSIncoming.class.getName());
// This is a hack to handle a bug in the BonjourConformanceTest
// It is sending out target strings that don't follow the "domain name" format.
public static boolean USE_DOMAIN_NAME_FORMAT_FOR_SRV_TARGET = true;
public static class MessageInputStream extends ByteArrayInputStream {
private static Logger logger1 = Logger.getLogger(MessageInputStream.class.getName());
final Map<Integer, String> _names;
public MessageInputStream(byte[] buffer, int length) {
this(buffer, 0, length);
}
/**
* @param buffer
* @param offset
* @param length
*/
public MessageInputStream(byte[] buffer, int offset, int length) {
super(buffer, offset, length);
_names = new HashMap<Integer, String>();
}
public int readByte() {
return this.read();
}
public int readUnsignedByte() {
return (this.read() & 0xFF);
}
public int readUnsignedShort() {
return (this.readUnsignedByte() << 8) | this.readUnsignedByte();
}
public int readInt() {
return (this.readUnsignedShort() << 16) | this.readUnsignedShort();
}
public byte[] readBytes(int len) {
byte bytes[] = new byte[len];
this.read(bytes, 0, len);
return bytes;
}
public String readUTF(int len) {
StringBuilder buffer = new StringBuilder(len);
for (int index = 0; index < len; index++) {
int ch = this.readUnsignedByte();
switch (ch >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
// 0xxxxxxx
break;
case 12:
case 13:
// 110x xxxx 10xx xxxx
ch = ((ch & 0x1F) << 6) | (this.readUnsignedByte() & 0x3F);
index++;
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
ch = ((ch & 0x0f) << 12) | ((this.readUnsignedByte() & 0x3F) << 6) | (this.readUnsignedByte() & 0x3F);
index++;
index++;
break;
default:
// 10xx xxxx, 1111 xxxx
ch = ((ch & 0x3F) << 4) | (this.readUnsignedByte() & 0x0f);
index++;
break;
}
buffer.append((char) ch);
}
return buffer.toString();
}
protected synchronized int peek() {
return (pos < count) ? (buf[pos] & 0xff) : -1;
}
public String readName() {
Map<Integer, StringBuilder> names = new HashMap<Integer, StringBuilder>();
StringBuilder buffer = new StringBuilder();
boolean finished = false;
while (!finished) {
int len = this.readUnsignedByte();
if (len == 0) {
finished = true;
break;
}
switch (DNSLabel.labelForByte(len)) {
case Standard:
int offset = pos - 1;
String label = this.readUTF(len) + ".";
buffer.append(label);
for (StringBuilder previousLabel : names.values()) {
previousLabel.append(label);
}
names.put(Integer.valueOf(offset), new StringBuilder(label));
break;
case Compressed:
int index = (DNSLabel.labelValue(len) << 8) | this.readUnsignedByte();
String compressedLabel = _names.get(Integer.valueOf(index));
if (compressedLabel == null) {
logger1.severe("bad domain name: possible circular name detected. Bad offset: 0x" + Integer.toHexString(index) + " at 0x" + Integer.toHexString(pos - 2));
compressedLabel = "";
}
buffer.append(compressedLabel);
for (StringBuilder previousLabel : names.values()) {
previousLabel.append(compressedLabel);
}
finished = true;
break;
case Extended:
// int extendedLabelClass = DNSLabel.labelValue(len);
logger1.severe("Extended label are not currently supported.");
break;
case Unknown:
default:
logger1.severe("unsupported dns label type: '" + Integer.toHexString(len & 0xC0) + "'");
}
}
for (Integer index : names.keySet()) {
_names.put(index, names.get(index).toString());
}
return buffer.toString();
}
public String readNonNameString() {
int len = this.readUnsignedByte();
return this.readUTF(len);
}
}
private final DatagramPacket _packet;
private final long _receivedTime;
private final MessageInputStream _messageInputStream;
private int _senderUDPPayload;
/**
* Parse a message from a datagram packet.
*
* @param packet
* @exception IOException
*/
public DNSIncoming(DatagramPacket packet) throws IOException {
super(0, 0, packet.getPort() == DNSConstants.MDNS_PORT);
this._packet = packet;
InetAddress source = packet.getAddress();
this._messageInputStream = new MessageInputStream(packet.getData(), packet.getLength());
this._receivedTime = System.currentTimeMillis();
this._senderUDPPayload = DNSConstants.MAX_MSG_TYPICAL;
try {
this.setId(_messageInputStream.readUnsignedShort());
this.setFlags(_messageInputStream.readUnsignedShort());
if (this.getOperationCode() > 0) {
throw new IOException("Received a message with a non standard operation code. Currently unsupported in the specification.");
}
int numQuestions = _messageInputStream.readUnsignedShort();
int numAnswers = _messageInputStream.readUnsignedShort();
int numAuthorities = _messageInputStream.readUnsignedShort();
int numAdditionals = _messageInputStream.readUnsignedShort();
if (logger.isLoggable(Level.FINER)) {
logger.finer("DNSIncoming() questions:" + numQuestions + " answers:" + numAnswers + " authorities:" + numAuthorities + " additionals:" + numAdditionals);
}
// We need some sanity checks
// A question is at least 5 bytes and answer 11 so check what we have
if ((numQuestions * 5 + (numAnswers + numAuthorities + numAdditionals) * 11) > packet.getLength()) {
throw new IOException("questions:" + numQuestions + " answers:" + numAnswers + " authorities:" + numAuthorities + " additionals:" + numAdditionals);
}
// parse questions
if (numQuestions > 0) {
for (int i = 0; i < numQuestions; i++) {
_questions.add(this.readQuestion());
}
}
// parse answers
if (numAnswers > 0) {
for (int i = 0; i < numAnswers; i++) {
DNSRecord rec = this.readAnswer(source);
if (rec != null) {
// Add a record, if we were able to create one.
_answers.add(rec);
}
}
}
if (numAuthorities > 0) {
for (int i = 0; i < numAuthorities; i++) {
DNSRecord rec = this.readAnswer(source);
if (rec != null) {
// Add a record, if we were able to create one.
_authoritativeAnswers.add(rec);
}
}
}
if (numAdditionals > 0) {
for (int i = 0; i < numAdditionals; i++) {
DNSRecord rec = this.readAnswer(source);
if (rec != null) {
// Add a record, if we were able to create one.
_additionals.add(rec);
}
}
}
// We should have drained the entire stream by now
if (_messageInputStream.available() > 0) {
throw new IOException("Received a message with the wrong length.");
}
} catch (Exception e) {
logger.log(Level.WARNING, "DNSIncoming() dump " + print(true) + "\n exception ", e);
// This ugly but some JVM don't implement the cause on IOException
IOException ioe = new IOException("DNSIncoming corrupted message");
ioe.initCause(e);
throw ioe;
}
}
private DNSIncoming(int flags, int id, boolean multicast, DatagramPacket packet, long receivedTime) {
super(flags, id, multicast);
this._packet = packet;
this._messageInputStream = new MessageInputStream(packet.getData(), packet.getLength());
this._receivedTime = receivedTime;
}
/*
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
public DNSIncoming clone() {
DNSIncoming in = new DNSIncoming(this.getFlags(), this.getId(), this.isMulticast(), this._packet, this._receivedTime);
in._senderUDPPayload = this._senderUDPPayload;
in._questions.addAll(this._questions);
in._answers.addAll(this._answers);
in._authoritativeAnswers.addAll(this._authoritativeAnswers);
in._additionals.addAll(this._additionals);
return in;
}
private DNSQuestion readQuestion() {
String domain = _messageInputStream.readName();
DNSRecordType type = DNSRecordType.typeForIndex(_messageInputStream.readUnsignedShort());
if (type == DNSRecordType.TYPE_IGNORE) {
logger.log(Level.SEVERE, "Could not find record type: " + this.print(true));
}
int recordClassIndex = _messageInputStream.readUnsignedShort();
DNSRecordClass recordClass = DNSRecordClass.classForIndex(recordClassIndex);
boolean unique = recordClass.isUnique(recordClassIndex);
return DNSQuestion.newQuestion(domain, type, recordClass, unique);
}
private DNSRecord readAnswer(InetAddress source) {
String domain = _messageInputStream.readName();
DNSRecordType type = DNSRecordType.typeForIndex(_messageInputStream.readUnsignedShort());
if (type == DNSRecordType.TYPE_IGNORE) {
logger.log(Level.SEVERE, "Could not find record type. domain: " + domain + "\n" + this.print(true));
}
int recordClassIndex = _messageInputStream.readUnsignedShort();
DNSRecordClass recordClass = (type == DNSRecordType.TYPE_OPT ? DNSRecordClass.CLASS_UNKNOWN : DNSRecordClass.classForIndex(recordClassIndex));
if ((recordClass == DNSRecordClass.CLASS_UNKNOWN) && (type != DNSRecordType.TYPE_OPT)) {
logger.log(Level.SEVERE, "Could not find record class. domain: " + domain + " type: " + type + "\n" + this.print(true));
}
boolean unique = recordClass.isUnique(recordClassIndex);
int ttl = _messageInputStream.readInt();
int len = _messageInputStream.readUnsignedShort();
DNSRecord rec = null;
switch (type) {
case TYPE_A: // IPv4
rec = new DNSRecord.IPv4Address(domain, recordClass, unique, ttl, _messageInputStream.readBytes(len));
break;
case TYPE_AAAA: // IPv6
rec = new DNSRecord.IPv6Address(domain, recordClass, unique, ttl, _messageInputStream.readBytes(len));
break;
case TYPE_CNAME:
case TYPE_PTR:
String service = "";
service = _messageInputStream.readName();
if (service.length() > 0) {
rec = new DNSRecord.Pointer(domain, recordClass, unique, ttl, service);
} else {
logger.log(Level.WARNING, "PTR record of class: " + recordClass + ", there was a problem reading the service name of the answer for domain:" + domain);
}
break;
case TYPE_TXT:
rec = new DNSRecord.Text(domain, recordClass, unique, ttl, _messageInputStream.readBytes(len));
break;
case TYPE_SRV:
int priority = _messageInputStream.readUnsignedShort();
int weight = _messageInputStream.readUnsignedShort();
int port = _messageInputStream.readUnsignedShort();
String target = "";
// This is a hack to handle a bug in the BonjourConformanceTest
// It is sending out target strings that don't follow the "domain name" format.
if (USE_DOMAIN_NAME_FORMAT_FOR_SRV_TARGET) {
target = _messageInputStream.readName();
} else {
// [PJYF Nov 13 2010] Do we still need this? This looks really bad. All label are supposed to start by a length.
target = _messageInputStream.readNonNameString();
}
rec = new DNSRecord.Service(domain, recordClass, unique, ttl, priority, weight, port, target);
break;
case TYPE_HINFO:
StringBuilder buf = new StringBuilder();
buf.append(_messageInputStream.readUTF(len));
int index = buf.indexOf(" ");
String cpu = (index > 0 ? buf.substring(0, index) : buf.toString()).trim();
String os = (index > 0 ? buf.substring(index + 1) : "").trim();
rec = new DNSRecord.HostInformation(domain, recordClass, unique, ttl, cpu, os);
break;
case TYPE_OPT:
DNSResultCode extendedResultCode = DNSResultCode.resultCodeForFlags(this.getFlags(), ttl);
int version = (ttl & 0x00ff0000) >> 16;
if (version == 0) {
_senderUDPPayload = recordClassIndex;
while (_messageInputStream.available() > 0) {
// Read RDData
int optionCodeInt = 0;
DNSOptionCode optionCode = null;
if (_messageInputStream.available() >= 2) {
optionCodeInt = _messageInputStream.readUnsignedShort();
optionCode = DNSOptionCode.resultCodeForFlags(optionCodeInt);
} else {
logger.log(Level.WARNING, "There was a problem reading the OPT record. Ignoring.");
break;
}
int optionLength = 0;
if (_messageInputStream.available() >= 2) {
optionLength = _messageInputStream.readUnsignedShort();
} else {
logger.log(Level.WARNING, "There was a problem reading the OPT record. Ignoring.");
break;
}
byte[] optiondata = new byte[0];
if (_messageInputStream.available() >= optionLength) {
optiondata = _messageInputStream.readBytes(optionLength);
}
//
// We should really do something with those options.
switch (optionCode) {
case Owner:
// Valid length values are 8, 14, 18 and 20
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |Opt|Len|V|S|Primary MAC|Wakeup MAC | Password |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
int ownerVersion = 0;
int ownerSequence = 0;
byte[] ownerPrimaryMacAddress = null;
byte[] ownerWakeupMacAddress = null;
byte[] ownerPassword = null;
try {
ownerVersion = optiondata[0];
ownerSequence = optiondata[1];
ownerPrimaryMacAddress = new byte[] { optiondata[2], optiondata[3], optiondata[4], optiondata[5], optiondata[6], optiondata[7] };
ownerWakeupMacAddress = ownerPrimaryMacAddress;
if (optiondata.length > 8) {
// We have a wakeupMacAddress.
ownerWakeupMacAddress = new byte[] { optiondata[8], optiondata[9], optiondata[10], optiondata[11], optiondata[12], optiondata[13] };
}
if (optiondata.length == 18) {
// We have a short password.
ownerPassword = new byte[] { optiondata[14], optiondata[15], optiondata[16], optiondata[17] };
}
if (optiondata.length == 22) {
// We have a long password.
ownerPassword = new byte[] { optiondata[14], optiondata[15], optiondata[16], optiondata[17], optiondata[18], optiondata[19], optiondata[20], optiondata[21] };
}
} catch (Exception exception) {
logger.warning("Malformed OPT answer. Option code: Owner data: " + this._hexString(optiondata));
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Unhandled Owner OPT version: " + ownerVersion + " sequence: " + ownerSequence + " MAC address: " + this._hexString(ownerPrimaryMacAddress)
+ (ownerWakeupMacAddress != ownerPrimaryMacAddress ? " wakeup MAC address: " + this._hexString(ownerWakeupMacAddress) : "") + (ownerPassword != null ? " password: " + this._hexString(ownerPassword) : ""));
}
break;
case LLQ:
case NSID:
case UL:
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "There was an OPT answer. Option code: " + optionCode + " data: " + this._hexString(optiondata));
}
break;
case Unknown:
if (optionCodeInt >= 65001 && optionCodeInt <= 65534) {
// RFC 6891 defines this range as used for experimental/local purposes.
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "There was an OPT answer using an experimental/local option code: " + optionCodeInt + " data: " + this._hexString(optiondata));
}
} else {
logger.log(Level.WARNING, "There was an OPT answer. Not currently handled. Option code: " + optionCodeInt + " data: " + this._hexString(optiondata));
}
break;
default:
// This is to keep the compiler happy.
break;
}
}
} else {
logger.log(Level.WARNING, "There was an OPT answer. Wrong version number: " + version + " result code: " + extendedResultCode);
}
break;
default:
if (logger.isLoggable(Level.FINER)) {
logger.finer("DNSIncoming() unknown type:" + type);
}
_messageInputStream.skip(len);
break;
}
if (rec != null) {
rec.setRecordSource(source);
}
return rec;
}
/**
* Debugging.
*/
String print(boolean dump) {
StringBuilder buf = new StringBuilder();
buf.append(this.print());
if (dump) {
byte[] data = new byte[_packet.getLength()];
System.arraycopy(_packet.getData(), 0, data, 0, data.length);
buf.append(this.print(data));
}
return buf.toString();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(isQuery() ? "dns[query," : "dns[response,");
if (_packet.getAddress() != null) {
buf.append(_packet.getAddress().getHostAddress());
}
buf.append(':');
buf.append(_packet.getPort());
buf.append(", length=");
buf.append(_packet.getLength());
buf.append(", id=0x");
buf.append(Integer.toHexString(this.getId()));
if (this.getFlags() != 0) {
buf.append(", flags=0x");
buf.append(Integer.toHexString(this.getFlags()));
if ((this.getFlags() & DNSConstants.FLAGS_QR_RESPONSE) != 0) {
buf.append(":r");
}
if ((this.getFlags() & DNSConstants.FLAGS_AA) != 0) {
buf.append(":aa");
}
if ((this.getFlags() & DNSConstants.FLAGS_TC) != 0) {
buf.append(":tc");
}
}
if (this.getNumberOfQuestions() > 0) {
buf.append(", questions=");
buf.append(this.getNumberOfQuestions());
}
if (this.getNumberOfAnswers() > 0) {
buf.append(", answers=");
buf.append(this.getNumberOfAnswers());
}
if (this.getNumberOfAuthorities() > 0) {
buf.append(", authorities=");
buf.append(this.getNumberOfAuthorities());
}
if (this.getNumberOfAdditionals() > 0) {
buf.append(", additionals=");
buf.append(this.getNumberOfAdditionals());
}
if (this.getNumberOfQuestions() > 0) {
buf.append("\nquestions:");
for (DNSQuestion question : _questions) {
buf.append("\n\t");
buf.append(question);
}
}
if (this.getNumberOfAnswers() > 0) {
buf.append("\nanswers:");
for (DNSRecord record : _answers) {
buf.append("\n\t");
buf.append(record);
}
}
if (this.getNumberOfAuthorities() > 0) {
buf.append("\nauthorities:");
for (DNSRecord record : _authoritativeAnswers) {
buf.append("\n\t");
buf.append(record);
}
}
if (this.getNumberOfAdditionals() > 0) {
buf.append("\nadditionals:");
for (DNSRecord record : _additionals) {
buf.append("\n\t");
buf.append(record);
}
}
buf.append("]");
return buf.toString();
}
/**
* Appends answers to this Incoming.
*
* @exception IllegalArgumentException
* If not a query or if Truncated.
*/
void append(DNSIncoming that) {
if (this.isQuery() && this.isTruncated() && that.isQuery()) {
this._questions.addAll(that.getQuestions());
this._answers.addAll(that.getAnswers());
this._authoritativeAnswers.addAll(that.getAuthorities());
this._additionals.addAll(that.getAdditionals());
} else {
throw new IllegalArgumentException();
}
}
public int elapseSinceArrival() {
return (int) (System.currentTimeMillis() - _receivedTime);
}
/**
* This will return the default UDP payload except if an OPT record was found with a different size.
*
* @return the senderUDPPayload
*/
public int getSenderUDPPayload() {
return this._senderUDPPayload;
}
private static final char[] _nibbleToHex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* Returns a hex-string for printing
*
* @param bytes
* @return Returns a hex-string which can be used within a SQL expression
*/
private String _hexString(byte[] bytes) {
StringBuilder result = new StringBuilder(2 * bytes.length);
for (int i = 0; i < bytes.length; i++) {
int b = bytes[i] & 0xFF;
result.append(_nibbleToHex[b / 16]);
result.append(_nibbleToHex[b % 16]);
}
return result.toString();
}
}

Some files were not shown because too many files have changed in this diff Show more