Compare commits
No commits in common. "master" and "ANT_PLUS" have entirely different histories.
1
.gitignore
vendored
|
@ -4,6 +4,5 @@
|
|||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/Application/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
|
@ -10,7 +11,12 @@
|
|||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
|
@ -1,22 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="delegatedBuild" value="true" />
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/Application" />
|
||||
<option value="$PROJECT_DIR$/android_antlib_4-14" />
|
||||
<option value="$PROJECT_DIR$/android_antlib_4-14-0" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google2" />
|
||||
<option name="name" value="Google2" />
|
||||
<option name="url" value="https://maven.google.com/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
|
@ -1,70 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownProjectSettings">
|
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true">
|
||||
<PanelProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
||||
</PanelProvider>
|
||||
</PreviewSettings>
|
||||
<ParserSettings>
|
||||
<PegdownExtensions>
|
||||
<option name="ABBREVIATIONS" value="false" />
|
||||
<option name="ANCHORLINKS" value="true" />
|
||||
<option name="ASIDE" value="false" />
|
||||
<option name="ATXHEADERSPACE" value="true" />
|
||||
<option name="AUTOLINKS" value="true" />
|
||||
<option name="DEFINITIONS" value="false" />
|
||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||
<option name="FOOTNOTES" value="false" />
|
||||
<option name="HARDWRAPS" value="false" />
|
||||
<option name="INSERTED" value="false" />
|
||||
<option name="QUOTES" value="false" />
|
||||
<option name="RELAXEDHRULES" value="true" />
|
||||
<option name="SMARTS" value="false" />
|
||||
<option name="STRIKETHROUGH" value="true" />
|
||||
<option name="SUBSCRIPT" value="false" />
|
||||
<option name="SUPERSCRIPT" value="false" />
|
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
||||
<option name="TABLES" value="true" />
|
||||
<option name="TASKLISTITEMS" value="true" />
|
||||
<option name="TOC" value="false" />
|
||||
<option name="WIKILINKS" value="true" />
|
||||
</PegdownExtensions>
|
||||
<ParserOptions>
|
||||
<option name="COMMONMARK_LISTS" value="false" />
|
||||
<option name="DUMMY" value="false" />
|
||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="true" />
|
||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
||||
<option name="GITHUB_EMOJI_URL" value="false" />
|
||||
<option name="GITHUB_LISTS" value="true" />
|
||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||
</ParserOptions>
|
||||
</ParserSettings>
|
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true">
|
||||
<GeneratorProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
||||
</GeneratorProvider>
|
||||
<headerTop />
|
||||
<headerBottom />
|
||||
<bodyTop />
|
||||
<bodyBottom />
|
||||
</HtmlSettings>
|
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||
<StylesheetProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
||||
</StylesheetProvider>
|
||||
<ScriptProviders />
|
||||
<cssText />
|
||||
</CssSettings>
|
||||
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" />
|
||||
<LinkMapSettings>
|
||||
<textMaps />
|
||||
</LinkMapSettings>
|
||||
</component>
|
||||
</project>
|
|
@ -1,3 +0,0 @@
|
|||
<component name="MarkdownNavigator.ProfileManager">
|
||||
<settings default="" pdf-export="" />
|
||||
</component>
|
|
@ -5,47 +5,26 @@
|
|||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="15">
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
<item index="4" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||
<item index="6" class="java.lang.String" itemvalue="android.annotation.Nullable" />
|
||||
<item index="7" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
||||
<item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
|
||||
<item index="13" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
|
||||
<item index="14" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="14">
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||
<item index="5" class="java.lang.String" itemvalue="android.annotation.NonNull" />
|
||||
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
||||
<item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
|
||||
<item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
|
||||
<item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -53,43 +32,9 @@
|
|||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="GlobalLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="JdkListConfigurable.UI">
|
||||
<settings>
|
||||
<last-edited>Android API 19 Platform</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
<state key="ProjectLibrariesConfigurable.UI">
|
||||
<settings>
|
||||
<last-edited>Android API 24 Platform</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/android_antlib_4-14-0/android_antlib_4-14-0.iml" filepath="$PROJECT_DIR$/android_antlib_4-14-0/android_antlib_4-14-0.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/iconsole-android.iml" filepath="$PROJECT_DIR$/iconsole-android.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Application/iconsole-android.Application.iml" filepath="$PROJECT_DIR$/.idea/modules/Application/iconsole-android.Application.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/android_antlib_4-14/iconsole-android.android_antlib_4-14.iml" filepath="$PROJECT_DIR$/.idea/modules/android_antlib_4-14/iconsole-android.android_antlib_4-14.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -1,83 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":Application" external.linked.project.path="$MODULE_DIR$/../../../Application" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="iconsole-android" 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=":Application" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="4.1.3" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" value="4.1.3" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<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$/../../../Application/src/main/res;file://$MODULE_DIR$/../../../Application/src/common/res;file://$MODULE_DIR$/../../../Application/src/template/res;file://$MODULE_DIR$/../../../Application/src/debug/res;file://$MODULE_DIR$/../../../Application/build/generated/res/rs/debug;file://$MODULE_DIR$/../../../Application/build/generated/res/resValues/debug" />
|
||||
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../../../Application/tests/res;file://$MODULE_DIR$/../../../Application/src/androidTestDebug/res;file://$MODULE_DIR$/../../../Application/build/generated/res/rs/androidTest/debug;file://$MODULE_DIR$/../../../Application/build/generated/res/resValues/androidTest/debug" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/../../../Application/build/intermediates/javac/debug/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/../../../Application/build/intermediates/javac/debugUnitTest/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$/../../../Application">
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/build/generated/ap_generated_sources/debug/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Application/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../../Application/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../../Application/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:collections:28.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:28.0.0" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:2.0.4" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:gridlayout-v7:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout:2.0.4@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-v13:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-v4:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:viewpager:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:coordinatorlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:drawerlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:slidingpanelayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:customview:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:swiperefreshlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:loader:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:cardview-v7:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:versionedparcelable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:cursoradapter:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:interpolator:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:localbroadcastmanager:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:print:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.1@aar" level="project" />
|
||||
<orderEntry type="module" module-name="iconsole-android.android_antlib_4-14" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,28 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":android_antlib_4-14" external.linked.project.path="$MODULE_DIR$/../../../android_antlib_4-14" external.root.project.path="$MODULE_DIR$/../../.." external.system.id="GRADLE" external.system.module.group="iconsole-android" 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=":android_antlib_4-14" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/../../../android_antlib_4-14/build" />
|
||||
<option name="BUILDABLE" value="false" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$/../../../android_antlib_4-14">
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../../android_antlib_4-14/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../../android_antlib_4-14/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="Gradle: iconsole-android.android_antlib_4-14.android_antlib_4-14-0" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,70 +0,0 @@
|
|||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url 'https://maven.google.com/'
|
||||
name 'Google'
|
||||
}
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url 'https://maven.google.com/'
|
||||
name 'Google'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.android.support:gridlayout-v7:28.0.0"
|
||||
implementation "com.android.support:cardview-v7:28.0.0"
|
||||
implementation "com.android.support:appcompat-v7:28.0.0"
|
||||
implementation 'com.android.support:support-v13:28.0.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
|
||||
implementation project(':android_antlib_4-14')
|
||||
}
|
||||
|
||||
|
||||
// The sample build uses multiple directories to
|
||||
// keep boilerplate and common code separate from
|
||||
// the main sample code.
|
||||
List<String> dirs = [
|
||||
'main', // main sample code; look here for the interesting stuff.
|
||||
'common', // components that are reused by multiple samples
|
||||
'template'] // boilerplate code that is generated by the sample template process
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
dirs.each { dir ->
|
||||
java.srcDirs "src/${dir}/java"
|
||||
res.srcDirs "src/${dir}/res"
|
||||
}
|
||||
}
|
||||
androidTest.setRoot('tests')
|
||||
androidTest.java.srcDirs = ['tests/src']
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 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
|
||||
package="org.surfsite.iconsole"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
>
|
||||
|
||||
<activity
|
||||
android:name="org.surfsite.iconsole.MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/app_name" android:launchMode="singleTop">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<service android:name=".ChannelService"></service>
|
||||
|
||||
<activity
|
||||
android:name=".DeviceListActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/select_device"
|
||||
android:theme="@android:style/Theme.Holo.Dialog"/>
|
||||
<service android:name=".BluetoothChatService" android:exported="false"/>
|
||||
</application>
|
||||
</manifest>
|
|
@ -1,541 +0,0 @@
|
|||
/*
|
||||
* 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 org.surfsite.iconsole;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* This fragment controls Bluetooth to communicate with other devices.
|
||||
*/
|
||||
public class BluetoothChatFragment extends Fragment {
|
||||
static class MyInnerHandler extends Handler{
|
||||
WeakReference<BluetoothChatFragment> mFrag;
|
||||
|
||||
MyInnerHandler(BluetoothChatFragment aFragment) {
|
||||
mFrag = new WeakReference<BluetoothChatFragment>(aFragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
BluetoothChatFragment theFrag = mFrag.get();
|
||||
if (theFrag == null) {
|
||||
return;
|
||||
}
|
||||
FragmentActivity activity = theFrag.getActivity();
|
||||
|
||||
switch (msg.what) {
|
||||
case Constants.MESSAGE_STATE_CHANGE:
|
||||
switch (msg.arg1) {
|
||||
case BluetoothChatService.STATE_CONNECTED:
|
||||
theFrag.setStatus(theFrag.getString(R.string.title_connected_to, theFrag.mConnectedDeviceName));
|
||||
//mConversationArrayAdapter.clear();
|
||||
theFrag.mStartButton.setEnabled(true);
|
||||
theFrag.mStopButton.setEnabled(true);
|
||||
theFrag.mDisconnectButton.setEnabled(true);
|
||||
theFrag.mLevel.setEnabled(true);
|
||||
theFrag.mLevel.setValue(1);
|
||||
break;
|
||||
case BluetoothChatService.STATE_CONNECTING:
|
||||
theFrag.setStatus(R.string.title_connecting);
|
||||
theFrag.mStartButton.setEnabled(false);
|
||||
theFrag.mStopButton.setEnabled(false);
|
||||
theFrag.mDisconnectButton.setEnabled(false);
|
||||
theFrag.mLevel.setEnabled(false);
|
||||
break;
|
||||
case BluetoothChatService.STATE_LISTEN:
|
||||
case BluetoothChatService.STATE_NONE:
|
||||
theFrag.setStatus(R.string.title_not_connected);
|
||||
theFrag.mStartButton.setEnabled(false);
|
||||
theFrag.mStopButton.setEnabled(false);
|
||||
theFrag.mDisconnectButton.setEnabled(false);
|
||||
theFrag.mLevel.setEnabled(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Constants.MESSAGE_DATA:
|
||||
if (!(msg.obj instanceof IConsole.Data))
|
||||
return;
|
||||
IConsole.Data data = (IConsole.Data) msg.obj;
|
||||
theFrag.mChannelService.setSpeed(data.mSpeed10 / 10.0);
|
||||
theFrag.mChannelService.setPower(data.mPower10 / 10);
|
||||
theFrag.mChannelService.setCadence(data.mRPM);
|
||||
|
||||
theFrag.mSpeedText.setText(String.format("% 3.1f", data.mSpeed10 / 10.0));
|
||||
theFrag.mPowerText.setText(String.format("% 3.1f", data.mPower10 / 10.0));
|
||||
theFrag.mRPMText.setText(String.format("%d", data.mRPM));
|
||||
theFrag.mDistanceText.setText(String.format("% 3.1f", data.mDistance10 / 10.0));
|
||||
theFrag.mCaloriesText.setText(String.format("% 3d", data.mCalories));
|
||||
theFrag.mHFText.setText(String.format("%d", data.mHF));
|
||||
theFrag.mTimeText.setText(String.format("%s", data.getTimeStr()));
|
||||
//mLevel.setValue(data.mLevel);
|
||||
break;
|
||||
case Constants.MESSAGE_WRITE:
|
||||
//byte[] writeBuf = (byte[]) msg.obj;
|
||||
// construct a string from the buffer
|
||||
//String writeMessage = new String(writeBuf);
|
||||
//mConversationArrayAdapter.add("Me: " + writeMessage);
|
||||
break;
|
||||
case Constants.MESSAGE_READ:
|
||||
//byte[] readBuf = (byte[]) msg.obj;
|
||||
// construct a string from the valid bytes in the buffer
|
||||
//String readMessage = new String(readBuf, 0, msg.arg1);
|
||||
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
|
||||
break;
|
||||
case Constants.MESSAGE_DEVICE_NAME:
|
||||
// save the connected device's name
|
||||
theFrag.mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
|
||||
if (null != activity) {
|
||||
Toast.makeText(activity, "Connected to "
|
||||
+ theFrag.mConnectedDeviceName, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
case Constants.MESSAGE_TOAST:
|
||||
if (null != activity) {
|
||||
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Handler mHandler = new MyInnerHandler(this);
|
||||
|
||||
private static final String TAG = "BluetoothChatFragment";
|
||||
|
||||
// Intent request codes
|
||||
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
|
||||
private static final int REQUEST_ENABLE_BT = 3;
|
||||
|
||||
// Layout Views
|
||||
//private ListView mConversationView;
|
||||
private Button mStartButton;
|
||||
private Button mStopButton;
|
||||
private Button mDisconnectButton;
|
||||
private NumberPicker mLevel;
|
||||
private TextView mSpeedText;
|
||||
private TextView mPowerText;
|
||||
private TextView mRPMText;
|
||||
private TextView mDistanceText;
|
||||
private TextView mCaloriesText;
|
||||
private TextView mHFText;
|
||||
private TextView mTimeText;
|
||||
/**
|
||||
* Name of the connected device
|
||||
*/
|
||||
private String mConnectedDeviceName = null;
|
||||
|
||||
/**
|
||||
* Array adapter for the conversation thread
|
||||
private ArrayAdapter<String> mConversationArrayAdapter;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Local Bluetooth adapter
|
||||
*/
|
||||
private BluetoothAdapter mBluetoothAdapter = null;
|
||||
|
||||
/**
|
||||
* Member object for the chat services
|
||||
*/
|
||||
private BluetoothChatService mChatService = null;
|
||||
private boolean mIsBound;
|
||||
private ChannelService.ChannelServiceComm mChannelService;
|
||||
/**
|
||||
* The Handler that gets information back from the BluetoothChatService
|
||||
*/
|
||||
private boolean mChannelServiceBound = false;
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
// interact with the service. Because we have bound to a explicit
|
||||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
mChatService = ((BluetoothChatService.BluetoothChatServiceI) service).getService();
|
||||
((BluetoothChatService.BluetoothChatServiceI) service).setHandler(mHandler);
|
||||
Log.d(TAG, "onServiceConnected()");
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
// This is called when the connection with the service has been
|
||||
// unexpectedly disconnected -- that is, its process crashed.
|
||||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
mChatService = null;
|
||||
|
||||
}
|
||||
};
|
||||
private ServiceConnection mChannelServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder serviceBinder) {
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceConnected...");
|
||||
|
||||
mChannelService = (ChannelService.ChannelServiceComm) serviceBinder;
|
||||
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceConnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceDisconnected...");
|
||||
|
||||
// Clearing and disabling when disconnecting from ChannelService
|
||||
mChannelService = null;
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceDisconnected");
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
// Get local Bluetooth adapter
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
// If the adapter is null, then Bluetooth is not supported
|
||||
if (mBluetoothAdapter == null) {
|
||||
FragmentActivity activity = getActivity();
|
||||
Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// If BT is not on, request that it be enabled.
|
||||
// setupChat() will then be called during onActivityResult
|
||||
if (null == mBluetoothAdapter || !mBluetoothAdapter.isEnabled()) {
|
||||
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
|
||||
// Otherwise, setup the chat session
|
||||
} else if (mChatService == null) {
|
||||
setupChat();
|
||||
}
|
||||
if (!mChannelServiceBound) doBindChannelService();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mChatService != null) {
|
||||
mChatService.stopBT();
|
||||
}
|
||||
Log.d(TAG, "onDestroy()");
|
||||
doUnbindService();
|
||||
doUnbindChannelService();
|
||||
mChannelServiceConnection = null;
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Performing this check in onResume() covers the case in which BT was
|
||||
// not enabled during onStart(), so we were paused to enable it...
|
||||
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
|
||||
if (mChatService != null) {
|
||||
// Only if the state is STATE_NONE, do we know that we haven't started already
|
||||
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
|
||||
// Start the Bluetooth chat services
|
||||
mChatService.startBT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_bluetooth_chat, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
//mConversationView = (ListView) view.findViewById(R.id.in);
|
||||
mStartButton = (Button) view.findViewById(R.id.button_start);
|
||||
mStopButton = (Button) view.findViewById(R.id.button_stop);
|
||||
mDisconnectButton = (Button) view.findViewById(R.id.button_disconnect);
|
||||
mLevel = (NumberPicker) view.findViewById(R.id.Level);
|
||||
mLevel.setMaxValue(32);
|
||||
mLevel.setMinValue(1);
|
||||
mLevel.setValue(1);
|
||||
mLevel.setWrapSelectorWheel(false);
|
||||
mLevel.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
|
||||
mSpeedText = (TextView) view.findViewById(R.id.Speed);
|
||||
mPowerText = (TextView) view.findViewById(R.id.Power);
|
||||
mRPMText = (TextView) view.findViewById(R.id.RPM);
|
||||
mDistanceText = (TextView) view.findViewById(R.id.Distance);
|
||||
mCaloriesText = (TextView) view.findViewById(R.id.Calories);
|
||||
mHFText = (TextView) view.findViewById(R.id.Heart);
|
||||
mTimeText = (TextView) view.findViewById(R.id.Time);
|
||||
}
|
||||
|
||||
void doBindService() {
|
||||
Log.d(TAG, "doBindService()");
|
||||
|
||||
// Establish a connection with the service. We use an explicit
|
||||
// class name because we want a specific service implementation that
|
||||
// we know will be running in our own process (and thus won't be
|
||||
// supporting component replacement by other applications).
|
||||
getActivity().bindService(new Intent(getActivity(), BluetoothChatService.class), mConnection, Context.BIND_AUTO_CREATE);
|
||||
mIsBound = true;
|
||||
}
|
||||
|
||||
void doUnbindService() {
|
||||
if (mIsBound) {
|
||||
// Detach our existing connection.
|
||||
getActivity().unbindService(mConnection);
|
||||
mIsBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void doBindChannelService() {
|
||||
Log.v(TAG, "doBindChannelService...");
|
||||
|
||||
// Binds to ChannelService. ChannelService binds and manages connection between the
|
||||
// app and the ANT Radio Service
|
||||
mChannelServiceBound = getActivity().bindService(new Intent(getActivity(), ChannelService.class), mChannelServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
if (!mChannelServiceBound) //If the bind returns false, run the unbind method to update the GUI
|
||||
doUnbindChannelService();
|
||||
|
||||
Log.i(TAG, " Channel Service binding = " + mChannelServiceBound);
|
||||
|
||||
Log.v(TAG, "...doBindChannelService");
|
||||
}
|
||||
|
||||
private void doUnbindChannelService() {
|
||||
Log.v(TAG, "doUnbindChannelService...");
|
||||
|
||||
if (mChannelServiceBound) {
|
||||
getActivity().unbindService(mChannelServiceConnection);
|
||||
|
||||
mChannelServiceBound = false;
|
||||
}
|
||||
|
||||
Log.v(TAG, "...doUnbindChannelService");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the UI and background operations for chat.
|
||||
*/
|
||||
private void setupChat() {
|
||||
Log.d(TAG, "setupChat()");
|
||||
|
||||
if (!mIsBound)
|
||||
doBindService();
|
||||
|
||||
mStartButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mLevel.setValue(1);
|
||||
if (mChatService != null)
|
||||
mChatService.startIConsole();
|
||||
}
|
||||
});
|
||||
|
||||
mStopButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mLevel.setValue(1);
|
||||
if (mChatService != null)
|
||||
mChatService.stopIConsole();
|
||||
}
|
||||
});
|
||||
|
||||
mDisconnectButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mLevel.setValue(1);
|
||||
if (mChatService != null)
|
||||
mChatService.stopBT();
|
||||
}
|
||||
});
|
||||
|
||||
mStartButton.setEnabled(false);
|
||||
mStopButton.setEnabled(false);
|
||||
mDisconnectButton.setEnabled(false);
|
||||
mLevel.setEnabled(false);
|
||||
mLevel.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
|
||||
@Override
|
||||
public void onValueChange(NumberPicker p, int oldval, int newval) {
|
||||
//Log.e(TAG, "setLevel");
|
||||
if (mChatService != null) {
|
||||
if (!mChatService.setLevel(newval))
|
||||
Log.e(TAG, "setLevel failed");
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this device discoverable for 300 seconds (5 minutes).
|
||||
*/
|
||||
private void ensureDiscoverable() {
|
||||
if (mBluetoothAdapter.getScanMode() !=
|
||||
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
||||
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
||||
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
|
||||
startActivity(discoverableIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message.
|
||||
*
|
||||
* @param message A string of text to send.
|
||||
*/
|
||||
private void sendMessage(String message) {
|
||||
if (mChatService == null)
|
||||
return;
|
||||
|
||||
// Check that we're actually connected before trying anything
|
||||
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
|
||||
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
mChatService.startIConsole();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status on the action bar.
|
||||
*
|
||||
* @param resId a string resource ID
|
||||
*/
|
||||
private void setStatus(int resId) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (null == activity) {
|
||||
return;
|
||||
}
|
||||
final ActionBar actionBar = activity.getActionBar();
|
||||
if (null == actionBar) {
|
||||
return;
|
||||
}
|
||||
actionBar.setSubtitle(resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status on the action bar.
|
||||
*
|
||||
* @param subTitle status
|
||||
*/
|
||||
private void setStatus(CharSequence subTitle) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (null == activity) {
|
||||
return;
|
||||
}
|
||||
final ActionBar actionBar = activity.getActionBar();
|
||||
if (null == actionBar) {
|
||||
return;
|
||||
}
|
||||
actionBar.setSubtitle(subTitle);
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_CONNECT_DEVICE_SECURE:
|
||||
// When DeviceListActivity returns with a device to connect
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
connectDevice(data, true);
|
||||
}
|
||||
break;
|
||||
case REQUEST_ENABLE_BT:
|
||||
// When the request to enable Bluetooth returns
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
// Bluetooth is now enabled, so set up a chat session
|
||||
setupChat();
|
||||
} else {
|
||||
// User did not enable Bluetooth or an error occurred
|
||||
Log.d(TAG, "BT not enabled");
|
||||
Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish connection with other device
|
||||
*
|
||||
* @param data An {@link Intent} with {@link DeviceListActivity#EXTRA_DEVICE_ADDRESS} extra.
|
||||
* @param secure Socket Security type - Secure (true) , Insecure (false)
|
||||
*/
|
||||
private void connectDevice(Intent data, boolean secure) {
|
||||
// Get the device MAC address
|
||||
String address = data.getExtras()
|
||||
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
|
||||
// Get the BluetoothDevice object
|
||||
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
|
||||
// Attempt to connect to the device
|
||||
if (mChatService != null)
|
||||
mChatService.connect(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.bluetooth_chat, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.secure_connect_scan: {
|
||||
// Launch the DeviceListActivity to see devices and do scan
|
||||
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
|
||||
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,501 +0,0 @@
|
|||
/*
|
||||
* 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 org.surfsite.iconsole;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class does all the work for setting up and managing Bluetooth
|
||||
* connections with other devices. It has a thread that listens for
|
||||
* incoming connections, a thread for connecting with a device, and a
|
||||
* thread for performing data transmissions when connected.
|
||||
*/
|
||||
public class BluetoothChatService extends Service {
|
||||
// Constants that indicate the current connection state
|
||||
public static final int STATE_NONE = 0; // we're doing nothing
|
||||
public static final int STATE_LISTEN = 1; // now listening for incoming connections
|
||||
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
|
||||
public static final int STATE_CONNECTED = 3; // now connected to a remote device
|
||||
// Debugging
|
||||
private static final String TAG = "BluetoothChatService";
|
||||
// Name for the SDP record when creating server socket
|
||||
private static final String NAME_SECURE = "BluetoothChatSecure";
|
||||
private static final String NAME_INSECURE = "BluetoothChatInsecure";
|
||||
// Unique UUID for this application
|
||||
private static final UUID SERIAL_PORT_CLASS = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
|
||||
// Member fields
|
||||
private final BluetoothAdapter mAdapter;
|
||||
// This is the object that receives interactions from clients. See
|
||||
// RemoteService for a more complete example.
|
||||
private final IBinder mBinder = new BluetoothChatServiceI();
|
||||
private Handler mHandler;
|
||||
private ConnectThread mConnectThread;
|
||||
private ConnectedThread mConnectedThread;
|
||||
private int mState;
|
||||
private int mNewState;
|
||||
private NotificationManager mNM;
|
||||
private int NOTIFICATION = R.string.local_service_started;
|
||||
|
||||
|
||||
public BluetoothChatService() {
|
||||
super();
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
mState = STATE_NONE;
|
||||
mNewState = mState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
|
||||
}
|
||||
|
||||
boolean startIConsole() {
|
||||
return mConnectedThread.startIConsole();
|
||||
}
|
||||
|
||||
boolean stopIConsole() {
|
||||
return mConnectedThread.stopIConsole();
|
||||
}
|
||||
|
||||
boolean setLevel(int level) {
|
||||
return mConnectedThread.setLevel(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ConnectThread to initiate a connection to a remote device.
|
||||
*
|
||||
* @param device The BluetoothDevice to connect
|
||||
*/
|
||||
public synchronized void connect(BluetoothDevice device) {
|
||||
Log.d(TAG, "connect to: " + device);
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (mState == STATE_CONNECTING) {
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
}
|
||||
|
||||
// Start the thread to connect with the given device
|
||||
mConnectThread = new ConnectThread(device);
|
||||
mConnectThread.start();
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
Log.i(TAG, "onBind");
|
||||
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update UI title according to the current state of the chat connection
|
||||
*/
|
||||
private synchronized void updateUserInterfaceTitle() {
|
||||
mState = getState();
|
||||
Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
|
||||
mNewState = mState;
|
||||
|
||||
// Give the new state to the Handler so the UI Activity can update
|
||||
if (mHandler != null)
|
||||
mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current connection state.
|
||||
*/
|
||||
public synchronized int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the chat service. Specifically startBT AcceptThread to begin a
|
||||
* session in listening (server) mode. Called by the Activity onResume()
|
||||
*/
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.i(TAG, "Received onStartCommand() id " + startId + ": " + intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopBT();
|
||||
|
||||
// Tell the user we stopped.
|
||||
Log.i(TAG, "onDestroy");
|
||||
super.onDestroy();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a notification while this service is running.
|
||||
*/
|
||||
private void showNotification() {
|
||||
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||
CharSequence text = getText(R.string.local_service_started);
|
||||
Intent myIntent = new Intent(this, MainActivity.class);
|
||||
myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
// The PendingIntent to launch our activity if the user selects this notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
Notification notification = new Notification.Builder(this)
|
||||
.setSmallIcon(R.drawable.ic_action_device_access_bluetooth_searching) // the status icon
|
||||
.setTicker(text) // the status text
|
||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||
.setContentTitle(getText(R.string.local_service_label)) // the label of the entry
|
||||
.setContentText(text) // the contents of the entry
|
||||
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||
.build();
|
||||
|
||||
// Send the notification.
|
||||
mNM.notify(NOTIFICATION, notification);
|
||||
}
|
||||
|
||||
void startBT() {
|
||||
Log.d(TAG, "startBT");
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
}
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ConnectedThread to begin managing a Bluetooth connection
|
||||
*
|
||||
* @param socket The BluetoothSocket on which the connection was made
|
||||
* @param device The BluetoothDevice that has been connected
|
||||
*/
|
||||
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
|
||||
device) {
|
||||
Log.d(TAG, "connected");
|
||||
|
||||
// Cancel the thread that completed the connection
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
}
|
||||
|
||||
// Start the thread to manage the connection and perform transmissions
|
||||
mConnectedThread = new ConnectedThread(socket);
|
||||
mConnectedThread.start();
|
||||
// Send the name of the connected device back to the UI Activity
|
||||
Message msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(Constants.DEVICE_NAME, device.getName());
|
||||
msg.setData(bundle);
|
||||
mHandler.sendMessage(msg);
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all threads
|
||||
*/
|
||||
public synchronized void stopBT() {
|
||||
Log.d(TAG, "stopBT");
|
||||
// Cancel the persistent notification.
|
||||
mNM.cancel(NOTIFICATION);
|
||||
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
}
|
||||
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
}
|
||||
|
||||
mState = STATE_NONE;
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the connection attempt failed and notify the UI Activity.
|
||||
*/
|
||||
private void connectionFailed() {
|
||||
// Send a failure message back to the Activity
|
||||
Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(Constants.TOAST, "Unable to connect device");
|
||||
msg.setData(bundle);
|
||||
mHandler.sendMessage(msg);
|
||||
|
||||
mState = STATE_NONE;
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
|
||||
// Start the service over to restart listening mode
|
||||
BluetoothChatService.this.startBT();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the connection was lost and notify the UI Activity.
|
||||
*/
|
||||
private void connectionLost() {
|
||||
// Send a failure message back to the Activity
|
||||
Message msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(Constants.TOAST, "Device connection was lost");
|
||||
msg.setData(bundle);
|
||||
mHandler.sendMessage(msg);
|
||||
|
||||
mState = STATE_NONE;
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
|
||||
// Start the service over to restart listening mode
|
||||
BluetoothChatService.this.startBT();
|
||||
}
|
||||
|
||||
public class BluetoothChatServiceI extends Binder {
|
||||
BluetoothChatService getService() {
|
||||
return BluetoothChatService.this;
|
||||
}
|
||||
|
||||
void setHandler(Handler handler) {
|
||||
mHandler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread runs while attempting to make an outgoing connection
|
||||
* with a device. It runs straight through; the connection either
|
||||
* succeeds or fails.
|
||||
*/
|
||||
class ConnectThread extends Thread {
|
||||
private final BluetoothSocket mmSocket;
|
||||
private final BluetoothDevice mmDevice;
|
||||
|
||||
public ConnectThread(BluetoothDevice device) {
|
||||
mmDevice = device;
|
||||
BluetoothSocket tmp = null;
|
||||
|
||||
// Get a BluetoothSocket for a connection with the
|
||||
// given BluetoothDevice
|
||||
try {
|
||||
tmp = device.createRfcommSocketToServiceRecord(SERIAL_PORT_CLASS);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Socket Type: create() failed", e);
|
||||
}
|
||||
mmSocket = tmp;
|
||||
mState = STATE_CONNECTING;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Log.i(TAG, "BEGIN mConnectThread");
|
||||
setName("ConnectThread");
|
||||
|
||||
// Always cancel discovery because it will slow down a connection
|
||||
mAdapter.cancelDiscovery();
|
||||
|
||||
// Make a connection to the BluetoothSocket
|
||||
try {
|
||||
// This is a blocking call and will only return on a
|
||||
// successful connection or an exception
|
||||
mmSocket.connect();
|
||||
} catch (IOException e) {
|
||||
// Close the socket
|
||||
try {
|
||||
mmSocket.close();
|
||||
} catch (IOException e2) {
|
||||
Log.e(TAG, "unable to close() socket during connection failure", e2);
|
||||
}
|
||||
connectionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the ConnectThread because we're done
|
||||
synchronized (BluetoothChatService.this) {
|
||||
mConnectThread = null;
|
||||
}
|
||||
|
||||
// Start the connected thread
|
||||
connected(mmSocket, mmDevice);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
mmSocket.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "close() of socket failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread runs during a connection with a remote device.
|
||||
* It handles all incoming and outgoing transmissions.
|
||||
*/
|
||||
class ConnectedThread extends Thread {
|
||||
private final BluetoothSocket mmSocket;
|
||||
private final InputStream mmInStream;
|
||||
private final OutputStream mmOutStream;
|
||||
private final IConsole mmIConsole;
|
||||
|
||||
public ConnectedThread(BluetoothSocket socket) {
|
||||
Log.d(TAG, "create ConnectedThread");
|
||||
mmSocket = socket;
|
||||
InputStream tmpIn = null;
|
||||
OutputStream tmpOut = null;
|
||||
|
||||
// Get the BluetoothSocket input and output streams
|
||||
try {
|
||||
tmpIn = socket.getInputStream();
|
||||
tmpOut = socket.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "temp sockets not created", e);
|
||||
}
|
||||
|
||||
mmInStream = tmpIn;
|
||||
mmOutStream = tmpOut;
|
||||
mState = STATE_CONNECTED;
|
||||
|
||||
mmIConsole = new IConsole(mmInStream, mmOutStream, new IConsole.DataListener() {
|
||||
@Override
|
||||
public void onData(IConsole.Data data) {
|
||||
//Log.i(TAG, "mConnectedThread: onData");
|
||||
// Share the sent message back to the UI Activity
|
||||
mHandler.obtainMessage(Constants.MESSAGE_DATA, -1, -1, data)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
Log.e(TAG, "mConnectedThread Error: ", e);
|
||||
|
||||
if (e instanceof IOException)
|
||||
connectionLost();
|
||||
}
|
||||
}, /* new IConsole.DebugListener() {
|
||||
@Override
|
||||
public void onRead(byte[] buffer) {
|
||||
if (buffer.length > 0) {
|
||||
String hexbuf = IConsole.byteArrayToHex(buffer);
|
||||
|
||||
// Send the obtained bytes to the UI Activity
|
||||
mHandler.obtainMessage(Constants.MESSAGE_READ, hexbuf.length(), -1, hexbuf.getBytes())
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWrite(byte[] buffer) {
|
||||
String hexbuf = IConsole.byteArrayToHex(buffer);
|
||||
|
||||
// Share the sent message back to the UI Activity
|
||||
mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, hexbuf.getBytes())
|
||||
.sendToTarget();
|
||||
}
|
||||
}*/ null);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
showNotification();
|
||||
|
||||
Log.i(TAG, "BEGIN mConnectedThread");
|
||||
|
||||
while (mState == STATE_CONNECTED) {
|
||||
if (!mmIConsole.processIO()) {
|
||||
Log.i(TAG, "processIO = false");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
; // ignore
|
||||
}
|
||||
}
|
||||
Log.i(TAG, "END mConnectedThread");
|
||||
// Cancel the persistent notification.
|
||||
mNM.cancel(NOTIFICATION);
|
||||
}
|
||||
|
||||
|
||||
public boolean setLevel(int level) {
|
||||
return mmIConsole.setLevel(level);
|
||||
}
|
||||
|
||||
public boolean startIConsole() {
|
||||
return mmIConsole.start();
|
||||
}
|
||||
|
||||
public boolean stopIConsole() {
|
||||
return mmIConsole.stop();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mmIConsole.stop();
|
||||
|
||||
try {
|
||||
mmSocket.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "close() of connect socket failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 org.surfsite.iconsole;
|
||||
|
||||
/**
|
||||
* Defines several constants used between {@link BluetoothChatService} and the UI.
|
||||
*/
|
||||
public interface Constants {
|
||||
|
||||
// Message types sent from the BluetoothChatService Handler
|
||||
public static final int MESSAGE_STATE_CHANGE = 1;
|
||||
public static final int MESSAGE_READ = 2;
|
||||
public static final int MESSAGE_WRITE = 3;
|
||||
public static final int MESSAGE_DEVICE_NAME = 4;
|
||||
public static final int MESSAGE_TOAST = 5;
|
||||
public static final int MESSAGE_DATA = 6;
|
||||
|
||||
// Key names received from the BluetoothChatService Handler
|
||||
public static final String DEVICE_NAME = "device_name";
|
||||
public static final String TOAST = "toast";
|
||||
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
/*
|
||||
* 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 org.surfsite.iconsole;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.surfsite.iconsole.R;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This Activity appears as a dialog. It lists any paired devices and
|
||||
* devices detected in the area after discovery. When a device is chosen
|
||||
* by the user, the MAC address of the device is sent back to the parent
|
||||
* Activity in the result Intent.
|
||||
*/
|
||||
public class DeviceListActivity extends Activity {
|
||||
|
||||
/**
|
||||
* Tag for Log
|
||||
*/
|
||||
private static final String TAG = "DeviceListActivity";
|
||||
|
||||
/**
|
||||
* Return Intent extra
|
||||
*/
|
||||
public static String EXTRA_DEVICE_ADDRESS = "device_address";
|
||||
|
||||
/**
|
||||
* Member fields
|
||||
*/
|
||||
private BluetoothAdapter mBtAdapter;
|
||||
|
||||
/**
|
||||
* Newly discovered devices
|
||||
*/
|
||||
private ArrayAdapter<String> mNewDevicesArrayAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Setup the window
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.activity_device_list);
|
||||
|
||||
// Set result CANCELED in case the user backs out
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
|
||||
// Initialize the button to perform device discovery
|
||||
Button scanButton = (Button) findViewById(R.id.button_scan);
|
||||
scanButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
doDiscovery();
|
||||
v.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize array adapters. One for already paired devices and
|
||||
// one for newly discovered devices
|
||||
ArrayAdapter<String> pairedDevicesArrayAdapter =
|
||||
new ArrayAdapter<String>(this, R.layout.device_name);
|
||||
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
|
||||
|
||||
// Find and set up the ListView for paired devices
|
||||
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
|
||||
pairedListView.setAdapter(pairedDevicesArrayAdapter);
|
||||
pairedListView.setOnItemClickListener(mDeviceClickListener);
|
||||
|
||||
// Find and set up the ListView for newly discovered devices
|
||||
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
|
||||
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
|
||||
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
|
||||
|
||||
// Register for broadcasts when a device is discovered
|
||||
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
|
||||
this.registerReceiver(mReceiver, filter);
|
||||
|
||||
// Register for broadcasts when discovery has finished
|
||||
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
|
||||
this.registerReceiver(mReceiver, filter);
|
||||
|
||||
// Get the local Bluetooth adapter
|
||||
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
// Get a set of currently paired devices
|
||||
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
|
||||
|
||||
// If there are paired devices, add each one to the ArrayAdapter
|
||||
if (pairedDevices.size() > 0) {
|
||||
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
|
||||
}
|
||||
} else {
|
||||
String noDevices = getResources().getText(R.string.none_paired).toString();
|
||||
pairedDevicesArrayAdapter.add(noDevices);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// Make sure we're not doing discovery anymore
|
||||
if (mBtAdapter != null) {
|
||||
mBtAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
// Unregister broadcast listeners
|
||||
this.unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start device discover with the BluetoothAdapter
|
||||
*/
|
||||
private void doDiscovery() {
|
||||
Log.d(TAG, "doDiscovery()");
|
||||
|
||||
// Indicate scanning in the title
|
||||
setProgressBarIndeterminateVisibility(true);
|
||||
setTitle(R.string.scanning);
|
||||
|
||||
// Turn on sub-title for new devices
|
||||
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
|
||||
|
||||
// If we're already discovering, stopBT it
|
||||
if (mBtAdapter.isDiscovering()) {
|
||||
mBtAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
// Request discover from BluetoothAdapter
|
||||
mBtAdapter.startDiscovery();
|
||||
}
|
||||
|
||||
/**
|
||||
* The on-click listener for all devices in the ListViews
|
||||
*/
|
||||
private AdapterView.OnItemClickListener mDeviceClickListener
|
||||
= new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
|
||||
// Cancel discovery because it's costly and we're about to connect
|
||||
mBtAdapter.cancelDiscovery();
|
||||
|
||||
// Get the device MAC address, which is the last 17 chars in the View
|
||||
String info = ((TextView) v).getText().toString();
|
||||
String address = info.substring(info.length() - 17);
|
||||
|
||||
// Create the result Intent and include the MAC address
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
|
||||
|
||||
// Set result and finish this Activity
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The BroadcastReceiver that listens for discovered devices and changes the title when
|
||||
* discovery is finished
|
||||
*/
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
// When discovery finds a device
|
||||
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
|
||||
// Get the BluetoothDevice object from the Intent
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
// If it's already paired, skip it, because it's been listed already
|
||||
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
|
||||
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
|
||||
}
|
||||
// When discovery is finished, change the Activity title
|
||||
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
setTitle(R.string.select_device);
|
||||
if (mNewDevicesArrayAdapter.getCount() == 0) {
|
||||
String noDevices = getResources().getText(R.string.none_found).toString();
|
||||
mNewDevicesArrayAdapter.add(noDevices);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,370 +0,0 @@
|
|||
package org.surfsite.iconsole;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Created by harald on 25.04.17.
|
||||
*/
|
||||
|
||||
class IConsole {
|
||||
private static final String TAG = "IConsole";
|
||||
|
||||
private static final byte[] PING = {(byte) 0xf0, (byte) 0xa0, (byte) 0x01, (byte) 0x01, (byte) 0x92 };
|
||||
private static final byte[] INIT_A0 = {(byte) 0xf0, (byte) 0xa0, 0x02, 0x02, (byte) 0x94};
|
||||
//private static final byte[] PONG = {(byte) 0xf0, (byte) 0xb0, 0x01, 0x01, (byte) 0xa2};
|
||||
private static final byte[] STATUS = {(byte) 0xf0, (byte) 0xa1, 0x01, 0x01, (byte) 0x93};
|
||||
private static final byte[] INIT_A3 = {(byte) 0xf0, (byte) 0xa3, 0x01, 0x01, 0x01, (byte) 0x96};
|
||||
private static final byte[] INIT_A4 = {(byte) 0xf0, (byte) 0xa4, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, (byte) 0xa0};
|
||||
private static final byte[] START = {(byte) 0xf0, (byte) 0xa5, 0x01, 0x01, 0x02, (byte) 0x99};
|
||||
private static final byte[] STOP = {(byte) 0xf0, (byte) 0xa5, 0x01, 0x01, 0x04, (byte) 0x9b};
|
||||
private static final byte[] READ = {(byte) 0xf0, (byte) 0xa2, 0x01, 0x01, (byte) 0x94};
|
||||
private static final byte[] SETLEVEL = {(byte) 0xf0, (byte) 0xa6, 0x01, 0x01, 0x01, (byte)((0xf0+0xa6+3) & 0xFF)};
|
||||
|
||||
private enum State {
|
||||
BEGIN,
|
||||
PING,
|
||||
A0,
|
||||
A1,
|
||||
A1_POST_PING,
|
||||
A3,
|
||||
A4,
|
||||
START,
|
||||
STOP,
|
||||
READ,
|
||||
SETLEVEL,
|
||||
}
|
||||
|
||||
private State mCurrentState = State.BEGIN;
|
||||
private State mNextState = State.PING;
|
||||
private boolean mWaitAck = false;
|
||||
private int mSetLevel = 1;
|
||||
private long mTimesent = 0;
|
||||
private int mExpectLen = 0;
|
||||
private byte[] mExpectPacket;
|
||||
private final InputStream mInputStream;
|
||||
private final OutputStream mOutputStream;
|
||||
private final DataListener mDataListener;
|
||||
private final DebugListener mDebugListener;
|
||||
|
||||
IConsole(InputStream inputStream, OutputStream outputStream,
|
||||
@Nullable DataListener dataListener, @Nullable DebugListener debugListener) {
|
||||
this.mInputStream = inputStream;
|
||||
this.mOutputStream = outputStream;
|
||||
this.mDataListener = dataListener;
|
||||
this.mDebugListener = debugListener;
|
||||
}
|
||||
|
||||
class Data implements java.io.Serializable {
|
||||
long mTime; // in seconds
|
||||
int mSpeed10;
|
||||
int mRPM;
|
||||
int mDistance10;
|
||||
int mCalories;
|
||||
int mHF;
|
||||
int mPower10;
|
||||
int mLevel;
|
||||
|
||||
Data(long mTime, int mSpeed10, int mRPM, int mDistance10, int mCalories, int mHF, int mPower10, int mLevel) {
|
||||
this.mTime = mTime;
|
||||
this.mSpeed10 = mSpeed10;
|
||||
this.mRPM = mRPM;
|
||||
this.mDistance10 = mDistance10;
|
||||
this.mCalories = mCalories;
|
||||
this.mHF = mHF;
|
||||
this.mPower10 = mPower10;
|
||||
this.mLevel = mLevel;
|
||||
}
|
||||
|
||||
Data(byte[] bytes) {
|
||||
this.mTime = (((bytes[2]-1) * 24 + bytes[3]-1) * 60 + bytes[4]-1) * 60 + bytes[5]-1 ;
|
||||
this.mSpeed10 = 100 * (bytes[ 6] - 1) + bytes[ 7] - 1;
|
||||
this.mRPM = 100 * (bytes[ 8] - 1) + bytes[ 9] - 1;
|
||||
this.mDistance10 = 100 * (bytes[10] - 1) + bytes[11] - 1;
|
||||
this.mCalories = 100 * (bytes[12] - 1) + bytes[13] - 1;
|
||||
this.mHF = 100 * (bytes[14] - 1) + bytes[15] - 1;
|
||||
this.mPower10 = 100 * (bytes[16] - 1) + bytes[17] - 1;
|
||||
this.mLevel = bytes[18] -1;
|
||||
}
|
||||
|
||||
String getTimeStr() {
|
||||
long day, hour, min, sec;
|
||||
StringBuilder b = new StringBuilder();
|
||||
day = mTime / 60 / 60 / 24;
|
||||
if (day > 0)
|
||||
b.append(String.format(Locale.US, "%02d:", day));
|
||||
hour = (mTime % (60 * 60 * 24)) / 60 / 60;
|
||||
if (hour > 0)
|
||||
if (day > 0)
|
||||
b.append(String.format(Locale.US, "%02d:", hour));
|
||||
else
|
||||
b.append(String.format(Locale.US, "%d:", hour));
|
||||
min = (mTime % (60 * 60)) / 60;
|
||||
sec = mTime % 60;
|
||||
b.append(String.format(Locale.US, "%02d:%02d", min, sec));
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface DataListener {
|
||||
void onData(Data data);
|
||||
void onError(Exception e);
|
||||
}
|
||||
|
||||
interface DebugListener {
|
||||
void onRead(byte[] bytes);
|
||||
void onWrite(byte[] bytes);
|
||||
}
|
||||
|
||||
boolean start() {
|
||||
synchronized (this) {
|
||||
this.mNextState = State.A0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean stop() {
|
||||
synchronized (this) {
|
||||
this.mNextState = State.STOP;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean setLevel(int level) {
|
||||
synchronized (this) {
|
||||
if (mCurrentState != State.READ)
|
||||
return false;
|
||||
|
||||
this.mNextState = State.SETLEVEL;
|
||||
Log.d(TAG, String.format("Set Level to %d", level));
|
||||
this.mSetLevel = level;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean send(byte[] packet, byte expect, int plen) throws IOException {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if ((now - mTimesent) < ((mCurrentState == State.READ) ? 500 : 200)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Flush input stream
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
mInputStream.skip(mInputStream.available());
|
||||
} catch (IOException e) {
|
||||
; // ignore
|
||||
}
|
||||
|
||||
// Send packet
|
||||
mOutputStream.write(packet);
|
||||
|
||||
if (null != mDebugListener)
|
||||
mDebugListener.onWrite(packet);
|
||||
//Log.d(TAG, "sent: " + byteArrayToHex(packet));
|
||||
|
||||
mTimesent = System.currentTimeMillis();
|
||||
mExpectPacket = packet.clone();
|
||||
mExpectPacket[1] = expect;
|
||||
mExpectLen = plen;
|
||||
mWaitAck = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean send(byte[] packet) throws IOException {
|
||||
return send(packet, (byte)(0xb0 | (packet[1] & 0xF)), packet.length);
|
||||
}
|
||||
|
||||
private boolean send(byte[] packet, int plen) throws IOException {
|
||||
return send(packet, (byte)(0xb0 | (packet[1] & 0xF)), plen);
|
||||
}
|
||||
|
||||
private boolean send_level(int level) throws IOException {
|
||||
byte[] packet = SETLEVEL.clone();
|
||||
packet[4] = (byte) (packet[4] + level);
|
||||
packet[5] = (byte) ((packet[5] + level) & 0xFF);
|
||||
//Log.d(TAG, "send_level");
|
||||
return send(packet);
|
||||
}
|
||||
|
||||
private byte[] wait_ack() throws IOException, TimeoutException {
|
||||
byte[] buffer = new byte[mExpectLen];
|
||||
int bytes;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if ((now - mTimesent) > 10000) {
|
||||
mWaitAck = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mInputStream.available() < mExpectLen) {
|
||||
//Log.d(TAG, String.format(Locale.US, "Avail: %d Expected: %d", mInputStream.available(), mExpectLen));
|
||||
return null;
|
||||
}
|
||||
|
||||
bytes = mInputStream.read(buffer);
|
||||
|
||||
if (null != mDebugListener) {
|
||||
mDebugListener.onRead(Arrays.copyOfRange(buffer, 0, bytes));
|
||||
//Log.d(TAG, "wait ack got: " + byteArrayToHex(Arrays.copyOfRange(buffer, 0, bytes)));
|
||||
}
|
||||
|
||||
//Log.d(TAG, "wait ack checking");
|
||||
|
||||
if (bytes != mExpectLen) {
|
||||
throw new IOException("Wrong number of bytes read. Expected " + mExpectLen + ", got " + bytes);
|
||||
}
|
||||
|
||||
if (buffer[0] != mExpectPacket[0]) {
|
||||
throw new IOException("Byte 0 wrong. Expected " + String.format("%02x", mExpectPacket[0]) + ", got " + String.format("%02x", buffer[0]));
|
||||
}
|
||||
|
||||
if (buffer[1] != mExpectPacket[1]) {
|
||||
throw new IOException("Byte 1 wrong. Expected " + String.format("%02x", mExpectPacket[1]) + ", got " + String.format("%02x", buffer[1]));
|
||||
}
|
||||
|
||||
//Log.d(TAG, "wait ack success");
|
||||
mWaitAck = false;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private boolean processIOSend() throws IOException {
|
||||
switch (mCurrentState) {
|
||||
case BEGIN:
|
||||
send(PING);
|
||||
break;
|
||||
case PING:
|
||||
send(PING);
|
||||
break;
|
||||
case A0:
|
||||
send(INIT_A0, (byte)0xb7, 6);
|
||||
break;
|
||||
case A1:
|
||||
send(STATUS, 6);
|
||||
break;
|
||||
case A1_POST_PING:
|
||||
send(PING);
|
||||
break;
|
||||
case A3:
|
||||
send(INIT_A3);
|
||||
break;
|
||||
case A4:
|
||||
send(INIT_A4);
|
||||
break;
|
||||
case START:
|
||||
send(START);
|
||||
break;
|
||||
case STOP:
|
||||
send(STOP);
|
||||
break;
|
||||
case READ:
|
||||
send(READ, 21);
|
||||
break;
|
||||
case SETLEVEL:
|
||||
send_level(mSetLevel);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processIOAck() throws IOException, TimeoutException {
|
||||
byte[] got = null;
|
||||
got = wait_ack();
|
||||
if (null == got) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Log.d(TAG, "processIOAck next state");
|
||||
|
||||
if(mCurrentState == State.READ)
|
||||
if (null != mDataListener)
|
||||
mDataListener.onData(new Data(got));
|
||||
|
||||
mCurrentState = mNextState;
|
||||
switch (mNextState) {
|
||||
case BEGIN:
|
||||
mNextState = State.PING;
|
||||
break;
|
||||
case PING:
|
||||
mNextState = State.PING;
|
||||
break;
|
||||
case A0:
|
||||
mNextState = State.A1;
|
||||
break;
|
||||
case A1:
|
||||
mNextState = State.A1_POST_PING;
|
||||
break;
|
||||
case A1_POST_PING:
|
||||
mNextState = State.A3;
|
||||
break;
|
||||
case A3:
|
||||
mNextState = State.A4;
|
||||
break;
|
||||
case A4:
|
||||
mNextState = State.START;
|
||||
break;
|
||||
case START:
|
||||
mNextState = State.READ;
|
||||
break;
|
||||
case STOP:
|
||||
mNextState = State.PING;
|
||||
break;
|
||||
case READ:
|
||||
mNextState = State.READ;
|
||||
break;
|
||||
case SETLEVEL:
|
||||
mNextState = State.READ;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean processIO() {
|
||||
//Log.i(TAG, "Begin processIO");
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
if (!mWaitAck) {
|
||||
//Log.i(TAG, "processIOSend");
|
||||
return processIOSend();
|
||||
} else {
|
||||
//Log.i(TAG, "processIOAck");
|
||||
return processIOAck();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "processIO", e);
|
||||
if (null != mDataListener)
|
||||
mDataListener.onError(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] hexStringToByteArray(String s) {
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||
+ Character.digit(s.charAt(i+1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static String byteArrayToHex(byte[] a) {
|
||||
StringBuilder sb = new StringBuilder(a.length * 2);
|
||||
for(byte b: a)
|
||||
sb.append(String.format("%02x", b));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 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 org.surfsite.iconsole;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import org.surfsite.iconsole.ChannelService.ChannelServiceComm;
|
||||
|
||||
|
||||
/**
|
||||
* A simple launcher activity containing a summary sample description, sample log and a custom
|
||||
* {@link android.support.v4.app.Fragment} which can display a view.
|
||||
* <p>
|
||||
* For devices with displays with a width of 720dp or greater, the sample log is always visible,
|
||||
* on other devices it's visibility is controlled by an item on the Action Bar.
|
||||
*/
|
||||
public class MainActivity extends FragmentActivity {
|
||||
|
||||
public static final String TAG = "MainActivity";
|
||||
|
||||
// Whether the Log Fragment is currently shown
|
||||
private boolean mLogShown;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
BluetoothChatFragment fragment = new BluetoothChatFragment();
|
||||
transaction.replace(R.id.sample_content_fragment, fragment);
|
||||
transaction.commit();
|
||||
}
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
|
||||
ComponentName componentName = startService(new Intent(this, BluetoothChatService.class));
|
||||
if (componentName == null)
|
||||
Log.e(TAG, "componentName == null");
|
||||
else
|
||||
Log.i(TAG, "Service started");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
|
||||
if(isFinishing())
|
||||
{
|
||||
stopService(new Intent(this, BluetoothChatService.class));
|
||||
stopService(new Intent(this, ChannelService.class));
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,306 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 org.surfsite.iconsole;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
import com.dsi.ant.channel.AntCommandFailedException;
|
||||
import com.dsi.ant.channel.IAntChannelEventHandler;
|
||||
import com.dsi.ant.message.ChannelId;
|
||||
import com.dsi.ant.message.ChannelType;
|
||||
import com.dsi.ant.message.EventCode;
|
||||
import com.dsi.ant.message.fromant.ChannelEventMessage;
|
||||
import com.dsi.ant.message.fromant.MessageFromAntType;
|
||||
import com.dsi.ant.message.ipc.AntMessageParcel;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class SpeedChannelController {
|
||||
// The device type and transmission type to be part of the channel ID message
|
||||
private static final int CHANNEL_SPEED_DEVICE_TYPE = 0x7B;
|
||||
private static final int CHANNEL_SPEED_TRANSMISSION_TYPE = 1;
|
||||
|
||||
// The period and frequency values the channel will be configured to
|
||||
private static final int CHANNEL_SPEED_PERIOD = 8118; // 1 Hz
|
||||
private static final int CHANNEL_SPEED_FREQUENCY = 57;
|
||||
|
||||
private static final String TAG = SpeedChannelController.class.getSimpleName();
|
||||
public static final int SPEED_SENSOR_ID = 0x9e3d4b65;
|
||||
|
||||
private static Random randGen = new Random();
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
|
||||
private boolean mIsOpen;
|
||||
double speed = 0.0;
|
||||
|
||||
public SpeedChannelController(AntChannel antChannel) {
|
||||
mAntChannel = antChannel;
|
||||
openChannel();
|
||||
}
|
||||
|
||||
boolean openChannel() {
|
||||
if (null != mAntChannel) {
|
||||
if (mIsOpen) {
|
||||
Log.w(TAG, "Channel was already open");
|
||||
} else {
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(SPEED_SENSOR_ID & 0xFFFF,
|
||||
CHANNEL_SPEED_DEVICE_TYPE, CHANNEL_SPEED_TRANSMISSION_TYPE);
|
||||
|
||||
try {
|
||||
// Setting the channel event handler so that we can receive messages from ANT
|
||||
mAntChannel.setChannelEventHandler(mChannelEventCallback);
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
|
||||
mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
|
||||
|
||||
/*
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* then opening the channel.
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
mAntChannel.setChannelId(channelId);
|
||||
mAntChannel.setPeriod(CHANNEL_SPEED_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_SPEED_FREQUENCY);
|
||||
mAntChannel.open();
|
||||
mIsOpen = true;
|
||||
|
||||
Log.d(TAG, "Opened channel with device number: " + SPEED_SENSOR_ID);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
} catch (AntCommandFailedException e) {
|
||||
// This will release, and therefore unassign if required
|
||||
channelError("Open failed", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "No channel available");
|
||||
}
|
||||
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if (e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x" + Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
|
||||
Log.e(TAG, "ANT Command Failed");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel) {
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
Log.e(TAG, "Channel Closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Channel Event Handler Interface so that messages can be
|
||||
* received and channel death events can be handled.
|
||||
*/
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler {
|
||||
int revCounts = 0;
|
||||
int ucMessageCount = 0;
|
||||
byte ucPageChange = 0;
|
||||
byte ucExtMesgType = 1;
|
||||
long lastTime = 0;
|
||||
double way;
|
||||
int rev;
|
||||
double remWay;
|
||||
double wheel = 0.1;
|
||||
|
||||
@Override
|
||||
public void onChannelDeath() {
|
||||
// Display channel death message when channel dies
|
||||
Log.e(TAG, "Channel Death");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
|
||||
Log.d(TAG, "Rx: " + antParcel);
|
||||
Log.d(TAG, "Message Type: " + messageType);
|
||||
|
||||
// Switching on message type to handle different types of messages
|
||||
switch (messageType) {
|
||||
// If data message, construct from parcel and update channel data
|
||||
case BROADCAST_DATA:
|
||||
// Rx Data
|
||||
//updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case ACKNOWLEDGED_DATA:
|
||||
// Rx Data
|
||||
//updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case CHANNEL_EVENT:
|
||||
// Constructing channel event message from parcel
|
||||
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
|
||||
EventCode code = eventMessage.getEventCode();
|
||||
Log.d(TAG, "Event Code: " + code);
|
||||
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch (code) {
|
||||
case TX:
|
||||
long unixTime = System.currentTimeMillis() / 1000L;
|
||||
|
||||
if (lastTime != 0) {
|
||||
way = speed * (unixTime - lastTime) / 3.6 + remWay;
|
||||
rev = (int)(way / wheel + 0.5);
|
||||
remWay = way - rev * wheel;
|
||||
revCounts += rev;
|
||||
}
|
||||
lastTime = unixTime;
|
||||
|
||||
ucPageChange += 0x20;
|
||||
ucPageChange &= 0xF0;
|
||||
ucMessageCount += 1;
|
||||
byte[] payload = new byte[8];
|
||||
|
||||
if (ucMessageCount >= 65) {
|
||||
if (ucExtMesgType >= 4)
|
||||
ucExtMesgType = 1;
|
||||
|
||||
if (ucExtMesgType == 1) {
|
||||
int halfunixTime = (int) (unixTime / 2L);
|
||||
payload[0] = (byte) ((byte) 0x01 | (byte) (ucPageChange & (byte) 0x80));
|
||||
payload[1] = (byte) (halfunixTime & 0xFF);
|
||||
payload[2] = (byte) ((halfunixTime >> 8) & 0xFF);
|
||||
payload[3] = (byte) ((halfunixTime >> 16) & 0xFF);
|
||||
}
|
||||
else if (ucExtMesgType == 2) {
|
||||
payload[0] = (byte) ((byte) 0x02 | (byte) (ucPageChange & (byte) 0x80));
|
||||
payload[1] = (byte) 0xFF;
|
||||
payload[2] = (byte) ((SPEED_SENSOR_ID >> 16) & 0xFF);
|
||||
payload[3] = (byte) ((SPEED_SENSOR_ID >> 24) & 0xFF);
|
||||
}
|
||||
else if (ucExtMesgType == 3) {
|
||||
payload[0] = (byte) ((byte) 0x03 | (byte) (ucPageChange & (byte) 0x80));
|
||||
payload[1] = (byte) 0x01;
|
||||
payload[2] = (byte) 0x01;
|
||||
payload[3] = (byte) 0x01;
|
||||
}
|
||||
if (ucMessageCount >= 68) {
|
||||
ucMessageCount = 0;
|
||||
ucExtMesgType += 1;
|
||||
}
|
||||
} else {
|
||||
payload[0] = (byte) (ucPageChange & 0x80);
|
||||
payload[1] = (byte) 0xFF;
|
||||
payload[2] = (byte) 0xFF;
|
||||
payload[3] = (byte) 0xFF;
|
||||
}
|
||||
|
||||
int unixTime1024 = (int) (unixTime * 1024);
|
||||
payload[4] = (byte) (unixTime1024 & 0xFF);
|
||||
payload[5] = (byte) ((unixTime1024 >> 8) & 0xFF);
|
||||
payload[6] = (byte) (revCounts & 0xFF);
|
||||
payload[7] = (byte) ((revCounts >> 8) & 0xFF);
|
||||
|
||||
if (mIsOpen) {
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLLISION:
|
||||
ucPageChange += 0x20;
|
||||
ucPageChange &= 0xF0;
|
||||
ucMessageCount += 1;
|
||||
break;
|
||||
case RX_SEARCH_TIMEOUT:
|
||||
// TODO May want to keep searching
|
||||
Log.e(TAG, "No Device Found");
|
||||
break;
|
||||
case CHANNEL_CLOSED:
|
||||
case RX_FAIL:
|
||||
case RX_FAIL_GO_TO_SEARCH:
|
||||
case TRANSFER_RX_FAILED:
|
||||
case TRANSFER_TX_COMPLETED:
|
||||
case TRANSFER_TX_FAILED:
|
||||
case TRANSFER_TX_START:
|
||||
case UNKNOWN:
|
||||
// TODO More complex communication will need to handle these events
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANT_VERSION:
|
||||
case BURST_TRANSFER_DATA:
|
||||
case CAPABILITIES:
|
||||
case CHANNEL_ID:
|
||||
case CHANNEL_RESPONSE:
|
||||
case CHANNEL_STATUS:
|
||||
case SERIAL_NUMBER:
|
||||
case OTHER:
|
||||
// TODO More complex communication will need to handle these message types
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 841 B |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 13 KiB |
|
@ -1,31 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/sample_main_layout">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/sample_content_fragment"
|
||||
android:layout_weight="2"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_paired_devices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dp"
|
||||
android:text="@string/title_paired_devices"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/paired_devices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:stackFromBottom="true"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_new_devices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dp"
|
||||
android:text="@string/title_other_devices"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/new_devices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2"
|
||||
android:stackFromBottom="true"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_scan"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_scan"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -1,30 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/sample_main_layout">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/sample_content_fragment"
|
||||
android:layout_weight="4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dp"
|
||||
android:textSize="18sp"
|
||||
/>
|
|
@ -1,413 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 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.
|
||||
-->
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout_editor_absoluteY="0dp"
|
||||
tools:layout_editor_absoluteX="0dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView8"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="RPM"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/textView7" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Calories"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Calories"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Heart"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/textView4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Distance"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/textView3" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Speed"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Speed"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Power corr"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Power"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Time"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Time"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/Level"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline2"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineright"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/time_n00_00_00"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintHorizontal_bias="0.501"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Speed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/speed_n0_0_km_h"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline6"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Power"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/power_n0_0_w"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/RPM"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/rpm_n0"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/Calories" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/distance_n0_0_km"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/Power" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Calories"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/calories_n0_cal"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline2"
|
||||
app:layout_constraintHorizontal_bias="0.507"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Heart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/heart_n0"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineleft"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guidelineright"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/Speed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/level"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintHorizontal_bias="0.509"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guidelineright"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guidelineleft"
|
||||
app:layout_constraintGuide_percent="0.35"
|
||||
android:orientation="vertical"
|
||||
tools:layout_editor_absoluteY="0dp"
|
||||
tools:layout_editor_absoluteX="154dp" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline4"
|
||||
app:layout_constraintGuide_percent="0.4"
|
||||
android:orientation="horizontal"
|
||||
tools:layout_editor_absoluteY="205dp"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline5"
|
||||
app:layout_constraintGuide_percent="0.2"
|
||||
android:orientation="horizontal"
|
||||
tools:layout_editor_absoluteY="102dp"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline6"
|
||||
app:layout_constraintGuide_percent="0.6"
|
||||
android:orientation="horizontal"
|
||||
tools:layout_editor_absoluteY="307dp"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guidelineright"
|
||||
app:layout_constraintGuide_percent="0.7"
|
||||
android:orientation="vertical"
|
||||
tools:layout_editor_absoluteY="0dp"
|
||||
tools:layout_editor_absoluteX="307dp" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/guideline2"
|
||||
app:layout_constraintGuide_percent="0.8"
|
||||
android:orientation="horizontal"
|
||||
tools:layout_editor_absoluteY="409dp"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline2">
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/start" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_stop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/stop" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="4" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_disconnect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disconnect" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dp"
|
||||
android:textSize="18sp"
|
||||
/>
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/secure_connect_scan"
|
||||
android:icon="@drawable/ic_action_device_access_bluetooth_searching"
|
||||
android:showAsAction="ifRoom"
|
||||
android:title="@string/secure_connect"/>
|
||||
|
||||
|
||||
</menu>
|
|
@ -1,24 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Semantic definitions -->
|
||||
|
||||
<dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
|
||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
||||
|
||||
</resources>
|
|
@ -1,25 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="Widget.SampleMessage">
|
||||
<item name="android:textAppearance">?android:textAppearanceLarge</item>
|
||||
<item name="android:lineSpacingMultiplier">1.2</item>
|
||||
<item name="android:shadowDy">-6.5</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -1,22 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Activity themes -->
|
||||
<style name="Theme.Base" parent="android:Theme.Holo.Light" />
|
||||
|
||||
</resources>
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
|
||||
</resources>
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Activity themes -->
|
||||
<style name="Theme.Base" parent="android:Theme.Material.Light">
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">OpeniConsole</string>
|
||||
<string name="intro_message">
|
||||
<![CDATA[
|
||||
|
||||
This application connects to an iConsole+ mount unit for fitness devices.
|
||||
|
||||
]]>
|
||||
</string>
|
||||
</resources>
|
|
@ -1,19 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
<string name="sample_show_log">Show Log</string>
|
||||
<string name="sample_hide_log">Hide Log</string>
|
||||
</resources>
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<!-- BluetoothChat -->
|
||||
<string name="not_connected">You are not connected to a device</string>
|
||||
<string name="bt_not_enabled_leaving">Bluetooth was not enabled. Leaving OpeniConsole.</string>
|
||||
<string name="title_connecting">connecting...</string>
|
||||
<string name="title_connected_to">connected to <xliff:g id="device_name">%1$s</xliff:g></string>
|
||||
<string name="title_not_connected">not connected</string>
|
||||
|
||||
<!-- DeviceListActivity -->
|
||||
<string name="scanning">scanning for devices...</string>
|
||||
<string name="select_device">select a device to connect</string>
|
||||
<string name="none_paired">No devices have been paired</string>
|
||||
<string name="none_found">No devices found</string>
|
||||
<string name="title_paired_devices">Paired Devices</string>
|
||||
<string name="title_other_devices">Other Available Devices</string>
|
||||
<string name="button_scan">Scan for devices</string>
|
||||
|
||||
<!-- Options Menu -->
|
||||
<string name="start">Start</string>
|
||||
<string name="stop">Stop</string>
|
||||
<string name="disconnect">Disconnect</string>
|
||||
<string name="time_n00_00_00">00:00:00</string>
|
||||
<string name="speed_n0_0_km_h">0.0</string>
|
||||
<string name="rpm_n0">0</string>
|
||||
<string name="level_n1">Level\n1</string>
|
||||
<string name="distance_n0_0_km">0.0</string>
|
||||
<string name="calories_n0_cal">0</string>
|
||||
<string name="heart_n0">0</string>
|
||||
<string name="power_n0_0_w">0.0</string>
|
||||
<string name="level">Level</string>
|
||||
<string name="local_service_started">OpeniConsole Bluetooth active</string>
|
||||
<string name="local_service_label">OpeniConsole - TEST</string>
|
||||
<string name="secure_connect">Connect to iConsole</string>
|
||||
|
||||
</resources>
|
|
@ -1,32 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
|
||||
|
||||
<dimen name="margin_tiny">4dp</dimen>
|
||||
<dimen name="margin_small">8dp</dimen>
|
||||
<dimen name="margin_medium">16dp</dimen>
|
||||
<dimen name="margin_large">32dp</dimen>
|
||||
<dimen name="margin_huge">64dp</dimen>
|
||||
|
||||
<!-- Semantic definitions -->
|
||||
|
||||
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
|
||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
|
||||
|
||||
</resources>
|
|
@ -1,41 +0,0 @@
|
|||
<!--
|
||||
Copyright 2013 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Activity themes -->
|
||||
|
||||
<style name="Theme.Base" parent="android:Theme.Light" />
|
||||
|
||||
<style name="Theme.Sample" parent="Theme.Base" />
|
||||
|
||||
<style name="AppTheme" parent="Theme.Sample" />
|
||||
<!-- Widget styling -->
|
||||
|
||||
<style name="Widget" />
|
||||
|
||||
<style name="Widget.SampleMessage">
|
||||
<item name="android:textAppearance">?android:textAppearanceMedium</item>
|
||||
<item name="android:lineSpacingMultiplier">1.1</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.SampleMessageTile">
|
||||
<item name="android:background">@drawable/tile</item>
|
||||
<item name="android:shadowColor">#7F000000</item>
|
||||
<item name="android:shadowDy">-3.5</item>
|
||||
<item name="android:shadowRadius">2</item>
|
||||
</style>
|
||||
</resources>
|
647
LICENSE
|
@ -1,647 +0,0 @@
|
|||
Apache License
|
||||
--------------
|
||||
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
||||
All image and audio files (including *.png, *.jpg, *.svg, *.mp3, *.wav
|
||||
and *.ogg) are licensed under the CC-BY-NC license. All other files are
|
||||
licensed under the Apache 2 license.
|
||||
|
||||
CC-BY-NC License
|
||||
----------------
|
||||
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-NC-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
l. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
m. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
n. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material for
|
||||
NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public licenses.
|
||||
Notwithstanding, Creative Commons may elect to apply one of its public
|
||||
licenses to material it publishes and in those instances will be
|
||||
considered the "Licensor." Except for the limited purpose of indicating
|
||||
that material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the public
|
||||
licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
|
29
README.md
|
@ -1,29 +0,0 @@
|
|||
|
||||
# OpeniConsole
|
||||

|
||||
|
||||
## Description
|
||||
OpeniConsole connects to an iConsole+ fitness bike head unit over bluetooth.
|
||||
|
||||
You can set the resistance level and all data is displayed.
|
||||
|
||||
This application is in beta status and under heavy development.
|
||||
|
||||
OpeniConsole is an open source project and you are invited to improve it.
|
||||
|
||||
## Download
|
||||
Google Play Store [beta testing](https://play.google.com/apps/testing/org.surfsite.iconsole)
|
||||
|
||||
## Screenshot
|
||||

|
||||
|
||||
## Development
|
||||
Contribute via pull requests. If you want to do major contributions, drop me a message and I will create a development group.
|
||||
|
||||
### TODO/Ideas
|
||||
- workout recording to FIT/TCX/GPX
|
||||
- workout profiles
|
||||
- Google street view cycling
|
||||
- sensor data broadcasting via ANT (works, message me for a howto or look [here](https://github.com/haraldh/iconsole-android/issues/4))
|
||||
|
||||
See also my [python prototype](https://github.com/haraldh/iconsole) for the bluetooth protocol reverse engineering and sensor broadcasting.
|
27
android_antlib_4-14-0/android_antlib_4-14-0.iml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":android_antlib_4-14-0" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":android_antlib_4-14-0" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<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" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="android_antlib_4-14-0.android_antlib_4-14-0" level="project" />
|
||||
|
||||
</component>
|
||||
</module>
|
1
app/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
133
app/app.iml
Normal file
|
@ -0,0 +1,133 @@
|
|||
<?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" 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="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<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" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
||||
<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/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<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/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
|
||||
<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/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
||||
<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/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<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/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-main-apk-res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/splits-support" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-v4-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:24.2.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-24.2.1" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-24.2.1" level="project" />
|
||||
<orderEntry type="module" module-name="android_antlib_4-14-0" />
|
||||
</component>
|
||||
</module>
|
27
app/build.gradle
Normal file
|
@ -0,0 +1,27 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion '27.0.3'
|
||||
defaultConfig {
|
||||
applicationId "xyz.hoyer.iconsole"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 24
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:24.2.1'
|
||||
implementation 'com.android.support:support-v4:24.2.1'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
||||
implementation project(':android_antlib_4-14-0')
|
||||
}
|
25
app/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/harald/Android/Sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
25
app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="xyz.hoyer.iconsole">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".ChannelList"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FullscreenTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name=".ChannelService"></service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -13,7 +13,7 @@
|
|||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.surfsite.iconsole;
|
||||
package xyz.hoyer.iconsole;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
@ -23,70 +23,104 @@ import com.dsi.ant.channel.AntCommandFailedException;
|
|||
import com.dsi.ant.channel.IAntChannelEventHandler;
|
||||
import com.dsi.ant.message.ChannelId;
|
||||
import com.dsi.ant.message.ChannelType;
|
||||
import com.dsi.ant.message.EventCode;
|
||||
import com.dsi.ant.message.fromant.AcknowledgedDataMessage;
|
||||
import com.dsi.ant.message.fromant.BroadcastDataMessage;
|
||||
import com.dsi.ant.message.fromant.ChannelEventMessage;
|
||||
import com.dsi.ant.message.fromant.MessageFromAntType;
|
||||
import com.dsi.ant.message.ipc.AntMessageParcel;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class PowerChannelController {
|
||||
public static final int POWER_SENSOR_ID = 0x9e3d4b66;
|
||||
public class ChannelController
|
||||
{
|
||||
// The device type and transmission type to be part of the channel ID message
|
||||
private static final int CHANNEL_POWER_DEVICE_TYPE = 0x0B;
|
||||
private static final int CHANNEL_POWER_TRANSMISSION_TYPE = 5;
|
||||
private static final int CHANNEL_PROOF_DEVICE_TYPE = 0x08;
|
||||
private static final int CHANNEL_PROOF_TRANSMISSION_TYPE = 1;
|
||||
|
||||
// The period and frequency values the channel will be configured to
|
||||
private static final int CHANNEL_POWER_PERIOD = 8182; // 1 Hz
|
||||
private static final int CHANNEL_POWER_FREQUENCY = 57;
|
||||
private static final String TAG = PowerChannelController.class.getSimpleName();
|
||||
private static final int CHANNEL_PROOF_PERIOD = 32768; // 1 Hz
|
||||
private static final int CHANNEL_PROOF_FREQUENCY = 77;
|
||||
|
||||
private static final String TAG = ChannelController.class.getSimpleName();
|
||||
|
||||
private static Random randGen = new Random();
|
||||
int power = 0;
|
||||
int cadence = 0;
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
private ChannelBroadcastListener mChannelBroadcastListener;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
private ChannelInfo mChannelInfo;
|
||||
|
||||
private boolean mIsOpen;
|
||||
|
||||
public PowerChannelController(AntChannel antChannel) {
|
||||
static public abstract class ChannelBroadcastListener
|
||||
{
|
||||
public abstract void onBroadcastChanged(ChannelInfo newInfo);
|
||||
}
|
||||
|
||||
public ChannelController(AntChannel antChannel, boolean isMaster, int deviceId,
|
||||
ChannelBroadcastListener broadcastListener)
|
||||
{
|
||||
mAntChannel = antChannel;
|
||||
mChannelInfo = new ChannelInfo(deviceId, isMaster, randGen.nextInt(256));
|
||||
mChannelBroadcastListener = broadcastListener;
|
||||
|
||||
openChannel();
|
||||
}
|
||||
|
||||
boolean openChannel() {
|
||||
if (null != mAntChannel) {
|
||||
if (mIsOpen) {
|
||||
|
||||
|
||||
boolean openChannel()
|
||||
{
|
||||
if(null != mAntChannel)
|
||||
{
|
||||
if(mIsOpen)
|
||||
{
|
||||
Log.w(TAG, "Channel was already open");
|
||||
} else {
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(POWER_SENSOR_ID & 0xFFFF,
|
||||
CHANNEL_POWER_DEVICE_TYPE, CHANNEL_POWER_TRANSMISSION_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Although this reference code sets ChannelType to either a transmitting master or a receiving slave,
|
||||
* the standard for ANT is that channels communication is bidirectional. The use of single-direction
|
||||
* communication in this app is for ease of understanding as reference code. For more information and
|
||||
* any additional features on ANT channel communication, refer to the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
ChannelType channelType = (mChannelInfo.isMaster ?
|
||||
ChannelType.BIDIRECTIONAL_MASTER : ChannelType.BIDIRECTIONAL_SLAVE);
|
||||
|
||||
try {
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(mChannelInfo.deviceNumber,
|
||||
CHANNEL_PROOF_DEVICE_TYPE, CHANNEL_PROOF_TRANSMISSION_TYPE);
|
||||
|
||||
try
|
||||
{
|
||||
// Setting the channel event handler so that we can receive messages from ANT
|
||||
mAntChannel.setChannelEventHandler(mChannelEventCallback);
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
|
||||
mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
|
||||
|
||||
mAntChannel.assign(channelType);
|
||||
|
||||
/*
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* then opening the channel.
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
mAntChannel.setChannelId(channelId);
|
||||
mAntChannel.setPeriod(CHANNEL_POWER_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_POWER_FREQUENCY);
|
||||
mAntChannel.setPeriod(CHANNEL_PROOF_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_PROOF_FREQUENCY);
|
||||
mAntChannel.open();
|
||||
mIsOpen = true;
|
||||
|
||||
Log.d(TAG, "Opened channel with device number: " + POWER_SENSOR_ID);
|
||||
Log.d(TAG, "Opened channel with device number: " + mChannelInfo.deviceNumber);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
} catch (AntCommandFailedException e) {
|
||||
|
@ -94,177 +128,79 @@ public class PowerChannelController {
|
|||
channelError("Open failed", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.w(TAG, "No channel available");
|
||||
}
|
||||
|
||||
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if (e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x" + Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel) {
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
Log.e(TAG, "Channel Closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Channel Event Handler Interface so that messages can be
|
||||
* received and channel death events can be handled.
|
||||
*/
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler {
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler
|
||||
{
|
||||
private void updateData(byte[] data) {
|
||||
mChannelInfo.broadcastData = data;
|
||||
|
||||
int cnt = 0;
|
||||
int eventCount = 0;
|
||||
int cumulativePower = 0;
|
||||
|
||||
@Override
|
||||
public void onChannelDeath() {
|
||||
// Display channel death message when channel dies
|
||||
Log.e(TAG, "Channel Death");
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelDeath()
|
||||
{
|
||||
// Display channel death message when channel dies
|
||||
displayChannelError("Channel Death");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
|
||||
Log.d(TAG, "Rx: " + antParcel);
|
||||
Log.d(TAG, "Message Type: " + messageType);
|
||||
byte[] payload = new byte[8];
|
||||
Log.d(TAG, "Rx: "+ antParcel);
|
||||
|
||||
// Switching on message type to handle different types of messages
|
||||
switch (messageType) {
|
||||
switch(messageType)
|
||||
{
|
||||
// If data message, construct from parcel and update channel data
|
||||
case BROADCAST_DATA:
|
||||
// Rx Data
|
||||
//updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case ACKNOWLEDGED_DATA:
|
||||
// Rx Data
|
||||
//updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
payload = new AcknowledgedDataMessage(antParcel).getPayload();
|
||||
Log.d(TAG, "AcknowledgedDataMessage: " + payload);
|
||||
|
||||
if ((payload[0] == 0) && (payload[1] == 1) && (payload[2] == (byte)0xAA)) {
|
||||
payload[0] = (byte) 0x01;
|
||||
payload[1] = (byte) 0xAC;
|
||||
payload[2] = (byte) 0xFF;
|
||||
payload[3] = (byte) 0xFF;
|
||||
payload[4] = (byte) 0xFF;
|
||||
payload[5] = (byte) 0xFF;
|
||||
payload[6] = (byte) 0x00;
|
||||
payload[7] = (byte) 0x00;
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case CHANNEL_EVENT:
|
||||
// Constructing channel event message from parcel
|
||||
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
|
||||
EventCode code = eventMessage.getEventCode();
|
||||
Log.d(TAG, "Event Code: " + code);
|
||||
|
||||
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch (code) {
|
||||
switch(eventMessage.getEventCode())
|
||||
{
|
||||
case TX:
|
||||
cnt += 1;
|
||||
// Use old info as this is what remote device has just received
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
|
||||
if (cnt % 61 == 15) {
|
||||
payload[0] = (byte) 0x50;
|
||||
payload[1] = (byte) 0xFF;
|
||||
payload[2] = (byte) 0xFF;
|
||||
payload[3] = (byte) 0x01;
|
||||
payload[4] = (byte) 0xFF;
|
||||
payload[5] = (byte) 0x00;
|
||||
payload[6] = (byte) 0x01;
|
||||
payload[7] = (byte) 0x00;
|
||||
} else if (cnt % 61 == 30) {
|
||||
payload[0] = (byte) 0x51;
|
||||
payload[1] = (byte) 0xFF;
|
||||
payload[2] = (byte) 0xFF;
|
||||
payload[3] = (byte) 0x01;
|
||||
payload[4] = (byte) ((POWER_SENSOR_ID) & 0xFF);
|
||||
payload[5] = (byte) ((POWER_SENSOR_ID >> 8) & 0xFF);
|
||||
payload[6] = (byte) ((POWER_SENSOR_ID >> 16) & 0xFF);
|
||||
payload[7] = (byte) ((POWER_SENSOR_ID >> 24) & 0xFF);
|
||||
} else {
|
||||
eventCount = (eventCount + 1) & 0xFF;
|
||||
cumulativePower = (cumulativePower + power) & 0xFFFF;
|
||||
payload[0] = (byte) 0x10;
|
||||
payload[1] = (byte) eventCount;
|
||||
payload[2] = (byte) 0xFF;
|
||||
payload[3] = (byte) cadence;
|
||||
payload[4] = (byte) ((cumulativePower) & 0xFF);
|
||||
payload[5] = (byte) ((cumulativePower >> 8) & 0xFF);
|
||||
payload[6] = (byte) ((power) & 0xFF);
|
||||
payload[7] = (byte) ((power >> 8) & 0xFF);
|
||||
}
|
||||
mChannelInfo.broadcastData[0]++;
|
||||
|
||||
if (mIsOpen) {
|
||||
if(mIsOpen)
|
||||
{
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
mAntChannel.setBroadcastData(mChannelInfo.broadcastData);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLLISION:
|
||||
cnt += 1;
|
||||
break;
|
||||
case RX_SEARCH_TIMEOUT:
|
||||
// TODO May want to keep searching
|
||||
Log.e(TAG, "No Device Found");
|
||||
// TODO May want to keep searching
|
||||
displayChannelError("No Device Found");
|
||||
break;
|
||||
case CHANNEL_CLOSED:
|
||||
case CHANNEL_COLLISION:
|
||||
case RX_FAIL:
|
||||
case RX_FAIL_GO_TO_SEARCH:
|
||||
case TRANSFER_RX_FAILED:
|
||||
|
@ -272,7 +208,7 @@ public class PowerChannelController {
|
|||
case TRANSFER_TX_FAILED:
|
||||
case TRANSFER_TX_START:
|
||||
case UNKNOWN:
|
||||
// TODO More complex communication will need to handle these events
|
||||
// TODO More complex communication will need to handle these events
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -284,9 +220,77 @@ public class PowerChannelController {
|
|||
case CHANNEL_STATUS:
|
||||
case SERIAL_NUMBER:
|
||||
case OTHER:
|
||||
// TODO More complex communication will need to handle these message types
|
||||
// TODO More complex communication will need to handle these message types
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelInfo getCurrentInfo()
|
||||
{
|
||||
return mChannelInfo;
|
||||
}
|
||||
|
||||
void displayChannelError(String displayText)
|
||||
{
|
||||
mChannelInfo.die(displayText);
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
}
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
|
||||
displayChannelError(logString);
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if(e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x"+ Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x"+ Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x"+ Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
|
||||
displayChannelError("ANT Command Failed");
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel)
|
||||
{
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
displayChannelError("Channel Closed");
|
||||
}
|
||||
}
|
54
app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import com.dsi.ant.message.fromant.DataMessage;
|
||||
|
||||
public class ChannelInfo
|
||||
{
|
||||
public final int deviceNumber;
|
||||
|
||||
/** Master / Slave */
|
||||
public final boolean isMaster;
|
||||
|
||||
public byte[] broadcastData = new byte[DataMessage.LENGTH_STANDARD_PAYLOAD];
|
||||
|
||||
public boolean error;
|
||||
private String mErrorMessage;
|
||||
|
||||
public ChannelInfo(int deviceNumber, boolean isMaster, int initialBroadcastValue)
|
||||
{
|
||||
this.deviceNumber = deviceNumber;
|
||||
this.isMaster = isMaster;
|
||||
|
||||
// Not actually concerned with this value, so can cast to byte and lose data without issues
|
||||
broadcastData[0] = (byte)initialBroadcastValue;
|
||||
|
||||
error = false;
|
||||
mErrorMessage = null;
|
||||
}
|
||||
|
||||
public void die(String errorMessage)
|
||||
{
|
||||
error = true;
|
||||
mErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public String getErrorString()
|
||||
{
|
||||
return mErrorMessage;
|
||||
}
|
||||
}
|
387
app/src/main/java/xyz/hoyer/iconsole/ChannelList.java
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import com.dsi.ant.channel.ChannelNotAvailableException;
|
||||
import xyz.hoyer.iconsole.ChannelService.ChannelChangedListener;
|
||||
import xyz.hoyer.iconsole.ChannelService.ChannelServiceComm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChannelList extends Activity {
|
||||
private static final String TAG = ChannelList.class.getSimpleName();
|
||||
|
||||
private final String PREF_TX_BUTTON_CHECKED_KEY = "ChannelList.TX_BUTTON_CHECKED";
|
||||
private boolean mCreateChannelAsMaster;
|
||||
|
||||
private ChannelServiceComm mChannelService;
|
||||
|
||||
private ArrayList<String> mChannelDisplayList = new ArrayList<String>();
|
||||
private ArrayAdapter<String> mChannelListAdapter;
|
||||
private SparseArray<Integer> mIdChannelListIndexMap = new SparseArray<Integer>();
|
||||
|
||||
private boolean mChannelServiceBound = false;
|
||||
|
||||
private void initButtons()
|
||||
{
|
||||
Log.v(TAG, "initButtons...");
|
||||
|
||||
//Register Master/Slave Toggle handler
|
||||
ToggleButton toggleButton_MasterSlave = (ToggleButton)findViewById(R.id.toggleButton_MasterSlave);
|
||||
toggleButton_MasterSlave.setEnabled(mChannelServiceBound);
|
||||
toggleButton_MasterSlave.setChecked(mCreateChannelAsMaster);
|
||||
toggleButton_MasterSlave.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton arg0, boolean enabled)
|
||||
{
|
||||
mCreateChannelAsMaster = enabled;
|
||||
}
|
||||
});
|
||||
|
||||
//Register Add Channel Button handler
|
||||
Button button_addChannel = (Button)findViewById(R.id.button_AddChannel);
|
||||
button_addChannel.setEnabled(mChannelServiceBound);
|
||||
button_addChannel.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
addNewChannel(mCreateChannelAsMaster);
|
||||
}
|
||||
});
|
||||
|
||||
//Register Clear Channels Button handler
|
||||
Button button_clearChannels = (Button)findViewById(R.id.button_ClearChannels);
|
||||
button_clearChannels.setEnabled(mChannelServiceBound);
|
||||
button_clearChannels.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
clearAllChannels();
|
||||
}
|
||||
});
|
||||
|
||||
Log.v(TAG, "...initButtons");
|
||||
}
|
||||
|
||||
private void initPrefs()
|
||||
{
|
||||
Log.v(TAG, "initPrefs...");
|
||||
|
||||
// Retrieves the app's current state of channel transmission mode
|
||||
// from preferences to handle app resuming.
|
||||
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
|
||||
|
||||
mCreateChannelAsMaster = preferences.getBoolean(PREF_TX_BUTTON_CHECKED_KEY, true);
|
||||
|
||||
Log.v(TAG, "...initPrefs");
|
||||
}
|
||||
|
||||
private void savePrefs()
|
||||
{
|
||||
Log.v(TAG, "savePrefs...");
|
||||
|
||||
// Saves the app's current state of channel transmission mode to preferences
|
||||
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
|
||||
editor.putBoolean(PREF_TX_BUTTON_CHECKED_KEY, mCreateChannelAsMaster);
|
||||
|
||||
editor.commit();
|
||||
|
||||
Log.v(TAG, "...savePrefs");
|
||||
}
|
||||
|
||||
private void doBindChannelService()
|
||||
{
|
||||
Log.v(TAG, "doBindChannelService...");
|
||||
|
||||
// Binds to ChannelService. ChannelService binds and manages connection between the
|
||||
// app and the ANT Radio Service
|
||||
Intent bindIntent = new Intent(this, ChannelService.class);
|
||||
startService(bindIntent);
|
||||
mChannelServiceBound = bindService(bindIntent, mChannelServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
if(!mChannelServiceBound) //If the bind returns false, run the unbind method to update the GUI
|
||||
doUnbindChannelService();
|
||||
|
||||
Log.i(TAG, " Channel Service binding = "+ mChannelServiceBound);
|
||||
|
||||
Log.v(TAG, "...doBindChannelService");
|
||||
}
|
||||
|
||||
private void doUnbindChannelService()
|
||||
{
|
||||
Log.v(TAG, "doUnbindChannelService...");
|
||||
|
||||
if(mChannelServiceBound)
|
||||
{
|
||||
unbindService(mChannelServiceConnection);
|
||||
|
||||
mChannelServiceBound = false;
|
||||
}
|
||||
|
||||
((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
|
||||
|
||||
Log.v(TAG, "...doUnbindChannelService");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.v(TAG, "onCreate...");
|
||||
|
||||
mChannelServiceBound = false;
|
||||
|
||||
setContentView(R.layout.activity_fullscreen);
|
||||
|
||||
initPrefs();
|
||||
|
||||
mChannelListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, mChannelDisplayList);
|
||||
ListView listView_channelList = (ListView)findViewById(R.id.listView_channelList);
|
||||
listView_channelList.setAdapter(mChannelListAdapter);
|
||||
|
||||
if(!mChannelServiceBound) doBindChannelService();
|
||||
|
||||
initButtons();
|
||||
|
||||
Log.v(TAG, "...onCreate");
|
||||
}
|
||||
|
||||
public void onBack() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
Log.v(TAG, "onDestroy...");
|
||||
|
||||
doUnbindChannelService();
|
||||
|
||||
if(isFinishing())
|
||||
{
|
||||
stopService(new Intent(this, ChannelService.class));
|
||||
}
|
||||
|
||||
mChannelServiceConnection = null;
|
||||
|
||||
savePrefs();
|
||||
|
||||
Log.v(TAG, "...onDestroy");
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private ServiceConnection mChannelServiceConnection = new ServiceConnection()
|
||||
{
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder serviceBinder)
|
||||
{
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceConnected...");
|
||||
|
||||
mChannelService = (ChannelServiceComm) serviceBinder;
|
||||
|
||||
// Sets a listener that handles channel events
|
||||
mChannelService.setOnChannelChangedListener(new ChannelChangedListener()
|
||||
{
|
||||
// Occurs when a channel has new info/data
|
||||
@Override
|
||||
public void onChannelChanged(final ChannelInfo newInfo)
|
||||
{
|
||||
Integer index = mIdChannelListIndexMap.get(newInfo.deviceNumber);
|
||||
|
||||
if(null != index && index.intValue() < mChannelDisplayList.size())
|
||||
{
|
||||
mChannelDisplayList.set(index.intValue(), getDisplayText(newInfo));
|
||||
runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the UI to allow/disallow acquiring new channels
|
||||
@Override
|
||||
public void onAllowAddChannel(boolean addChannelAllowed) {
|
||||
// Enable Add Channel button and Master/Slave toggle if
|
||||
// adding channels is allowed
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(addChannelAllowed);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(addChannelAllowed);
|
||||
}
|
||||
});
|
||||
|
||||
// Initial check when connecting to ChannelService if adding channels is allowed
|
||||
boolean allowAcquireChannel = mChannelService.isAddChannelAllowed();
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(allowAcquireChannel);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(allowAcquireChannel);
|
||||
|
||||
refreshList();
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceConnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0)
|
||||
{
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceDisconnected...");
|
||||
|
||||
// Clearing and disabling when disconnecting from ChannelService
|
||||
mChannelService = null;
|
||||
|
||||
((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceDisconnected");
|
||||
}
|
||||
};
|
||||
|
||||
// This method is called when 'Add Channel' button is clicked
|
||||
private void addNewChannel(final boolean isMaster)
|
||||
{
|
||||
Log.v(TAG, "addNewChannel...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
ChannelInfo newChannelInfo;
|
||||
try
|
||||
{
|
||||
// Telling the ChannelService to add a new channel. This method
|
||||
// in ChannelService contains code required to acquire an ANT
|
||||
// channel from ANT Radio Service.
|
||||
newChannelInfo = mChannelService.addNewChannel(isMaster);
|
||||
} catch (ChannelNotAvailableException e)
|
||||
{
|
||||
// Occurs when a channel is not available. Printing out the
|
||||
// stack trace will show why no channels are available.
|
||||
Toast.makeText(this, "Channel Not Available", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if(null != newChannelInfo)
|
||||
{
|
||||
// Adding new channel info to the list
|
||||
addChannelToList(newChannelInfo);
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "...addNewChannel");
|
||||
}
|
||||
|
||||
private void refreshList()
|
||||
{
|
||||
Log.v(TAG, "refreshList...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
ArrayList<ChannelInfo> chInfoList = mChannelService.getCurrentChannelInfoForAllChannels();
|
||||
|
||||
mChannelDisplayList.clear();
|
||||
for(ChannelInfo i: chInfoList)
|
||||
{
|
||||
addChannelToList(i);
|
||||
}
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
Log.v(TAG, "...refreshList");
|
||||
}
|
||||
|
||||
private void addChannelToList(ChannelInfo channelInfo)
|
||||
{
|
||||
Log.v(TAG, "addChannelToList...");
|
||||
|
||||
mIdChannelListIndexMap.put(channelInfo.deviceNumber, mChannelDisplayList.size());
|
||||
mChannelDisplayList.add(getDisplayText(channelInfo));
|
||||
|
||||
Log.v(TAG, "...addChannelToList");
|
||||
}
|
||||
|
||||
|
||||
private static String getDisplayText(ChannelInfo channelInfo)
|
||||
{
|
||||
Log.v(TAG, "getDisplayText...");
|
||||
String displayText = null;
|
||||
|
||||
if(channelInfo.error)
|
||||
{
|
||||
displayText = String.format("#%-6d !:%s", channelInfo.deviceNumber, channelInfo.getErrorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(channelInfo.isMaster)
|
||||
{
|
||||
displayText = String.format("#%-6d Tx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
displayText = String.format("#%-6d Rx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "...getDisplayText");
|
||||
|
||||
return displayText;
|
||||
}
|
||||
|
||||
|
||||
private void clearAllChannels()
|
||||
{
|
||||
Log.v(TAG, "clearAllChannels...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
// Telling ChannelService to close all the channels
|
||||
mChannelService.clearAllChannels();
|
||||
|
||||
mChannelDisplayList.clear();
|
||||
mIdChannelListIndexMap.clear();
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
Log.v(TAG, "...clearAllChannels");
|
||||
}
|
||||
}
|
|
@ -13,7 +13,9 @@
|
|||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.surfsite.iconsole;
|
||||
package xyz.hoyer.iconsole;
|
||||
|
||||
import xyz.hoyer.iconsole.ChannelController.ChannelBroadcastListener;
|
||||
|
||||
import com.dsi.ant.AntService;
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
|
@ -36,22 +38,31 @@ import android.util.SparseArray;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChannelService extends Service {
|
||||
public class ChannelService extends Service
|
||||
{
|
||||
private static final String TAG = "ChannelService";
|
||||
|
||||
|
||||
private Object mCreateChannel_LOCK = new Object();
|
||||
|
||||
SparseArray<ChannelController> mChannelControllerList = new SparseArray<ChannelController>();
|
||||
|
||||
ChannelChangedListener mListener;
|
||||
|
||||
int channelDeviceIdCounter = 0;
|
||||
|
||||
private boolean mAntRadioServiceBound;
|
||||
private AntService mAntRadioService = null;
|
||||
private AntChannelProvider mAntChannelProvider = null;
|
||||
private boolean mAllowAddChannel = false;
|
||||
PowerChannelController powerChannelController = null;
|
||||
SpeedChannelController speedChannelController = null;
|
||||
|
||||
private ServiceConnection mAntRadioServiceConnection = new ServiceConnection() {
|
||||
private ServiceConnection mAntRadioServiceConnection = new ServiceConnection()
|
||||
{
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
public void onServiceConnected(ComponentName name, IBinder service)
|
||||
{
|
||||
// Must pass in the received IBinder object to correctly construct an AntService object
|
||||
mAntRadioService = new AntService(service);
|
||||
|
||||
|
||||
try {
|
||||
// Getting a channel provider in order to acquire channels
|
||||
mAntChannelProvider = mAntRadioService.getChannelProvider();
|
||||
|
@ -62,83 +73,142 @@ public class ChannelService extends Service {
|
|||
// legacy interface is in use, applications can free the ANT
|
||||
// radio by attempting to acquire a channel.
|
||||
boolean legacyInterfaceInUse = mAntChannelProvider.isLegacyInterfaceInUse();
|
||||
|
||||
|
||||
// If there are channels OR legacy interface in use, allow adding channels
|
||||
if (mChannelAvailable || legacyInterfaceInUse) {
|
||||
if(mChannelAvailable || legacyInterfaceInUse) {
|
||||
mAllowAddChannel = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// If no channels available AND legacy interface is not in use, disallow adding channels
|
||||
mAllowAddChannel = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(mAllowAddChannel) {
|
||||
if(null != mListener) {
|
||||
// Send an event that indicates if adding channels is allowed
|
||||
mListener.onAllowAddChannel(mAllowAddChannel);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RemoteException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
public void onServiceDisconnected(ComponentName name)
|
||||
{
|
||||
die("Binder Died");
|
||||
|
||||
|
||||
mAntChannelProvider = null;
|
||||
mAntRadioService = null;
|
||||
|
||||
|
||||
if(mAllowAddChannel) { mListener.onAllowAddChannel(false); }
|
||||
mAllowAddChannel = false;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
public interface ChannelChangedListener
|
||||
{
|
||||
/**
|
||||
* Occurs when a Channel's Info has changed (i.e. a newly created
|
||||
* channel, channel has transmitted or received data, or if channel has
|
||||
* been closed.
|
||||
*
|
||||
* @param newInfo The channel's updated info
|
||||
*/
|
||||
void onChannelChanged(ChannelInfo newInfo);
|
||||
|
||||
/**
|
||||
* Occurs when there is adding a channel is being allowed or disallowed.
|
||||
*
|
||||
* @param addChannelAllowed True if adding channels is allowed. False, otherwise.
|
||||
*/
|
||||
void onAllowAddChannel(boolean addChannelAllowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface used to communicate with the ChannelService
|
||||
*/
|
||||
public class ChannelServiceComm extends Binder {
|
||||
|
||||
void setSpeed(double speed) {
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.speed = speed;
|
||||
}
|
||||
public class ChannelServiceComm extends Binder
|
||||
{
|
||||
/**
|
||||
* Sets the listener to be used for channel changed event callbacks.
|
||||
*
|
||||
* @param listener The listener that will receive events
|
||||
*/
|
||||
void setOnChannelChangedListener(ChannelChangedListener listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
void setPower(int power) {
|
||||
if (null != powerChannelController) {
|
||||
powerChannelController.power = power;
|
||||
|
||||
/**
|
||||
* Retrieves the current info for all channels currently added.
|
||||
*
|
||||
* @return A list that contains info for all the channels
|
||||
*/
|
||||
ArrayList<ChannelInfo> getCurrentChannelInfoForAllChannels()
|
||||
{
|
||||
ArrayList<ChannelInfo> retList = new ArrayList<ChannelInfo>();
|
||||
for(int i = 0; i < mChannelControllerList.size(); i++)
|
||||
{
|
||||
ChannelController channel = mChannelControllerList.valueAt(i);
|
||||
|
||||
retList.add(channel.getCurrentInfo());
|
||||
}
|
||||
|
||||
return retList;
|
||||
}
|
||||
|
||||
void setCadence(int cadence) {
|
||||
if (null != powerChannelController) {
|
||||
powerChannelController.cadence = cadence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires and adds a channel from ANT Radio Service
|
||||
*
|
||||
* @param isMaster True if channel is transmitting, False if channel is receiving
|
||||
* @return The info for the newly acquired and added channel
|
||||
* @throws ChannelNotAvailableException
|
||||
*/
|
||||
ChannelInfo addNewChannel(final boolean isMaster) throws ChannelNotAvailableException
|
||||
{
|
||||
return createNewChannel(isMaster);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes all channels currently added.
|
||||
*/
|
||||
void clearAllChannels() {
|
||||
closeAllChannels();
|
||||
void clearAllChannels() { closeAllChannels(); }
|
||||
|
||||
/**
|
||||
* Queries if adding a channel is allowed.
|
||||
* @return True if adding a channel is allowed. False, otherwise.
|
||||
*/
|
||||
boolean isAddChannelAllowed() { return mAllowAddChannel; }
|
||||
}
|
||||
|
||||
private void closeAllChannels()
|
||||
{
|
||||
synchronized (mChannelControllerList)
|
||||
{
|
||||
// Closing all channels in the list
|
||||
for(int i = 0; i < mChannelControllerList.size(); i++)
|
||||
{
|
||||
mChannelControllerList.valueAt(i).close();
|
||||
}
|
||||
mChannelControllerList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void openAllChannels() throws ChannelNotAvailableException {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
|
||||
// Reset the device id counter
|
||||
channelDeviceIdCounter = 0;
|
||||
}
|
||||
|
||||
private void closeAllChannels() {
|
||||
if (powerChannelController != null)
|
||||
powerChannelController.close();
|
||||
if (speedChannelController != null)
|
||||
speedChannelController.close();
|
||||
powerChannelController = null;
|
||||
speedChannelController = null;
|
||||
}
|
||||
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException {
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException
|
||||
{
|
||||
AntChannel mAntChannel = null;
|
||||
if (null != mAntChannelProvider) {
|
||||
try {
|
||||
if(null != mAntChannelProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
* If applications require a channel with specific capabilities
|
||||
* (event buffering, background scanning etc.), a Capabilities
|
||||
|
@ -155,81 +225,124 @@ public class ChannelService extends Service {
|
|||
Log.v(TAG, mNK.toString());
|
||||
mAntChannel = mAntChannelProvider.acquireChannelOnPrivateNetwork(this, mNK);
|
||||
*/
|
||||
} catch (RemoteException e) {
|
||||
} catch (RemoteException e)
|
||||
{
|
||||
die("ACP Remote Ex");
|
||||
}
|
||||
}
|
||||
}
|
||||
return mAntChannel;
|
||||
}
|
||||
|
||||
public ChannelInfo createNewChannel(final boolean isMaster) throws ChannelNotAvailableException
|
||||
{
|
||||
ChannelController channelController = null;
|
||||
|
||||
synchronized(mCreateChannel_LOCK)
|
||||
{
|
||||
// Acquiring a channel from ANT Radio Service
|
||||
AntChannel antChannel = acquireChannel();
|
||||
|
||||
if(null != antChannel)
|
||||
{
|
||||
|
||||
channelDeviceIdCounter += 1;
|
||||
|
||||
// Constructing a controller that will manage and control the channel
|
||||
channelController = new ChannelController(antChannel, isMaster, channelDeviceIdCounter,
|
||||
new ChannelBroadcastListener()
|
||||
{
|
||||
@Override
|
||||
public void onBroadcastChanged(ChannelInfo newInfo)
|
||||
{
|
||||
// Sending a channel changed event when message from ANT is received
|
||||
mListener.onChannelChanged(newInfo);
|
||||
}
|
||||
});
|
||||
|
||||
mChannelControllerList.put(channelDeviceIdCounter, channelController);
|
||||
}
|
||||
}
|
||||
|
||||
if(null == channelController) return null;
|
||||
|
||||
return channelController.getCurrentInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
public IBinder onBind(Intent arg0)
|
||||
{
|
||||
return new ChannelServiceComm();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receives AntChannelProvider state changes being sent from ANT Radio Service
|
||||
*/
|
||||
private final BroadcastReceiver mChannelProviderStateChangedReceiver = new BroadcastReceiver() {
|
||||
private final BroadcastReceiver mChannelProviderStateChangedReceiver = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED.equals(intent.getAction())) {
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
if(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED.equals(intent.getAction())) {
|
||||
boolean update = false;
|
||||
// Retrieving the data contained in the intent
|
||||
int numChannels = intent.getIntExtra(AntChannelProvider.NUM_CHANNELS_AVAILABLE, 0);
|
||||
boolean legacyInterfaceInUse = intent.getBooleanExtra(AntChannelProvider.LEGACY_INTERFACE_IN_USE, false);
|
||||
|
||||
if (mAllowAddChannel) {
|
||||
|
||||
if(mAllowAddChannel) {
|
||||
// Was a acquire channel allowed
|
||||
// If no channels available AND legacy interface is not in use, disallow acquiring of channels
|
||||
if (0 == numChannels && !legacyInterfaceInUse) {
|
||||
if(0 == numChannels && !legacyInterfaceInUse) {
|
||||
mAllowAddChannel = false;
|
||||
update = true;
|
||||
closeAllChannels();
|
||||
}
|
||||
} else {
|
||||
// Acquire channels not allowed
|
||||
// If there are channels OR legacy interface in use, allow acquiring of channels
|
||||
if (numChannels > 0 || legacyInterfaceInUse) {
|
||||
if(numChannels > 0 || legacyInterfaceInUse) {
|
||||
mAllowAddChannel = true;
|
||||
update = true;
|
||||
try {
|
||||
openAllChannels();
|
||||
} catch (ChannelNotAvailableException exception) {
|
||||
Log.e(TAG, "Channel not available!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(update && (null != mListener)) {
|
||||
// AllowAddChannel has been changed, sending event callback
|
||||
mListener.onAllowAddChannel(mAllowAddChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void doBindAntRadioService() {
|
||||
if (BuildConfig.DEBUG) Log.v(TAG, "doBindAntRadioService");
|
||||
|
||||
|
||||
private void doBindAntRadioService()
|
||||
{
|
||||
if(BuildConfig.DEBUG) Log.v(TAG, "doBindAntRadioService");
|
||||
|
||||
// Start listing for channel available intents
|
||||
registerReceiver(mChannelProviderStateChangedReceiver, new IntentFilter(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED));
|
||||
|
||||
|
||||
// Creating the intent and calling context.bindService() is handled by
|
||||
// the static bindService() method in AntService
|
||||
mAntRadioServiceBound = AntService.bindService(this, mAntRadioServiceConnection);
|
||||
}
|
||||
|
||||
private void doUnbindAntRadioService() {
|
||||
if (BuildConfig.DEBUG) Log.v(TAG, "doUnbindAntRadioService");
|
||||
|
||||
|
||||
private void doUnbindAntRadioService()
|
||||
{
|
||||
if(BuildConfig.DEBUG) Log.v(TAG, "doUnbindAntRadioService");
|
||||
|
||||
// Stop listing for channel available intents
|
||||
try {
|
||||
try{
|
||||
unregisterReceiver(mChannelProviderStateChangedReceiver);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, "Attempting to unregister a never registered Channel Provider State Changed receiver.");
|
||||
if(BuildConfig.DEBUG) Log.d(TAG, "Attempting to unregister a never registered Channel Provider State Changed receiver.");
|
||||
}
|
||||
|
||||
if (mAntRadioServiceBound) {
|
||||
try {
|
||||
|
||||
if(mAntRadioServiceBound)
|
||||
{
|
||||
try
|
||||
{
|
||||
unbindService(mAntRadioServiceConnection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
catch(IllegalArgumentException e)
|
||||
{
|
||||
// Not bound, that's what we want anyway
|
||||
}
|
||||
|
||||
|
@ -238,27 +351,29 @@ public class ChannelService extends Service {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
|
||||
|
||||
mAntRadioServiceBound = false;
|
||||
|
||||
|
||||
doBindAntRadioService();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
public void onDestroy()
|
||||
{
|
||||
closeAllChannels();
|
||||
|
||||
doUnbindAntRadioService();
|
||||
mAntChannelProvider = null;
|
||||
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
static void die(String error) {
|
||||
Log.e(TAG, "DIE: " + error);
|
||||
static void die(String error)
|
||||
{
|
||||
Log.e(TAG, "DIE: "+ error);
|
||||
}
|
||||
|
||||
|
||||
}
|
77
app/src/main/res/layout/activity_fullscreen.xml
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2012 Dynastream Innovations Inc.
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ToggleButton
|
||||
android:id="@+id/toggleButton_MasterSlave"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_margin="5dp"
|
||||
android:textOn="Tx"
|
||||
android:textOff="Rx"
|
||||
android:text="Toggle Master/Slave" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_AddChannel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Open New Channel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_ClearChannels"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Clear Channels" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="3dp"
|
||||
android:background="@android:color/darker_gray"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Open Channels: (dev#, [data])" />
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray"/>
|
||||
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listView_channelList"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
</ListView>
|
||||
|
||||
|
||||
</LinearLayout>
|
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 10 KiB |
12
app/src/main/res/values/attrs.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<resources>
|
||||
|
||||
<!-- Declare custom theme attributes that allow changing which styles are
|
||||
used for button bars depending on the API level.
|
||||
?android:attr/buttonBarStyle is new as of API 11 so this is
|
||||
necessary to support previous API levels. -->
|
||||
<declare-styleable name="ButtonBarContainerTheme">
|
||||
<attr name="metaButtonBarStyle" format="reference" />
|
||||
<attr name="metaButtonBarButtonStyle" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
8
app/src/main/res/values/colors.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="black_overlay">#66000000</color>
|
||||
</resources>
|
6
app/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<resources>
|
||||
<string name="app_name">iconsole</string>
|
||||
|
||||
<string name="dummy_button">Dummy Button</string>
|
||||
<string name="dummy_content">Buh!</string>
|
||||
</resources>
|
23
app/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="FullscreenTheme" parent="AppTheme">
|
||||
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
|
||||
<item name="android:windowActionBarOverlay">true</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="metaButtonBarStyle">?android:attr/buttonBarStyle</item>
|
||||
<item name="metaButtonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar">
|
||||
<item name="android:background">@color/black_overlay</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
17
app/src/test/java/xyz/hoyer/iconsole/ExampleUnitTest.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package xyz.hoyer.iconsole;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
17
gradle.properties
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Mon Apr 12 12:52:47 CEST 2021
|
||||
#Fri Jul 06 14:40:55 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
|
|
10
gradlew
vendored
|
@ -42,11 +42,6 @@ case "`uname`" in
|
|||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
|
@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
|
|||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
@ -114,6 +109,7 @@ fi
|
|||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="iconsole-android" 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">
|
||||
<module external.linked.project.id="iconsole-android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
|
@ -8,10 +8,10 @@
|
|||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
|
|
@ -1 +1 @@
|
|||
include 'Application', ':android_antlib_4-14'
|
||||
include ':app', ':android_antlib_4-14-0'
|
||||
|
|