mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-20 07:24:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8c4df4897 | ||
|
|
5ee16124bc | ||
|
|
8702ac72f0 | ||
|
|
004552ec30 | ||
|
|
2f28400234 | ||
|
|
78d213d686 | ||
|
|
1a71dda243 | ||
|
|
21822f259c | ||
|
|
4f79607015 | ||
|
|
d8576d4c50 | ||
|
|
2f4042da8f | ||
|
|
c1397e331b | ||
|
|
cd182b3265 | ||
|
|
28f2d7b84a | ||
|
|
e8de7908fd | ||
|
|
419c4c5592 | ||
|
|
a9a8346f58 | ||
|
|
7e1b3f861f | ||
|
|
f4204e1268 | ||
|
|
60f35cd0aa | ||
|
|
bbcdaa94a1 | ||
|
|
8f6e8c00ef | ||
|
|
24cb347b10 | ||
|
|
d1b4e9464f | ||
|
|
18f7bfab7f | ||
|
|
d84b4bcf9a | ||
|
|
57d919798a | ||
|
|
efeeebb0a2 | ||
|
|
bc1409ba6c | ||
|
|
6f05b2af8a | ||
|
|
d441bef33e | ||
|
|
562569dc6b | ||
|
|
a18aa51f5a | ||
|
|
8efe194682 | ||
|
|
f07e927103 | ||
|
|
a50211ab95 | ||
|
|
247a19766c | ||
|
|
731e4dc31e | ||
|
|
cd4bf9a28b | ||
|
|
196c0e6cbc | ||
|
|
e2cb7c953c | ||
|
|
426b3c8522 | ||
|
|
9648cf257f | ||
|
|
31d8687f67 | ||
|
|
991407a2cf | ||
|
|
1b026f1354 | ||
|
|
9d4ca6293f | ||
|
|
2296b80edb | ||
|
|
5577d48dcf | ||
|
|
e92a281fd8 | ||
|
|
b4c3f9678a | ||
|
|
82f79c466a | ||
|
|
d428f316b4 | ||
|
|
828f4877b6 | ||
|
|
09e8e8e6b3 | ||
|
|
77c8051ec6 | ||
|
|
6bae056e3a | ||
|
|
bb869a51fd | ||
|
|
25b3d08bb9 |
No files matched your search
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry kind="src" path="src"/>
|
|
||||||
<classpathentry kind="src" path="gen"/>
|
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
|
||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
|
||||||
</classpath>
|
|
||||||
+35
-1
@@ -1 +1,35 @@
|
|||||||
/bin/*
|
#built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
|
||||||
|
# files for the dex VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Windows thumbnail db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# OSX files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Eclipse project files
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
|
||||||
|
# Android Studio
|
||||||
|
.idea
|
||||||
|
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Compiled JNI libraries folder
|
||||||
|
**/jniLibs
|
||||||
Whitespace-only changes.
@@ -1,2 +0,0 @@
|
|||||||
*** SESSION Sep 21, 2013 18:55:11.17 -------------------------------------------
|
|
||||||
*** SESSION Sep 21, 2013 18:55:55.08 -------------------------------------------
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
-3
@@ -1,3 +0,0 @@
|
|||||||
com.android.ide.eclipse.adt.fixLegacyEditors=1
|
|
||||||
com.android.ide.eclipse.adt.sdk=C\:\\Users\\Andrew\\Desktop\\ADT\\adt-bundle-windows-x86_64-20130917\\sdk
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
spelling_locale_initialized=true
|
|
||||||
useAnnotationsPrefPage=true
|
|
||||||
useQuickDiffPrefPage=true
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
version=1
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
content_assist_proposals_background=255,255,255
|
|
||||||
content_assist_proposals_foreground=0,0,0
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
fontPropagated=true
|
|
||||||
org.eclipse.jdt.ui.editor.tab.width=
|
|
||||||
org.eclipse.jdt.ui.formatterprofiles.version=12
|
|
||||||
org.eclipse.jdt.ui.javadoclocations.migrated=true
|
|
||||||
org.eclipse.jface.textfont=1|Courier New|10.0|0|WINDOWS|1|0|0|0|0|0|0|0|0|1|0|0|0|0|Courier New;
|
|
||||||
proposalOrderMigrated=true
|
|
||||||
spelling_locale_initialized=true
|
|
||||||
tabWidthPropagated=true
|
|
||||||
useAnnotationsPrefPage=true
|
|
||||||
useQuickDiffPrefPage=true
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
PROBLEMS_FILTERS_MIGRATE=true
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
platformState=1379804095671
|
|
||||||
quickStart=false
|
|
||||||
tipsAndTricks=true
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
showIntro=false
|
|
||||||
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<typeInfoHistroy/>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<qualifiedTypeNameHistroy/>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<section name="Workbench">
|
|
||||||
<section name="org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart">
|
|
||||||
<item value="true" key="group_libraries"/>
|
|
||||||
<item value="false" key="linkWithEditor"/>
|
|
||||||
<item value="2" key="layout"/>
|
|
||||||
<item value="1" key="rootMode"/>
|
|
||||||
<item value="<?xml version="1.0" encoding="UTF-8"?>
<packageExplorer group_libraries="1" layout="2" linkWithEditor="0" rootMode="1" workingSetName="">
<customFilters userDefinedPatternsEnabled="false">
<xmlDefinedFilters>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.LibraryFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.LocalTypesFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.StaticsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ClosedProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonSharedProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonJavaElementFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ContainedLibraryFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.CuAndClassFileFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonJavaProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.EmptyInnerPackageFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.PackageDeclarationFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.EmptyPackageFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ImportDeclarationFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.FieldsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.HideInnerClassFilesFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonPublicFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer_patternFilterId_.*" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.EmptyLibraryContainerFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.SyntheticMembersFilter" isEnabled="true"/>
</xmlDefinedFilters>
</customFilters>
</packageExplorer>" key="memento"/>
|
|
||||||
</section>
|
|
||||||
<section name="JavaElementSearchActions">
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<section name="Workbench">
|
|
||||||
<section name="ChooseWorkspaceDialogSettings">
|
|
||||||
<item value="185" key="DIALOG_Y_ORIGIN"/>
|
|
||||||
<item value="381" key="DIALOG_X_ORIGIN"/>
|
|
||||||
</section>
|
|
||||||
<section name="WORKBENCH_SETTINGS">
|
|
||||||
<list key="ENABLED_TRANSFERS">
|
|
||||||
</list>
|
|
||||||
</section>
|
|
||||||
<section name="ExternalProjectImportWizard">
|
|
||||||
<item value="false" key="WizardProjectsImportPage.STORE_ARCHIVE_SELECTED"/>
|
|
||||||
<item value="false" key="WizardProjectsImportPage.STORE_COPY_PROJECT_ID"/>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<section name="Workbench">
|
|
||||||
<section name="org.eclipse.ui.internal.QuickAccess">
|
|
||||||
<item value="1025" key="dialogWidth"/>
|
|
||||||
<item value="525" key="dialogHeight"/>
|
|
||||||
<list key="orderedProviders">
|
|
||||||
</list>
|
|
||||||
<list key="textArray">
|
|
||||||
</list>
|
|
||||||
<list key="orderedElements">
|
|
||||||
</list>
|
|
||||||
<list key="textEntries">
|
|
||||||
</list>
|
|
||||||
</section>
|
|
||||||
<section name="ImportExportAction">
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<workingSetManager>
|
|
||||||
<workingSet aggregate="true" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1379804109849_0" label="Window Working Set" name="Aggregate for window 1379804109848"/>
|
|
||||||
<workingSet aggregate="true" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1379804153983_1" label="Window Working Set" name="Aggregate for window 1379804153983"/>
|
|
||||||
</workingSetManager>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
org.eclipse.core.runtime=1
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>Limelight</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
|
||||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
|
||||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
|
||||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#Limelight
|
#Limelight
|
||||||
|
|
||||||
Limelight is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
|
Limelight is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
|
||||||
We reverse engineered the Shield streaming software, and created a version that can be run on any Android device.
|
We reverse engineered the Shield streaming software and created a version that can be run on any Android device.
|
||||||
|
|
||||||
Limelight will allow you to stream your full collection of games from your Windows PC to your Android device,
|
Limelight will allow you to stream your full collection of games from your Windows PC to your Android device,
|
||||||
in your own home, or over the internet.
|
whether in your own home or over the internet.
|
||||||
|
|
||||||
[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows Phone](https://github.com/limelight-stream/limelight-wp) are also in development.
|
[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) are also in development.
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
|
|
||||||
@@ -14,9 +14,6 @@ in your own home, or over the internet.
|
|||||||
* Full gamepad support for MOGA, Xbox 360, PS3, OUYA, and Shield
|
* Full gamepad support for MOGA, Xbox 360, PS3, OUYA, and Shield
|
||||||
* Automatically finds GameStream-compatible PCs on your network
|
* Automatically finds GameStream-compatible PCs on your network
|
||||||
|
|
||||||
##Features in development
|
|
||||||
* Keyboard input
|
|
||||||
|
|
||||||
##Installation
|
##Installation
|
||||||
|
|
||||||
* Download and install Limelight for Android from
|
* Download and install Limelight for Android from
|
||||||
@@ -28,7 +25,6 @@ in your own home, or over the internet.
|
|||||||
* [GameStream compatible](http://shield.nvidia.com/play-pc-games/) computer with GTX 600/700 series GPU
|
* [GameStream compatible](http://shield.nvidia.com/play-pc-games/) computer with GTX 600/700 series GPU
|
||||||
* Android device running 4.1 (Jelly Bean) or higher
|
* Android device running 4.1 (Jelly Bean) or higher
|
||||||
* High-end wireless router (802.11n dual-band recommended)
|
* High-end wireless router (802.11n dual-band recommended)
|
||||||
* Exynos/Snapdragon SoC __OR__ Quad-Core 1.4 GHz Cortex-A9 or higher (Tegra 3)
|
|
||||||
|
|
||||||
##Usage
|
##Usage
|
||||||
|
|
||||||
|
|||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="limelight-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=":app" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
<facet type="android" name="Android">
|
||||||
|
<configuration>
|
||||||
|
<option name="SELECTED_BUILD_VARIANT" value="nonRootDebug" />
|
||||||
|
<option name="ASSEMBLE_TASK_NAME" value="assembleNonRootDebug" />
|
||||||
|
<option name="COMPILE_JAVA_TASK_NAME" value="compileNonRootDebugSources" />
|
||||||
|
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleNonRootDebugTest" />
|
||||||
|
<option name="SOURCE_GEN_TASK_NAME" value="generateNonRootDebugSources" />
|
||||||
|
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateNonRootDebugTestSources" />
|
||||||
|
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||||
|
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||||
|
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||||
|
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||||
|
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||||
|
<output url="file://$MODULE_DIR$/build/intermediates/classes/nonRoot/debug" />
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/nonRoot/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/nonRoot/debug" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/res" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/assets" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/aidl" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/jni" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRootDebug/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/nonRoot/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/nonRoot/debug" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/res" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/assets" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/aidl" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/jni" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/res" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/resources" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/assets" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/aidl" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/java" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/jni" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/rs" isTestSource="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/jni" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" exported="" name="bcprov-jdk15on-1.51" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="jmdns-fixed" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="jcodec-0.1.6-3" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="bcpkix-jdk15on-1.51" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="tinyrtsp" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="limelight-common" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import com.android.builder.model.ProductFlavor
|
||||||
|
import org.apache.tools.ant.taskdefs.condition.Os
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 21
|
||||||
|
buildToolsVersion "21.0.2"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 16
|
||||||
|
targetSdkVersion 21
|
||||||
|
|
||||||
|
versionName "2.9"
|
||||||
|
versionCode = 38
|
||||||
|
}
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
root {
|
||||||
|
applicationId "com.limelight.root"
|
||||||
|
}
|
||||||
|
|
||||||
|
nonRoot {
|
||||||
|
applicationId "com.limelight"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
runProguard false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.jni.srcDirs = []
|
||||||
|
|
||||||
|
//noinspection GroovyAssignabilityCheck,GroovyAssignabilityCheck
|
||||||
|
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
|
||||||
|
Properties properties = new Properties()
|
||||||
|
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||||
|
def ndkDir = properties.getProperty('ndk.dir')
|
||||||
|
|
||||||
|
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
|
commandLine "$ndkDir\\ndk-build.cmd",
|
||||||
|
'NDK_PROJECT_PATH=build/intermediates/ndk',
|
||||||
|
'NDK_LIBS_OUT=src/main/jniLibs',
|
||||||
|
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
|
||||||
|
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
commandLine "$ndkDir/ndk-build",
|
||||||
|
'NDK_PROJECT_PATH=build/intermediates/ndk',
|
||||||
|
'NDK_LIBS_OUT=src/main/jniLibs',
|
||||||
|
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
|
||||||
|
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
compileTask -> compileTask.dependsOn ndkBuild
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile group: 'org.jcodec', name: 'jcodec', version: '0.1.6-3'
|
||||||
|
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.51'
|
||||||
|
compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.51'
|
||||||
|
compile files('libs/jmdns-fixed.jar')
|
||||||
|
compile files('libs/limelight-common.jar')
|
||||||
|
compile files('libs/tinyrtsp.jar')
|
||||||
|
}
|
||||||
File renamed without changes.
Binary file not shown.
File renamed without changes.
@@ -1,12 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.limelight"
|
package="com.limelight">
|
||||||
android:versionCode="36"
|
|
||||||
android:versionName="2.5.7" >
|
|
||||||
|
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="16"
|
|
||||||
android:targetSdkVersion="21" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
@@ -21,14 +15,12 @@
|
|||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/AppTheme" >
|
android:theme="@style/AppTheme" >
|
||||||
|
|
||||||
<!-- Launcher for traditional devices -->
|
<!-- Launcher for traditional devices -->
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.PcView"
|
android:name=".PcView"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||||
android:label="@string/app_name">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -38,11 +30,10 @@
|
|||||||
|
|
||||||
<!-- Launcher for Android TV devices -->
|
<!-- Launcher for Android TV devices -->
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.PcViewTv"
|
android:name=".PcViewTv"
|
||||||
android:logo="@drawable/atv_banner"
|
android:logo="@drawable/atv_banner"
|
||||||
android:icon="@drawable/atv_banner"
|
android:icon="@drawable/atv_banner"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||||
android:label="@string/app_name">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
@@ -50,48 +41,39 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.AppView"
|
android:name=".AppView"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
|
||||||
android:label="App List" >
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.PcView" />
|
android:value="com.limelight.PcView" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.StreamSettings"
|
android:name=".preferences.StreamSettings"
|
||||||
android:label="Streaming Settings" >
|
android:label="Streaming Settings" >
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.PcView" />
|
android:value="com.limelight.PcView" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.AdvancedSettings"
|
android:name=".preferences.AddComputerManually"
|
||||||
android:label="Advanced Settings" >
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
|
||||||
android:value="com.limelight.StreamSettings" />
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name="com.limelight.AddComputerManually"
|
|
||||||
android:label="Add Computer Manually" >
|
android:label="Add Computer Manually" >
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.PcView" />
|
android:value="com.limelight.PcView" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.limelight.Game"
|
android:name=".Game"
|
||||||
android:screenOrientation="sensorLandscape"
|
android:screenOrientation="sensorLandscape"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
|
||||||
android:theme="@style/FullscreenTheme" >
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.Connection" />
|
android:value="com.limelight.Connection" />
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
<service
|
||||||
android:name="com.limelight.discovery.DiscoveryService"
|
android:name=".discovery.DiscoveryService"
|
||||||
android:label="mDNS PC Auto-Discovery Service" />
|
android:label="mDNS PC Auto-Discovery Service" />
|
||||||
<service
|
<service
|
||||||
android:name="com.limelight.computers.ComputerManagerService"
|
android:name=".computers.ComputerManagerService"
|
||||||
android:label="Computer Management Service" />
|
android:label="Computer Management Service" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ import com.limelight.binding.PlatformBinding;
|
|||||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
import com.limelight.nvstream.http.NvHTTP;
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
|
import com.limelight.R;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
import com.limelight.utils.SpinnerDialog;
|
import com.limelight.utils.SpinnerDialog;
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ public class AppView extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||||
long id) {
|
long id) {
|
||||||
AppObject app = (AppObject) appListAdapter.getItem(pos);
|
AppObject app = appListAdapter.getItem(pos);
|
||||||
if (app == null || app.app == null) {
|
if (app == null || app.app == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -133,7 +134,7 @@ public class AppView extends Activity {
|
|||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
|
||||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
||||||
AppObject selectedApp = (AppObject) appListAdapter.getItem(info.position);
|
AppObject selectedApp = appListAdapter.getItem(info.position);
|
||||||
if (selectedApp == null || selectedApp.app == null) {
|
if (selectedApp == null || selectedApp.app == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@ public class AppView extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
||||||
AppObject app = (AppObject) appListAdapter.getItem(info.position);
|
AppObject app = appListAdapter.getItem(info.position);
|
||||||
switch (item.getItemId())
|
switch (item.getItemId())
|
||||||
{
|
{
|
||||||
case RESUME_ID:
|
case RESUME_ID:
|
||||||
@@ -220,9 +221,9 @@ public class AppView extends Activity {
|
|||||||
|
|
||||||
// Success case
|
// Success case
|
||||||
return;
|
return;
|
||||||
} catch (GfeHttpResponseException e) {
|
} catch (GfeHttpResponseException ignored) {
|
||||||
} catch (IOException e) {
|
} catch (IOException ignored) {
|
||||||
} catch (XmlPullParserException e) {
|
} catch (XmlPullParserException ignored) {
|
||||||
} finally {
|
} finally {
|
||||||
spinner.dismiss();
|
spinner.dismiss();
|
||||||
}
|
}
|
||||||
@@ -14,13 +14,13 @@ import com.limelight.nvstream.StreamConfiguration;
|
|||||||
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||||
import com.limelight.nvstream.input.KeyboardPacket;
|
import com.limelight.nvstream.input.KeyboardPacket;
|
||||||
import com.limelight.nvstream.input.MouseButtonPacket;
|
import com.limelight.nvstream.input.MouseButtonPacket;
|
||||||
|
import com.limelight.preferences.PreferenceConfiguration;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
import com.limelight.utils.SpinnerDialog;
|
import com.limelight.utils.SpinnerDialog;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -57,8 +57,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private ControllerHandler controllerHandler;
|
private ControllerHandler controllerHandler;
|
||||||
private KeyboardTranslator keybTranslator;
|
private KeyboardTranslator keybTranslator;
|
||||||
|
|
||||||
private int height;
|
private PreferenceConfiguration prefConfig;
|
||||||
private int width;
|
|
||||||
private Point screenSize = new Point(0, 0);
|
private Point screenSize = new Point(0, 0);
|
||||||
|
|
||||||
private NvConnection conn;
|
private NvConnection conn;
|
||||||
@@ -67,9 +66,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private boolean connecting = false;
|
private boolean connecting = false;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
|
||||||
private boolean stretchToFit;
|
|
||||||
private boolean toastsDisabled;
|
|
||||||
|
|
||||||
private EvdevWatcher evdevWatcher;
|
private EvdevWatcher evdevWatcher;
|
||||||
private int modifierFlags = 0;
|
private int modifierFlags = 0;
|
||||||
private boolean grabbedInput = true;
|
private boolean grabbedInput = true;
|
||||||
@@ -86,35 +82,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
public static final String EXTRA_UNIQUEID = "UniqueId";
|
public static final String EXTRA_UNIQUEID = "UniqueId";
|
||||||
public static final String EXTRA_STREAMING_REMOTE = "Remote";
|
public static final String EXTRA_STREAMING_REMOTE = "Remote";
|
||||||
|
|
||||||
public static final String PREFS_FILE_NAME = "gameprefs";
|
|
||||||
|
|
||||||
public static final String WIDTH_PREF_STRING = "ResH";
|
|
||||||
public static final String HEIGHT_PREF_STRING = "ResV";
|
|
||||||
public static final String REFRESH_RATE_PREF_STRING = "FPS";
|
|
||||||
public static final String DECODER_PREF_STRING = "Decoder";
|
|
||||||
public static final String BITRATE_PREF_STRING = "Bitrate";
|
|
||||||
public static final String STRETCH_PREF_STRING = "Stretch";
|
|
||||||
public static final String SOPS_PREF_STRING = "Sops";
|
|
||||||
public static final String DISABLE_TOASTS_PREF_STRING = "NoToasts";
|
|
||||||
|
|
||||||
public static final int BITRATE_DEFAULT_720_30 = 5;
|
|
||||||
public static final int BITRATE_DEFAULT_720_60 = 10;
|
|
||||||
public static final int BITRATE_DEFAULT_1080_30 = 10;
|
|
||||||
public static final int BITRATE_DEFAULT_1080_60 = 30;
|
|
||||||
|
|
||||||
public static final int DEFAULT_WIDTH = 1280;
|
|
||||||
public static final int DEFAULT_HEIGHT = 720;
|
|
||||||
public static final int DEFAULT_REFRESH_RATE = 60;
|
|
||||||
public static final int DEFAULT_DECODER = 0;
|
|
||||||
public static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60;
|
|
||||||
public static final boolean DEFAULT_STRETCH = false;
|
|
||||||
public static final boolean DEFAULT_SOPS = true;
|
|
||||||
public static final boolean DEFAULT_DISABLE_TOASTS = false;
|
|
||||||
|
|
||||||
public static final int FORCE_HARDWARE_DECODER = -1;
|
|
||||||
public static final int AUTOSELECT_DECODER = 0;
|
|
||||||
public static final int FORCE_SOFTWARE_DECODER = 1;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -151,32 +118,22 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
spinner = SpinnerDialog.displayDialog(this, "Establishing Connection", "Starting connection", true);
|
spinner = SpinnerDialog.displayDialog(this, "Establishing Connection", "Starting connection", true);
|
||||||
|
|
||||||
// Read the stream preferences
|
// Read the stream preferences
|
||||||
SharedPreferences prefs = getSharedPreferences(PREFS_FILE_NAME, Context.MODE_MULTI_PROCESS);
|
prefConfig = PreferenceConfiguration.readPreferences(this);
|
||||||
switch (prefs.getInt(Game.DECODER_PREF_STRING, Game.DEFAULT_DECODER)) {
|
switch (prefConfig.decoder) {
|
||||||
case Game.FORCE_SOFTWARE_DECODER:
|
case PreferenceConfiguration.FORCE_SOFTWARE_DECODER:
|
||||||
drFlags |= VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING;
|
drFlags |= VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING;
|
||||||
break;
|
break;
|
||||||
case Game.AUTOSELECT_DECODER:
|
case PreferenceConfiguration.AUTOSELECT_DECODER:
|
||||||
break;
|
break;
|
||||||
case Game.FORCE_HARDWARE_DECODER:
|
case PreferenceConfiguration.FORCE_HARDWARE_DECODER:
|
||||||
drFlags |= VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING;
|
drFlags |= VideoDecoderRenderer.FLAG_FORCE_HARDWARE_DECODING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stretchToFit = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH);
|
if (prefConfig.stretchVideo) {
|
||||||
if (stretchToFit) {
|
|
||||||
drFlags |= VideoDecoderRenderer.FLAG_FILL_SCREEN;
|
drFlags |= VideoDecoderRenderer.FLAG_FILL_SCREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
int refreshRate, bitrate;
|
|
||||||
boolean sops;
|
|
||||||
width = prefs.getInt(WIDTH_PREF_STRING, DEFAULT_WIDTH);
|
|
||||||
height = prefs.getInt(HEIGHT_PREF_STRING, DEFAULT_HEIGHT);
|
|
||||||
refreshRate = prefs.getInt(REFRESH_RATE_PREF_STRING, DEFAULT_REFRESH_RATE);
|
|
||||||
bitrate = prefs.getInt(BITRATE_PREF_STRING, DEFAULT_BITRATE);
|
|
||||||
sops = prefs.getBoolean(SOPS_PREF_STRING, DEFAULT_SOPS);
|
|
||||||
toastsDisabled = prefs.getBoolean(DISABLE_TOASTS_PREF_STRING, DEFAULT_DISABLE_TOASTS);
|
|
||||||
|
|
||||||
Display display = getWindowManager().getDefaultDisplay();
|
Display display = getWindowManager().getDefaultDisplay();
|
||||||
display.getSize(screenSize);
|
display.getSize(screenSize);
|
||||||
|
|
||||||
@@ -201,11 +158,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
decoderRenderer = new ConfigurableDecoderRenderer();
|
decoderRenderer = new ConfigurableDecoderRenderer();
|
||||||
decoderRenderer.initializeWithFlags(drFlags);
|
decoderRenderer.initializeWithFlags(drFlags);
|
||||||
|
|
||||||
StreamConfiguration config =
|
StreamConfiguration config = new StreamConfiguration.Builder()
|
||||||
new StreamConfiguration(app, width, height,
|
.setResolution(prefConfig.width, prefConfig.height)
|
||||||
refreshRate, bitrate * 1000, sops,
|
.setRefreshRate(prefConfig.fps)
|
||||||
(decoderRenderer.getCapabilities() &
|
.setApp(app)
|
||||||
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0);
|
.setBitrate(prefConfig.bitrate * 1000)
|
||||||
|
.setEnableSops(prefConfig.enableSops)
|
||||||
|
.enableAdaptiveResolution((decoderRenderer.getCapabilities() &
|
||||||
|
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0)
|
||||||
|
.enableLocalAudioPlayback(prefConfig.playHostAudio)
|
||||||
|
.build();
|
||||||
|
|
||||||
// Initialize the connection
|
// Initialize the connection
|
||||||
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
|
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
|
||||||
@@ -213,9 +175,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
controllerHandler = new ControllerHandler(conn);
|
controllerHandler = new ControllerHandler(conn);
|
||||||
|
|
||||||
SurfaceHolder sh = sv.getHolder();
|
SurfaceHolder sh = sv.getHolder();
|
||||||
if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) {
|
if (prefConfig.stretchVideo || !decoderRenderer.isHardwareAccelerated()) {
|
||||||
// Set the surface to the size of the video
|
// Set the surface to the size of the video
|
||||||
sh.setFixedSize(width, height);
|
sh.setFixedSize(prefConfig.width, prefConfig.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize touch contexts
|
// Initialize touch contexts
|
||||||
@@ -554,9 +516,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
// ACTION_MOVE is special because it always has actionIndex == 0
|
// ACTION_MOVE is special because it always has actionIndex == 0
|
||||||
// We'll call the move handlers for all indexes manually
|
// We'll call the move handlers for all indexes manually
|
||||||
for (int i = 0; i < touchContextMap.length; i++) {
|
for (TouchContext aTouchContextMap : touchContextMap) {
|
||||||
touchContextMap[i].touchMoveEvent(eventX, eventY);
|
aTouchContextMap.touchMoveEvent(eventX, eventY);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -620,21 +582,15 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
if (!handleMotionEvent(event)) {
|
return handleMotionEvent(event) || super.onTouchEvent(event);
|
||||||
return super.onTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||||
if (!handleMotionEvent(event)) {
|
return handleMotionEvent(event) || super.onGenericMotionEvent(event);
|
||||||
return super.onGenericMotionEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void updateMousePosition(int eventX, int eventY) {
|
private void updateMousePosition(int eventX, int eventY) {
|
||||||
// Send a mouse move if we already have a mouse location
|
// Send a mouse move if we already have a mouse location
|
||||||
@@ -648,8 +604,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
// Scale the deltas if the device resolution is different
|
// Scale the deltas if the device resolution is different
|
||||||
// than the stream resolution
|
// than the stream resolution
|
||||||
deltaX = (int)Math.round((double)deltaX * ((double)width / (double)screenSize.x));
|
deltaX = (int)Math.round((double)deltaX * ((double)prefConfig.width / (double)screenSize.x));
|
||||||
deltaY = (int)Math.round((double)deltaY * ((double)height / (double)screenSize.y));
|
deltaY = (int)Math.round((double)deltaY * ((double)prefConfig.height / (double)screenSize.y));
|
||||||
|
|
||||||
conn.sendMouseMove((short)deltaX, (short)deltaY);
|
conn.sendMouseMove((short)deltaX, (short)deltaY);
|
||||||
}
|
}
|
||||||
@@ -744,7 +700,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void displayTransientMessage(final String message) {
|
public void displayTransientMessage(final String message) {
|
||||||
if (!toastsDisabled) {
|
if (!prefConfig.disableWarnings) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -765,8 +721,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
// Resize the surface to match the aspect ratio of the video
|
// Resize the surface to match the aspect ratio of the video
|
||||||
// This must be done after the surface is created.
|
// This must be done after the surface is created.
|
||||||
if (!stretchToFit && decoderRenderer.isHardwareAccelerated()) {
|
if (!prefConfig.stretchVideo && decoderRenderer.isHardwareAccelerated()) {
|
||||||
resizeSurfaceWithAspectRatio((SurfaceView) findViewById(R.id.surfaceView), width, height);
|
resizeSurfaceWithAspectRatio((SurfaceView) findViewById(R.id.surfaceView),
|
||||||
|
prefConfig.width, prefConfig.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
||||||
@@ -819,6 +776,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
conn.sendMouseScroll(amount);
|
conn.sendMouseScroll(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void keyboardEvent(boolean buttonDown, short keyCode) {
|
public void keyboardEvent(boolean buttonDown, short keyCode) {
|
||||||
short keyMap = keybTranslator.translate(keyCode);
|
short keyMap = keybTranslator.translate(keyCode);
|
||||||
if (keyMap != 0) {
|
if (keyMap != 0) {
|
||||||
@@ -14,6 +14,8 @@ import com.limelight.nvstream.http.NvHTTP;
|
|||||||
import com.limelight.nvstream.http.PairingManager;
|
import com.limelight.nvstream.http.PairingManager;
|
||||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||||
|
import com.limelight.preferences.AddComputerManually;
|
||||||
|
import com.limelight.preferences.StreamSettings;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -24,6 +26,7 @@ import android.content.ServiceConnection;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -89,6 +92,9 @@ public class PcView extends Activity {
|
|||||||
private void initializeViews() {
|
private void initializeViews() {
|
||||||
setContentView(R.layout.activity_pc_view);
|
setContentView(R.layout.activity_pc_view);
|
||||||
|
|
||||||
|
// Set default preferences if we've never been run
|
||||||
|
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
|
||||||
|
|
||||||
// Setup the list view
|
// Setup the list view
|
||||||
settingsButton = (Button)findViewById(R.id.settingsButton);
|
settingsButton = (Button)findViewById(R.id.settingsButton);
|
||||||
addComputerButton = (Button)findViewById(R.id.manuallyAddPc);
|
addComputerButton = (Button)findViewById(R.id.manuallyAddPc);
|
||||||
@@ -100,7 +106,7 @@ public class PcView extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
|
||||||
long id) {
|
long id) {
|
||||||
ComputerObject computer = (ComputerObject) pcListAdapter.getItem(pos);
|
ComputerObject computer = pcListAdapter.getItem(pos);
|
||||||
if (computer.details == null) {
|
if (computer.details == null) {
|
||||||
// Placeholder item; no context menu for it
|
// Placeholder item; no context menu for it
|
||||||
return;
|
return;
|
||||||
@@ -235,7 +241,7 @@ public class PcView extends Activity {
|
|||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
|
||||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
||||||
ComputerObject computer = (ComputerObject) pcListAdapter.getItem(info.position);
|
ComputerObject computer = pcListAdapter.getItem(info.position);
|
||||||
if (computer == null || computer.details == null) {
|
if (computer == null || computer.details == null) {
|
||||||
startComputerUpdates();
|
startComputerUpdates();
|
||||||
return;
|
return;
|
||||||
@@ -476,7 +482,7 @@ public class PcView extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
|
||||||
ComputerObject computer = (ComputerObject) pcListAdapter.getItem(info.position);
|
ComputerObject computer = pcListAdapter.getItem(info.position);
|
||||||
switch (item.getItemId())
|
switch (item.getItemId())
|
||||||
{
|
{
|
||||||
case PAIR_ID:
|
case PAIR_ID:
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+5
-2
@@ -52,7 +52,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
private RSAPrivateKey key;
|
private RSAPrivateKey key;
|
||||||
private byte[] pemCertBytes;
|
private byte[] pemCertBytes;
|
||||||
|
|
||||||
private static Object globalCryptoLock = new Object();
|
private static final Object globalCryptoLock = new Object();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Install the Bouncy Castle provider
|
// Install the Bouncy Castle provider
|
||||||
@@ -74,7 +74,10 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
try {
|
try {
|
||||||
FileInputStream fin = new FileInputStream(f);
|
FileInputStream fin = new FileInputStream(f);
|
||||||
byte[] fileData = new byte[(int) f.length()];
|
byte[] fileData = new byte[(int) f.length()];
|
||||||
fin.read(fileData);
|
if (fin.read(fileData) != f.length()) {
|
||||||
|
// Failed to read
|
||||||
|
fileData = null;
|
||||||
|
}
|
||||||
fin.close();
|
fin.close();
|
||||||
return fileData;
|
return fileData;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
+3
-3
@@ -418,7 +418,7 @@ public class ControllerHandler {
|
|||||||
// UI thread.
|
// UI thread.
|
||||||
try {
|
try {
|
||||||
Thread.sleep(ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS);
|
Thread.sleep(ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS);
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keyCode) {
|
switch (keyCode) {
|
||||||
@@ -495,7 +495,7 @@ public class ControllerHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(EMULATED_SELECT_UP_DELAY_MS);
|
Thread.sleep(EMULATED_SELECT_UP_DELAY_MS);
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,7 +513,7 @@ public class ControllerHandler {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(EMULATED_SPECIAL_UP_DELAY_MS);
|
Thread.sleep(EMULATED_SPECIAL_UP_DELAY_MS);
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File renamed without changes.
+1
-1
@@ -65,7 +65,7 @@ public class TouchContext {
|
|||||||
// do input detection by polling
|
// do input detection by polling
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
|
|
||||||
// Raise the mouse button
|
// Raise the mouse button
|
||||||
conn.sendMouseButtonUp(buttonIndex);
|
conn.sendMouseButtonUp(buttonIndex);
|
||||||
+10
@@ -8,6 +8,7 @@ public class EvdevEvent {
|
|||||||
public static final short EV_SYN = 0x00;
|
public static final short EV_SYN = 0x00;
|
||||||
public static final short EV_KEY = 0x01;
|
public static final short EV_KEY = 0x01;
|
||||||
public static final short EV_REL = 0x02;
|
public static final short EV_REL = 0x02;
|
||||||
|
public static final short EV_MSC = 0x04;
|
||||||
|
|
||||||
/* Relative axes */
|
/* Relative axes */
|
||||||
public static final short REL_X = 0x00;
|
public static final short REL_X = 0x00;
|
||||||
@@ -18,6 +19,15 @@ public class EvdevEvent {
|
|||||||
public static final short BTN_LEFT = 0x110;
|
public static final short BTN_LEFT = 0x110;
|
||||||
public static final short BTN_RIGHT = 0x111;
|
public static final short BTN_RIGHT = 0x111;
|
||||||
public static final short BTN_MIDDLE = 0x112;
|
public static final short BTN_MIDDLE = 0x112;
|
||||||
|
public static final short BTN_SIDE = 0x113;
|
||||||
|
public static final short BTN_EXTRA = 0x114;
|
||||||
|
public static final short BTN_FORWARD = 0x115;
|
||||||
|
public static final short BTN_BACK = 0x116;
|
||||||
|
public static final short BTN_TASK = 0x117;
|
||||||
|
public static final short BTN_GAMEPAD = 0x130;
|
||||||
|
|
||||||
|
/* Keys */
|
||||||
|
public static final short KEY_Q = 16;
|
||||||
|
|
||||||
public short type;
|
public short type;
|
||||||
public short code;
|
public short code;
|
||||||
+39
-6
@@ -10,6 +10,7 @@ public class EvdevHandler {
|
|||||||
private String absolutePath;
|
private String absolutePath;
|
||||||
private EvdevListener listener;
|
private EvdevListener listener;
|
||||||
private boolean shutdown = false;
|
private boolean shutdown = false;
|
||||||
|
private int fd = -1;
|
||||||
|
|
||||||
private Thread handlerThread = new Thread() {
|
private Thread handlerThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
@@ -19,16 +20,17 @@ public class EvdevHandler {
|
|||||||
// system-wide input problems.
|
// system-wide input problems.
|
||||||
|
|
||||||
// Open the /dev/input/eventX file
|
// Open the /dev/input/eventX file
|
||||||
int fd = EvdevReader.open(absolutePath);
|
fd = EvdevReader.open(absolutePath);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
LimeLog.warning("Unable to open "+absolutePath);
|
LimeLog.warning("Unable to open "+absolutePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if it's a mouse
|
// Check if it's a mouse or keyboard, but not a gamepad
|
||||||
if (!EvdevReader.isMouse(fd)) {
|
if ((!EvdevReader.isMouse(fd) && !EvdevReader.isAlphaKeyboard(fd)) ||
|
||||||
// We only handle mice
|
EvdevReader.isGamepad(fd)) {
|
||||||
|
// We only handle keyboards and mice
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +40,7 @@ public class EvdevHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LimeLog.info("Grabbed device for raw mouse input: "+absolutePath);
|
LimeLog.info("Grabbed device for raw keyboard/mouse input: "+absolutePath);
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(EvdevEvent.EVDEV_MAX_EVENT_SIZE).order(ByteOrder.nativeOrder());
|
ByteBuffer buffer = ByteBuffer.allocate(EvdevEvent.EVDEV_MAX_EVENT_SIZE).order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
@@ -96,7 +98,31 @@ public class EvdevHandler {
|
|||||||
listener.mouseButtonEvent(EvdevListener.BUTTON_RIGHT,
|
listener.mouseButtonEvent(EvdevListener.BUTTON_RIGHT,
|
||||||
event.value != 0);
|
event.value != 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EvdevEvent.BTN_SIDE:
|
||||||
|
case EvdevEvent.BTN_EXTRA:
|
||||||
|
case EvdevEvent.BTN_FORWARD:
|
||||||
|
case EvdevEvent.BTN_BACK:
|
||||||
|
case EvdevEvent.BTN_TASK:
|
||||||
|
// Other unhandled mouse buttons
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// We got some unrecognized button. This means
|
||||||
|
// someone is trying to use the other device in this
|
||||||
|
// "combination" input device. We'll try to handle
|
||||||
|
// it via keyboard, but we're not going to disconnect
|
||||||
|
// if we can't
|
||||||
|
short keyCode = EvdevTranslator.translateEvdevKeyCode(event.code);
|
||||||
|
if (keyCode != 0) {
|
||||||
|
listener.keyboardEvent(event.value != 0, keyCode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EvdevEvent.EV_MSC:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -120,12 +146,19 @@ public class EvdevHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
// Close the fd. It doesn't matter if this races
|
||||||
|
// with the handler thread. We'll close this out from
|
||||||
|
// under the thread to wake it up
|
||||||
|
if (fd != -1) {
|
||||||
|
EvdevReader.close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
shutdown = true;
|
shutdown = true;
|
||||||
handlerThread.interrupt();
|
handlerThread.interrupt();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
handlerThread.join();
|
handlerThread.join();
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyDeleted() {
|
public void notifyDeleted() {
|
||||||
+1
@@ -8,4 +8,5 @@ public interface EvdevListener {
|
|||||||
public void mouseMove(int deltaX, int deltaY);
|
public void mouseMove(int deltaX, int deltaY);
|
||||||
public void mouseButtonEvent(int buttonId, boolean down);
|
public void mouseButtonEvent(int buttonId, boolean down);
|
||||||
public void mouseScroll(byte amount);
|
public void mouseScroll(byte amount);
|
||||||
|
public void keyboardEvent(boolean buttonDown, short keyCode);
|
||||||
}
|
}
|
||||||
+21
-2
@@ -28,6 +28,7 @@ public class EvdevReader {
|
|||||||
|
|
||||||
p.waitFor();
|
p.waitFor();
|
||||||
p.destroy();
|
p.destroy();
|
||||||
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -44,8 +45,26 @@ public class EvdevReader {
|
|||||||
public static native boolean grab(int fd);
|
public static native boolean grab(int fd);
|
||||||
public static native boolean ungrab(int fd);
|
public static native boolean ungrab(int fd);
|
||||||
|
|
||||||
// Returns true if the device is a mouse
|
// Used for checking device capabilities
|
||||||
public static native boolean isMouse(int fd);
|
public static native boolean hasRelAxis(int fd, short axis);
|
||||||
|
public static native boolean hasAbsAxis(int fd, short axis);
|
||||||
|
public static native boolean hasKey(int fd, short key);
|
||||||
|
|
||||||
|
public static boolean isMouse(int fd) {
|
||||||
|
// This is the same check that Android does in EventHub.cpp
|
||||||
|
return hasRelAxis(fd, EvdevEvent.REL_X) &&
|
||||||
|
hasRelAxis(fd, EvdevEvent.REL_Y) &&
|
||||||
|
hasKey(fd, EvdevEvent.BTN_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAlphaKeyboard(int fd) {
|
||||||
|
// This is the same check that Android does in EventHub.cpp
|
||||||
|
return hasKey(fd, EvdevEvent.KEY_Q);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isGamepad(int fd) {
|
||||||
|
return hasKey(fd, EvdevEvent.BTN_GAMEPAD);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the bytes read or -1 on error
|
// Returns the bytes read or -1 on error
|
||||||
private static native int read(int fd, byte[] buffer);
|
private static native int read(int fd, byte[] buffer);
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package com.limelight.binding.input.evdev;
|
||||||
|
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
|
public class EvdevTranslator {
|
||||||
|
|
||||||
|
public static final short EVDEV_KEY_CODES[] = {
|
||||||
|
0, //KeyEvent.VK_RESERVED
|
||||||
|
KeyEvent.KEYCODE_ESCAPE,
|
||||||
|
KeyEvent.KEYCODE_1,
|
||||||
|
KeyEvent.KEYCODE_2,
|
||||||
|
KeyEvent.KEYCODE_3,
|
||||||
|
KeyEvent.KEYCODE_4,
|
||||||
|
KeyEvent.KEYCODE_5,
|
||||||
|
KeyEvent.KEYCODE_6,
|
||||||
|
KeyEvent.KEYCODE_7,
|
||||||
|
KeyEvent.KEYCODE_8,
|
||||||
|
KeyEvent.KEYCODE_9,
|
||||||
|
KeyEvent.KEYCODE_0,
|
||||||
|
KeyEvent.KEYCODE_MINUS,
|
||||||
|
KeyEvent.KEYCODE_EQUALS,
|
||||||
|
KeyEvent.KEYCODE_DEL,
|
||||||
|
KeyEvent.KEYCODE_TAB,
|
||||||
|
KeyEvent.KEYCODE_Q,
|
||||||
|
KeyEvent.KEYCODE_W,
|
||||||
|
KeyEvent.KEYCODE_E,
|
||||||
|
KeyEvent.KEYCODE_R,
|
||||||
|
KeyEvent.KEYCODE_T,
|
||||||
|
KeyEvent.KEYCODE_Y,
|
||||||
|
KeyEvent.KEYCODE_U,
|
||||||
|
KeyEvent.KEYCODE_I,
|
||||||
|
KeyEvent.KEYCODE_O,
|
||||||
|
KeyEvent.KEYCODE_P,
|
||||||
|
KeyEvent.KEYCODE_LEFT_BRACKET,
|
||||||
|
KeyEvent.KEYCODE_RIGHT_BRACKET,
|
||||||
|
KeyEvent.KEYCODE_ENTER,
|
||||||
|
KeyEvent.KEYCODE_CTRL_LEFT,
|
||||||
|
KeyEvent.KEYCODE_A,
|
||||||
|
KeyEvent.KEYCODE_S,
|
||||||
|
KeyEvent.KEYCODE_D,
|
||||||
|
KeyEvent.KEYCODE_F,
|
||||||
|
KeyEvent.KEYCODE_G,
|
||||||
|
KeyEvent.KEYCODE_H,
|
||||||
|
KeyEvent.KEYCODE_J,
|
||||||
|
KeyEvent.KEYCODE_K,
|
||||||
|
KeyEvent.KEYCODE_L,
|
||||||
|
KeyEvent.KEYCODE_SEMICOLON,
|
||||||
|
KeyEvent.KEYCODE_APOSTROPHE,
|
||||||
|
KeyEvent.KEYCODE_GRAVE,
|
||||||
|
KeyEvent.KEYCODE_SHIFT_LEFT,
|
||||||
|
KeyEvent.KEYCODE_BACKSLASH,
|
||||||
|
KeyEvent.KEYCODE_Z,
|
||||||
|
KeyEvent.KEYCODE_X,
|
||||||
|
KeyEvent.KEYCODE_C,
|
||||||
|
KeyEvent.KEYCODE_V,
|
||||||
|
KeyEvent.KEYCODE_B,
|
||||||
|
KeyEvent.KEYCODE_N,
|
||||||
|
KeyEvent.KEYCODE_M,
|
||||||
|
KeyEvent.KEYCODE_COMMA,
|
||||||
|
KeyEvent.KEYCODE_PERIOD,
|
||||||
|
KeyEvent.KEYCODE_SLASH,
|
||||||
|
KeyEvent.KEYCODE_SHIFT_RIGHT,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
|
||||||
|
KeyEvent.KEYCODE_ALT_LEFT,
|
||||||
|
KeyEvent.KEYCODE_SPACE,
|
||||||
|
KeyEvent.KEYCODE_CAPS_LOCK,
|
||||||
|
KeyEvent.KEYCODE_F1,
|
||||||
|
KeyEvent.KEYCODE_F2,
|
||||||
|
KeyEvent.KEYCODE_F3,
|
||||||
|
KeyEvent.KEYCODE_F4,
|
||||||
|
KeyEvent.KEYCODE_F5,
|
||||||
|
KeyEvent.KEYCODE_F6,
|
||||||
|
KeyEvent.KEYCODE_F7,
|
||||||
|
KeyEvent.KEYCODE_F8,
|
||||||
|
KeyEvent.KEYCODE_F9,
|
||||||
|
KeyEvent.KEYCODE_F10,
|
||||||
|
KeyEvent.KEYCODE_NUM_LOCK,
|
||||||
|
KeyEvent.KEYCODE_SCROLL_LOCK,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_7,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_8,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_9,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_4,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_5,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_6,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_ADD,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_1,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_2,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_3,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_0,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_DOT,
|
||||||
|
0,
|
||||||
|
0, //KeyEvent.VK_ZENKAKUHANKAKU,
|
||||||
|
0, //KeyEvent.VK_102ND,
|
||||||
|
KeyEvent.KEYCODE_F11,
|
||||||
|
KeyEvent.KEYCODE_F12,
|
||||||
|
0, //KeyEvent.VK_RO,
|
||||||
|
0, //KeyEvent.VK_KATAKANA,
|
||||||
|
0, //KeyEvent.VK_HIRAGANA,
|
||||||
|
0, //KeyEvent.VK_HENKAN,
|
||||||
|
0, //KeyEvent.VK_KATAKANAHIRAGANA,
|
||||||
|
0, //KeyEvent.VK_MUHENKAN,
|
||||||
|
0, //KeyEvent.VK_KPJPCOMMA,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_ENTER,
|
||||||
|
KeyEvent.KEYCODE_CTRL_RIGHT,
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_DIVIDE,
|
||||||
|
KeyEvent.KEYCODE_SYSRQ,
|
||||||
|
KeyEvent.KEYCODE_ALT_RIGHT,
|
||||||
|
0, //KeyEvent.VK_LINEFEED,
|
||||||
|
KeyEvent.KEYCODE_HOME,
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP,
|
||||||
|
KeyEvent.KEYCODE_PAGE_UP,
|
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||||
|
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||||
|
KeyEvent.KEYCODE_MOVE_END,
|
||||||
|
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||||
|
KeyEvent.KEYCODE_PAGE_DOWN,
|
||||||
|
KeyEvent.KEYCODE_INSERT,
|
||||||
|
KeyEvent.KEYCODE_FORWARD_DEL,
|
||||||
|
0, //KeyEvent.VK_MACRO,
|
||||||
|
0, //KeyEvent.VK_MUTE,
|
||||||
|
0, //KeyEvent.VK_VOLUMEDOWN,
|
||||||
|
0, //KeyEvent.VK_VOLUMEUP,
|
||||||
|
0, //KeyEvent.VK_POWER, /* SC System Power Down */
|
||||||
|
KeyEvent.KEYCODE_NUMPAD_EQUALS,
|
||||||
|
0, //KeyEvent.VK_KPPLUSMINUS,
|
||||||
|
KeyEvent.KEYCODE_BREAK,
|
||||||
|
0, //KeyEvent.VK_SCALE, /* AL Compiz Scale (Expose) */
|
||||||
|
};
|
||||||
|
|
||||||
|
public static short translateEvdevKeyCode(short evdevKeyCode) {
|
||||||
|
if (evdevKeyCode < EVDEV_KEY_CODES.length) {
|
||||||
|
return EVDEV_KEY_CODES[evdevKeyCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
-1
@@ -8,11 +8,12 @@ import com.limelight.LimeLog;
|
|||||||
|
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
|
|
||||||
|
@SuppressWarnings("ALL")
|
||||||
public class EvdevWatcher {
|
public class EvdevWatcher {
|
||||||
private static final String PATH = "/dev/input";
|
private static final String PATH = "/dev/input";
|
||||||
private static final String REQUIRED_FILE_PREFIX = "event";
|
private static final String REQUIRED_FILE_PREFIX = "event";
|
||||||
|
|
||||||
private HashMap<String, EvdevHandler> handlers = new HashMap<String, EvdevHandler>();
|
private final HashMap<String, EvdevHandler> handlers = new HashMap<String, EvdevHandler>();
|
||||||
private boolean shutdown = false;
|
private boolean shutdown = false;
|
||||||
private boolean init = false;
|
private boolean init = false;
|
||||||
private boolean ungrabbed = false;
|
private boolean ungrabbed = false;
|
||||||
@@ -73,6 +74,9 @@ public class EvdevWatcher {
|
|||||||
// Rundown existing files
|
// Rundown existing files
|
||||||
File devInputDir = new File(PATH);
|
File devInputDir = new File(PATH);
|
||||||
File[] files = devInputDir.listFiles();
|
File[] files = devInputDir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
return new File[0];
|
||||||
|
}
|
||||||
|
|
||||||
// Set desired permissions
|
// Set desired permissions
|
||||||
String[] filePaths = new String[files.length];
|
String[] filePaths = new String[files.length];
|
||||||
+1
@@ -18,6 +18,7 @@ import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
|||||||
import com.limelight.nvstream.av.video.VideoDepacketizer;
|
import com.limelight.nvstream.av.video.VideoDepacketizer;
|
||||||
import com.limelight.nvstream.av.video.cpu.AvcDecoder;
|
import com.limelight.nvstream.av.video.cpu.AvcDecoder;
|
||||||
|
|
||||||
|
@SuppressWarnings("EmptyCatchBlock")
|
||||||
public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
|
public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
|
||||||
|
|
||||||
private Thread rendererThread;
|
private Thread rendererThread;
|
||||||
File renamed without changes.
+17
-4
@@ -22,12 +22,13 @@ import android.media.MediaCodec.CodecException;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
||||||
|
|
||||||
private ByteBuffer[] videoDecoderInputBuffers;
|
private ByteBuffer[] videoDecoderInputBuffers;
|
||||||
private MediaCodec videoDecoder;
|
private MediaCodec videoDecoder;
|
||||||
private Thread rendererThread;
|
private Thread rendererThread;
|
||||||
private boolean needsSpsBitstreamFixup;
|
private boolean needsSpsBitstreamFixup, isExynos4;
|
||||||
private VideoDepacketizer depacketizer;
|
private VideoDepacketizer depacketizer;
|
||||||
private boolean adaptivePlayback;
|
private boolean adaptivePlayback;
|
||||||
private int initialWidth, initialHeight;
|
private int initialWidth, initialHeight;
|
||||||
@@ -65,6 +66,10 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
if (needsSpsBitstreamFixup) {
|
if (needsSpsBitstreamFixup) {
|
||||||
LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup");
|
LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup");
|
||||||
}
|
}
|
||||||
|
isExynos4 = MediaCodecHelper.isExynos4Device();
|
||||||
|
if (isExynos4) {
|
||||||
|
LimeLog.info("Decoder "+decoderName+" is on Exynos 4");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
@@ -319,7 +324,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
rendererThread.interrupt();
|
rendererThread.interrupt();
|
||||||
try {
|
try {
|
||||||
rendererThread.join();
|
rendererThread.join();
|
||||||
} catch (InterruptedException e) { }
|
} catch (InterruptedException ignored) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the decoder
|
// Stop the decoder
|
||||||
@@ -406,7 +411,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
LimeLog.info("Patching num_ref_frames in SPS");
|
LimeLog.info("Patching num_ref_frames in SPS");
|
||||||
sps.num_ref_frames = 1;
|
sps.num_ref_frames = 1;
|
||||||
|
|
||||||
if (needsSpsBitstreamFixup) {
|
if (needsSpsBitstreamFixup || isExynos4) {
|
||||||
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
||||||
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
||||||
LimeLog.info("Adding bitstream restrictions");
|
LimeLog.info("Adding bitstream restrictions");
|
||||||
@@ -449,7 +454,6 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
timestampUs, codecFlags);
|
timestampUs, codecFlags);
|
||||||
|
|
||||||
depacketizer.freeDecodeUnit(decodeUnit);
|
depacketizer.freeDecodeUnit(decodeUnit);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -512,6 +516,15 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
str += "Buffer codec flags: "+currentCodecFlags+"\n";
|
str += "Buffer codec flags: "+currentCodecFlags+"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str += "Is Exynos 4: "+renderer.isExynos4+"\n";
|
||||||
|
|
||||||
|
str += "/proc/cpuinfo:\n";
|
||||||
|
try {
|
||||||
|
str += MediaCodecHelper.readCpuinfo();
|
||||||
|
} catch (Exception e) {
|
||||||
|
str += e.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
str += "Full decoder dump:\n";
|
str += "Full decoder dump:\n";
|
||||||
try {
|
try {
|
||||||
str += MediaCodecHelper.dumpDecoders();
|
str += MediaCodecHelper.dumpDecoders();
|
||||||
+69
-5
@@ -1,7 +1,12 @@
|
|||||||
package com.limelight.binding.video;
|
package com.limelight.binding.video;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
@@ -95,9 +100,7 @@ public class MediaCodecHelper {
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||||
for (MediaCodecInfo info : mcl.getCodecInfos()) {
|
Collections.addAll(infoList, mcl.getCodecInfos());
|
||||||
infoList.add(info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||||
@@ -108,7 +111,8 @@ public class MediaCodecHelper {
|
|||||||
return infoList;
|
return infoList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String dumpDecoders() throws Exception {
|
@SuppressWarnings("RedundantThrows")
|
||||||
|
public static String dumpDecoders() throws Exception {
|
||||||
String str = "";
|
String str = "";
|
||||||
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
|
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
|
||||||
// Skip encoders
|
// Skip encoders
|
||||||
@@ -199,7 +203,8 @@ public class MediaCodecHelper {
|
|||||||
// We declare this method as explicitly throwing Exception
|
// We declare this method as explicitly throwing Exception
|
||||||
// since some bad decoders can throw IllegalArgumentExceptions unexpectedly
|
// since some bad decoders can throw IllegalArgumentExceptions unexpectedly
|
||||||
// and we want to be sure all callers are handling this possibility
|
// and we want to be sure all callers are handling this possibility
|
||||||
public static MediaCodecInfo findKnownSafeDecoder() throws Exception {
|
@SuppressWarnings("RedundantThrows")
|
||||||
|
public static MediaCodecInfo findKnownSafeDecoder() throws Exception {
|
||||||
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
|
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
|
||||||
// Skip encoders
|
// Skip encoders
|
||||||
if (codecInfo.isEncoder()) {
|
if (codecInfo.isEncoder()) {
|
||||||
@@ -233,4 +238,63 @@ public class MediaCodecHelper {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String readCpuinfo() throws Exception {
|
||||||
|
StringBuilder cpuInfo = new StringBuilder();
|
||||||
|
BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo")));
|
||||||
|
try {
|
||||||
|
for (;;) {
|
||||||
|
int ch = br.read();
|
||||||
|
if (ch == -1)
|
||||||
|
break;
|
||||||
|
cpuInfo.append((char)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpuInfo.toString();
|
||||||
|
} finally {
|
||||||
|
br.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean stringContainsIgnoreCase(String string, String substring) {
|
||||||
|
return string.toLowerCase(Locale.ENGLISH).contains(substring.toLowerCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isExynos4Device() {
|
||||||
|
try {
|
||||||
|
// Try reading CPU info too look for
|
||||||
|
String cpuInfo = readCpuinfo();
|
||||||
|
|
||||||
|
// SMDK4xxx is Exynos 4
|
||||||
|
if (stringContainsIgnoreCase(cpuInfo, "SMDK4")) {
|
||||||
|
LimeLog.info("Found SMDK4 in /proc/cpuinfo");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we see "Exynos 4" also we'll count it
|
||||||
|
if (stringContainsIgnoreCase(cpuInfo, "Exynos 4")) {
|
||||||
|
LimeLog.info("Found Exynos 4 in /proc/cpuinfo");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File systemDir = new File("/sys/devices/system");
|
||||||
|
File[] files = systemDir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File f : files) {
|
||||||
|
if (stringContainsIgnoreCase(f.getName(), "exynos4")) {
|
||||||
|
LimeLog.info("Found exynos4 in /sys/devices/system");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
+111
-101
@@ -1,6 +1,7 @@
|
|||||||
package com.limelight.computers;
|
package com.limelight.computers;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
@@ -25,7 +26,6 @@ import android.os.Binder;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
public class ComputerManagerService extends Service {
|
public class ComputerManagerService extends Service {
|
||||||
private static final int MAX_CONCURRENT_REQUESTS = 4;
|
|
||||||
private static final int POLLING_PERIOD_MS = 5000;
|
private static final int POLLING_PERIOD_MS = 5000;
|
||||||
private static final int MDNS_QUERY_PERIOD_MS = 1000;
|
private static final int MDNS_QUERY_PERIOD_MS = 1000;
|
||||||
|
|
||||||
@@ -35,14 +35,12 @@ public class ComputerManagerService extends Service {
|
|||||||
private AtomicInteger dbRefCount = new AtomicInteger(0);
|
private AtomicInteger dbRefCount = new AtomicInteger(0);
|
||||||
|
|
||||||
private IdentityManager idManager;
|
private IdentityManager idManager;
|
||||||
private ThreadPoolExecutor pollingPool;
|
private HashMap<ComputerDetails, Thread> pollingThreads;
|
||||||
private Timer pollingTimer;
|
|
||||||
private ComputerManagerListener listener = null;
|
private ComputerManagerListener listener = null;
|
||||||
private AtomicInteger activePolls = new AtomicInteger(0);
|
private AtomicInteger activePolls = new AtomicInteger(0);
|
||||||
private boolean stopped;
|
|
||||||
|
|
||||||
private DiscoveryService.DiscoveryBinder discoveryBinder;
|
private DiscoveryService.DiscoveryBinder discoveryBinder;
|
||||||
private ServiceConnection discoveryServiceConnection = new ServiceConnection() {
|
private final ServiceConnection discoveryServiceConnection = new ServiceConnection() {
|
||||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||||
synchronized (discoveryServiceConnection) {
|
synchronized (discoveryServiceConnection) {
|
||||||
DiscoveryService.DiscoveryBinder privateBinder = ((DiscoveryService.DiscoveryBinder)binder);
|
DiscoveryService.DiscoveryBinder privateBinder = ((DiscoveryService.DiscoveryBinder)binder);
|
||||||
@@ -61,11 +59,81 @@ public class ComputerManagerService extends Service {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns true if the details object was modified
|
||||||
|
private boolean runPoll(ComputerDetails details)
|
||||||
|
{
|
||||||
|
boolean newPc = (details.name == null);
|
||||||
|
|
||||||
|
if (!getLocalDatabaseReference()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
activePolls.incrementAndGet();
|
||||||
|
|
||||||
|
// Poll the machine
|
||||||
|
if (!doPollMachine(details)) {
|
||||||
|
details.state = ComputerDetails.State.OFFLINE;
|
||||||
|
details.reachability = ComputerDetails.Reachability.OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
activePolls.decrementAndGet();
|
||||||
|
|
||||||
|
// If it's online, update our persistent state
|
||||||
|
if (details.state == ComputerDetails.State.ONLINE) {
|
||||||
|
if (!newPc) {
|
||||||
|
// Check if it's in the database because it could have been
|
||||||
|
// removed after this was issued
|
||||||
|
if (dbManager.getComputerByName(details.name) == null) {
|
||||||
|
// It's gone
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbManager.updateComputer(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't call the listener if this is a failed lookup of a new PC
|
||||||
|
if ((!newPc || details.state == ComputerDetails.State.ONLINE) && listener != null) {
|
||||||
|
listener.notifyComputerUpdated(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Thread createPollingThread(final ComputerDetails details) {
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
ComputerDetails originalDetails = new ComputerDetails();
|
||||||
|
originalDetails.update(details);
|
||||||
|
|
||||||
|
// Check if this poll has modified the details
|
||||||
|
if (runPoll(details) && !originalDetails.equals(details)) {
|
||||||
|
// Replace our thread entry with the new one
|
||||||
|
synchronized (pollingThreads) {
|
||||||
|
pollingThreads.remove(originalDetails);
|
||||||
|
pollingThreads.put(details, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the next polling interval
|
||||||
|
try {
|
||||||
|
Thread.sleep(POLLING_PERIOD_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
t.setName("Polling thread for "+details.localIp.getHostAddress());
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
public class ComputerManagerBinder extends Binder {
|
public class ComputerManagerBinder extends Binder {
|
||||||
public void startPolling(ComputerManagerListener listener) {
|
public void startPolling(ComputerManagerListener listener) {
|
||||||
// Not stopped
|
|
||||||
stopped = false;
|
|
||||||
|
|
||||||
// Set the listener
|
// Set the listener
|
||||||
ComputerManagerService.this.listener = listener;
|
ComputerManagerService.this.listener = listener;
|
||||||
|
|
||||||
@@ -73,8 +141,22 @@ public class ComputerManagerService extends Service {
|
|||||||
discoveryBinder.startDiscovery(MDNS_QUERY_PERIOD_MS);
|
discoveryBinder.startDiscovery(MDNS_QUERY_PERIOD_MS);
|
||||||
|
|
||||||
// Start polling known machines
|
// Start polling known machines
|
||||||
pollingTimer = new Timer();
|
if (!getLocalDatabaseReference()) {
|
||||||
pollingTimer.schedule(getTimerTask(), 0, POLLING_PERIOD_MS);
|
return;
|
||||||
|
}
|
||||||
|
List<ComputerDetails> computerList = dbManager.getAllComputers();
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
|
||||||
|
synchronized (pollingThreads) {
|
||||||
|
for (ComputerDetails computer : computerList) {
|
||||||
|
// This polling thread might already be there
|
||||||
|
if (!pollingThreads.containsKey(computer)) {
|
||||||
|
Thread t = createPollingThread(computer);
|
||||||
|
pollingThreads.put(computer, t);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForReady() {
|
public void waitForReady() {
|
||||||
@@ -84,7 +166,7 @@ public class ComputerManagerService extends Service {
|
|||||||
// Wait for the bind notification
|
// Wait for the bind notification
|
||||||
discoveryServiceConnection.wait(1000);
|
discoveryServiceConnection.wait(1000);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +175,7 @@ public class ComputerManagerService extends Service {
|
|||||||
while (activePolls.get() != 0) {
|
while (activePolls.get() != 0) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(250);
|
Thread.sleep(250);
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,17 +203,16 @@ public class ComputerManagerService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onUnbind(Intent intent) {
|
public boolean onUnbind(Intent intent) {
|
||||||
// Stopped now
|
|
||||||
stopped = true;
|
|
||||||
|
|
||||||
// Stop mDNS autodiscovery
|
// Stop mDNS autodiscovery
|
||||||
discoveryBinder.stopDiscovery();
|
discoveryBinder.stopDiscovery();
|
||||||
|
|
||||||
// Stop polling
|
// Stop polling
|
||||||
if (pollingTimer != null) {
|
synchronized (pollingThreads) {
|
||||||
pollingTimer.cancel();
|
for (Thread t : pollingThreads.values()) {
|
||||||
pollingTimer = null;
|
t.interrupt();
|
||||||
}
|
}
|
||||||
|
pollingThreads.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the listener
|
// Remove the listener
|
||||||
listener = null;
|
listener = null;
|
||||||
@@ -166,8 +247,15 @@ public class ComputerManagerService extends Service {
|
|||||||
fakeDetails.localIp = addr;
|
fakeDetails.localIp = addr;
|
||||||
fakeDetails.remoteIp = addr;
|
fakeDetails.remoteIp = addr;
|
||||||
|
|
||||||
// Put it in the thread pool to process later
|
// Spawn a thread for this computer
|
||||||
pollingPool.execute(getPollingRunnable(fakeDetails));
|
synchronized (pollingThreads) {
|
||||||
|
// This polling thread might already be there
|
||||||
|
if (!pollingThreads.containsKey(fakeDetails)) {
|
||||||
|
Thread t = createPollingThread(fakeDetails);
|
||||||
|
pollingThreads.put(fakeDetails, t);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addComputerBlocking(InetAddress addr) {
|
public boolean addComputerBlocking(InetAddress addr) {
|
||||||
@@ -177,7 +265,7 @@ public class ComputerManagerService extends Service {
|
|||||||
fakeDetails.remoteIp = addr;
|
fakeDetails.remoteIp = addr;
|
||||||
|
|
||||||
// Block while we try to fill the details
|
// Block while we try to fill the details
|
||||||
getPollingRunnable(fakeDetails).run();
|
runPoll(fakeDetails);
|
||||||
|
|
||||||
// If the machine is reachable, it was successful
|
// If the machine is reachable, it was successful
|
||||||
return fakeDetails.state == ComputerDetails.State.ONLINE;
|
return fakeDetails.state == ComputerDetails.State.ONLINE;
|
||||||
@@ -209,23 +297,6 @@ public class ComputerManagerService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimerTask getTimerTask() {
|
|
||||||
return new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!getLocalDatabaseReference()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<ComputerDetails> computerList = dbManager.getAllComputers();
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
|
|
||||||
for (ComputerDetails computer : computerList) {
|
|
||||||
pollingPool.execute(getPollingRunnable(computer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private ComputerDetails tryPollIp(InetAddress ipAddr) {
|
private ComputerDetails tryPollIp(InetAddress ipAddr) {
|
||||||
try {
|
try {
|
||||||
NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(),
|
NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(),
|
||||||
@@ -281,71 +352,13 @@ public class ComputerManagerService extends Service {
|
|||||||
return pollComputer(details, true);
|
return pollComputer(details, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable getPollingRunnable(final ComputerDetails details) {
|
|
||||||
return new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean newPc = (details.name == null);
|
|
||||||
|
|
||||||
// This is called from addComputerManually() where we don't
|
|
||||||
// want to block the initial poll if polling is disabled, so
|
|
||||||
// we explicitly let this through if we've never seen this
|
|
||||||
// PC before. This path won't be triggered normally when polling
|
|
||||||
// is disabled because the mDNS discovery is stopped.
|
|
||||||
if (stopped && !newPc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getLocalDatabaseReference()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activePolls.incrementAndGet();
|
|
||||||
|
|
||||||
// Poll the machine
|
|
||||||
if (!doPollMachine(details)) {
|
|
||||||
details.state = ComputerDetails.State.OFFLINE;
|
|
||||||
details.reachability = ComputerDetails.Reachability.OFFLINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
activePolls.decrementAndGet();
|
|
||||||
|
|
||||||
// If it's online, update our persistent state
|
|
||||||
if (details.state == ComputerDetails.State.ONLINE) {
|
|
||||||
if (!newPc) {
|
|
||||||
// Check if it's in the database because it could have been
|
|
||||||
// removed after this was issued
|
|
||||||
if (dbManager.getComputerByName(details.name) == null) {
|
|
||||||
// It's gone
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbManager.updateComputer(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't call the listener if this is a failed lookup of a new PC
|
|
||||||
if ((!newPc || details.state == ComputerDetails.State.ONLINE) && listener != null) {
|
|
||||||
listener.notifyComputerUpdated(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
// Bind to the discovery service
|
// Bind to the discovery service
|
||||||
bindService(new Intent(this, DiscoveryService.class),
|
bindService(new Intent(this, DiscoveryService.class),
|
||||||
discoveryServiceConnection, Service.BIND_AUTO_CREATE);
|
discoveryServiceConnection, Service.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
// Create the thread pool for updating computer state
|
pollingThreads = new HashMap<ComputerDetails, Thread>();
|
||||||
pollingPool = new ThreadPoolExecutor(MAX_CONCURRENT_REQUESTS, MAX_CONCURRENT_REQUESTS,
|
|
||||||
Long.MAX_VALUE, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>(),
|
|
||||||
new ThreadPoolExecutor.DiscardPolicy());
|
|
||||||
|
|
||||||
// Lookup or generate this device's UID
|
// Lookup or generate this device's UID
|
||||||
idManager = new IdentityManager(this);
|
idManager = new IdentityManager(this);
|
||||||
@@ -362,9 +375,6 @@ public class ComputerManagerService extends Service {
|
|||||||
unbindService(discoveryServiceConnection);
|
unbindService(discoveryServiceConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the thread pool
|
|
||||||
pollingPool.shutdownNow();
|
|
||||||
|
|
||||||
// FIXME: Should await termination here but we have timeout issues in HttpURLConnection
|
// FIXME: Should await termination here but we have timeout issues in HttpURLConnection
|
||||||
|
|
||||||
// Remove the initial DB reference
|
// Remove the initial DB reference
|
||||||
+2
-2
@@ -54,7 +54,7 @@ public class IdentityManager {
|
|||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
try {
|
try {
|
||||||
reader.close();
|
reader.close();
|
||||||
} catch (IOException e) {}
|
} catch (IOException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ public class IdentityManager {
|
|||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
try {
|
try {
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (IOException e) {}
|
} catch (IOException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
+3
-2
@@ -1,10 +1,11 @@
|
|||||||
package com.limelight;
|
package com.limelight.preferences;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
import com.limelight.computers.ComputerManagerService;
|
import com.limelight.computers.ComputerManagerService;
|
||||||
|
import com.limelight.R;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -97,7 +98,7 @@ public class AddComputerManually extends Activity {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
addThread.join();
|
addThread.join();
|
||||||
} catch (InterruptedException e) {}
|
} catch (InterruptedException ignored) {}
|
||||||
|
|
||||||
addThread = null;
|
addThread = null;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package com.limelight.preferences;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
public class PreferenceConfiguration {
|
||||||
|
static final String RES_FPS_PREF_STRING = "list_resolution_fps";
|
||||||
|
private static final String DECODER_PREF_STRING = "list_decoders";
|
||||||
|
static final String BITRATE_PREF_STRING = "seekbar_bitrate";
|
||||||
|
private static final String STRETCH_PREF_STRING = "checkbox_stretch_video";
|
||||||
|
private static final String SOPS_PREF_STRING = "checkbox_enable_sops";
|
||||||
|
private static final String DISABLE_TOASTS_PREF_STRING = "checkbox_disable_warnings";
|
||||||
|
private static final String HOST_AUDIO_PREF_STRING = "checkbox_host_audio";
|
||||||
|
|
||||||
|
private static final int BITRATE_DEFAULT_720_30 = 5;
|
||||||
|
private static final int BITRATE_DEFAULT_720_60 = 10;
|
||||||
|
private static final int BITRATE_DEFAULT_1080_30 = 10;
|
||||||
|
private static final int BITRATE_DEFAULT_1080_60 = 30;
|
||||||
|
|
||||||
|
private static final String DEFAULT_RES_FPS = "720p60";
|
||||||
|
private static final String DEFAULT_DECODER = "auto";
|
||||||
|
private static final int DEFAULT_BITRATE = BITRATE_DEFAULT_720_60;
|
||||||
|
private static final boolean DEFAULT_STRETCH = false;
|
||||||
|
private static final boolean DEFAULT_SOPS = true;
|
||||||
|
private static final boolean DEFAULT_DISABLE_TOASTS = false;
|
||||||
|
private static final boolean DEFAULT_HOST_AUDIO = false;
|
||||||
|
|
||||||
|
public static final int FORCE_HARDWARE_DECODER = -1;
|
||||||
|
public static final int AUTOSELECT_DECODER = 0;
|
||||||
|
public static final int FORCE_SOFTWARE_DECODER = 1;
|
||||||
|
|
||||||
|
public int width, height, fps;
|
||||||
|
public int bitrate;
|
||||||
|
public int decoder;
|
||||||
|
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
|
||||||
|
|
||||||
|
public static int getDefaultBitrate(String resFpsString) {
|
||||||
|
if (resFpsString.equals("720p30")) {
|
||||||
|
return BITRATE_DEFAULT_720_30;
|
||||||
|
}
|
||||||
|
else if (resFpsString.equals("720p60")) {
|
||||||
|
return BITRATE_DEFAULT_720_60;
|
||||||
|
}
|
||||||
|
else if (resFpsString.equals("1080p30")) {
|
||||||
|
return BITRATE_DEFAULT_1080_30;
|
||||||
|
}
|
||||||
|
else if (resFpsString.equals("1080p60")) {
|
||||||
|
return BITRATE_DEFAULT_1080_60;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Should never get here
|
||||||
|
return DEFAULT_BITRATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDefaultBitrate(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS);
|
||||||
|
if (str.equals("720p30")) {
|
||||||
|
return BITRATE_DEFAULT_720_30;
|
||||||
|
}
|
||||||
|
else if (str.equals("720p60")) {
|
||||||
|
return BITRATE_DEFAULT_720_60;
|
||||||
|
}
|
||||||
|
else if (str.equals("1080p30")) {
|
||||||
|
return BITRATE_DEFAULT_1080_30;
|
||||||
|
}
|
||||||
|
else if (str.equals("1080p60")) {
|
||||||
|
return BITRATE_DEFAULT_1080_60;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Should never get here
|
||||||
|
return DEFAULT_BITRATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getDecoderValue(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
String str = prefs.getString(DECODER_PREF_STRING, DEFAULT_DECODER);
|
||||||
|
if (str.equals("auto")) {
|
||||||
|
return AUTOSELECT_DECODER;
|
||||||
|
}
|
||||||
|
else if (str.equals("software")) {
|
||||||
|
return FORCE_SOFTWARE_DECODER;
|
||||||
|
}
|
||||||
|
else if (str.equals("hardware")) {
|
||||||
|
return FORCE_HARDWARE_DECODER;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Should never get here
|
||||||
|
return AUTOSELECT_DECODER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PreferenceConfiguration readPreferences(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
PreferenceConfiguration config = new PreferenceConfiguration();
|
||||||
|
|
||||||
|
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, getDefaultBitrate(context));
|
||||||
|
String str = prefs.getString(RES_FPS_PREF_STRING, DEFAULT_RES_FPS);
|
||||||
|
if (str.equals("720p30")) {
|
||||||
|
config.width = 1280;
|
||||||
|
config.height = 720;
|
||||||
|
config.fps = 30;
|
||||||
|
}
|
||||||
|
else if (str.equals("720p60")) {
|
||||||
|
config.width = 1280;
|
||||||
|
config.height = 720;
|
||||||
|
config.fps = 60;
|
||||||
|
}
|
||||||
|
else if (str.equals("1080p30")) {
|
||||||
|
config.width = 1920;
|
||||||
|
config.height = 1080;
|
||||||
|
config.fps = 30;
|
||||||
|
}
|
||||||
|
else if (str.equals("1080p60")) {
|
||||||
|
config.width = 1920;
|
||||||
|
config.height = 1080;
|
||||||
|
config.fps = 60;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Should never get here
|
||||||
|
config.width = 1280;
|
||||||
|
config.height = 720;
|
||||||
|
config.fps = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.decoder = getDecoderValue(context);
|
||||||
|
|
||||||
|
// Checkbox preferences
|
||||||
|
config.disableWarnings = prefs.getBoolean(DISABLE_TOASTS_PREF_STRING, DEFAULT_DISABLE_TOASTS);
|
||||||
|
config.enableSops = prefs.getBoolean(SOPS_PREF_STRING, DEFAULT_SOPS);
|
||||||
|
config.stretchVideo = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH);
|
||||||
|
config.playHostAudio = prefs.getBoolean(HOST_AUDIO_PREF_STRING, DEFAULT_HOST_AUDIO);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.limelight.preferences;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.DialogPreference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
// Based on a Stack Overflow example: http://stackoverflow.com/questions/1974193/slider-on-my-preferencescreen
|
||||||
|
public class SeekBarPreference extends DialogPreference
|
||||||
|
{
|
||||||
|
private static final String SCHEMA_URL = "http://schemas.android.com/apk/res/android";
|
||||||
|
|
||||||
|
private SeekBar seekBar;
|
||||||
|
private TextView splashText, valueText;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private String dialogMessage, suffix;
|
||||||
|
private int defaultValue, maxValue, currentValue;
|
||||||
|
|
||||||
|
public SeekBarPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
|
// Read the message from XML
|
||||||
|
int dialogMessageId = attrs.getAttributeResourceValue(SCHEMA_URL, "dialogMessage", 0);
|
||||||
|
if (dialogMessageId == 0) {
|
||||||
|
dialogMessage = attrs.getAttributeValue(SCHEMA_URL, "dialogMessage");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dialogMessage = context.getString(dialogMessageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the suffix for the number displayed in the dialog
|
||||||
|
int suffixId = attrs.getAttributeResourceValue(SCHEMA_URL, "text", 0);
|
||||||
|
if (suffixId == 0) {
|
||||||
|
suffix = attrs.getAttributeValue(SCHEMA_URL, "text");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
suffix = context.getString(suffixId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get default and max seekbar values
|
||||||
|
defaultValue = PreferenceConfiguration.getDefaultBitrate(context);
|
||||||
|
maxValue = attrs.getAttributeIntValue(SCHEMA_URL, "max", 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View onCreateDialogView() {
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams params;
|
||||||
|
LinearLayout layout = new LinearLayout(context);
|
||||||
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
layout.setPadding(6, 6, 6, 6);
|
||||||
|
|
||||||
|
splashText = new TextView(context);
|
||||||
|
splashText.setPadding(30, 10, 30, 10);
|
||||||
|
if (dialogMessage != null) {
|
||||||
|
splashText.setText(dialogMessage);
|
||||||
|
}
|
||||||
|
layout.addView(splashText);
|
||||||
|
|
||||||
|
valueText = new TextView(context);
|
||||||
|
valueText.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||||
|
valueText.setTextSize(32);
|
||||||
|
params = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.FILL_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
layout.addView(valueText, params);
|
||||||
|
|
||||||
|
seekBar = new SeekBar(context);
|
||||||
|
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int value, boolean b) {
|
||||||
|
String t = String.valueOf(value);
|
||||||
|
valueText.setText(suffix == null ? t : t.concat(" " + suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
layout.addView(seekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
|
if (shouldPersist()) {
|
||||||
|
currentValue = getPersistedInt(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
seekBar.setMax(maxValue);
|
||||||
|
seekBar.setProgress(currentValue);
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBindDialogView(View v) {
|
||||||
|
super.onBindDialogView(v);
|
||||||
|
seekBar.setMax(maxValue);
|
||||||
|
seekBar.setProgress(currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSetInitialValue(boolean restore, Object defaultValue)
|
||||||
|
{
|
||||||
|
super.onSetInitialValue(restore, defaultValue);
|
||||||
|
if (restore) {
|
||||||
|
currentValue = shouldPersist() ? getPersistedInt(this.defaultValue) : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentValue = (Integer) defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMax(int max) {
|
||||||
|
this.maxValue = max;
|
||||||
|
}
|
||||||
|
public int getMax() {
|
||||||
|
return this.maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(int progress) {
|
||||||
|
this.currentValue = progress;
|
||||||
|
if (seekBar != null) {
|
||||||
|
seekBar.setProgress(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int getProgress() {
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showDialog(Bundle state) {
|
||||||
|
super.showDialog(state);
|
||||||
|
|
||||||
|
Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
|
positiveButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (shouldPersist()) {
|
||||||
|
currentValue = seekBar.getProgress();
|
||||||
|
persistInt(seekBar.getProgress());
|
||||||
|
callChangeListener(Integer.valueOf(seekBar.getProgress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
((AlertDialog) getDialog()).dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.limelight.preferences;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import com.limelight.R;
|
||||||
|
|
||||||
|
public class StreamSettings extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_stream_settings);
|
||||||
|
getFragmentManager().beginTransaction().replace(
|
||||||
|
R.id.stream_settings, new SettingsFragment()
|
||||||
|
).commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SettingsFragment extends PreferenceFragment {
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
|
||||||
|
// Add a listener to the FPS and resolution preference
|
||||||
|
// so the bitrate can be auto-adjusted
|
||||||
|
Preference pref = findPreference(PreferenceConfiguration.RES_FPS_PREF_STRING);
|
||||||
|
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
|
||||||
|
String valueStr = (String) newValue;
|
||||||
|
|
||||||
|
// Write the new bitrate value
|
||||||
|
prefs.edit()
|
||||||
|
.putInt(PreferenceConfiguration.BITRATE_PREF_STRING,
|
||||||
|
PreferenceConfiguration.getDefaultBitrate(valueStr))
|
||||||
|
.apply();
|
||||||
|
|
||||||
|
// Allow the original preference change to take place
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -13,7 +13,7 @@ public class Dialog implements Runnable {
|
|||||||
|
|
||||||
private AlertDialog alert;
|
private AlertDialog alert;
|
||||||
|
|
||||||
private static ArrayList<Dialog> rundownDialogs = new ArrayList<Dialog>();
|
private static final ArrayList<Dialog> rundownDialogs = new ArrayList<Dialog>();
|
||||||
|
|
||||||
public Dialog(Activity activity, String title, String message, boolean endAfterDismiss)
|
public Dialog(Activity activity, String title, String message, boolean endAfterDismiss)
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ public class Dialog implements Runnable {
|
|||||||
alert.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
|
alert.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
synchronized (rundownDialogs) {
|
synchronized (rundownDialogs) {
|
||||||
rundownDialogs.remove(this);
|
rundownDialogs.remove(Dialog.this);
|
||||||
alert.dismiss();
|
alert.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
+1
-1
@@ -14,7 +14,7 @@ public class SpinnerDialog implements Runnable,OnCancelListener {
|
|||||||
private ProgressDialog progress;
|
private ProgressDialog progress;
|
||||||
private boolean finish;
|
private boolean finish;
|
||||||
|
|
||||||
private static ArrayList<SpinnerDialog> rundownDialogs = new ArrayList<SpinnerDialog>();
|
private static final ArrayList<SpinnerDialog> rundownDialogs = new ArrayList<SpinnerDialog>();
|
||||||
|
|
||||||
public SpinnerDialog(Activity activity, String title, String message, boolean finish)
|
public SpinnerDialog(Activity activity, String title, String message, boolean finish)
|
||||||
{
|
{
|
||||||
File renamed without changes.
File renamed without changes.
@@ -8,5 +8,6 @@ LOCAL_PATH := $(MY_LOCAL_PATH)
|
|||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := evdev_reader
|
LOCAL_MODULE := evdev_reader
|
||||||
LOCAL_SRC_FILES := evdev_reader.c
|
LOCAL_SRC_FILES := evdev_reader.c
|
||||||
|
LOCAL_LDLIBS := -llog
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_open(JNIEnv *env, jobject this, jstring absolutePath) {
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
path = (*env)->GetStringUTFChars(env, absolutePath, NULL);
|
||||||
|
|
||||||
|
return open(path, O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_grab(JNIEnv *env, jobject this, jint fd) {
|
||||||
|
return ioctl(fd, EVIOCGRAB, 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_ungrab(JNIEnv *env, jobject this, jint fd) {
|
||||||
|
return ioctl(fd, EVIOCGRAB, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// has*() and friends are based on Android's EventHub.cpp
|
||||||
|
|
||||||
|
#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_hasRelAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
|
||||||
|
unsigned char relBitmask[(REL_MAX + 1) / 8];
|
||||||
|
|
||||||
|
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBitmask)), relBitmask);
|
||||||
|
|
||||||
|
return test_bit(axis, relBitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_hasAbsAxis(JNIEnv *env, jobject this, jint fd, jshort axis) {
|
||||||
|
unsigned char absBitmask[(ABS_MAX + 1) / 8];
|
||||||
|
|
||||||
|
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBitmask)), absBitmask);
|
||||||
|
|
||||||
|
return test_bit(axis, absBitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_hasKey(JNIEnv *env, jobject this, jint fd, jshort key) {
|
||||||
|
unsigned char keyBitmask[(KEY_MAX + 1) / 8];
|
||||||
|
|
||||||
|
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBitmask)), keyBitmask);
|
||||||
|
|
||||||
|
return test_bit(key, keyBitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_read(JNIEnv *env, jobject this, jint fd, jbyteArray buffer) {
|
||||||
|
jint ret;
|
||||||
|
jbyte *data;
|
||||||
|
int pollres;
|
||||||
|
struct pollfd pollinfo;
|
||||||
|
|
||||||
|
data = (*env)->GetByteArrayElements(env, buffer, NULL);
|
||||||
|
if (data == NULL) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "EvdevReader",
|
||||||
|
"Failed to get byte array");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Unwait every 250 ms to return to caller if the fd is closed
|
||||||
|
pollinfo.fd = fd;
|
||||||
|
pollinfo.events = POLLIN;
|
||||||
|
pollinfo.revents = 0;
|
||||||
|
pollres = poll(&pollinfo, 1, 250);
|
||||||
|
}
|
||||||
|
while (pollres == 0);
|
||||||
|
|
||||||
|
if (pollres > 0 && (pollinfo.revents & POLLIN)) {
|
||||||
|
// We'll have data available now
|
||||||
|
ret = read(fd, data, sizeof(struct input_event));
|
||||||
|
if (ret < 0) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "EvdevReader",
|
||||||
|
"read() failed: %d", errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// There must have been a failure
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
if (pollres < 0) {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "EvdevReader",
|
||||||
|
"poll() failed: %d", errno);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "EvdevReader",
|
||||||
|
"Unexpected revents: %d", pollinfo.revents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->ReleaseByteArrayElements(env, buffer, data, 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_limelight_binding_input_evdev_EvdevReader_close(JNIEnv *env, jobject this, jint fd) {
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 557 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user