Order files

This commit is contained in:
Andros Fenollosa
2016-11-12 12:27:08 +01:00
parent 73cec1f153
commit 892d89c7f1
1814 changed files with 85 additions and 80 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
#!/bin/sh
# Copyright 2005-2007, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=sdkmanager.jar
frameworkdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
# Check args.
if [ debug = "$1" ]; then
# add this in for debugging
java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
shift 1
else
java_debug=
fi
java_cmd="java"
# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
if [ `uname` = "Darwin" ]; then
os_opts="-XstartOnFirstThread"
else
os_opts=
fi
if [ `uname` = "Linux" ]; then
export GDK_NATIVE_WINDOWS=true
fi
if [ "$OSTYPE" = "cygwin" ] ; then
jarpath=`cygpath -w "$frameworkdir/$jarfile"`
jarpath="$jarpath;"`cygpath -w "$frameworkdir/swtmenubar.jar"`
progdir=`cygpath -w "$progdir"`
else
jarpath="$frameworkdir/$jarfile:$frameworkdir/swtmenubar.jar"
fi
# Get the current content of java.ext.dirs so that we can add to it instead of replacing
javaExtDirs=`"${java_cmd}" -jar "${frameworkdir}/archquery.jar" java.ext.dirs`
# Figure out the path to the swt.jar for the current architecture.
# if ANDROID_SWT is defined, then just use this.
# else, if running in the Android source tree, then look for the correct swt folder in prebuilt
# else, look for the correct swt folder in the SDK under tools/lib/
swtpath=""
if [ -n "$ANDROID_SWT" ]; then
swtpath="$ANDROID_SWT"
else
vmarch=`"${java_cmd}" -jar "${frameworkdir}/archquery.jar"`
if [ -n "$ANDROID_BUILD_TOP" ]; then
osname=`uname -s | tr A-Z a-z`
swtpath="${ANDROID_BUILD_TOP}/prebuilts/tools/${osname}-${vmarch}/swt"
else
swtpath="${frameworkdir}/${vmarch}"
fi
fi
if [ ! -d "$swtpath" ]; then
echo "SWT folder '${swtpath}' does not exist."
echo "Please export ANDROID_SWT to point to the folder containing swt.jar for your platform."
exit 1
fi
# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
exec "$java_cmd" \
-Xmx256M $os_opts $java_debug \
-Dcom.android.sdkmanager.toolsdir="$progdir" \
-classpath "$jarpath:$swtpath/swt.jar" \
com.android.sdkmanager.Main "$@"

View File

@ -0,0 +1,190 @@
Copyright (c) 2005-2014, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="android_rules" default="debug">
<!--
This build file is imported by the project build file. It contains
all the targets and tasks necessary to build Android projects, be they
regular projects, library projects, or test projects.
At the beginning of the file is a list of properties that can be overridden
by adding them to your ant.properties (properties are immutable, so their
first definition sticks and is never changed).
Follows:
- custom task definitions,
- more properties (do not override those unless the whole build system is modified).
- macros used throughout the build,
- base build targets,
- debug-specific build targets,
- release-specific build targets,
- instrument-specific build targets,
- test project-specific build targets,
- install targets,
- help target
-->
<!-- ******************************************************* -->
<!-- **************** Overridable Properties *************** -->
<!-- ******************************************************* -->
<!-- You can override these values in your build.xml or ant.properties.
Overriding any other properties may result in broken build. -->
<!-- Tells adb which device to target. You can change this from the command line
by invoking "ant -Dadb.device.arg=-d" for device "ant -Dadb.device.arg=-e" for
the emulator. -->
<property name="adb.device.arg" value="" />
<!-- filename only of the output file. Cannot be a path -->
<property name="out.filename" value="${ant.project.name}.jar" />
<!-- compilation options -->
<property name="java.encoding" value="UTF-8" />
<property name="java.target" value="1.5" />
<property name="java.source" value="1.5" />
<property name="java.compilerargs" value="" />
<!-- Verbosity -->
<property name="verbose" value="false" />
<!-- ******************************************************* -->
<!-- ********************* Custom Tasks ******************** -->
<!-- ******************************************************* -->
<!-- jar file from where the tasks are loaded -->
<path id="android.antlibs">
<pathelement path="${sdk.dir}/tools/lib/ant-tasks.jar" />
</path>
<!-- Custom tasks -->
<taskdef resource="anttasks.properties" classpathref="android.antlibs" />
<!-- Emma configuration -->
<property name="emma.dir" value="${sdk.dir}/tools/lib" />
<path id="emma.lib">
<pathelement location="${emma.dir}/emma.jar" />
<pathelement location="${emma.dir}/emma_ant.jar" />
</path>
<taskdef resource="emma_ant.properties" classpathref="emma.lib" />
<!-- End of emma configuration -->
<!-- ******************************************************* -->
<!-- ******************* Other Properties ****************** -->
<!-- ******************************************************* -->
<!-- overriding these properties may break the build
unless the whole file is updated -->
<!-- Input directories -->
<property name="source.dir" value="src" />
<property name="source.absolute.dir" location="${source.dir}" />
<property name="jar.libs.dir" value="libs" />
<property name="jar.libs.absolute.dir" location="${jar.libs.dir}" />
<!-- Output directories -->
<property name="out.dir" value="bin" />
<property name="out.absolute.dir" location="${out.dir}" />
<property name="out.classes.absolute.dir" location="${out.dir}/classes" />
<property name="out.file" value="${out.absolute.dir}/${out.filename}" />
<!-- tools location -->
<property name="android.tools.dir" location="${sdk.dir}/tools" />
<property name="android.platform.tools.dir" location="${sdk.dir}/platform-tools" />
<condition property="exe" value=".exe" else=""><os family="windows" /></condition>
<condition property="bat" value=".bat" else=""><os family="windows" /></condition>
<property name="adb" location="${android.platform.tools.dir}/adb${exe}" />
<!-- Intermediate files -->
<property name="dex.file.name" value="classes.dex" />
<property name="intermediate.dex.file" location="${out.absolute.dir}/${dex.file.name}" />
<property name="resource.package.file.name" value="${ant.project.name}.ap_" />
<!-- whether we need to fork javac.
This is only needed on Windows when running Java < 7 -->
<condition else="false" property="need.javac.fork">
<and>
<matches pattern="1\.[56]" string="${java.specification.version}"/>
<not>
<os family="unix"/>
</not>
</and>
</condition>
<macrodef name="run-tests-helper">
<attribute name="emma.enabled" default="false" />
<element name="extra-instrument-args" optional="yes" />
<sequential>
<echo level="info">Running tests ...</echo>
<exec executable="${adb}" failonerror="true">
<arg line="${adb.device.arg}" />
<arg value="shell" />
<arg value="am" />
<arg value="instrument" />
<arg value="-w" />
<arg value="-e" />
<arg value="coverage" />
<arg value="@{emma.enabled}" />
<extra-instrument-args />
<arg value="${project.app.package}/${test.runner}" />
</exec>
</sequential>
</macrodef>
<!-- ******************************************************* -->
<!-- ******************** Build Targets ******************** -->
<!-- ******************************************************* -->
<!-- Basic Ant + SDK check -->
<target name="-check-env">
<checkenv />
</target>
<!-- empty default pre-clean target. Create a similar target in
your build.xml and it'll be called instead of this one. -->
<target name="-pre-clean"/>
<!-- clean target -->
<target name="clean" depends="-check-env, -pre-clean"
description="Removes output files created by other targets.">
<delete dir="${out.absolute.dir}" verbose="${verbose}" />
</target>
<!-- Pre build setup -->
<target name="-build-setup" depends="-check-env">
<getbuildtools name="android.build.tools.dir" />
<property name="dx" location="${android.build.tools.dir}/dx${bat}" />
<echo level="info">Resolving Build Target for ${ant.project.name}...</echo>
<!-- load project properties, resolve Android target, library dependencies
and set some properties with the results.
All property names are passed as parameters ending in -Out -->
<getuitarget compileClassPathOut="project.target.class.path" />
<echo level="info">----------</echo>
<echo level="info">Creating output directories if needed...</echo>
<mkdir dir="${out.absolute.dir}" />
<mkdir dir="${out.classes.absolute.dir}" />
</target>
<!-- empty default pre-compile target. Create a similar target in
your build.xml and it'll be called instead of this one. -->
<target name="-pre-compile"/>
<!-- Compiles this project's .java files into .class files. -->
<target name="compile" depends="-build-setup, -pre-compile">
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
fork="${need.javac.fork}">
<src path="${source.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
</javac>
</target>
<!-- empty default post-compile target. Create a similar target in
your build.xml and it'll be called instead of this one. -->
<target name="-post-compile"/>
<!-- Converts this project's .class files into .dex files -->
<target name="-dex" depends="compile, -post-compile">
<dex executable="${dx}"
output="${intermediate.dex.file}"
nolocals="@{nolocals}"
verbose="${verbose}">
<path path="${out.classes.absolute.dir}"/>
</dex>
</target>
<!-- empty default post-dex target. Create a similar target in
your build.xml and it'll be called instead of this one. -->
<target name="-post-dex"/>
<target name="-jar" depends="-dex, -post-dex" >
<jar destfile="${out.file}">
<fileset file="${intermediate.dex.file}" />
</jar>
</target>
<!-- empty default post-jar target. Create a similar target in
your build.xml and it'll be called instead of this one. -->
<target name="-post-jar"/>
<target name="build" depends="-jar, -post-jar" />
<target name="install" description="Install the test package">
<exec executable="${adb}" failonerror="true">
<arg line="${adb.device.arg}" />
<arg value="push" />
<arg value="${out.file}" />
<arg value="/data/local/tmp" />
</exec>
</target>
<target name="test" description="Runs tests">
<!-- todo: fix this -->
<fail message="Launching tests from Ant not supported yet" />
<exec executable="${adb}" failonerror="true">
<arg line="${adb.device.arg}" />
<arg value="shell" />
<arg value="uiautomator" />
<arg value="runtest" />
<arg value="${out.filename}" />
<arg value="-e" />
<arg value="class" />
<arg value="com.android.uiautomator.samples.skeleton.DemoTestCase" />
</exec>
</target>
<target name="help">
<!-- displays starts at col 13
|13 80| -->
<echo>Android Ant Build. Available targets:</echo>
<echo> help: Displays this help.</echo>
<echo> clean: Removes output files created by other targets.</echo>
<echo> build: Builds the test library.</echo>
<echo> install: Installs the library on a connected device or</echo>
<echo> emulator.</echo>
<echo> test: Runs the tests.</echo>
<echo></echo>
<echo>It is possible to mix targets. For instance:</echo>
<echo> ant build install test</echo>
<echo>This will build, install and run the test in a single command.</echo>
</target>
</project>

View File

@ -0,0 +1,8 @@
<?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 kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SdkControllerApp</name>
<comment></comment>
<projects>
<project>SdkControllerLib</project>
</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>

View File

@ -0,0 +1,12 @@
#Fri Apr 06 22:06:54 PDT 2012
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

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tools.sdkcontroller"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".activities.MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.SensorActivity"
android:launchMode="singleInstance"
android:windowSoftInputMode="stateUnchanged" android:label="@string/sensors_activity_title"/>
<activity
android:name=".activities.MultiTouchActivity"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:theme="@style/Theme.MultiTouch"
android:windowSoftInputMode="stateHidden"/>
<service
android:name=".service.ControllerService"
android:description="@string/service_description"
android:icon="@drawable/ic_launcher" />
</application>
</manifest>

View File

@ -0,0 +1,85 @@
Implementation Details for SdkControllerApp
-------------------------------------------
---- 2012-03-22
App is in the namespace com.android.tools.sdkcontroller.
This is an app that has a minSdkVersion of 7 (Eclair)
and a targetSdkVersion of 15 (ICS). The target version
means the app is forbidden under ICS from doing any network
communication on its main thread.
The overall design:
- A background service is started by the app. It handles the connection
to the emulator and provides a number of "handlers". Handlers can be
though as being separate tasks that the user wants to achieve, for example
sending sensor data, sending multi-touch events, receiving screen updates,
sending a camera feed, etc.
- All the handlers are started when the service starts and shutdown with it.
They basically stay there as long as the app is running, and its up to the
handler to deal with emulator connections starts/stopping. Some handlers
will run in the background (e.g. sending sensor data) whereas other might
need an activity to connect to them first.
- The app has a number of activities which connect to existing handlers.
Another way to see it is that the app handles a number of tasks which are
composed of a background handler (that consumes data form the emulator and
can send data to the emulator) and an optional activity for UI (that displays
or controls the handler's state.)
Here's a quick overview of the classes in the application:
The main UI is in activities.MainActivity.
There are 2 tasks activities: SensorActivity and MultiTouchActivity.
These all derive from BaseBindingActivity which provides a few convenient common features
- in onResume this will bind to the service, creating and starting it if necessary.
- in onPause, this will unbind from the service, but does not stop it.
Note however that due to the asynchronous nature of the bind operation, the activity
must not attempt to use the service from onResume. Instead there are 2 callbacks to use:
- onServiceConnected when the bind succeeded.
- onServiceDisconnected as the reverse operation.
When the activity is connected to the service, it can then use getServiceBinder()
to get an interface to talk to the service.
In the other direction, the activity provides a listener for the service to notify
the application: ControllerListener createControllerListener().
The activity can then access the handler:
handler = getServiceBinder().getHandler(HandlerType....)
and then the activity wants to provide a listener to get notified by the handler:
handler.addUiHandler(new android.os.Handler(this));
The emulator connection is separated in the "lib" subpackage:
- EmulatorConnection abstracts a connection to the emulator.
- Object is first created by giving a non-null EmulatorListener.
- then connect(port) is called to initiate the connection.
- The EmulatorConnection is always created in SYNC mode.
- EmulatorListener is a callback: the emulator connection uses it to indicate
when the connection is actually connected or disconnected.
In the end we have the following workflow describing who controls what (-->):
Emulator
^ ^
| | EmuCnxHandler
sendEventToEmulator| | (EmulatorListener)
| +-------------+
| |
handlers.BaseHandler | v
Activity ------------------------> Handler <---- ControllerService
UI <------------------------ | ^
android.os.Handler | |
| ^ | |
| | ControllerListener | |
| +--------------------------------------------------+ |
+-----------------------------------------------------------+
ControllerBinder
----

View File

@ -0,0 +1,190 @@
Copyright (c) 2005-2014, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,42 @@
<html>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
body { color: white; background-color: black }
a:link { color: #33B5E5; /*blue*/ }
a:visited { color: #99CC00; /*green*/ }
a:hover { color: #FFBB33; /*yellow*/; }
</style>
</head>
<body>
<hr/>
<b>SdkController</b> is used to send sensor data from an actual device to an emulator. <p/>
To use it, do the following: <br/>
<ol>
<li>Connect your device to your computer via USB. Make sure to enable <i>USB Debugging</i> in <i>Settings &gt; Developer Options</i>. </li>
<li>Start this application on your device. </li>
<li>On the computer in a shell, run: <br/><i>adb forward tcp:1970 localabstract:android.sdk.controller</i> </li>
<li>Finally <b>run an emulator</b> with an AVD targetting <b>API 15</b>.
Multi-touch emulation must be explicitly enabled in emulator either by setting "Touch screen type" property to "multi-touch" in AVD Manager,
or by starting the emulator with "-screen multi-touch" option.</li>
</ol>
<a href="https://sites.google.com/a/android.com/tools/recent/sensoremulation">Read more.</a>
</body>
</html>

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
# Project target.
target=android-15

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TableRow
android:id="@+id/row1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_sample_rate"
android:gravity="right"
android:layout_marginRight="8dp"
/>
<EditText
android:id="@+id/textSampleRate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="4"
android:gravity="right"
android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen|"
android:inputType="number"
android:text="@string/sensors_default_sample_rate"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_hz_per_sensor" />
</TableRow>
<TableRow
android:id="@+id/row2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignBaseline="@+id/row1"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_marginRight="8dp"
android:text="@string/sensors_actual_rate" />
<TextView
android:id="@+id/textActualRate"
android:gravity="right"
android:text="--"
tools:ignore="HardcodedText"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_hz_average" />
<!-- This 1-pixel wide invisible edit field makes sure that row1 and
row2 have the same height and an equal baseline. This works around
the fact that row2's attribute layout_alignBaseline=row1 is in fact
ignored. -->
<EditText
android:layout_width="1px"
android:layout_height="wrap_content"
android:imeOptions="actionNone"
android:focusable="false"
android:focusableInTouchMode="false"
android:visibility="invisible"
/>
</TableRow>
</RelativeLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TableRow>
</TableLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/sensors_top_description" />
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<TableLayout
android:id="@+id/tableLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:saveEnabled="false" />
</ScrollView>
<!-- Placeholder status text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAppearance="?android:attr/textAppearanceSmall" />
<!-- Placeholder error text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textError"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:background="#F00F"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFF0" />
</LinearLayout>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp" >
<ToggleButton
android:id="@+id/toggleService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
/>
<TextView
android:id="@+id/labelService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/toggleService"
android:layout_alignParentLeft="true"
android:layout_marginTop="20dp"
android:text="@string/main_label_service"
android:textAppearance="?android:attr/textAppearanceLarge" />
<!-- Placeholder status text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/labelService"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@+id/labelService"
android:text="[status]"
android:textAppearance="?android:attr/textAppearanceLarge"
tools:ignore="HardcodedText" />
<!-- Placeholder error text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/toggleService"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="#F00F"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="[service errors]"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#FFF0"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/labelButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textError"
android:layout_marginTop="16dp"
android:text="@string/main_label_buttons"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/btnOpenMultitouch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/labelButtons"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:text="@string/main_btn_open_multitouch" />
<Button
android:id="@+id/btnOpenSensors"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btnOpenMultitouch"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:text="@string/main_btn_open_sensors" />
<WebView
android:id="@+id/webIntro"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btnOpenSensors"
android:layout_marginTop="16dp"
android:background="@null"
/>
</RelativeLayout>
</ScrollView>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.android.tools.sdkcontroller.views.MultiTouchView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<!-- Placeholder status text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
<!-- Placeholder error text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textError"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/textStatus"
android:gravity="center_horizontal"
android:background="#F00F"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFF0" />
</RelativeLayout>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<!-- One row per sensor added to the TableLayout from layout/sensors.xml -->
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<CheckBox
android:id="@+id/row_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:saveEnabled="false"
android:text="Some CheckBox"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/row_textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmall" />
</TableRow>

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_sample_rate"
android:gravity="right"
android:layout_marginRight="8dp"
/>
<EditText
android:id="@+id/textSampleRate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="4"
android:gravity="right"
android:imeOptions="actionNone|flagNoExtractUi|flagNoFullscreen|"
android:inputType="number"
android:text="@string/sensors_default_sample_rate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_hz_per_sensor" />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_marginRight="8dp"
android:text="@string/sensors_actual_rate" />
<TextView
android:id="@+id/textActualRate"
android:gravity="right"
android:text="--"
tools:ignore="HardcodedText"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sensors_hz_average" />
</TableRow>
</TableLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/sensors_top_description" />
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<TableLayout
android:id="@+id/tableLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:saveEnabled="false" />
</ScrollView>
<!-- Placeholder status text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAppearance="?android:attr/textAppearanceSmall" />
<!-- Placeholder error text. Becomes visibility=gone when empty. -->
<TextView
android:id="@+id/textError"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:background="#F00F"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFF0" />
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<resources>
<style name="Theme.MultiTouch" parent="android:Theme.Holo.NoActionBar.Fullscreen">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<resources>
<!-- Strings for manifest. -->
<string name="app_name">SDK Controller</string>
<string name="service_description">Background service for SDK Controller</string>
<!-- Strings for service. -->
<string name="service_notif_title">SDK Controller is running</string>
<!-- Strings for layout/main -->
<string name="main_label_service">Service:</string>
<string name="main_label_buttons">What you can do:</string>
<string name="main_btn_open_multitouch">Control Multi-touch</string>
<string name="main_btn_open_sensors">Control Sensors</string>
<string name="main_service_status_connected">Emulator Connected</string>
<string name="main_service_status_disconnected">Emulator Connected</string>
<!-- Strings for layout/sensors -->
<string name="sensors_activity_title">SDK Controller &gt; Sensors</string>
<string name="sensors_top_description">Available Sensors:</string>
<string name="sensors_sample_rate">Sample Rate</string>
<string name="sensors_hz_per_sensor">Hz per sensor</string>
<string name="sensors_actual_rate">Actual</string>
<string name="sensors_hz_average">Hz average</string>
<!-- Default sample rate for SensorsActivity UI.
Should match the default for SensorsHandler.mUpdateTargetMs. -->
<string name="sensors_default_sample_rate">20</string>
</resources>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
-->
<resources>
<style name="Theme.MultiTouch" parent="android:Theme.NoTitleBar.Fullscreen">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>

View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.activities;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import com.android.tools.sdkcontroller.service.ControllerService;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener;
/**
* Base activity class that knows how to bind and unbind from the
* {@link ControllerService}.
*/
public abstract class BaseBindingActivity extends Activity {
public static String TAG = BaseBindingActivity.class.getSimpleName();
private static boolean DEBUG = true;
private ServiceConnection mServiceConnection;
private ControllerBinder mServiceBinder;
/**
* Returns the binder. Activities can use that to query the controller service.
* @return An existing {@link ControllerBinder}.
* The binder is only valid between calls {@link #onServiceConnected()} and
* {@link #onServiceDisconnected()}. Returns null when not valid.
*/
public ControllerBinder getServiceBinder() {
return mServiceBinder;
}
/**
* Called when the activity resumes.
* This automatically binds to the service, starting it as needed.
* <p/>
* Since on resume we automatically bind to the service, the {@link ServiceConnection}
* will is restored and {@link #onServiceConnected()} is called as necessary.
* Derived classes that need to initialize anything that is related to the service
* (e.g. getting their handler) should thus do so in {@link #onServiceConnected()} and
* <em>not</em> in {@link #onResume()} -- since binding to the service is asynchronous
* there is <em>no</em> guarantee that {@link #getServiceBinder()} returns non-null
* when this call finishes.
*/
@Override
protected void onResume() {
super.onResume();
bindToService();
}
/**
* Called when the activity is paused.
* This automatically unbinds from the service but does not stop it.
*/
@Override
protected void onPause() {
super.onPause();
unbindFromService();
}
// ----------
/**
* Called when binding to the service to get the activity's {@link ControllerListener}.
* @return A new non-null {@link ControllerListener}.
*/
protected abstract ControllerListener createControllerListener();
/**
* Called by the service once the activity is connected (bound) to it.
* <p/>
* When this is called, {@link #getServiceBinder()} returns a non-null binder that
* can be used by the activity to control the service.
*/
protected abstract void onServiceConnected();
/**
* Called by the service when it is forcibly disconnected OR when we know
* we're unbinding the service.
* <p/>
* When this is called, {@link #getServiceBinder()} returns a null binder and
* the activity should stop using that binder and remove any reference to it.
*/
protected abstract void onServiceDisconnected();
/**
* Starts the service and binds to it.
*/
protected void bindToService() {
if (mServiceConnection == null) {
final ControllerListener listener = createControllerListener();
mServiceConnection = new ServiceConnection() {
/**
* Called when the service is connected.
* Allows us to retrieve the binder to talk to the service.
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.d(TAG, "Activity connected to service");
mServiceBinder = (ControllerBinder) service;
mServiceBinder.addControllerListener(listener);
BaseBindingActivity.this.onServiceConnected();
}
/**
* Called when the service got disconnected, e.g. because it crashed.
* This is <em>not</em> called when we unbind from the service.
*/
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.d(TAG, "Activity disconnected from service");
mServiceBinder = null;
BaseBindingActivity.this.onServiceDisconnected();
}
};
}
// Start service so that it doesn't stop when we unbind
if (DEBUG) Log.d(TAG, "start requested & bind service");
Intent service = new Intent(this, ControllerService.class);
startService(service);
bindService(service,
mServiceConnection,
Context.BIND_AUTO_CREATE);
}
/**
* Unbinds from the service but does not actually stop the service.
* This lets us have it run in the background even if this isn't the active activity.
*/
protected void unbindFromService() {
if (mServiceConnection != null) {
if (DEBUG) Log.d(TAG, "unbind service");
mServiceConnection.onServiceDisconnected(null /*name*/);
unbindService(mServiceConnection);
mServiceConnection = null;
}
}
}

View File

@ -0,0 +1,208 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.activities;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;
import com.android.tools.sdkcontroller.R;
import com.android.tools.sdkcontroller.service.ControllerService;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener;
/**
* Main activity. It's the entry point for the application.
* It allows the user to start/stop the service and see it's current state and errors.
* It also has buttons to start either the sensor control activity or the multitouch activity.
*/
public class MainActivity extends BaseBindingActivity {
@SuppressWarnings("hiding")
public static String TAG = MainActivity.class.getSimpleName();
private static boolean DEBUG = true;
private Button mBtnOpenMultitouch;
private Button mBtnOpenSensors;
private ToggleButton mBtnToggleService;
private TextView mTextError;
private TextView mTextStatus;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTextError = (TextView) findViewById(R.id.textError);
mTextStatus = (TextView) findViewById(R.id.textStatus);
WebView wv = (WebView) findViewById(R.id.webIntro);
wv.loadUrl("file:///android_asset/intro_help.html");
setupButtons();
}
@Override
protected void onResume() {
// BaseBindingActivity.onResume will bind to the service.
super.onResume();
updateError();
}
@Override
protected void onPause() {
// BaseBindingActivity.onResume will unbind from (but not stop) the service.
super.onPause();
}
@Override
public void onBackPressed() {
if (DEBUG) Log.d(TAG, "onBackPressed");
// If back is pressed, we stop the service automatically.
// It seems more intuitive that way.
stopService();
super.onBackPressed();
}
// ----------
@Override
protected void onServiceConnected() {
updateButtons();
}
@Override
protected void onServiceDisconnected() {
updateButtons();
}
@Override
protected ControllerListener createControllerListener() {
return new MainControllerListener();
}
// ----------
private void setupButtons() {
mBtnOpenMultitouch = (Button) findViewById(R.id.btnOpenMultitouch);
mBtnOpenSensors = (Button) findViewById(R.id.btnOpenSensors);
mBtnOpenMultitouch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Open the multi-touch activity.
Intent i = new Intent(MainActivity.this, MultiTouchActivity.class);
startActivity(i);
}
});
mBtnOpenSensors.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Open the sensor activity.
Intent i = new Intent(MainActivity.this, SensorActivity.class);
startActivity(i);
}
});
mBtnToggleService = (ToggleButton) findViewById(R.id.toggleService);
// set initial state
updateButtons();
mBtnToggleService.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
bindToService();
updateButtons();
} else {
stopService();
updateButtons();
}
}
});
}
private void updateButtons() {
boolean running = ControllerService.isServiceIsRunning();
mBtnOpenMultitouch.setEnabled(running);
mBtnOpenSensors.setEnabled(running);
mBtnToggleService.setChecked(running);
}
/**
* Unbind and then actually stops the service.
*/
private void stopService() {
Intent service = new Intent(this, ControllerService.class);
unbindFromService();
if (DEBUG) Log.d(TAG, "stop service requested");
stopService(service);
}
private class MainControllerListener implements ControllerListener {
@Override
public void onErrorChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
updateError();
}
});
}
@Override
public void onStatusChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
updateStatus();
}
});
}
}
private void updateError() {
ControllerBinder binder = getServiceBinder();
String error = binder == null ? "" : binder.getServiceError();
if (error == null) {
error = "";
}
mTextError.setVisibility(error.length() == 0 ? View.GONE : View.VISIBLE);
mTextError.setText(error);
}
private void updateStatus() {
ControllerBinder binder = getServiceBinder();
boolean connected = binder == null ? false : binder.isEmuConnected();
mTextStatus.setText(
getText(connected ? R.string.main_service_status_connected
: R.string.main_service_status_disconnected));
}
}

View File

@ -0,0 +1,388 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.activities;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
import com.android.tools.sdkcontroller.R;
import com.android.tools.sdkcontroller.handlers.MultiTouchChannel;
import com.android.tools.sdkcontroller.lib.Channel;
import com.android.tools.sdkcontroller.lib.ProtocolConstants;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener;
import com.android.tools.sdkcontroller.utils.ApiHelper;
import com.android.tools.sdkcontroller.views.MultiTouchView;
/**
* Activity that controls and displays the {@link MultiTouchChannel}.
*/
public class MultiTouchActivity extends BaseBindingActivity
implements android.os.Handler.Callback {
@SuppressWarnings("hiding")
private static String TAG = MultiTouchActivity.class.getSimpleName();
private static boolean DEBUG = true;
private volatile MultiTouchChannel mHandler;
private TextView mTextError;
private TextView mTextStatus;
private MultiTouchView mImageView;
/** Width of the emulator's display. */
private int mEmulatorWidth = 0;
/** Height of the emulator's display. */
private int mEmulatorHeight = 0;
/** Bitmap storage. */
private int[] mColors;
private final TouchListener mTouchListener = new TouchListener();
private final android.os.Handler mUiHandler = new android.os.Handler(this);
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multitouch);
mImageView = (MultiTouchView) findViewById(R.id.imageView);
mTextError = (TextView) findViewById(R.id.textError);
mTextStatus = (TextView) findViewById(R.id.textStatus);
updateStatus("Waiting for connection");
ApiHelper ah = ApiHelper.get();
ah.View_setSystemUiVisibility(mImageView, View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
@Override
protected void onResume() {
if (DEBUG) Log.d(TAG, "onResume");
// BaseBindingActivity.onResume will bind to the service.
// Note: any initialization related to the service or the handler should
// go in onServiceConnected() since in this call the service may not be
// bound yet.
super.onResume();
updateError();
}
@Override
protected void onPause() {
if (DEBUG) Log.d(TAG, "onPause");
// BaseBindingActivity.onResume will unbind from (but not stop) the service.
super.onPause();
mImageView.setEnabled(false);
updateStatus("Paused");
}
// ----------
@Override
protected void onServiceConnected() {
if (DEBUG) Log.d(TAG, "onServiceConnected");
mHandler = (MultiTouchChannel) getServiceBinder().getChannel(Channel.MULTITOUCH_CHANNEL);
if (mHandler != null) {
mHandler.setViewSize(mImageView.getWidth(), mImageView.getHeight());
mHandler.addUiHandler(mUiHandler);
}
}
@Override
protected void onServiceDisconnected() {
if (DEBUG) Log.d(TAG, "onServiceDisconnected");
if (mHandler != null) {
mHandler.removeUiHandler(mUiHandler);
mHandler = null;
}
}
@Override
protected ControllerListener createControllerListener() {
return new MultiTouchControllerListener();
}
// ----------
private class MultiTouchControllerListener implements ControllerListener {
@Override
public void onErrorChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
updateError();
}
});
}
@Override
public void onStatusChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControllerBinder binder = getServiceBinder();
if (binder != null) {
boolean connected = binder.isEmuConnected();
mImageView.setEnabled(connected);
updateStatus(connected ? "Emulator connected" : "Emulator disconnected");
}
}
});
}
}
// ----------
/**
* Implements OnTouchListener interface that receives touch screen events,
* and reports them to the emulator application.
*/
class TouchListener implements OnTouchListener {
/**
* Touch screen event handler.
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
ByteBuffer bb = null;
final int action = event.getAction();
final int action_code = action & MotionEvent.ACTION_MASK;
final int action_pid_index = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
int msg_type = 0;
MultiTouchChannel h = mHandler;
// Build message for the emulator.
switch (action_code) {
case MotionEvent.ACTION_MOVE:
if (h != null) {
bb = ByteBuffer.allocate(
event.getPointerCount() * ProtocolConstants.MT_EVENT_ENTRY_SIZE);
bb.order(h.getEndian());
for (int n = 0; n < event.getPointerCount(); n++) {
mImageView.constructEventMessage(bb, event, n);
}
msg_type = ProtocolConstants.MT_MOVE;
}
break;
case MotionEvent.ACTION_DOWN:
if (h != null) {
bb = ByteBuffer.allocate(ProtocolConstants.MT_EVENT_ENTRY_SIZE);
bb.order(h.getEndian());
mImageView.constructEventMessage(bb, event, action_pid_index);
msg_type = ProtocolConstants.MT_FISRT_DOWN;
}
break;
case MotionEvent.ACTION_UP:
if (h != null) {
bb = ByteBuffer.allocate(ProtocolConstants.MT_EVENT_ENTRY_SIZE);
bb.order(h.getEndian());
bb.putInt(event.getPointerId(action_pid_index));
msg_type = ProtocolConstants.MT_LAST_UP;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (h != null) {
bb = ByteBuffer.allocate(ProtocolConstants.MT_EVENT_ENTRY_SIZE);
bb.order(h.getEndian());
mImageView.constructEventMessage(bb, event, action_pid_index);
msg_type = ProtocolConstants.MT_POINTER_DOWN;
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (h != null) {
bb = ByteBuffer.allocate(ProtocolConstants.MT_EVENT_ENTRY_SIZE);
bb.order(h.getEndian());
bb.putInt(event.getPointerId(action_pid_index));
msg_type = ProtocolConstants.MT_POINTER_UP;
}
break;
default:
Log.w(TAG, "Unknown action type: " + action_code);
return true;
}
if (DEBUG && bb != null) Log.d(TAG, bb.toString());
if (h != null && bb != null) {
h.postMessage(msg_type, bb);
}
return true;
}
} // TouchListener
/** Implementation of Handler.Callback */
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MultiTouchChannel.EVENT_MT_START:
MultiTouchChannel h = mHandler;
if (h != null) {
mImageView.setEnabled(true);
mImageView.setOnTouchListener(mTouchListener);
}
break;
case MultiTouchChannel.EVENT_MT_STOP:
mImageView.setOnTouchListener(null);
break;
case MultiTouchChannel.EVENT_FRAME_BUFFER:
onFrameBuffer(((ByteBuffer) msg.obj).array());
mHandler.postMessage(ProtocolConstants.MT_FB_HANDLED, (byte[]) null);
break;
}
return true; // we consumed this message
}
/**
* Called when a BLOB query is received from the emulator.
* <p/>
* This query is used to deliver framebuffer updates in the emulator. The
* blob contains an update header, followed by the bitmap containing updated
* rectangle. The header is defined as MTFrameHeader structure in
* external/qemu/android/multitouch-port.h
* <p/>
* NOTE: This method is called from the I/O loop, so all communication with
* the emulator will be "on hold" until this method returns.
*
* TODO ===> CHECK that we can consume that array from a different thread than the producer's.
* E.g. does the produce reuse the same array or does it generate a new one each time?
*
* @param array contains BLOB data for the query.
*/
private void onFrameBuffer(byte[] array) {
final ByteBuffer bb = ByteBuffer.wrap(array);
bb.order(ByteOrder.LITTLE_ENDIAN);
// Read frame header.
final int header_size = bb.getInt();
final int disp_width = bb.getInt();
final int disp_height = bb.getInt();
final int x = bb.getInt();
final int y = bb.getInt();
final int w = bb.getInt();
final int h = bb.getInt();
final int bpl = bb.getInt();
final int bpp = bb.getInt();
final int format = bb.getInt();
// Update application display.
updateDisplay(disp_width, disp_height);
if (format == ProtocolConstants.MT_FRAME_JPEG) {
/*
* Framebuffer is in JPEG format.
*/
final ByteArrayInputStream jpg = new ByteArrayInputStream(bb.array());
// Advance input stream to JPEG image.
jpg.skip(header_size);
// Draw the image.
mImageView.drawJpeg(x, y, w, h, jpg);
} else {
/*
* Framebuffer is in a raw RGB format.
*/
final int pixel_num = h * w;
// Advance stream to the beginning of framebuffer data.
bb.position(header_size);
// Make sure that mColors is large enough to contain the
// update bitmap.
if (mColors == null || mColors.length < pixel_num) {
mColors = new int[pixel_num];
}
// Convert the blob bitmap into bitmap that we will display.
if (format == ProtocolConstants.MT_FRAME_RGB565) {
for (int n = 0; n < pixel_num; n++) {
// Blob bitmap is in RGB565 format.
final int color = bb.getShort();
final int r = ((color & 0xf800) >> 8) | ((color & 0xf800) >> 14);
final int g = ((color & 0x7e0) >> 3) | ((color & 0x7e0) >> 9);
final int b = ((color & 0x1f) << 3) | ((color & 0x1f) >> 2);
mColors[n] = Color.rgb(r, g, b);
}
} else if (format == ProtocolConstants.MT_FRAME_RGB888) {
for (int n = 0; n < pixel_num; n++) {
// Blob bitmap is in RGB565 format.
final int r = bb.getChar();
final int g = bb.getChar();
final int b = bb.getChar();
mColors[n] = Color.rgb(r, g, b);
}
} else {
Log.w(TAG, "Invalid framebuffer format: " + format);
return;
}
mImageView.drawBitmap(x, y, w, h, mColors);
}
}
/**
* Updates application's screen accordingly to the emulator screen.
*
* @param e_width Width of the emulator screen.
* @param e_height Height of the emulator screen.
*/
private void updateDisplay(int e_width, int e_height) {
if (e_width != mEmulatorWidth || e_height != mEmulatorHeight) {
mEmulatorWidth = e_width;
mEmulatorHeight = e_height;
boolean rotateDisplay = false;
int w = mImageView.getWidth();
int h = mImageView.getHeight();
if (w > h != e_width > e_height) {
rotateDisplay = true;
int tmp = w;
w = h;
h = tmp;
}
float dx = (float) w / (float) e_width;
float dy = (float) h / (float) e_height;
mImageView.setDxDy(dx, dy, rotateDisplay);
if (DEBUG) Log.d(TAG, "Dispay updated: " + e_width + " x " + e_height +
" -> " + w + " x " + h + " ratio: " +
dx + " x " + dy);
}
}
// ----------
private void updateStatus(String status) {
mTextStatus.setVisibility(status == null ? View.GONE : View.VISIBLE);
if (status != null) mTextStatus.setText(status);
}
private void updateError() {
ControllerBinder binder = getServiceBinder();
String error = binder == null ? "" : binder.getServiceError();
if (error == null) {
error = "";
}
mTextError.setVisibility(error.length() == 0 ? View.GONE : View.VISIBLE);
mTextError.setText(error);
}
}

View File

@ -0,0 +1,338 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.activities;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.android.tools.sdkcontroller.R;
import com.android.tools.sdkcontroller.handlers.SensorChannel;
import com.android.tools.sdkcontroller.handlers.SensorChannel.MonitoredSensor;
import com.android.tools.sdkcontroller.lib.Channel;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerBinder;
import com.android.tools.sdkcontroller.service.ControllerService.ControllerListener;
/**
* Activity that displays and controls the sensors from {@link SensorChannel}.
* For each sensor it displays a checkbox that is enabled if the sensor is supported
* by the emulator. The user can select whether the sensor is active. It also displays
* data from the sensor when available.
*/
public class SensorActivity extends BaseBindingActivity
implements android.os.Handler.Callback {
@SuppressWarnings("hiding")
public static String TAG = SensorActivity.class.getSimpleName();
private static boolean DEBUG = true;
private static final int MSG_UPDATE_ACTUAL_HZ = 0x31415;
private TableLayout mTableLayout;
private TextView mTextError;
private TextView mTextStatus;
private TextView mTextTargetHz;
private TextView mTextActualHz;
private SensorChannel mSensorHandler;
private final Map<MonitoredSensor, DisplayInfo> mDisplayedSensors =
new HashMap<SensorChannel.MonitoredSensor, SensorActivity.DisplayInfo>();
private final android.os.Handler mUiHandler = new android.os.Handler(this);
private int mTargetSampleRate;
private long mLastActualUpdateMs;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sensors);
mTableLayout = (TableLayout) findViewById(R.id.tableLayout);
mTextError = (TextView) findViewById(R.id.textError);
mTextStatus = (TextView) findViewById(R.id.textStatus);
mTextTargetHz = (TextView) findViewById(R.id.textSampleRate);
mTextActualHz = (TextView) findViewById(R.id.textActualRate);
updateStatus("Waiting for connection");
mTextTargetHz.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
updateSampleRate();
return false;
}
});
mTextTargetHz.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
updateSampleRate();
}
});
}
@Override
protected void onResume() {
if (DEBUG) Log.d(TAG, "onResume");
// BaseBindingActivity.onResume will bind to the service.
super.onResume();
updateError();
}
@Override
protected void onPause() {
if (DEBUG) Log.d(TAG, "onPause");
// BaseBindingActivity.onResume will unbind from (but not stop) the service.
super.onPause();
}
@Override
protected void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
super.onDestroy();
removeSensorUi();
}
// ----------
@Override
protected void onServiceConnected() {
if (DEBUG) Log.d(TAG, "onServiceConnected");
createSensorUi();
}
@Override
protected void onServiceDisconnected() {
if (DEBUG) Log.d(TAG, "onServiceDisconnected");
removeSensorUi();
}
@Override
protected ControllerListener createControllerListener() {
return new SensorsControllerListener();
}
// ----------
private class SensorsControllerListener implements ControllerListener {
@Override
public void onErrorChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
updateError();
}
});
}
@Override
public void onStatusChanged() {
runOnUiThread(new Runnable() {
@Override
public void run() {
ControllerBinder binder = getServiceBinder();
if (binder != null) {
boolean connected = binder.isEmuConnected();
mTableLayout.setEnabled(connected);
updateStatus(connected ? "Emulated connected" : "Emulator disconnected");
}
}
});
}
}
private void createSensorUi() {
final LayoutInflater inflater = getLayoutInflater();
if (!mDisplayedSensors.isEmpty()) {
removeSensorUi();
}
mSensorHandler = (SensorChannel) getServiceBinder().getChannel(Channel.SENSOR_CHANNEL);
if (mSensorHandler != null) {
mSensorHandler.addUiHandler(mUiHandler);
mUiHandler.sendEmptyMessage(MSG_UPDATE_ACTUAL_HZ);
assert mDisplayedSensors.isEmpty();
List<MonitoredSensor> sensors = mSensorHandler.getSensors();
for (MonitoredSensor sensor : sensors) {
final TableRow row = (TableRow) inflater.inflate(R.layout.sensor_row,
mTableLayout,
false);
mTableLayout.addView(row);
mDisplayedSensors.put(sensor, new DisplayInfo(sensor, row));
}
}
}
private void removeSensorUi() {
if (mSensorHandler != null) {
mSensorHandler.removeUiHandler(mUiHandler);
mSensorHandler = null;
}
mTableLayout.removeAllViews();
for (DisplayInfo info : mDisplayedSensors.values()) {
info.release();
}
mDisplayedSensors.clear();
}
private class DisplayInfo implements CompoundButton.OnCheckedChangeListener {
private MonitoredSensor mSensor;
private CheckBox mChk;
private TextView mVal;
public DisplayInfo(MonitoredSensor sensor, TableRow row) {
mSensor = sensor;
// Initialize displayed checkbox for this sensor, and register
// checked state listener for it.
mChk = (CheckBox) row.findViewById(R.id.row_checkbox);
mChk.setText(sensor.getUiName());
mChk.setEnabled(sensor.isEnabledByEmulator());
mChk.setChecked(sensor.isEnabledByUser());
mChk.setOnCheckedChangeListener(this);
// Initialize displayed text box for this sensor.
mVal = (TextView) row.findViewById(R.id.row_textview);
mVal.setText(sensor.getValue());
}
/**
* Handles checked state change for the associated CheckBox. If check
* box is checked we will register sensor change listener. If it is
* unchecked, we will unregister sensor change listener.
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mSensor != null) {
mSensor.onCheckedChanged(isChecked);
}
}
public void release() {
mChk = null;
mVal = null;
mSensor = null;
}
public void updateState() {
if (mChk != null && mSensor != null) {
mChk.setEnabled(mSensor.isEnabledByEmulator());
mChk.setChecked(mSensor.isEnabledByUser());
}
}
public void updateValue() {
if (mVal != null && mSensor != null) {
mVal.setText(mSensor.getValue());
}
}
}
/** Implementation of Handler.Callback */
@Override
public boolean handleMessage(Message msg) {
DisplayInfo info = null;
switch (msg.what) {
case SensorChannel.SENSOR_STATE_CHANGED:
info = mDisplayedSensors.get(msg.obj);
if (info != null) {
info.updateState();
}
break;
case SensorChannel.SENSOR_DISPLAY_MODIFIED:
info = mDisplayedSensors.get(msg.obj);
if (info != null) {
info.updateValue();
}
if (mSensorHandler != null) {
updateStatus(Integer.toString(mSensorHandler.getMsgSentCount()) + " events sent");
// Update the "actual rate" field if the value has changed
long ms = mSensorHandler.getActualUpdateMs();
if (ms != mLastActualUpdateMs) {
mLastActualUpdateMs = ms;
String hz = mLastActualUpdateMs <= 0 ? "--" :
Integer.toString((int) Math.ceil(1000. / ms));
mTextActualHz.setText(hz);
}
}
break;
case MSG_UPDATE_ACTUAL_HZ:
if (mSensorHandler != null) {
// Update the "actual rate" field if the value has changed
long ms = mSensorHandler.getActualUpdateMs();
if (ms != mLastActualUpdateMs) {
mLastActualUpdateMs = ms;
String hz = mLastActualUpdateMs <= 0 ? "--" :
Integer.toString((int) Math.ceil(1000. / ms));
mTextActualHz.setText(hz);
}
mUiHandler.sendEmptyMessageDelayed(MSG_UPDATE_ACTUAL_HZ, 1000 /*1s*/);
}
}
return true; // we consumed this message
}
private void updateStatus(String status) {
mTextStatus.setVisibility(status == null ? View.GONE : View.VISIBLE);
if (status != null) mTextStatus.setText(status);
}
private void updateError() {
ControllerBinder binder = getServiceBinder();
String error = binder == null ? "" : binder.getServiceError();
if (error == null) {
error = "";
}
mTextError.setVisibility(error.length() == 0 ? View.GONE : View.VISIBLE);
mTextError.setText(error);
}
private void updateSampleRate() {
String str = mTextTargetHz.getText().toString();
try {
int hz = Integer.parseInt(str.trim());
// Cap the value. 50 Hz is a reasonable max value for the emulator.
if (hz <= 0 || hz > 50) {
hz = 50;
}
if (hz != mTargetSampleRate) {
mTargetSampleRate = hz;
if (mSensorHandler != null) {
mSensorHandler.setUpdateTargetMs(hz <= 0 ? 0 : (int)(1000.0f / hz));
}
}
} catch (Exception ignore) {}
}
}

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.handlers;
import android.graphics.Point;
import android.os.Message;
import android.util.Log;
import com.android.tools.sdkcontroller.lib.Channel;
import com.android.tools.sdkcontroller.lib.ProtocolConstants;
import com.android.tools.sdkcontroller.service.ControllerService;
import java.nio.ByteBuffer;
/**
* Implements multi-touch emulation.
*/
public class MultiTouchChannel extends Channel {
@SuppressWarnings("hiding")
private static final String TAG = MultiTouchChannel.class.getSimpleName();
/**
* A new frame buffer has been received from the emulator.
* Parameter {@code obj} is a {@code byte[] array} containing the screen data.
*/
public static final int EVENT_FRAME_BUFFER = 1;
/**
* A multi-touch "start" command has been received from the emulator.
* Parameter {@code obj} is the string parameter from the start command.
*/
public static final int EVENT_MT_START = 2;
/**
* A multi-touch "stop" command has been received from the emulator. There
* is no {@code obj} parameter associated.
*/
public static final int EVENT_MT_STOP = 3;
private static final Point mViewSize = new Point(0, 0);
/**
* Constructs MultiTouchChannel instance.
*/
public MultiTouchChannel(ControllerService service) {
super(service, Channel.MULTITOUCH_CHANNEL);
}
/**
* Sets size of the display view for emulated screen updates.
*
* @param width View width in pixels.
* @param height View height in pixels.
*/
public void setViewSize(int width, int height) {
mViewSize.set(width, height);
}
/*
* Channel abstract implementation.
*/
/**
* This method is invoked when this channel is fully connected with its
* counterpart in the emulator.
*/
@Override
public void onEmulatorConnected() {
if (hasUiHandler()) {
enable();
notifyUiHandlers(EVENT_MT_START);
}
}
/**
* This method is invoked when this channel loses connection with its
* counterpart in the emulator.
*/
@Override
public void onEmulatorDisconnected() {
if (hasUiHandler()) {
disable();
notifyUiHandlers(EVENT_MT_STOP);
}
}
/**
* A message has been received from the emulator.
*
* @param msg_type Message type.
* @param msg_data Packet received from the emulator.
*/
@Override
public void onEmulatorMessage(int msg_type, ByteBuffer msg_data) {
switch (msg_type) {
case ProtocolConstants.MT_FB_UPDATE:
Message msg = Message.obtain();
msg.what = EVENT_FRAME_BUFFER;
msg.obj = msg_data;
postMessage(ProtocolConstants.MT_FB_ACK, (byte[]) null);
notifyUiHandlers(msg);
break;
default:
Log.e(TAG, "Unknown message type " + msg_type);
}
}
/**
* A query has been received from the emulator.
*
* @param query_id Identifies the query. This ID must be used when replying
* to the query.
* @param query_type Query type.
* @param query_data Query data.
*/
@Override
public void onEmulatorQuery(int query_id, int query_type, ByteBuffer query_data) {
Loge("Unexpected query " + query_type + " in multi-touch");
sendQueryResponse(query_id, (byte[]) null);
}
/**
* Registers a new UI handler.
*
* @param uiHandler A non-null UI handler to register. Ignored if the UI
* handler is null or already registered.
*/
@Override
public void addUiHandler(android.os.Handler uiHandler) {
final boolean first_handler = !hasUiHandler();
super.addUiHandler(uiHandler);
if (first_handler && isConnected()) {
enable();
notifyUiHandlers(EVENT_MT_START);
}
}
/**
* Unregisters an UI handler.
*
* @param uiHandler A non-null UI listener to unregister. Ignored if the
* listener is null or already registered.
*/
@Override
public void removeUiHandler(android.os.Handler uiHandler) {
super.removeUiHandler(uiHandler);
if (isConnected() && !hasUiHandler()) {
disable();
}
}
/***************************************************************************
* Logging wrappers
**************************************************************************/
private void Loge(String log) {
mService.addError(log);
Log.e(TAG, log);
}
}

View File

@ -0,0 +1,675 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.handlers;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import com.android.tools.sdkcontroller.lib.Channel;
import com.android.tools.sdkcontroller.lib.ProtocolConstants;
import com.android.tools.sdkcontroller.service.ControllerService;
/**
* Implements sensors emulation.
*/
public class SensorChannel extends Channel {
@SuppressWarnings("hiding")
private static String TAG = SensorChannel.class.getSimpleName();
@SuppressWarnings("hiding")
private static boolean DEBUG = false;
/**
* The target update time per sensor. Ignored if 0 or negative.
* Sensor updates that arrive faster than this delay are ignored.
* Ideally the emulator can be updated at up to 50 fps, however
* for average power devices something like 20 fps is more
* reasonable.
* Default value should match res/values/strings.xml > sensors_default_sample_rate.
*/
private long mUpdateTargetMs = 1000/20; // 20 fps in milliseconds
/** Accumulates average update frequency. */
private long mGlobalAvgUpdateMs = 0;
/** Array containing monitored sensors. */
private final List<MonitoredSensor> mSensors = new ArrayList<MonitoredSensor>();
/** Sensor manager. */
private SensorManager mSenMan;
/*
* Messages exchanged with the UI.
*/
/**
* Sensor "enabled by emulator" state has changed. Parameter {@code obj} is
* the {@link MonitoredSensor}.
*/
public static final int SENSOR_STATE_CHANGED = 1;
/**
* Sensor display value has changed. Parameter {@code obj} is the
* {@link MonitoredSensor}.
*/
public static final int SENSOR_DISPLAY_MODIFIED = 2;
/**
* Constructs SensorChannel instance.
*
* @param service Service context.
*/
public SensorChannel(ControllerService service) {
super(service, Channel.SENSOR_CHANNEL);
mSenMan = (SensorManager) service.getSystemService(Context.SENSOR_SERVICE);
// Iterate through the available sensors, adding them to the array.
List<Sensor> sensors = mSenMan.getSensorList(Sensor.TYPE_ALL);
int cur_index = 0;
for (int n = 0; n < sensors.size(); n++) {
Sensor avail_sensor = sensors.get(n);
// There can be multiple sensors of the same type. We need only one.
if (!isSensorTypeAlreadyMonitored(avail_sensor.getType())) {
// The first sensor we've got for the given type is not
// necessarily the right one. So, use the default sensor
// for the given type.
Sensor def_sens = mSenMan.getDefaultSensor(avail_sensor.getType());
MonitoredSensor to_add = new MonitoredSensor(def_sens);
cur_index++;
mSensors.add(to_add);
if (DEBUG)
Log.d(TAG, String.format(
"Monitoring sensor #%02d: Name = '%s', Type = 0x%x",
cur_index, def_sens.getName(), def_sens.getType()));
}
}
}
/**
* Returns the list of sensors found on the device.
* The list is computed once by {@link #SensorChannel(ControllerService)}.
*
* @return A non-null possibly-empty list of sensors.
*/
public List<MonitoredSensor> getSensors() {
return mSensors;
}
/**
* Set the target update delay throttling per-sensor, in milliseconds.
* <p/>
* For example setting it to 1000/50 means that updates for a <em>given</em> sensor
* faster than 50 fps is discarded.
*
* @param updateTargetMs 0 to disable throttling, otherwise a > 0 millisecond minimum
* between sensor updates.
*/
public void setUpdateTargetMs(long updateTargetMs) {
mUpdateTargetMs = updateTargetMs;
}
/**
* Returns the actual average time in milliseconds between same-sensor updates.
*
* @return The actual average time in milliseconds between same-sensor updates or 0.
*/
public long getActualUpdateMs() {
return mGlobalAvgUpdateMs;
}
/*
* Channel abstract implementation.
*/
/**
* This method is invoked when this channel is fully connected with its
* counterpart in the emulator.
*/
@Override
public void onEmulatorConnected() {
// Emulation is now possible. Note though that it will start only after
// emulator tells us so with SENSORS_START command.
enable();
}
/**
* This method is invoked when this channel loses connection with its
* counterpart in the emulator.
*/
@Override
public void onEmulatorDisconnected() {
// Stop sensor event callbacks.
stopSensors();
}
/**
* A query has been received from the emulator.
*
* @param query_id Identifies the query. This ID should be used when
* replying to the query.
* @param query_type Query type.
* @param query_data Query data.
*/
@Override
public void onEmulatorQuery(int query_id, int query_type, ByteBuffer query_data) {
switch (query_type) {
case ProtocolConstants.SENSORS_QUERY_LIST:
// Preallocate large response buffer.
ByteBuffer resp = ByteBuffer.allocate(1024);
resp.order(getEndian());
// Iterate through the list of monitored sensors, dumping them
// into the response buffer.
for (MonitoredSensor sensor : mSensors) {
// Entry for each sensor must contain:
// - an integer for its ID
// - a zero-terminated emulator-friendly name.
final byte[] name = sensor.getEmulatorFriendlyName().getBytes();
final int required_size = 4 + name.length + 1;
resp = ExpandIf(resp, required_size);
resp.putInt(sensor.getType());
resp.put(name);
resp.put((byte) 0);
}
// Terminating entry contains single -1 integer.
resp = ExpandIf(resp, 4);
resp.putInt(-1);
sendQueryResponse(query_id, resp);
return;
default:
Loge("Unknown query " + query_type);
return;
}
}
/**
* A message has been received from the emulator.
*
* @param msg_type Message type.
* @param msg_data Packet received from the emulator.
*/
@Override
public void onEmulatorMessage(int msg_type, ByteBuffer msg_data) {
switch (msg_type) {
case ProtocolConstants.SENSORS_START:
Log.v(TAG, "Starting sensors emulation.");
startSensors();
break;
case ProtocolConstants.SENSORS_STOP:
Log.v(TAG, "Stopping sensors emulation.");
stopSensors();
break;
case ProtocolConstants.SENSORS_ENABLE:
String enable_name = new String(msg_data.array());
Log.v(TAG, "Enabling sensor: " + enable_name);
onEnableSensor(enable_name);
break;
case ProtocolConstants.SENSORS_DISABLE:
String disable_name = new String(msg_data.array());
Log.v(TAG, "Disabling sensor: " + disable_name);
onDisableSensor(disable_name);
break;
default:
Loge("Unknown message type " + msg_type);
break;
}
}
/**
* Handles 'enable' message.
*
* @param name Emulator-friendly name of a sensor to enable, or "all" to
* enable all sensors.
*/
private void onEnableSensor(String name) {
if (name.contentEquals("all")) {
// Enable all sensors.
for (MonitoredSensor sensor : mSensors) {
sensor.enableSensor();
}
} else {
// Lookup sensor by emulator-friendly name.
final MonitoredSensor sensor = getSensorByEFN(name);
if (sensor != null) {
sensor.enableSensor();
}
}
}
/**
* Handles 'disable' message.
*
* @param name Emulator-friendly name of a sensor to disable, or "all" to
* disable all sensors.
*/
private void onDisableSensor(String name) {
if (name.contentEquals("all")) {
// Disable all sensors.
for (MonitoredSensor sensor : mSensors) {
sensor.disableSensor();
}
} else {
// Lookup sensor by emulator-friendly name.
MonitoredSensor sensor = getSensorByEFN(name);
if (sensor != null) {
sensor.disableSensor();
}
}
}
/**
* Start listening to all monitored sensors.
*/
private void startSensors() {
for (MonitoredSensor sensor : mSensors) {
sensor.startListening();
}
}
/**
* Stop listening to all monitored sensors.
*/
private void stopSensors() {
for (MonitoredSensor sensor : mSensors) {
sensor.stopListening();
}
}
/***************************************************************************
* Internals
**************************************************************************/
/**
* Checks if a sensor for the given type is already monitored.
*
* @param type Sensor type (one of the Sensor.TYPE_XXX constants)
* @return true if a sensor for the given type is already monitored, or
* false if the sensor is not monitored.
*/
private boolean isSensorTypeAlreadyMonitored(int type) {
for (MonitoredSensor sensor : mSensors) {
if (sensor.getType() == type) {
return true;
}
}
return false;
}
/**
* Looks up a monitored sensor by its emulator-friendly name.
*
* @param name Emulator-friendly name to look up the monitored sensor for.
* @return Monitored sensor for the fiven name, or null if sensor was not
* found.
*/
private MonitoredSensor getSensorByEFN(String name) {
for (MonitoredSensor sensor : mSensors) {
if (sensor.mEmulatorFriendlyName.contentEquals(name)) {
return sensor;
}
}
return null;
}
/**
* Encapsulates a sensor that is being monitored. To monitor sensor changes
* each monitored sensor registers with sensor manager as a sensor listener.
* To control sensor monitoring from the UI, each monitored sensor has two
* UI controls associated with it: - A check box (named after sensor) that
* can be used to enable, or disable listening to the sensor changes. - A
* text view where current sensor value is displayed.
*/
public class MonitoredSensor {
/** Sensor to monitor. */
private final Sensor mSensor;
/** The sensor name to display in the UI. */
private String mUiName = "";
/** Text view displaying the value of the sensor. */
private String mValue = null;
/** Emulator-friendly name for the sensor. */
private String mEmulatorFriendlyName;
/** Formats string to show in the TextView. */
private String mTextFmt;
/** Sensor values. */
private float[] mValues = new float[3];
/**
* Enabled state. This state is controlled by the emulator, that
* maintains its own list of sensors. So, if a sensor is missing, or is
* disabled in the emulator, it should be disabled in this application.
*/
private boolean mEnabledByEmulator = false;
/** User-controlled enabled state. */
private boolean mEnabledByUser = true;
/** Sensor event listener for this sensor. */
private final OurSensorEventListener mListener = new OurSensorEventListener();
/**
* Constructs MonitoredSensor instance, and register the listeners.
*
* @param sensor Sensor to monitor.
*/
MonitoredSensor(Sensor sensor) {
mSensor = sensor;
mEnabledByUser = true;
// Set appropriate sensor name depending on the type. Unfortunately,
// we can't really use sensor.getName() here, since the value it
// returns (although resembles the purpose) is a bit vaguer than it
// should be. Also choose an appropriate format for the strings that
// display sensor's value.
switch (sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
mUiName = "Accelerometer";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "acceleration";
break;
case 9: // Sensor.TYPE_GRAVITY is missing in API 7
mUiName = "Gravity";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "gravity";
break;
case Sensor.TYPE_GYROSCOPE:
mUiName = "Gyroscope";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "gyroscope";
break;
case Sensor.TYPE_LIGHT:
mUiName = "Light";
mTextFmt = "%.0f";
mEmulatorFriendlyName = "light";
break;
case 10: // Sensor.TYPE_LINEAR_ACCELERATION is missing in API 7
mUiName = "Linear acceleration";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "linear-acceleration";
break;
case Sensor.TYPE_MAGNETIC_FIELD:
mUiName = "Magnetic field";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "magnetic-field";
break;
case Sensor.TYPE_ORIENTATION:
mUiName = "Orientation";
mTextFmt = "%+03.0f %+03.0f %+03.0f";
mEmulatorFriendlyName = "orientation";
break;
case Sensor.TYPE_PRESSURE:
mUiName = "Pressure";
mTextFmt = "%.0f";
mEmulatorFriendlyName = "pressure";
break;
case Sensor.TYPE_PROXIMITY:
mUiName = "Proximity";
mTextFmt = "%.0f";
mEmulatorFriendlyName = "proximity";
break;
case 11: // Sensor.TYPE_ROTATION_VECTOR is missing in API 7
mUiName = "Rotation";
mTextFmt = "%+.2f %+.2f %+.2f";
mEmulatorFriendlyName = "rotation";
break;
case Sensor.TYPE_TEMPERATURE:
mUiName = "Temperature";
mTextFmt = "%.0f";
mEmulatorFriendlyName = "temperature";
break;
default:
mUiName = "<Unknown>";
mTextFmt = "N/A";
mEmulatorFriendlyName = "unknown";
if (DEBUG) Loge("Unknown sensor type " + mSensor.getType() +
" for sensor " + mSensor.getName());
break;
}
}
/**
* Get name for this sensor to display.
*
* @return Name for this sensor to display.
*/
public String getUiName() {
return mUiName;
}
/**
* Gets current sensor value to display.
*
* @return Current sensor value to display.
*/
public String getValue() {
if (mValue == null) {
float[] values = mValues;
mValue = String.format(mTextFmt, values[0], values[1], values[2]);
}
return mValue == null ? "??" : mValue;
}
/**
* Checks if monitoring of this this sensor has been enabled by
* emulator.
*
* @return true if monitoring of this this sensor has been enabled by
* emulator, or false if emulator didn't enable this sensor.
*/
public boolean isEnabledByEmulator() {
return mEnabledByEmulator;
}
/**
* Checks if monitoring of this this sensor has been enabled by user.
*
* @return true if monitoring of this this sensor has been enabled by
* user, or false if user didn't enable this sensor.
*/
public boolean isEnabledByUser() {
return mEnabledByUser;
}
/**
* Handles checked state change for the associated CheckBox. If check
* box is checked we will register sensor change listener. If it is
* unchecked, we will unregister sensor change listener.
*/
public void onCheckedChanged(boolean isChecked) {
mEnabledByUser = isChecked;
if (isChecked) {
startListening();
} else {
stopListening();
}
}
/**
* Gets sensor type.
*
* @return Sensor type as one of the Sensor.TYPE_XXX constants.
*/
private int getType() {
return mSensor.getType();
}
/**
* Gets sensor's emulator-friendly name.
*
* @return Sensor's emulator-friendly name.
*/
private String getEmulatorFriendlyName() {
return mEmulatorFriendlyName;
}
/**
* Starts monitoring the sensor.
* NOTE: This method is called from outside of the UI thread.
*/
private void startListening() {
if (mEnabledByEmulator && mEnabledByUser) {
if (DEBUG) Log.d(TAG, "+++ Sensor " + getEmulatorFriendlyName() + " is started.");
mSenMan.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_FASTEST);
}
}
/**
* Stops monitoring the sensor.
* NOTE: This method is called from outside of the UI thread.
*/
private void stopListening() {
if (DEBUG) Log.d(TAG, "--- Sensor " + getEmulatorFriendlyName() + " is stopped.");
mSenMan.unregisterListener(mListener);
}
/**
* Enables sensor events.
* NOTE: This method is called from outside of the UI thread.
*/
private void enableSensor() {
if (DEBUG) Log.d(TAG, ">>> Sensor " + getEmulatorFriendlyName() + " is enabled.");
mEnabledByEmulator = true;
mValue = null;
Message msg = Message.obtain();
msg.what = SENSOR_STATE_CHANGED;
msg.obj = MonitoredSensor.this;
notifyUiHandlers(msg);
}
/**
* Disables sensor events.
* NOTE: This method is called from outside of the UI thread.
*/
private void disableSensor() {
if (DEBUG) Log.w(TAG, "<<< Sensor " + getEmulatorFriendlyName() + " is disabled.");
mEnabledByEmulator = false;
mValue = "Disabled by emulator";
Message msg = Message.obtain();
msg.what = SENSOR_STATE_CHANGED;
msg.obj = MonitoredSensor.this;
notifyUiHandlers(msg);
}
private class OurSensorEventListener implements SensorEventListener {
/** Last update's time-stamp in local thread millisecond time. */
private long mLastUpdateTS = 0;
/** Last display update time-stamp. */
private long mLastDisplayTS = 0;
/** Preallocated buffer for change notification message. */
private final ByteBuffer mChangeMsg = ByteBuffer.allocate(64);
/**
* Handles "sensor changed" event.
* This is an implementation of the SensorEventListener interface.
*/
@Override
public void onSensorChanged(SensorEvent event) {
long now = SystemClock.elapsedRealtime();
long deltaMs = 0;
if (mLastUpdateTS != 0) {
deltaMs = now - mLastUpdateTS;
if (mUpdateTargetMs > 0 && deltaMs < mUpdateTargetMs) {
// New sample is arriving too fast. Discard it.
return;
}
}
// Format and post message for the emulator.
float[] values = event.values;
final int len = values.length;
mChangeMsg.order(getEndian());
mChangeMsg.position(0);
mChangeMsg.putInt(getType());
mChangeMsg.putFloat(values[0]);
if (len > 1) {
mChangeMsg.putFloat(values[1]);
if (len > 2) {
mChangeMsg.putFloat(values[2]);
}
}
postMessage(ProtocolConstants.SENSORS_SENSOR_EVENT, mChangeMsg);
// Computes average update time for this sensor and average globally.
if (mLastUpdateTS != 0) {
if (mGlobalAvgUpdateMs != 0) {
mGlobalAvgUpdateMs = (mGlobalAvgUpdateMs + deltaMs) / 2;
} else {
mGlobalAvgUpdateMs = deltaMs;
}
}
mLastUpdateTS = now;
// Update the UI for the sensor, with a static throttling of 10 fps max.
if (hasUiHandler()) {
if (mLastDisplayTS != 0) {
long uiDeltaMs = now - mLastDisplayTS;
if (uiDeltaMs < 1000 / 4 /* 4fps in ms */) {
// Skip this UI update
return;
}
}
mLastDisplayTS = now;
mValues[0] = values[0];
if (len > 1) {
mValues[1] = values[1];
if (len > 2) {
mValues[2] = values[2];
}
}
mValue = null;
Message msg = Message.obtain();
msg.what = SENSOR_DISPLAY_MODIFIED;
msg.obj = MonitoredSensor.this;
notifyUiHandlers(msg);
}
if (DEBUG) {
long now2 = SystemClock.elapsedRealtime();
long processingTimeMs = now2 - now;
Log.d(TAG, String.format("glob %d - local %d > target %d - processing %d -- %s",
mGlobalAvgUpdateMs, deltaMs, mUpdateTargetMs, processingTimeMs,
mSensor.getName()));
}
}
/**
* Handles "sensor accuracy changed" event.
* This is an implementation of the SensorEventListener interface.
*/
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
} // MonitoredSensor
/***************************************************************************
* Logging wrappers
**************************************************************************/
private void Loge(String log) {
mService.addError(log);
Log.e(TAG, log);
}
}

View File

@ -0,0 +1,795 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.lib;
import android.os.Message;
import android.util.Log;
import com.android.tools.sdkcontroller.service.ControllerService;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Encapsulates basics of a connection with the emulator.
* This class must be used as a base class for all the channelss that provide
* particular type of emulation (such as sensors, multi-touch, etc.)
* <p/>
* Essentially, Channel is an implementation of a particular emulated functionality,
* that defines logical format of the data transferred between the emulator and
* SDK controller. For instance, "sensors" is a channel that emulates sensors,
* and transfers sensor value changes from the device to the emulator. "Multi-touch"
* is a channel that supports multi-touch emulation, and transfers multi-touch
* events to the emulator, while receiving frame buffer updates from the emulator.
* <p/>
* Besides connection with the emulator, each channel may contain one or more UI
* components associated with it. This class provides some basics for UI support,
* including:
* <p/>
* - Providing a way to register / unregister a UI component with the channel.
* <p/>
* - Implementing posting of messages to emulator in opposite to direct message
* sent. This is due to requirement that UI threads are prohibited from doing
* network I/O.
*/
public abstract class Channel {
/**
* Encapsulates a message posted to be sent to the emulator from a worker
* thread. This class is used to describe a message that is posted in UI
* thread, and then picked up in the worker thread.
*/
private class SdkControllerMessage {
/** Message type. */
private int mMessageType;
/** Message data (can be null). */
private byte[] mMessage;
/** Message data size */
private int mMessageSize;
/**
* Construct message from an array.
*
* @param type Message type.
* @param message Message data. Message data size is defined by size of
* the array.
*/
public SdkControllerMessage(int type, byte[] message) {
mMessageType = type;
mMessage = message;
mMessageSize = (message != null) ? message.length : 0;
}
/**
* Construct message from a ByteBuffer.
*
* @param type Message type.
* @param message Message data. Message data size is defined by
* position() property of the ByteBuffer.
*/
public SdkControllerMessage(int type, ByteBuffer message) {
mMessageType = type;
if (message != null) {
mMessage = message.array();
mMessageSize = message.position();
} else {
mMessage = null;
mMessageSize = 0;
}
}
/**
* Gets message type.
*
* @return Message type.
*/
public int getMessageType() {
return mMessageType;
}
/**
* Gets message buffer.
*
* @return Message buffer.
*/
public byte[] getMessage() {
return mMessage;
}
/**
* Gets message buffer size.
*
* @return Message buffer size.
*/
public int getMessageSize() {
return mMessageSize;
}
} // SdkControllerMessage
/*
* Names for currently implemented SDK controller channels.
*/
/** Name for a channel that handles sensors emulation */
public static final String SENSOR_CHANNEL = "sensors";
/** Name for a channel that handles multi-touch emulation */
public static final String MULTITOUCH_CHANNEL = "multi-touch";
/*
* Types of messages internally used by Channel class.
*/
/** Service-side emulator is connected. */
private static final int MSG_CONNECTED = -1;
/** Service-side emulator is disconnected. */
private static final int MSG_DISCONNECTED = -2;
/** Service-side emulator is enabled. */
private static final int MSG_ENABLED = -3;
/** Service-side emulator is disabled. */
private static final int MSG_DISABLED = -4;
/** Tag for logging messages. */
private static final String TAG = "SdkControllerChannel";
/** Controls debug log. */
private static final boolean DEBUG = false;
/** Service that has created this object. */
protected ControllerService mService;
/*
* Socket stuff.
*/
/** Socket to use to to communicate with the emulator. */
private Socket mSocket = null;
/** Channel name ("sensors", "multi-touch", etc.) */
private String mChannelName;
/** Endianness of data transferred in this channel. */
private ByteOrder mEndian;
/*
* Message posting support.
*/
/** Total number of messages posted in this channel */
private final AtomicInteger mMsgCount = new AtomicInteger(0);
/** Flags whether or not message thread is running. */
private volatile boolean mRunMsgQueue = true;
/** Queue of messages pending transmission. */
private final BlockingQueue<SdkControllerMessage>
mMsgQueue = new LinkedBlockingQueue<SdkControllerMessage>();
/** Message thread */
private final Thread mMsgThread;
/*
* UI support.
*/
/** Lists UI handlers attached to this channel. */
private final List<android.os.Handler> mUiHandlers = new ArrayList<android.os.Handler>();
/*
* Abstract methods.
*/
/**
* This method is invoked when this channel is fully connected with its
* counterpart in the emulator.
*/
public abstract void onEmulatorConnected();
/**
* This method is invoked when this channel loses connection with its
* counterpart in the emulator.
*/
public abstract void onEmulatorDisconnected();
/**
* A message has been received from the emulator.
*
* @param msg_type Message type.
* @param msg_data Message data. Message data size is defined by the length
* of the array wrapped by the ByteBuffer.
*/
public abstract void onEmulatorMessage(int msg_type, ByteBuffer msg_data);
/**
* A query has been received from the emulator.
*
* @param query_id Identifies the query. This ID must be used when replying
* to the query.
* @param query_type Query type.
* @param query_data Query data. Query data size is defined by the length of
* the array wrapped by the ByteBuffer.
*/
public abstract void onEmulatorQuery(int query_id, int query_type, ByteBuffer query_data);
/*
* Channel implementation.
*/
/**
* Constructs Channel instance.
*
* @param name Channel name.
*/
public Channel(ControllerService service, String name) {
mService = service;
mChannelName = name;
// Start the worker thread for posted messages.
mMsgThread = new Thread(new Runnable() {
@Override
public void run() {
if (DEBUG) Log.d(TAG, "MsgThread.started-" + mChannelName);
while (mRunMsgQueue) {
try {
SdkControllerMessage msg = mMsgQueue.take();
if (msg != null) {
sendMessage(
msg.getMessageType(), msg.getMessage(), msg.getMessageSize());
mMsgCount.incrementAndGet();
}
} catch (InterruptedException e) {
Log.e(TAG, "MsgThread-" + mChannelName, e);
}
}
if (DEBUG) Log.d(TAG, "MsgThread.terminate-" + mChannelName);
}
}, "MsgThread-" + name);
mMsgThread.start();
if (DEBUG) Log.d(TAG, "Channel is constructed for " + mChannelName);
}
/**
* Gets name for this channel.
*
* @return Emulator name.
*/
public String getChannelName() {
return mChannelName;
}
/**
* Gets endianness for this channel.
*
* @return Channel endianness.
*/
public ByteOrder getEndian() {
return mEndian;
}
/**
* Gets number of messages sent via postMessage method.
*
* @return Number of messages sent via postMessage method.
*/
public int getMsgSentCount() {
return mMsgCount.get();
}
/**
* Checks if this channel is connected with the emulator.
*
* @return true if this channel is connected with the emulator, or false if it is
* not connected.
*/
public boolean isConnected() {
// Use local copy of the socket, ensuring it's not going to NULL while
// we're working with it. If it gets closed, while we're in the middle
// of data transfer - it's OK, since it will produce an exception, and
// the caller will gracefully handle it.
//
// Same technique is used everywhere in this class where mSocket member
// is touched.
Socket socket = mSocket;
return socket != null && socket.isConnected();
}
/**
* Establishes connection with the emulator. This method is called by Connection
* object when emulator successfully connects to this channel, or this channel
* gets registered, and there is a pending socket connection for it.
*
* @param socket Channel connection socket.
*/
public void connect(Socket socket) {
mSocket = socket;
mEndian = socket.getEndian();
Logv("Channel " + mChannelName + " is now connected with the emulator.");
// Notify the emulator that connection is established.
sendMessage(MSG_CONNECTED, (byte[]) null);
// Let the derived class know that emulator is connected, and start the
// I/O loop in which we will receive data from the emulator. Note that
// we start the loop after onEmulatorConnected call, since we don't want
// to start dispatching messages before the derived class could set
// itself up for receiving them.
onEmulatorConnected();
new Thread(new Runnable() {
@Override
public void run() {
runIOLooper();
}
}, "ChannelIoLoop").start();
mService.notifyStatusChanged();
}
/**
* Disconnects this channel from the emulator.
*
* @return true if this channel has been disconnected in this call, or false if
* channel has been already disconnected when this method has been called.
*/
public boolean disconnect() {
// This is the only place in this class where we will null the
// socket object. Since this method can be called concurrently from
// different threads, lets do this under the lock.
Socket socket;
synchronized (this) {
socket = mSocket;
mSocket = null;
}
if (socket != null) {
// Notify the emulator about channel disconnection before we close
// the communication socket.
try {
sendMessage(socket, MSG_DISCONNECTED, null, 0);
} catch (IOException e) {
// Ignore I/O exception at this point. We don't care about
// it, since the socket is being closed anyways.
}
// This will eventually stop I/O looper thread.
socket.close();
mService.notifyStatusChanged();
}
return socket != null;
}
/**
* Enables the emulation. Typically, this method is called for channels that are
* dependent on UI to handle the emulation. For instance, multi-touch emulation is
* disabled until at least one UI component is attached to the channel. So, for
* multi-touch emulation this method is called when UI gets attached to the channel.
*/
public void enable() {
postMessage(MSG_ENABLED, (byte[]) null);
mService.notifyStatusChanged();
}
/**
* Disables the emulation. Just the opposite to enable(). For multi-touch this
* method is called when UI detaches from the channel.
*/
public void disable() {
postMessage(MSG_DISABLED, (byte[]) null);
mService.notifyStatusChanged();
}
/**
* Sends message to the emulator.
*
* @param socket Socket to send the message to.
* @param msg_type Message type.
* @param msg Message data to send.
* @param len Byte size of message data.
* @throws IOException
*/
private void sendMessage(Socket socket, int msg_type, byte[] msg, int len)
throws IOException {
// In async environment we must have message header and message data in
// one block to prevent messages from other threads getting between the
// header and the data. So, we can't sent header, and then the data. We
// must combine them in one data block instead.
ByteBuffer bb = ByteBuffer.allocate(ProtocolConstants.MESSAGE_HEADER_SIZE + len);
bb.order(mEndian);
// Initialize message header.
bb.putInt(ProtocolConstants.PACKET_SIGNATURE);
bb.putInt(ProtocolConstants.MESSAGE_HEADER_SIZE + len);
bb.putInt(ProtocolConstants.PACKET_TYPE_MESSAGE);
bb.putInt(msg_type);
// Save message data (if there is any).
if (len != 0) {
bb.put(msg, 0, len);
}
socket.send(bb.array());
}
/**
* Sends message to the emulator.
*
* @param msg_type Message type.
* @param msg Message data to send. Message size is defined by the size of
* the array.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendMessage(int msg_type, byte[] msg, int msg_len) {
try {
Socket socket = mSocket;
if (socket != null) {
sendMessage(socket, msg_type, msg, msg_len);
return true;
} else {
Logw("sendMessage is called on disconnected Channel " + mChannelName);
}
} catch (IOException e) {
Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
onIoFailure();
}
return false;
}
/**
* Sends message to the emulator.
*
* @param msg_type Message type.
* @param msg Message data to send. Message size is defined by the size of
* the array.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendMessage(int msg_type, byte[] msg) {
try {
Socket socket = mSocket;
if (socket != null) {
if (msg != null) {
sendMessage(socket, msg_type, msg, msg.length);
} else {
sendMessage(socket, msg_type, null, 0);
}
return true;
} else {
Logw("sendMessage is called on disconnected Channel " + mChannelName);
}
} catch (IOException e) {
Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
onIoFailure();
}
return false;
}
/**
* Sends message to the emulator.
*
* @param msg_type Message type.
* @param msg Message data to send. Message size is defined by the
* position() property of the ByteBuffer.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendMessage(int msg_type, ByteBuffer msg) {
try {
Socket socket = mSocket;
if (socket != null) {
if (msg != null) {
sendMessage(socket, msg_type, msg.array(), msg.position());
} else {
sendMessage(socket, msg_type, null, 0);
}
return true;
} else {
Logw("sendMessage is called on disconnected Channel " + mChannelName);
}
} catch (IOException e) {
Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
onIoFailure();
}
return false;
}
/**
* Posts message to the emulator.
*
* @param msg_type Message type.
* @param msg Message data to post. Message size is defined by the size of
* the array.
*/
public void postMessage(int msg_type, byte[] msg) {
try {
mMsgQueue.put(new SdkControllerMessage(msg_type, msg));
} catch (InterruptedException e) {
Log.e(TAG, "mMessageQueue.put", e);
}
}
/**
* Posts message to the emulator.
*
* @param msg_type Message type.
* @param msg Message data to post. Message size is defined by the
* position() property of the ByteBuffer.
*/
public void postMessage(int msg_type, ByteBuffer msg) {
try {
mMsgQueue.put(new SdkControllerMessage(msg_type, msg));
} catch (InterruptedException e) {
Log.e(TAG, "mMessageQueue.put", e);
}
}
/**
* Sends query response to the emulator.
*
* @param query_id Query identifier.
* @param qresp Response to the query.
* @param len Byte size of query response data.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendQueryResponse(int query_id, byte[] qresp, int len) {
// Just like with messages, we must combine header and data in a single
// transmitting block.
ByteBuffer bb = ByteBuffer.allocate(ProtocolConstants.QUERY_RESP_HEADER_SIZE + len);
bb.order(mEndian);
// Initialize response header.
bb.putInt(ProtocolConstants.PACKET_SIGNATURE);
bb.putInt(ProtocolConstants.QUERY_RESP_HEADER_SIZE + len);
bb.putInt(ProtocolConstants.PACKET_TYPE_QUERY_RESPONSE);
bb.putInt(query_id);
// Save response data (if there is any).
if (qresp != null && len != 0) {
bb.put(qresp, 0, len);
}
// Send the response.
try {
Socket socket = mSocket;
if (socket != null) {
socket.send(bb.array());
return true;
} else {
Logw("sendQueryResponse is called on disconnected Channel "
+ mChannelName);
}
} catch (IOException e) {
Loge("Exception " + e + " in sendQueryResponse for Channel " + mChannelName);
onIoFailure();
}
return false;
}
/**
* Sends query response to the emulator.
*
* @param query_id Query identifier.
* @param qresp Response to the query. Query response size is defined by the
* size of the array.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendQueryResponse(int query_id, byte[] qresp) {
return (qresp != null) ? sendQueryResponse(query_id, qresp, qresp.length) :
sendQueryResponse(query_id, null, 0);
}
/**
* Sends query response to the emulator.
*
* @param query_id Query identifier.
* @param qresp Response to the query. Query response size is defined by the
* position() property of the ByteBuffer.
* @return true on success, or false if data transmission has failed.
*/
public boolean sendQueryResponse(int query_id, ByteBuffer qresp) {
return (qresp != null) ? sendQueryResponse(query_id, qresp.array(), qresp.position()) :
sendQueryResponse(query_id, null, 0);
}
/**
* Handles an I/O failure occurred in the channel.
*/
private void onIoFailure() {
// All I/O failures cause disconnection.
if (disconnect()) {
// Success of disconnect() indicates that I/O failure is not the
// result of a disconnection request, but is in deed an I/O
// failure. Report lost connection to the derived class.
Loge("Connection with the emulator has been lost in Channel " + mChannelName);
onEmulatorDisconnected();
}
}
/**
* Loops on the local socket, handling connection attempts.
*/
private void runIOLooper() {
if (DEBUG) Log.d(TAG, "In I/O looper for Channel " + mChannelName);
// Initialize byte buffer large enough to receive packet header.
ByteBuffer header = ByteBuffer.allocate(ProtocolConstants.PACKET_HEADER_SIZE);
header.order(mEndian);
try {
// Since disconnection (which will null the mSocket) can be
// requested from outside of this thread, it's simpler just to make
// a copy of mSocket here, and work with that copy. Otherwise we
// will have to go through a complex synchronization algorithm that
// would decrease performance on normal runs. If socket gets closed
// while we're in the middle of transfer, an exception will occur,
// which we will catch and handle properly.
Socket socket = mSocket;
while (socket != null) {
// Reset header position.
header.position(0);
// This will receive total packet size + packet type.
socket.receive(header.array());
// First - signature.
final int signature = header.getInt();
assert signature == ProtocolConstants.PACKET_SIGNATURE;
// Next - packet size (including header).
int remains = header.getInt() - ProtocolConstants.PACKET_HEADER_SIZE;
// After the size comes packet type.
final int packet_type = header.getInt();
// Get the remainder of the data, and dispatch the packet to
// an appropriate handler.
switch (packet_type) {
case ProtocolConstants.PACKET_TYPE_MESSAGE:
// Read message header (one int: message type).
final int ext = ProtocolConstants.MESSAGE_HEADER_SIZE - ProtocolConstants.PACKET_HEADER_SIZE;
header.position(0);
socket.receive(header.array(), ext);
final int msg_type = header.getInt();
// Read message data.
remains -= ext;
final ByteBuffer msg_data = ByteBuffer.allocate(remains);
msg_data.order(mEndian);
socket.receive(msg_data.array());
// Dispatch message for handling.
onEmulatorMessage(msg_type, msg_data);
break;
case ProtocolConstants.PACKET_TYPE_QUERY:
// Read query ID and query type.
final int extq = ProtocolConstants.QUERY_HEADER_SIZE - ProtocolConstants.PACKET_HEADER_SIZE;
header.position(0);
socket.receive(header.array(), extq);
final int query_id = header.getInt();
final int query_type = header.getInt();
// Read query data.
remains -= extq;
final ByteBuffer query_data = ByteBuffer.allocate(remains);
query_data.order(mEndian);
socket.receive(query_data.array());
// Dispatch query for handling.
onEmulatorQuery(query_id, query_type, query_data);
break;
default:
// Unknown packet type. Just discard the remainder
// of the packet
Loge("Unknown packet type " + packet_type + " in Channel "
+ mChannelName);
final byte[] discard_data = new byte[remains];
socket.receive(discard_data);
break;
}
socket = mSocket;
}
} catch (IOException e) {
Loge("Exception " + e + " in I/O looper for Channel " + mChannelName);
onIoFailure();
}
if (DEBUG) Log.d(TAG, "Exiting I/O looper for Channel " + mChannelName);
}
/**
* Indicates any UI handler is currently registered with the channel. If no UI
* is displaying the channel's state, maybe the channel can skip UI related tasks.
*
* @return True if there's at least one UI handler registered.
*/
public boolean hasUiHandler() {
return !mUiHandlers.isEmpty();
}
/**
* Registers a new UI handler.
*
* @param uiHandler A non-null UI handler to register. Ignored if the UI
* handler is null or already registered.
*/
public void addUiHandler(android.os.Handler uiHandler) {
assert uiHandler != null;
if (uiHandler != null) {
if (!mUiHandlers.contains(uiHandler)) {
mUiHandlers.add(uiHandler);
}
}
}
/**
* Unregisters an UI handler.
*
* @param uiHandler A non-null UI listener to unregister. Ignored if the
* listener is null or already registered.
*/
public void removeUiHandler(android.os.Handler uiHandler) {
assert uiHandler != null;
mUiHandlers.remove(uiHandler);
}
/**
* Protected method to be used by handlers to send an event to all UI
* handlers.
*
* @param event An integer event code with no specific parameters. To be
* defined by the handler itself.
*/
protected void notifyUiHandlers(int event) {
for (android.os.Handler uiHandler : mUiHandlers) {
uiHandler.sendEmptyMessage(event);
}
}
/**
* Protected method to be used by handlers to send an event to all UI
* handlers.
*
* @param msg An event with parameters. To be defined by the handler itself.
*/
protected void notifyUiHandlers(Message msg) {
for (android.os.Handler uiHandler : mUiHandlers) {
uiHandler.sendMessage(msg);
}
}
/**
* A helper routine that expands ByteBuffer to contain given number of extra
* bytes.
*
* @param buff Buffer to expand.
* @param extra Number of bytes that are required to be available in the
* buffer after current position()
* @return ByteBuffer, containing required number of available bytes.
*/
public ByteBuffer ExpandIf(ByteBuffer buff, int extra) {
if (extra <= buff.remaining()) {
return buff;
}
ByteBuffer ret = ByteBuffer.allocate(buff.position() + extra);
ret.order(buff.order());
ret.put(buff.array(), 0, buff.position());
return ret;
}
/***************************************************************************
* Logging wrappers
**************************************************************************/
private void Loge(String log) {
mService.addError(log);
Log.e(TAG, log);
}
private void Logw(String log) {
Log.w(TAG, log);
}
private void Logv(String log) {
Log.v(TAG, log);
}
}

View File

@ -0,0 +1,412 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.lib;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import com.android.tools.sdkcontroller.lib.Channel;
import com.android.tools.sdkcontroller.service.ControllerService;
/**
* Encapsulates a connection between SdkController service and the emulator. On
* the device side, the connection is bound to the UNIX-domain socket named
* 'android.sdk.controller'. On the emulator side the connection is established
* via TCP port that is used to forward I/O traffic on the host machine to
* 'android.sdk.controller' socket on the device. Typically, the port forwarding
* can be enabled using adb command:
* <p/>
* 'adb forward tcp:<TCP port number> localabstract:android.sdk.controller'
* <p/>
* The way communication between the emulator and SDK controller service works
* is as follows:
* <p/>
* 1. Both sides, emulator and the service have components that implement a particular
* type of emulation. For instance, AndroidSensorsPort in the emulator, and
* SensorChannel in the application implement sensors emulation.
* Emulation channels are identified by unique names. For instance, sensor emulation
* is done via "sensors" channel, multi-touch emulation is done via "multi-touch"
* channel, etc.
* <p/>
* 2. Channels are connected to emulator via separate socket instance (though all
* of the connections share the same socket address).
* <p/>
* 3. Connection is initiated by the emulator side, while the service provides
* its side (a channel) that implement functionality and exchange protocol required
* by the requested type of emulation.
* <p/>
* Given that, the main responsibilities of this class are:
* <p/>
* 1. Bind to "android.sdk.controller" socket, listening to emulator connections.
* <p/>
* 2. Maintain a list of service-side channels registered by the application.
* <p/>
* 3. Bind emulator connection with service-side channel via port name, provided by
* the emulator.
* <p/>
* 4. Monitor connection state with the emulator, and automatically restore the
* connection once it is lost.
*/
public class Connection {
/** UNIX-domain name reserved for SDK controller. */
public static final String SDK_CONTROLLER_PORT = "android.sdk.controller";
/** Tag for logging messages. */
private static final String TAG = "SdkControllerConnection";
/** Controls debug logging */
private static final boolean DEBUG = false;
/** Server socket used to listen to emulator connections. */
private LocalServerSocket mServerSocket = null;
/** Service that has created this object. */
private ControllerService mService;
/**
* List of connected emulator sockets, pending for a channel to be registered.
* <p/>
* Emulator may connect to SDK controller before the app registers a channel
* for that connection. In this case (when app-side channel is not registered
* with this class) we will keep emulator connection in this list, pending
* for the app-side channel to register.
*/
private List<Socket> mPendingSockets = new ArrayList<Socket>();
/**
* List of registered app-side channels.
* <p/>
* Channels that are kept in this list may be disconnected from (or pending
* connection with) the emulator, or they may be connected with the
* emulator.
*/
private List<Channel> mChannels = new ArrayList<Channel>();
/**
* Constructs Connection instance.
*/
public Connection(ControllerService service) {
mService = service;
if (DEBUG) Log.d(TAG, "SdkControllerConnection is constructed.");
}
/**
* Binds to the socket, and starts the listening thread.
*/
public void connect() {
if (DEBUG) Log.d(TAG, "SdkControllerConnection is connecting...");
// Start connection listener.
new Thread(new Runnable() {
@Override
public void run() {
runIOLooper();
}
}, "SdkControllerConnectionIoLoop").start();
}
/**
* Stops the listener, and closes the socket.
*
* @return true if connection has been stopped in this call, or false if it
* has been already stopped when this method has been called.
*/
public boolean disconnect() {
// This is the only place in this class where we will null the
// socket object. Since this method can be called concurrently from
// different threads, lets do this under the lock.
LocalServerSocket socket;
synchronized (this) {
socket = mServerSocket;
mServerSocket = null;
}
if (socket != null) {
if (DEBUG) Log.d(TAG, "SdkControllerConnection is stopping I/O looper...");
// Stop accepting new connections.
wakeIOLooper(socket);
try {
socket.close();
} catch (Exception e) {
}
// Close all the pending sockets, and clear pending socket list.
if (DEBUG) Log.d(TAG, "SdkControllerConnection is closing pending sockets...");
for (Socket pending_socket : mPendingSockets) {
pending_socket.close();
}
mPendingSockets.clear();
// Disconnect all the emualtors.
if (DEBUG) Log.d(TAG, "SdkControllerConnection is disconnecting channels...");
for (Channel channel : mChannels) {
if (channel.disconnect()) {
channel.onEmulatorDisconnected();
}
}
if (DEBUG) Log.d(TAG, "SdkControllerConnection is disconnected.");
}
return socket != null;
}
/**
* Registers SDK controller channel.
*
* @param channel SDK controller emulator to register.
* @return true if channel has been registered successfully, or false if channel
* with the same name is already registered.
*/
public boolean registerChannel(Channel channel) {
for (Channel check_channel : mChannels) {
if (check_channel.getChannelName().equals(channel.getChannelName())) {
Loge("Registering a duplicate Channel " + channel.getChannelName());
return false;
}
}
if (DEBUG) Log.d(TAG, "Registering Channel " + channel.getChannelName());
mChannels.add(channel);
// Lets see if there is a pending socket for this channel.
for (Socket pending_socket : mPendingSockets) {
if (pending_socket.getChannelName().equals(channel.getChannelName())) {
// Remove the socket from the pending list, and connect the registered channel with it.
if (DEBUG) Log.d(TAG, "Found pending Socket for registering Channel "
+ channel.getChannelName());
mPendingSockets.remove(pending_socket);
channel.connect(pending_socket);
}
}
return true;
}
/**
* Checks if at least one socket connection exists with channel.
*
* @return true if at least one socket connection exists with channel.
*/
public boolean isEmulatorConnected() {
for (Channel channel : mChannels) {
if (channel.isConnected()) {
return true;
}
}
return !mPendingSockets.isEmpty();
}
/**
* Gets Channel instance for the given channel name.
*
* @param name Channel name to get Channel instance for.
* @return Channel instance for the given channel name, or NULL if no
* channel has been registered for that name.
*/
public Channel getChannel(String name) {
for (Channel channel : mChannels) {
if (channel.getChannelName().equals(name)) {
return channel;
}
}
return null;
}
/**
* Gets connected emulator socket that is pending for service-side channel
* registration.
*
* @param name Channel name to lookup Socket for.
* @return Connected emulator socket that is pending for service-side channel
* registration, or null if no socket is pending for service-size
* channel registration.
*/
private Socket getPendingSocket(String name) {
for (Socket socket : mPendingSockets) {
if (socket.getChannelName().equals(name)) {
return socket;
}
}
return null;
}
/**
* Wakes I/O looper waiting on connection with the emulator.
*
* @param socket Server socket waiting on connection.
*/
private void wakeIOLooper(LocalServerSocket socket) {
// We wake the looper by connecting to the socket.
LocalSocket waker = new LocalSocket();
try {
waker.connect(socket.getLocalSocketAddress());
} catch (IOException e) {
Loge("Exception " + e + " in SdkControllerConnection while waking up the I/O looper.");
}
}
/**
* Loops on the local socket, handling emulator connection attempts.
*/
private void runIOLooper() {
if (DEBUG) Log.d(TAG, "In SdkControllerConnection I/O looper.");
do {
try {
// Create non-blocking server socket that would listen for connections,
// and bind it to the given port on the local host.
mServerSocket = new LocalServerSocket(SDK_CONTROLLER_PORT);
LocalServerSocket socket = mServerSocket;
while (socket != null) {
final LocalSocket sk = socket.accept();
if (mServerSocket != null) {
onAccept(sk);
} else {
break;
}
socket = mServerSocket;
}
} catch (IOException e) {
Loge("Exception " + e + "SdkControllerConnection I/O looper.");
}
if (DEBUG) Log.d(TAG, "Exiting SdkControllerConnection I/O looper.");
// If we're exiting the internal loop for reasons other than an explicit
// disconnect request, we should reconnect again.
} while (disconnect());
}
/**
* Accepts new connection from the emulator.
*
* @param sock Connecting socket.
* @throws IOException
*/
private void onAccept(LocalSocket sock) throws IOException {
final ByteBuffer handshake = ByteBuffer.allocate(ProtocolConstants.QUERY_HEADER_SIZE);
// By protocol, first byte received from newly connected emulator socket
// indicates host endianness.
Socket.receive(sock, handshake.array(), 1);
final ByteOrder endian = (handshake.getChar() == 0) ? ByteOrder.LITTLE_ENDIAN :
ByteOrder.BIG_ENDIAN;
handshake.order(endian);
// Right after that follows the handshake query header.
handshake.position(0);
Socket.receive(sock, handshake.array(), handshake.array().length);
// First int - signature
final int signature = handshake.getInt();
assert signature == ProtocolConstants.PACKET_SIGNATURE;
// Second int - total query size (including fixed query header)
final int remains = handshake.getInt() - ProtocolConstants.QUERY_HEADER_SIZE;
// After that - header type (which must be SDKCTL_PACKET_TYPE_QUERY)
final int msg_type = handshake.getInt();
assert msg_type == ProtocolConstants.PACKET_TYPE_QUERY;
// After that - query ID.
final int query_id = handshake.getInt();
// And finally, query type (which must be ProtocolConstants.QUERY_HANDSHAKE for
// handshake query)
final int query_type = handshake.getInt();
assert query_type == ProtocolConstants.QUERY_HANDSHAKE;
// Verify that received is a query.
if (msg_type != ProtocolConstants.PACKET_TYPE_QUERY) {
// Message type is not a query. Lets read and discard the remainder
// of the message.
if (remains > 0) {
Loge("Unexpected handshake message type: " + msg_type);
byte[] discard = new byte[remains];
Socket.receive(sock, discard, discard.length);
}
return;
}
// Receive query data.
final byte[] name_array = new byte[remains];
Socket.receive(sock, name_array, name_array.length);
// Prepare response header.
handshake.position(0);
handshake.putInt(ProtocolConstants.PACKET_SIGNATURE);
// Handshake reply is just one int.
handshake.putInt(ProtocolConstants.QUERY_RESP_HEADER_SIZE + 4);
handshake.putInt(ProtocolConstants.PACKET_TYPE_QUERY_RESPONSE);
handshake.putInt(query_id);
// Verify that received query is in deed a handshake query.
if (query_type != ProtocolConstants.QUERY_HANDSHAKE) {
// Query is not a handshake. Reply with failure.
Loge("Unexpected handshake query type: " + query_type);
handshake.putInt(ProtocolConstants.HANDSHAKE_RESP_QUERY_UNKNOWN);
sock.getOutputStream().write(handshake.array());
return;
}
// Handshake query data consist of SDK controller channel name.
final String channel_name = new String(name_array);
if (DEBUG) Log.d(TAG, "Handshake received for channel " + channel_name);
// Respond to query depending on service-side channel availability
final Channel channel = getChannel(channel_name);
Socket sk = null;
if (channel != null) {
if (channel.isConnected()) {
// This is a duplicate connection.
Loge("Duplicate connection to a connected Channel " + channel_name);
handshake.putInt(ProtocolConstants.HANDSHAKE_RESP_DUP);
} else {
// Connecting to a registered channel.
if (DEBUG) Log.d(TAG, "Emulator is connected to a registered Channel " + channel_name);
handshake.putInt(ProtocolConstants.HANDSHAKE_RESP_CONNECTED);
}
} else {
// Make sure that there are no other channel connections for this
// channel name.
if (getPendingSocket(channel_name) != null) {
// This is a duplicate.
Loge("Duplicate connection to a pending Socket " + channel_name);
handshake.putInt(ProtocolConstants.HANDSHAKE_RESP_DUP);
} else {
// Connecting to a channel that has not been registered yet.
if (DEBUG) Log.d(TAG, "Emulator is connected to a pending Socket " + channel_name);
handshake.putInt(ProtocolConstants.HANDSHAKE_RESP_NOPORT);
sk = new Socket(sock, channel_name, endian);
mPendingSockets.add(sk);
}
}
// Send handshake reply.
sock.getOutputStream().write(handshake.array());
// If a disconnected channel for emulator connection has been found,
// connect it.
if (channel != null && !channel.isConnected()) {
if (DEBUG) Log.d(TAG, "Connecting Channel " + channel_name + " with emulator.");
sk = new Socket(sock, channel_name, endian);
channel.connect(sk);
}
mService.notifyStatusChanged();
}
/***************************************************************************
* Logging wrappers
**************************************************************************/
private void Loge(String log) {
mService.addError(log);
Log.e(TAG, log);
}
}

View File

@ -0,0 +1,146 @@
// Copyright 2012 Google Inc. All Rights Reserved.
package com.android.tools.sdkcontroller.lib;
/**
* Contains declarations of constants that are tied to emulator implementation.
* These constants can be changed only simultaneously in both places.
*/
public final class ProtocolConstants {
/*
* Constants related to data transfer.
*/
/** Signature of a packet sent via SDK controller socket ('SDKC') */
public static final int PACKET_SIGNATURE = 0x53444B43;
/*
* Header sizes for packets sent / received by SDK controller emulator.
*/
/**
* 12 bytes (3 ints) for the packet header:
* <p/>
* - Signature.
* <p/>
* - Total packet size.
* <p/>
* - Packet type.
*/
public static final int PACKET_HEADER_SIZE = 12;
/**
* 16 bytes (4 ints) for the message header:
* <p/>
* - Common packet header.
* <p/>
* - Message type.
*/
public static final int MESSAGE_HEADER_SIZE = 16;
/**
* 20 bytes (5 ints) for the query header:
* <p/>
* - Common packet header.
* <p/>
* - Query ID.
* <p/>
* - Query type.
*/
public static final int QUERY_HEADER_SIZE = 20;
/**
* 16 bytes (4 ints) for the query response:
* <p/>
* - Common packet header.
* <p/>
* - Query ID.
*/
public static final int QUERY_RESP_HEADER_SIZE = 16;
/*
* Types of packets transferred via SDK Controller channel.
*/
/** Packet is a message. */
public static final int PACKET_TYPE_MESSAGE = 1;
/** Packet is a query. */
public static final int PACKET_TYPE_QUERY = 2;
/** Packet is a response to a query. */
public static final int PACKET_TYPE_QUERY_RESPONSE = 3;
/*
* Constants related to handshake protocol between the emulator and a channel.
*/
/**
* Query type for a special "handshake" query.
* <p/>
* When emulator connects to SDK controller, the first thing that goes
* through the socket is a special "handshake" query that delivers channel name
* to the service.
*/
public static final int QUERY_HANDSHAKE = -1;
/**
* Handshake query response on condition that service-side channel is available
* (registered).
*/
public static final int HANDSHAKE_RESP_CONNECTED = 0;
/**
* Handshake query response on condition that service-side channel is not
* available (not registered).
*/
public static final int HANDSHAKE_RESP_NOPORT = 1;
/**
* Handshake query response on condition that there is already an existing
* emulator connection for this channel. Emulator should stop connection
* attempts in this case.
*/
public static final int HANDSHAKE_RESP_DUP = -1;
/** Response to an unknown handshake query type. */
public static final int HANDSHAKE_RESP_QUERY_UNKNOWN = -2;
/*
* Constants related to multi-touch emulation.
*/
/** Received frame is JPEG image. */
public static final int MT_FRAME_JPEG = 1;
/** Received frame is RGB565 bitmap. */
public static final int MT_FRAME_RGB565 = 2;
/** Received frame is RGB888 bitmap. */
public static final int MT_FRAME_RGB888 = 3;
/** Pointer(s) moved. */
public static final int MT_MOVE = 1;
/** First pointer down message. */
public static final int MT_FISRT_DOWN = 2;
/** Last pointer up message. */
public static final int MT_LAST_UP = 3;
/** Pointer down message. */
public static final int MT_POINTER_DOWN = 4;
/** Pointer up message. */
public static final int MT_POINTER_UP = 5;
/** Sends framebuffer update. */
public static final int MT_FB_UPDATE = 6;
/** Frame buffer update has been received. */
public static final int MT_FB_ACK = 7;
/** Frame buffer update has been handled. */
public static final int MT_FB_HANDLED = 8;
/** Size of an event entry in the touch event message to the emulator. */
public static final int MT_EVENT_ENTRY_SIZE = 16;
/*
* Constants related to sensor emulation.
*/
/** Query type for a query that should return the list of available sensors. */
public static final int SENSORS_QUERY_LIST = 1;
/** Message that starts sensor emulation. */
public static final int SENSORS_START = 1;
/** Message that stops sensor emulation. */
public static final int SENSORS_STOP = 2;
/** Message that enables emulation of a particular sensor. */
public static final int SENSORS_ENABLE = 3;
/** Message that disables emulation of a particular sensor. */
public static final int SENSORS_DISABLE = 4;
/** Message that delivers sensor events to emulator. */
public static final int SENSORS_SENSOR_EVENT = 5;
}

View File

@ -0,0 +1,213 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.lib;
import android.net.LocalSocket;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
import java.nio.channels.ClosedChannelException;
/**
* Encapsulates a connection with the emulator over a UNIX-domain socket.
*/
public class Socket {
/** UNIX-domain socket connected with the emulator. */
private LocalSocket mSocket = null;
/** Channel name for the connection established via this socket. */
private String mChannelName;
/** Endianness of data transferred in this connection. */
private ByteOrder mEndian;
/** Tag for message logging. */
private static final String TAG = "SdkControllerSocket";
/** Controls debug log. */
private static boolean DEBUG = false;
/**
* Constructs Socket instance.
*
* @param socket Socket connection with the emulator.
* @param name Channel port name for this connection.
* @param endian Endianness of data transferred in this connection.
*/
public Socket(LocalSocket socket, String name, ByteOrder endian) {
mSocket = socket;
mChannelName = name;
mEndian = endian;
if (DEBUG) Log.d(TAG, "Socket is constructed for " + mChannelName);
}
/**
* Gets connection status of this socket.
*
* @return true if socket is connected, or false if socket is not connected.
*/
public boolean isConnected() {
return mSocket != null;
}
/**
* Gets channel name for this socket.
*
* @return Channel name for this socket.
*/
public String getChannelName() {
return mChannelName;
}
/**
* Gets endianness of data transferred via this socket.
*
* @return Endianness of data transferred via this socket.
*/
public ByteOrder getEndian() {
return mEndian;
}
/**
* Sends data to the socket.
*
* @param data Data to send. Data size is defined by the length of the
* array.
* @throws IOException
*/
public void send(byte[] data) throws IOException {
// Use local copy of the socket, ensuring it's not going to NULL while
// we're working with it. If it gets closed, while we're in the middle
// of data transfer - it's OK, since it will produce an exception, and
// the caller will gracefully handle it.
//
// Same technique is used everywhere in this class where mSocket member
// is touched.
LocalSocket socket = mSocket;
if (socket == null) {
Logw("'send' request on closed Socket " + mChannelName);
throw new ClosedChannelException();
}
socket.getOutputStream().write(data);
}
/**
* Sends data to the socket.
*
* @param data Data to send.
* @param offset The start position in data from where to get bytes.
* @param len The number of bytes from data to write to this socket.
* @throws IOException
*/
public void send(byte[] data, int offset, int len) throws IOException {
LocalSocket socket = mSocket;
if (socket == null) {
Logw("'send' request on closed Socket " + mChannelName);
throw new ClosedChannelException();
}
socket.getOutputStream().write(data, offset, len);
}
/**
* Receives data from the socket.
*
* @param socket Socket from where to receive data.
* @param data Array where to save received data.
* @param len Number of bytes to receive.
* @throws IOException
*/
public static void receive(LocalSocket socket, byte[] data, int len) throws IOException {
final InputStream is = socket.getInputStream();
int received = 0;
while (received != len) {
final int chunk = is.read(data, received, len - received);
if (chunk < 0) {
throw new IOException(
"I/O failure while receiving SDK controller data from socket.");
}
received += chunk;
}
}
/**
* Receives data from the socket.
*
* @param data Array where to save received data.
* @param len Number of bytes to receive.
* @throws IOException
*/
public void receive(byte[] data, int len) throws IOException {
LocalSocket socket = mSocket;
if (socket == null) {
Logw("'receive' request on closed Socket " + mChannelName);
throw new ClosedChannelException();
}
receive(socket, data, len);
}
/**
* Receives data from the socket.
*
* @param data Array where to save received data. Data size is defined by
* the size of the array.
* @throws IOException
*/
public void receive(byte[] data) throws IOException {
receive(data, data.length);
}
/**
* Closes the socket.
*
* @return true if socket has been closed in this call, or false if it had
* been already closed when this method has been called.
*/
public boolean close() {
// This is the only place in this class where we will null the socket
// object. Since this method can be called concurrently from different
// threads, lets do this under the lock.
LocalSocket socket;
synchronized (this) {
socket = mSocket;
mSocket = null;
}
if (socket != null) {
try {
// Force all I/O to stop before closing the socket.
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
if (DEBUG) Log.d(TAG, "Socket is closed for " + mChannelName);
return true;
} catch (IOException e) {
Loge("Exception " + e + " while closing Socket for " + mChannelName);
}
}
return false;
}
/***************************************************************************
* Logging wrappers
**************************************************************************/
private void Loge(String log) {
Log.e(TAG, log);
}
private void Logw(String log) {
Log.w(TAG, log);
}
}

View File

@ -0,0 +1,319 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.service;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import com.android.tools.sdkcontroller.R;
import com.android.tools.sdkcontroller.activities.MainActivity;
import com.android.tools.sdkcontroller.handlers.MultiTouchChannel;
import com.android.tools.sdkcontroller.handlers.SensorChannel;
import com.android.tools.sdkcontroller.lib.Connection;
import com.android.tools.sdkcontroller.lib.Channel;
/**
* The background service of the SdkController.
* There can be only one instance of this.
* <p/>
* The service manages a number of SDK controller channels which can be seen as
* individual tasks that the user might want to accomplish, for example "sending
* sensor data to the emulator" or "sending multi-touch data and displaying an
* emulator screen".
* <p/>
* Each channel connects to the emulator via UNIX-domain socket that is bound to
* "android.sdk.controller" port. Connection class provides a socket server that
* listens to emulator connections on this port, and binds new connection with a
* channel, based on channel name.
* <p/>
* All the channels are created when the service starts, and whether the emulator
* connection is successful or not, and whether there's any UI to control it.
* It's up to the channels to deal with these specific details. <br/>
* For example the {@link SensorChannel} initializes its sensor list as soon as
* created and then tries to send data as soon as there's an emulator
* connection. On the other hand the {@link MultiTouchChannel} lays dormant till
* there's an UI interacting with it.
*/
public class ControllerService extends Service {
/*
* Implementation reference:
* http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
*/
/** Tag for logging messages. */
public static String TAG = ControllerService.class.getSimpleName();
/** Controls debug log. */
private static boolean DEBUG = true;
/** Identifier for the notification. */
private static int NOTIF_ID = 'S' << 24 + 'd' << 16 + 'k' << 8 + 'C' << 0;
/** Connection to the emulator. */
public Connection mConnection;
private final IBinder mBinder = new ControllerBinder();
private List<ControllerListener> mListeners = new ArrayList<ControllerListener>();
/**
* Whether the service is running. Set to true in onCreate, false in onDestroy.
*/
private static volatile boolean gServiceIsRunning = false;
/** Internal error reported by the service. */
private String mServiceError = "";
/**
* Interface that the service uses to notify binded activities.
* <p/>
* As a design rule, implementations of this listener should be aware that most calls
* will NOT happen on the UI thread. Any access to the UI should be properly protected
* by using {@link Activity#runOnUiThread(Runnable)}.
*/
public interface ControllerListener {
/**
* The error string reported by the service has changed. <br/>
* Note this may be called from a thread different than the UI thread.
*/
void onErrorChanged();
/**
* The service status has changed (emulator connected/disconnected.)
*/
void onStatusChanged();
}
/** Interface that callers can use to access the service. */
public class ControllerBinder extends Binder {
/**
* Adds a new listener that will be notified when the service state changes.
*
* @param listener A non-null listener. Ignored if already listed.
*/
public void addControllerListener(ControllerListener listener) {
assert listener != null;
if (listener != null) {
synchronized (mListeners) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}
}
}
/**
* Removes a listener.
*
* @param listener A listener to remove. Can be null.
*/
public void removeControllerListener(ControllerListener listener) {
assert listener != null;
synchronized (mListeners) {
mListeners.remove(listener);
}
}
/**
* Returns the error string accumulated by the service.
* Typically these would relate to failures to establish the communication
* channel(s) with the emulator, or unexpected disconnections.
*/
public String getServiceError() {
return mServiceError;
}
/**
* Indicates when <em>any</all> of the SDK controller channels is connected
* with the emulator.
*
* @return True if any of the SDK controller channels is connected with the
* emulator.
*/
public boolean isEmuConnected() {
return mConnection.isEmulatorConnected();
}
/**
* Returns the channel instance for the given type.
*
* @param name One of the channel names. Must not be null.
* @return Null if the type is not found, otherwise the handler's unique instance.
*/
public Channel getChannel(String name) {
return mConnection.getChannel(name);
}
}
/**
* Whether the service is running. Set to true in onCreate, false in onDestroy.
*/
public static boolean isServiceIsRunning() {
return gServiceIsRunning;
}
@Override
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "Service onCreate");
gServiceIsRunning = true;
showNotification();
onServiceStarted();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
if (DEBUG) Log.d(TAG, "Service onStartCommand");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
if (DEBUG) Log.d(TAG, "Service onBind");
return mBinder;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Service onDestroy");
gServiceIsRunning = false;
removeNotification();
resetError();
onServiceStopped();
super.onDestroy();
}
private void disconnectAll() {
if (mConnection != null) {
mConnection.disconnect();
}
}
/**
* Called when the service has been created.
*/
private void onServiceStarted() {
try {
disconnectAll();
// Bind to SDK controller port, and start accepting emulator
// connections.
mConnection = new Connection(ControllerService.this);
mConnection.connect();
// Create and register sensors channel.
mConnection.registerChannel(new SensorChannel(ControllerService.this));
// Create and register multi-touch channel.
mConnection.registerChannel(new MultiTouchChannel(ControllerService.this));
} catch (Exception e) {
addError("Connection failed: " + e.toString());
}
}
/**
* Called when the service is being destroyed.
*/
private void onServiceStopped() {
disconnectAll();
}
private void notifyErrorChanged() {
synchronized (mListeners) {
for (ControllerListener listener : mListeners) {
listener.onErrorChanged();
}
}
}
public void notifyStatusChanged() {
synchronized (mListeners) {
for (ControllerListener listener : mListeners) {
listener.onStatusChanged();
}
}
}
/**
* Resets the error string and notify listeners.
*/
private void resetError() {
mServiceError = "";
notifyErrorChanged();
}
/**
* An internal utility method to add a line to the error string and notify listeners.
* @param error A non-null non-empty error line. \n will be added automatically.
*/
public void addError(String error) {
Log.e(TAG, error);
if (mServiceError.length() > 0) {
mServiceError += "\n";
}
mServiceError += error;
notifyErrorChanged();
}
/**
* Displays a notification showing that the service is running.
* When the user touches the notification, it opens the main activity
* which allows the user to stop this service.
*/
@SuppressWarnings("deprecated")
private void showNotification() {
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String text = getString(R.string.service_notif_title);
// Note: Notification is marked as deprecated -- in API 11+ there's a new Builder class
// but we need to have API 7 compatibility so we ignore that warning.
Notification n = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
n.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(
this, //context
0, //requestCode
intent, //intent
0 //pending intent flags
);
n.setLatestEventInfo(this, text, text, pi);
nm.notify(NOTIF_ID, n);
}
private void removeNotification() {
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(NOTIF_ID);
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.utils;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
/**
* Helper to deal with methods only available at certain API levels.
* Users should get use {@link ApiHelper#get()} to retrieve a singleton
* and then call the methods they desire. If the method is not available
* on the current API level, a stub or a nop will be used instead.
*/
@TargetApi(7)
public class ApiHelper {
private static ApiHelper sApiHelper = null;
/** Creates a new ApiHelper adapted to the current runtime API level. */
public static ApiHelper get() {
if (sApiHelper == null) {
if (Build.VERSION.SDK_INT >= 11) {
sApiHelper = new ApiHelper_11();
} else {
sApiHelper = new ApiHelper();
}
}
return sApiHelper;
}
protected ApiHelper() {
}
/**
* Applies {@link View#setSystemUiVisibility(int)}, available only starting with API 11.
* Does nothing for API < 11.
*/
public void View_setSystemUiVisibility(View view, int visibility) {
// nop
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.utils;
import android.annotation.TargetApi;
import android.view.View;
/**
* API 11: support View_setSystemUiVisibility
*/
@TargetApi(11)
class ApiHelper_11 extends ApiHelper {
/**
* Applies {@link View#setSystemUiVisibility(int)}, available only starting with API 11.
* Does nothing for API < 11.
*/
@Override
public void View_setSystemUiVisibility(View view, int visibility) {
view.setSystemUiVisibility(visibility);
}
}

View File

@ -0,0 +1,232 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.tools.sdkcontroller.views;
import java.io.InputStream;
import java.nio.ByteBuffer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Implements a main view for the application providing multi-touch emulation.
*/
public class MultiTouchView extends View {
/** Tag for logging messages. */
private static final String TAG = MultiTouchView.class.getSimpleName();
/**
* Back-end bitmap. Initialized in onSizeChanged(), updated in
* onTouchEvent() and drawn in onDraw().
*/
private Bitmap mBitmap;
/** Default Paint instance for drawing the bitmap. */
private final Paint mPaint = new Paint();
/** Canvas instance for this view. */
private Canvas mCanvas;
/** Emulator screen width to this view width ratio. */
private float mDx = 1;
/** Emulator screen height to this view height ratio. */
private float mDy = 1;
/**
* Flags whether or not image received from the emulator should be rotated.
* Rotation is required when display orientation state of the emulator and
* the device doesn't match.
*/
private boolean mRotateDisplay;
/** Base matrix that keep emulator->device display scaling */
private Matrix mBaseMatrix = new Matrix();
/** Matrix that is used to draw emulator's screen on the device. */
private Matrix mDrawMatrix = new Matrix();
/**
* Simple constructor to use when creating a view from code.
*
* @see View#View(Context)
*/
public MultiTouchView(Context context) {
this(context, null);
}
/**
* Constructor that is called when inflating a view from XML.
*
* @see View#View(Context, AttributeSet)
*/
public MultiTouchView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* Perform inflation from XML and apply a class-specific base style.
*
* @see View#View(Context, AttributeSet, int)
*/
public MultiTouchView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Add constructor-time code here.
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Just draw the back-end bitmap without zooming or scaling.
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
/**
* Sets emulator screen width and height to this view width and height
* ratio.
*
* @param dx Emulator screen width to this view width ratio.
* @param dy Emulator screen height to this view height ratio.
* @param rotateDisplay Flags whether image received from the emulator
* should be rotated when drawn on the device.
*/
public void setDxDy(float dx, float dy, boolean rotateDisplay) {
mDx = dx;
mDy = dy;
mRotateDisplay = rotateDisplay;
mBaseMatrix.setScale(dx, dy);
if (mRotateDisplay) {
mBaseMatrix.postRotate(90);
mBaseMatrix.postTranslate(getWidth(), 0);
}
}
/**
* Computes draw matrix for the emulator screen update.
*
* @param x Left screen coordinate of the bitmap on emulator screen.
* @param y Top screen coordinate of the bitmap on emulator screen.
*/
private void computeDrawMatrix(int x, int y) {
mDrawMatrix.set(mBaseMatrix);
if (mRotateDisplay) {
mDrawMatrix.postTranslate(-y * mDy, x * mDx);
} else {
mDrawMatrix.postTranslate(x * mDx, y * mDy);
}
}
/**
* Draws a bitmap on the screen.
*
* @param x Left screen coordinate of the bitmap on emulator screen.
* @param y Top screen coordinate of the bitmap on emulator screen.
* @param w Width of the bitmap on the emulator screen.
* @param h Height of the bitmap on the emulator screen.
* @param colors Bitmap to draw.
*/
public void drawBitmap(int x, int y, int w, int h, int[] colors) {
if (mCanvas != null) {
final Bitmap bmp = Bitmap.createBitmap(colors, 0, w, w, h, Bitmap.Config.ARGB_8888);
computeDrawMatrix(x, y);
/* Draw the bitmap and invalidate the updated region. */
mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint);
invalidate();
}
}
/**
* Draws a JPEG bitmap on the screen.
*
* @param x Left screen coordinate of the bitmap on emulator screen.
* @param y Top screen coordinate of the bitmap on emulator screen.
* @param w Width of the bitmap on the emulator screen.
* @param h Height of the bitmap on the emulator screen.
* @param jpeg JPEG bitmap to draw.
*/
public void drawJpeg(int x, int y, int w, int h, InputStream jpeg) {
if (mCanvas != null) {
final Bitmap bmp = BitmapFactory.decodeStream(jpeg);
computeDrawMatrix(x, y);
/* Draw the bitmap and invalidate the updated region. */
mCanvas.drawBitmap(bmp, mDrawMatrix, mPaint);
invalidate();
}
}
/**
* Constructs touch event message to be send to emulator.
*
* @param bb ByteBuffer where to construct the message.
* @param event Event for which to construct the message.
* @param ptr_index Index of the motion pointer for which to construct the
* message.
*/
public void constructEventMessage(ByteBuffer bb, MotionEvent event, int ptr_index) {
bb.putInt(event.getPointerId(ptr_index));
if (mRotateDisplay == false) {
bb.putInt((int) (event.getX(ptr_index) / mDx));
bb.putInt((int) (event.getY(ptr_index) / mDy));
} else {
bb.putInt((int) (event.getY(ptr_index) / mDy));
bb.putInt((int) (getWidth() - event.getX(ptr_index) / mDx));
}
// At the system level the input reader takes integers in the range
// 0 - 100 for the pressure.
int pressure = (int) (event.getPressure(ptr_index) * 100);
// Make sure it doesn't exceed 100...
if (pressure > 100) {
pressure = 100;
}
bb.putInt(pressure);
}
/***************************************************************************
* Logging wrappers
**************************************************************************/
@SuppressWarnings("unused")
private void Loge(String log) {
Log.e(TAG, log);
}
@SuppressWarnings("unused")
private void Logw(String log) {
Log.w(TAG, log);
}
@SuppressWarnings("unused")
private void Logv(String log) {
Log.v(TAG, log);
}
}

View File

@ -0,0 +1,111 @@
#!/bin/bash
# Copyright 2005-2007, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=ddms.jar
frameworkdir="$progdir"
libdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
libdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
libdir=`dirname "$progdir"`/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
# Check args.
if [ debug = "$1" ]; then
# add this in for debugging
java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
shift 1
else
java_debug=
fi
javaCmd="java"
# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
if [ `uname` = "Darwin" ]; then
os_opts="-XstartOnFirstThread"
else
os_opts=
fi
if [ `uname` = "Linux" ]; then
export GDK_NATIVE_WINDOWS=true
fi
jarpath="$frameworkdir/$jarfile:$frameworkdir/swtmenubar.jar"
# Figure out the path to the swt.jar for the current architecture.
# if ANDROID_SWT is defined, then just use this.
# else, if running in the Android source tree, then look for the correct swt folder in prebuilt
# else, look for the correct swt folder in the SDK under tools/lib/
swtpath=""
if [ -n "$ANDROID_SWT" ]; then
swtpath="$ANDROID_SWT"
else
vmarch=`${javaCmd} -jar "${frameworkdir}"/archquery.jar`
if [ -n "$ANDROID_BUILD_TOP" ]; then
osname=`uname -s | tr A-Z a-z`
swtpath="${ANDROID_BUILD_TOP}/prebuilts/tools/${osname}-${vmarch}/swt"
else
swtpath="${frameworkdir}/${vmarch}"
fi
fi
if [ ! -d "$swtpath" ]; then
echo "SWT folder '${swtpath}' does not exist."
echo "Please export ANDROID_SWT to point to the folder containing swt.jar for your platform."
exit 1
fi
if [ -x $progdir/monitor ]; then
echo "The standalone version of DDMS is deprecated."
echo "Please use Android Device Monitor (tools/monitor) instead."
fi
exec "$javaCmd" \
-Xmx256M $os_opts $java_debug \
-Dcom.android.ddms.bindir="$progdir" \
-classpath "$jarpath:$swtpath/swt.jar" \
com.android.ddms.Main "$@"

View File

@ -0,0 +1,63 @@
#!/bin/sh
# Copyright 2008, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=draw9patch.jar
frameworkdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
libdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
libdir=`dirname "$progdir"`/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
if [ "$OSTYPE" = "cygwin" ] ; then
jarpath=`cygpath -w "$frameworkdir/$jarfile"`
progdir=`cygpath -w "$progdir"`
else
jarpath="$frameworkdir/$jarfile"
fi
# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
# might need more memory, e.g. -Xmx128M
exec java -Djava.ext.dirs="$frameworkdir" -jar "$jarpath" "$@"

View File

@ -0,0 +1,114 @@
#!/bin/sh
# Copyright 2008, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=hierarchyviewer2.jar
frameworkdir="$progdir"
libdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
libdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
libdir=`dirname "$progdir"`/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
# Check args.
if [ debug = "$1" ]; then
# add this in for debugging
java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
shift 1
else
java_debug=
fi
javaCmd="java"
# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
if [ `uname` = "Darwin" ]; then
os_opts="-XstartOnFirstThread"
else
os_opts=
fi
if [ `uname` = "Linux" ]; then
export GDK_NATIVE_WINDOWS=true
fi
jarpath="$frameworkdir/$jarfile:$frameworkdir/swtmenubar.jar"
# Figure out the path to the swt.jar for the current architecture.
# if ANDROID_SWT is defined, then just use this.
# else, if running in the Android source tree, then look for the correct swt folder in prebuilt
# else, look for the correct swt folder in the SDK under tools/lib/
swtpath=""
if [ -n "$ANDROID_SWT" ]; then
swtpath="$ANDROID_SWT"
else
vmarch=`${javaCmd} -jar "${frameworkdir}"/archquery.jar`
if [ -n "$ANDROID_BUILD_TOP" ]; then
osname=`uname -s | tr A-Z a-z`
swtpath="${ANDROID_BUILD_TOP}/prebuilts/tools/${osname}-${vmarch}/swt"
else
swtpath="${frameworkdir}/${vmarch}"
fi
fi
if [ ! -d "$swtpath" ]; then
echo "SWT folder '${swtpath}' does not exist."
echo "Please export ANDROID_SWT to point to the folder containing swt.jar for your platform."
exit 1
fi
if [ -x $progdir/monitor ]; then
echo "The standalone version of hieararchyviewer is deprecated."
echo "Please use Android Device Monitor (tools/monitor) instead."
fi
# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
# might need more memory, e.g. -Xmx128M
exec "$javaCmd" \
-Xmx512M $os_opts $java_debug \
-Dcom.android.hierarchyviewer.bindir="$progdir" \
-classpath "$jarpath:$swtpath/swt.jar" \
com.android.hierarchyviewer.HierarchyViewerApplication "$@"

View File

@ -0,0 +1,68 @@
#!/bin/sh
# Copyright 2008, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=jobb.jar
frameworkdir="$progdir"
libdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
libdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
libdir=`dirname "$progdir"`/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
javaCmd="java"
if [ `uname` = "Linux" ]; then
export GDK_NATIVE_WINDOWS=true
fi
jarpath="$frameworkdir/$jarfile:$frameworkdir/fat32lib.jar"
exec "$javaCmd" \
$os_opts \
-classpath "$jarpath" \
com.android.jobb.Main "$@"

View File

@ -0,0 +1,131 @@
;;;; Copyright 2007 The Android Open Source Project
;;; Set up GUD+JDB to attach to a Java process running on the phone or
;;; under the emulator.
(defvar android-jdb-port-history '("8700")
"history of ports supplied to `android-jdb'")
(defvar android-jdb-project-root-history '()
"history of project roots supplied to `android-jdb'")
(defvar android-jdb-history nil
"history of commands supplied to `android-jdb'")
(defvar android-jdb-activity-class-history ()
"history of activity classes supplied to `start-android-activity'")
(defcustom android-jdb-command-name "jdb"
"Name of Java debugger."
:type 'string
:group 'android)
(defgroup android nil
"Android Applications."
:group 'applications)
(defcustom android-project-root nil
"This is where your Android project root is stored."
:type 'directory
:group 'android )
(defcustom android-apk nil
"This is where your Android Application Package is stored."
:type 'string
:group 'android)
(defcustom android-activity-class nil
"This is where your Android Activity class is stored."
:type 'string
:group 'android)
(defun android-read-project-root ()
(if (or (string-match "XEmacs" emacs-version)
(>= emacs-major-version 22))
(read-file-name "Android project root: "
android-project-root
nil
t
nil
'file-directory-p)
(labels ((read-directory ()
(read-file-name "Android project root: "
android-project-root
nil
t
nil)))
(do ((entered-root (read-directory) (read-directory)))
((and entered-root
(file-directory-p entered-root))
(expand-file-name entered-root))))))
(defun android-jdb (port root)
"Set GUD+JDB up to run against Android on PORT in directory ROOT."
(interactive
(list
(read-from-minibuffer "Activity's JDWP DDMS port: "
(car android-jdb-port-history)
nil
t
'android-jdb-port-history)
(android-read-project-root)))
(setq android-project-root root)
(let ((jdb-command
(format "%s -attach localhost:%s -sourcepath%s"
android-jdb-command-name
port
(format "%s/src" root))))
(if (not (string= jdb-command (car android-jdb-history)))
(push jdb-command android-jdb-history))
(jdb jdb-command)))
(defun android-emulate ()
"Run the Android emulator. This expects the SDK tools directory to be in the current path."
(interactive)
(compile "emulator"))
(defun android-install-app (apk)
"Install an Android application package APK in the Android emulator. This expects the SDK tools directory to be in the current path."
(interactive (list (expand-file-name
(read-file-name "Android Application Package (.apk): "
nil
android-apk
t
nil
nil))))
(setq android-apk apk)
(compile (format "adb install -r %s" apk)))
(defun android-uninstall-app (package-name)
"Uninstall an Android application package APK in the Android emulator. This expects the SDK tools directory to be in the current path.
Specify the package name --- and not the name of the application e.g., com.android.foo."
(interactive
(list
(read-from-minibuffer "Package: ")))
(compile (format "adb uninstall %s" package-name)))
(defun android-start-activity (package class)
"Start the activity PACKAGE/CLASS in the Android emulator. This expects the SDK tools directory to be in the current path."
(interactive
(list
(read-from-minibuffer "Package: ")
(read-from-minibuffer "Activity Java class: "
(car android-jdb-activity-class-history)
nil
t
'android-jdb-activity-class-history)))
(compile (format "adb shell am start -n %s/%s" package class)))
(defun android-debug-activity (package class)
"Start the activity PACKAGE/CLASS within the debugger in the Android emulator. This expects the SDK tools directory to be in the current path."
(interactive
(list
(read-from-minibuffer "Package: ")
(read-from-minibuffer "Activity Java class: "
(car android-jdb-activity-class-history)
nil
t
'android-jdb-activity-class-history)))
(compile (format "adb shell am start -D -n %s/%s" package class)))
(provide 'android)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="PROJECT_NAME" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: VERSION_TAG -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,21 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:ARTIFACT_VERSION'
}
}
apply plugin: 'PLUGIN'
android {
compileSdkVersion 'TARGET'
buildToolsVersion 'BUILD_TOOL_REV'
buildTypes {
release {
runProguard false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,595 @@
<?xml version="1.0" encoding="UTF-8"?>
<d:devices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://schemas.android.com/sdk/devices/1">
<d:device>
<d:name>Nexus One</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>normal</d:screen-size>
<d:diagonal-length>3.7</d:diagonal-length>
<d:pixel-density>hdpi</d:pixel-density>
<d:screen-ratio>long</d:screen-ratio>
<d:dimensions>
<d:x-dimension>480</d:x-dimension>
<d:y-dimension>800</d:y-dimension>
</d:dimensions>
<d:xdpi>254</d:xdpi>
<d:ydpi>254</d:ydpi>
<d:touch>
<d:multitouch>basic</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Wifi
Bluetooth
</d:networking>
<d:sensors>
Accelerometer
Compass
GPS
LightSensor
ProximitySensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>back</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>true</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>trackball</d:nav>
<d:ram unit="MiB">512</d:ram>
<d:buttons>hard</d:buttons>
<d:internal-storage unit="MiB">503</d:internal-storage>
<d:removable-storage unit="MiB">0</d:removable-storage>
<d:cpu>Qualcomm Scorpion</d:cpu>
<d:gpu>Qualcomm Adreno 200</d:gpu>
<d:abi>
armeabi-v7a
armeabi
</d:abi>
<d:dock> </d:dock>
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>7-10</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles> </d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<d:gl-extensions>
</d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait" default="true">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
<d:device>
<d:name>Nexus S</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>normal</d:screen-size>
<d:diagonal-length>4</d:diagonal-length>
<d:pixel-density>hdpi</d:pixel-density>
<d:screen-ratio>long</d:screen-ratio>
<d:dimensions>
<d:x-dimension>480</d:x-dimension>
<d:y-dimension>800</d:y-dimension>
</d:dimensions>
<d:xdpi>235</d:xdpi>
<d:ydpi>235</d:ydpi>
<d:touch>
<d:multitouch>jazz-hands</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Wifi
Bluetooth
NFC
</d:networking>
<d:sensors>
Accelerometer
Compass
GPS
Gyroscope
LightSensor
ProximitySensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>back</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>true</d:flash>
</d:camera>
<d:camera>
<d:location>front</d:location>
<d:autofocus>false</d:autofocus>
<d:flash>false</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>nonav</d:nav>
<d:ram unit="KiB">351428</d:ram>
<d:buttons>hard</d:buttons>
<d:internal-storage unit="MiB">503</d:internal-storage>
<d:removable-storage unit="MiB">0</d:removable-storage>
<d:cpu>Samsung Exynos 3110</d:cpu>
<d:gpu>PowerVR SGX 540</d:gpu>
<d:abi>
armeabi-v7a
armeabi
</d:abi>
<d:dock> </d:dock>
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>9-16</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles> </d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<d:gl-extensions>
GL_EXT_debug_marker
GL_OES_rgb8_rgba8
GL_OES_depth24
GL_OES_vertex_half_float
GL_OES_texture_float
GL_OES_texture_half_float
GL_OES_element_index_uint
GL_OES_mapbuffer
GL_OES_fragment_precision_high
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_EGL_image
GL_OES_EGL_image_external
GL_OES_required_internalformat
GL_OES_depth_texture
GL_OES_get_program_binary
GL_OES_packed_depth_stencil
GL_OES_standard_derivatives
GL_OES_vertex_array_object
GL_OES_egl_sync
GL_EXT_multi_draw_arrays
GL_EXT_texture_format_BGRA8888
GL_EXT_discard_framebuffer
GL_EXT_shader_texture_lod
GL_IMG_shader_binary
GL_IMG_texture_compression_pvrtc
GL_IMG_texture_npot
GL_IMG_texture_format_BGRA8888
GL_IMG_read_format
GL_IMG_program_binary
GL_IMG_multisampled_render_to_texture
</d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait" default="true">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
<d:device>
<d:name>Galaxy Nexus</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>normal</d:screen-size>
<d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
<d:pixel-density>xhdpi</d:pixel-density>
<d:screen-ratio>long</d:screen-ratio>
<d:dimensions>
<d:x-dimension>720</d:x-dimension>
<d:y-dimension>1280</d:y-dimension>
</d:dimensions>
<d:xdpi>316</d:xdpi>
<d:ydpi>316</d:ydpi>
<d:touch>
<d:multitouch>jazz-hands</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Bluetooth
Wifi
NFC
</d:networking>
<d:sensors>
Accelerometer
Barometer
Gyroscope
Compass
GPS
ProximitySensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>front</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>false</d:flash>
</d:camera>
<d:camera>
<d:location>back</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>true</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>nonav</d:nav>
<d:ram unit="GiB">1</d:ram>
<d:buttons>soft</d:buttons>
<d:internal-storage unit="GiB">16</d:internal-storage>
<d:removable-storage unit="KiB"></d:removable-storage>
<d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
<d:gpu>PowerVR SGX540</d:gpu>
<d:abi>
armeabi
armeabi-v7a
</d:abi>
<!--dock (car, desk, tv, none)-->
<d:dock>
</d:dock>
<!-- power-type (battery, plugged-in) -->
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>14-</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles>
HSP
HFP
SPP
A2DP
AVRCP
OPP
PBAP
GAVDP
AVDTP
HID
HDP
PAN
</d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<!--
These can be gotten via
javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
-->
<d:gl-extensions>
GL_EXT_discard_framebuffer
GL_EXT_multi_draw_arrays
GL_EXT_shader_texture_lod
GL_EXT_texture_format_BGRA8888
GL_IMG_multisampled_render_to_texture
GL_IMG_program_binary
GL_IMG_read_format
GL_IMG_shader_binary
GL_IMG_texture_compression_pvrtc
GL_IMG_texture_format_BGRA8888
GL_IMG_texture_npot
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_depth_texture
GL_OES_depth24
GL_OES_EGL_image
GL_OES_EGL_image_external
GL_OES_egl_sync
GL_OES_element_index_uint
GL_OES_fragment_precision_high
GL_OES_get_program_binary
GL_OES_mapbuffer
GL_OES_packed_depth_stencil
GL_OES_required_internalformat
GL_OES_rgb8_rgba8
GL_OES_standard_derivatives
GL_OES_texture_float
GL_OES_texture_half_float
GL_OES_vertex_array_object
GL_OES_vertex_half_float
</d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait" default="true">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
<d:device>
<d:name>Nexus 7</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>large</d:screen-size>
<d:diagonal-length>7.27</d:diagonal-length>
<d:pixel-density>tvdpi</d:pixel-density>
<d:screen-ratio>notlong</d:screen-ratio>
<d:dimensions>
<d:x-dimension>800</d:x-dimension>
<d:y-dimension>1280</d:y-dimension>
</d:dimensions>
<d:xdpi>195</d:xdpi>
<d:ydpi>200</d:ydpi>
<d:touch>
<d:multitouch>jazz-hands</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Wifi
Bluetooth
NFC
</d:networking>
<d:sensors>
Accelerometer
Compass
GPS
Gyroscope
LightSensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>front</d:location>
<d:autofocus>false</d:autofocus>
<d:flash>false</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>nonav</d:nav>
<d:ram unit="GiB">1</d:ram>
<d:buttons>soft</d:buttons>
<d:internal-storage unit="GiB">8</d:internal-storage>
<d:removable-storage unit="MiB"> </d:removable-storage>
<d:cpu> Tegra3 </d:cpu>
<d:gpu> Tegra3 </d:gpu>
<d:abi>
armeabi-v7a
armeabi
</d:abi>
<d:dock> </d:dock>
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>16</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles> </d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<d:gl-extensions> </d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait" default="true">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
<d:device>
<d:name>Nexus 4</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>normal</d:screen-size>
<d:diagonal-length>4.7</d:diagonal-length>
<d:pixel-density>xhdpi</d:pixel-density>
<d:screen-ratio>notlong</d:screen-ratio>
<d:dimensions>
<d:x-dimension>768</d:x-dimension>
<d:y-dimension>1280</d:y-dimension>
</d:dimensions>
<d:xdpi>320</d:xdpi>
<d:ydpi>320</d:ydpi>
<d:touch>
<d:multitouch>jazz-hands</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Wifi
Bluetooth
NFC
</d:networking>
<d:sensors>
Accelerometer
Barometer
Compass
GPS
Gyroscope
LightSensor
ProximitySensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>back</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>true</d:flash>
</d:camera>
<d:camera>
<d:location>front</d:location>
<d:autofocus>false</d:autofocus>
<d:flash>false</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>nonav</d:nav>
<d:ram unit="KiB">1953125</d:ram>
<d:buttons>soft</d:buttons>
<d:internal-storage unit="KiB">7811891</d:internal-storage>
<d:removable-storage unit="MiB"></d:removable-storage>
<d:cpu>Qualcomm Snapdragon S4 Pro</d:cpu>
<d:gpu>Adreno 320</d:gpu>
<d:abi>
armeabi-v7a
armeabi
</d:abi>
<d:dock></d:dock>
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>16</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles></d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<d:gl-extensions>GL_EXT_debug_marker GL_AMD_compressed_ATC_texture
GL_AMD_performance_monitor GL_AMD_program_binary_Z400 GL_EXT_robustness
GL_EXT_texture_format_BGRA8888 GL_EXT_texture_type_2_10_10_10_REV GL_NV_fence
GL_OES_compressed_ETC1_RGB8_texture GL_OES_depth_texture GL_OES_depth24
GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_element_index_uint
GL_OES_fbo_render_mipmap GL_OES_fragment_precision_high GL_OES_get_program_binary
GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_OES_standard_derivatives
GL_OES_texture_3D GL_OES_texture_float GL_OES_texture_half_float
GL_OES_texture_half_float_linear GL_OES_texture_npot GL_OES_vertex_half_float
GL_OES_vertex_type_10_10_10_2 GL_OES_vertex_array_object GL_QCOM_alpha_test
GL_QCOM_binning_control GL_QCOM_driver_control GL_QCOM_perfmon_global_mode
GL_QCOM_extended_get GL_QCOM_extended_get2 GL_QCOM_tiled_rendering
GL_QCOM_writeonly_rendering GL_EXT_sRGB
</d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait" default="true">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
<d:device>
<d:name>Nexus 10</d:name>
<d:manufacturer>Google</d:manufacturer>
<d:hardware>
<d:screen>
<d:screen-size>xlarge</d:screen-size>
<d:diagonal-length>10.055</d:diagonal-length>
<d:pixel-density>xhdpi</d:pixel-density>
<d:screen-ratio>notlong</d:screen-ratio>
<d:dimensions>
<d:x-dimension>2560</d:x-dimension>
<d:y-dimension>1600</d:y-dimension>
</d:dimensions>
<d:xdpi>300</d:xdpi>
<d:ydpi>300</d:ydpi>
<d:touch>
<d:multitouch>jazz-hands</d:multitouch>
<d:mechanism>finger</d:mechanism>
<d:screen-type>capacitive</d:screen-type>
</d:touch>
</d:screen>
<d:networking>
Wifi
Bluetooth
NFC
</d:networking>
<d:sensors>
Accelerometer
Barometer
Compass
GPS
Gyroscope
LightSensor
</d:sensors>
<d:mic>true</d:mic>
<d:camera>
<d:location>back</d:location>
<d:autofocus>true</d:autofocus>
<d:flash>true</d:flash>
</d:camera>
<d:camera>
<d:location>front</d:location>
<d:autofocus>false</d:autofocus>
<d:flash>false</d:flash>
</d:camera>
<d:keyboard>nokeys</d:keyboard>
<d:nav>nonav</d:nav>
<d:ram unit="KiB">1953125</d:ram>
<d:buttons>soft</d:buttons>
<d:internal-storage unit="KiB">15623782</d:internal-storage>
<d:removable-storage unit="MiB"></d:removable-storage>
<d:cpu>Dual-core A15</d:cpu>
<d:gpu>Quad-core Mali T604</d:gpu>
<d:abi>
armeabi-v7a
armeabi
</d:abi>
<d:dock></d:dock>
<d:power-type>battery</d:power-type>
</d:hardware>
<d:software>
<d:api-level>16</d:api-level>
<d:live-wallpaper-support>true</d:live-wallpaper-support>
<d:bluetooth-profiles></d:bluetooth-profiles>
<d:gl-version>2.0</d:gl-version>
<d:gl-extensions>GL_EXT_debug_marker GL_ARM_rgba8 GL_ARM_mali_shader_binary
GL_OES_depth24 GL_OES_depth_texture GL_OES_depth_texture_cube_map
GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra
GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture
GL_OES_standard_derivatives GL_OES_EGL_image GL_OES_EGL_image_external
GL_OES_EGL_sync GL_OES_texture_npot GL_OES_vertex_half_float
GL_OES_required_internalformat GL_OES_vertex_array_object GL_OES_mapbuffer
GL_EXT_texture_format_BGRA8888 GL_EXT_texture_rg GL_EXT_texture_type_2_10_10_10_REV
GL_OES_fbo_render_mipmap GL_OES_element_index_uint GL_EXT_shadow_samplers
GL_EXT_occlusion_query_boolean GL_EXT_blend_minmax GL_EXT_discard_framebuffer
GL_OES_get_program_binary GL_OES_texture_3D GL_EXT_texture_storage
GL_EXT_multisampled_render_to_texture GL_OES_surfaceless_context
GL_ARM_mali_program_binary
</d:gl-extensions>
<d:status-bar>true</d:status-bar>
</d:software>
<d:state name="Portrait">
<d:description>The phone in portrait view</d:description>
<d:screen-orientation>port</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
<d:state name="Landscape" default="true">
<d:description>The phone in landscape view</d:description>
<d:screen-orientation>land</d:screen-orientation>
<d:keyboard-state>keyssoft</d:keyboard-state>
<d:nav-state>nonav</d:nav-state>
</d:state>
</d:device>
</d:devices>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,402 @@
# This file describes the properties of a given virtual device configuration file.
#
# Note: Most top-level properties are boolean that control whether a feature is
# present or not. Sub-features that depend on it are ignored if their
# parent is set to 'false' or 'no'
#
# This file is parsed by 'android/tools/gen-hw-config.py' to generate
# 'android/avd/hw-config-defs.h'. The latter is a special header containing
# macro statements that is used several times:
#
# - once to define the fields of the AndroidHwConfig structure
# (see android/avd/hw-config.h)
#
# - once to implement the hardware configuration loader
# (see android/avd/hw-config.h)
#
# It is also packaged by the SDK and parsed by tools to let the developers
# create AVDs.
#
# NOTE: if you remove items from this file, be sure that you do not break
# the emulator build.
#
# CPU Architecture
name = hw.cpu.arch
type = string
default = arm
abstract = CPU Architecture
description = The CPU Architecture to emulator
# CPU Model
# Leave it empty, and the default value will be computed from
# hw.cpu.arch. This is only useful for experimentation for now.
name = hw.cpu.model
type = string
default =
abstract = CPU model
description = The CPU model (QEMU-specific string)
# Ram size
# Default value will be computed based on screen pixels
# or skin version
name = hw.ramSize
type = integer
default = 0
abstract = Device ram size
description = The amount of physical RAM on the device, in megabytes.
# Touch screen type
name = hw.screen
type = string
enum = touch, multi-touch, no-touch
default = touch
abstract = Touch screen type
description = Defines type of the screen.
# Hardware main keys (back/home)
name = hw.mainKeys
type = boolean
default = yes
abstract = Hardware Back/Home keys
description = Whether there are hardware back/home keys on the device.
# Trackball support
name = hw.trackBall
type = boolean
default = yes
abstract = Track-ball support
description = Whether there is a trackball on the device.
# Keyboard support (qwerty/azerty)
name = hw.keyboard
type = boolean
default = no
abstract = Keyboard support
description = Whether the device has a QWERTY keyboard.
# Keyboard lid support
# (I.e. can the qwerty keyboard be closed/hidden or opened/visible)
# this will be ignored if hw.keyboard is false
#
# NOTE: As a special case, the default value will be 'false' if the
# AVD targets API level 12 or higher. See hwConfig_init()
# in external/qemu/android/avd/hw-config.c for more details.
#
name = hw.keyboard.lid
type = boolean
default = yes
abstract = Keyboard lid support
description = Whether the QWERTY keyboard can be opened/closed.
# The name of the hardware charmap for this device.
#
# NOTE: This should always be the default 'qwerty2' unless you have
# modified the system image accordingly. This name is sent to
# the kernel at boot time. Using an incorrect name will result
# in an unusable machine.
name = hw.keyboard.charmap
type = string
default = qwerty2
abstract = Keyboard charmap name
description = Name of the system keyboard charmap file.
# DPad keys
name = hw.dPad
type = boolean
default = yes
abstract = DPad support
description = Whether the device has DPad keys
# GSM Modem support
name = hw.gsmModem
type = boolean
default = yes
abstract = GSM modem support
description = Whether there is a GSM modem in the device.
# GPS support
name = hw.gps
type = boolean
default = yes
abstract = GPS support
description = Whether there is a GPS in the device.
# Battery
name = hw.battery
type = boolean
default = yes
abstract = Battery support
description = Whether the device can run on a battery.
# Accelerometer (used for auto-rotation)
name = hw.accelerometer
type = boolean
default = yes
abstract = Accelerometer
description = Whether there is an accelerometer in the device.
# Audio input
name = hw.audioInput
type = boolean
default = yes
abstract = Audio recording support
description = Whether the device can record audio
# Audio output
name = hw.audioOutput
type = boolean
default = yes
abstract = Audio playback support
description = Whether the device can play audio
# SDCard support
name = hw.sdCard
type = boolean
default = yes
abstract = SD Card support
description = Whether the device supports insertion/removal of virtual SD Cards.
name = hw.sdCard.path
type = string
default =
abstract = SD Card image path
# Cache partition
name = disk.cachePartition
type = boolean
default = yes
abstract = Cache partition support
description = Whether we use a /cache partition on the device.
name = disk.cachePartition.path
type = string
default =
abstract = Cache partition
description = Cache partition to use on the device. Ignored if disk.cachePartition is not 'yes'.
name = disk.cachePartition.size
type = diskSize
abstract = Cache partition size
default = 66MB
# LCD width
name = hw.lcd.width
type = integer
default = 320
abstract = LCD pixel width
name = hw.lcd.height
type = integer
default = 640
abstract = LCD pixel height
name = hw.lcd.depth
type = integer
enum = 16, 32
default = 16
abstract = LCD color depth
description = Color bit depth of emulated framebuffer.
# LCD density
name = hw.lcd.density
type = integer
enum = 120, 160, 240, 213, 320
default = 160
abstract = Abstracted LCD density
description = A value used to roughly describe the density of the LCD screen for automatic resource/asset selection.
# LCD backlight - Enable/Disable LCD backlight simulation
# default = no : Disabled
# default = yes : Enabled
name = hw.lcd.backlight
type = boolean
default = yes
abstract = LCD backlight
description = Enable/Disable LCD backlight simulation,yes-enabled,no-disabled.
# Hardware OpenGLES emulation support
#
name = hw.gpu.enabled
type = boolean
default = no
abstract = GPU emulation
description = Enable/Disable emulated OpenGLES GPU
name = hw.gpu.mode
type = string
default = auto
enum = auto, host, mesa
abstract = GPU emulation mode
description = This value determines how GPU emulation is implemented.
# Configures the initial orientation: portrait or landscape
#
name = hw.initialOrientation
type = string
enum = portrait, landscape
default = portrait
abstract = Initial screen orientation
description = Setup initial screen orientation, can be rotated later on.
# Configures camera facing back
#
name = hw.camera.back
type = string
enum = emulated, none, webcam0, ...
default = emulated
abstract = Configures camera facing back
description = Must be 'emulated' for a fake camera, 'webcam<N>' for a web camera, or 'none' if back camera is disabled.
# Configures camera facing front
#
name = hw.camera.front
type = string
enum = emulated, none, webcam0, ...
default = none
abstract = Configures camera facing front
description = Must be 'emulated' for a fake camera, 'webcam<N>' for a web camera, or 'none' if front camera is disabled.
# Maximum VM heap size
# Higher values are required for high-dpi devices
# Default will depend on RAM size.
name = vm.heapSize
type = integer
default = 0
abstract = Max VM application heap size
description = The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.
# Proximity sensor
name = hw.sensors.proximity
type = boolean
default = yes
abstract = Proximity support
description = Whether there is an proximity in the device.
# Magnetic field sensor
name = hw.sensors.magnetic_field
type = boolean
default = yes
abstract = Magnetic field support
description = Provides magnetic field sensor values.
# Orientation sensor
name = hw.sensors.orientation
type = boolean
default = yes
abstract = Orientation support
description = Provides orientation sensor values.
# Temperature sensor
name = hw.sensors.temperature
type = boolean
default = yes
abstract = Temperature support
description = Provides temperature sensor values.
# File system
name = hw.useext4
type = boolean
default = yes
abstract = Deprecated option. Ignored.
description = Used to specify the Ext4 partition image type. This is now autodetected.
# Kernel image.
#
# kernel.path specified the path to the kernel image
# kernel.parameters specifies the string of kernel boot parameters.
#
name = kernel.path
type = string
default =
abstract = Path to the kernel image
description = Path to the kernel image.
name = kernel.parameters
type = string
default =
abstract = kernel boot parameters string.
name = kernel.newDeviceNaming
type = string
enum = autodetect, yes, no
default = autodetect
abstract = Does the kernel require a new device naming scheme?
description = Used to specify whether the kernel requires a new device naming scheme. Typically for Linux 3.10 and above.
name = kernel.supportsYaffs2
type = string
enum = autodetect, yes, no
default = autodetect
abstract = Does the kernel supports YAFFS2 partitions?
description = Used to specify whether the kernel supports YAFFS2 partition images. Typically before 3.10 only.
# Path to the ramdisk image.
name = disk.ramdisk.path
type = string
default =
abstract = Path to the ramdisk image
description = Path to the ramdisk image.
# System partition image(s).
#
# disk.systemPartition.path points to the read/write system partition image.
# if empty, a temporary file will be created, initialized with the content
# of .initPath
#
# disk.systemPartition.initPath is only used when .path is empty. It must
# then point to a read-only initialization system image file.
#
# disk.systemPartition.size is the ideal size of the system partition. The
# size is ignored if the actual system partition image is larger. Otherwise,
# it indicates the maximum size the disk image file can grow to.
#
name = disk.systemPartition.path
type = string
default =
abstract = Path to runtime system partition image
name = disk.systemPartition.initPath
type = string
default =
abstract = Initial system partition image
name = disk.systemPartition.size
type = diskSize
default = 0
abstract = Ideal size of system partition
# Path to the data partition.
name = disk.dataPartition.path
type = string
default = <temp>
abstract = Path to data partition file
description = Path to data partition file. Cannot be empty. Special value <temp> means using a temporary file. If disk.dataPartition.initPath is not empty, its content will be copied to the disk.dataPartition.path file at boot-time.
# Initial path to the data partition.
name = disk.dataPartition.initPath
type = string
default =
abstract = Initial data partition
description = If not empty, its content will be copied to the disk.dataPartition.path file at boot-time.
# Data partition size.
name = disk.dataPartition.size
type = diskSize
default = 0
abstract = Ideal size of data partition
# Path to the snapshots storage file.
name = disk.snapStorage.path
type = string
default =
abstract = Path to snapshot storage
description = Path to a 'snapshot storage' file, where all snapshots are stored.
# Android AVD name
# This is set automatically before launching a core.
#
name = avd.name
type = string
default = <build>
abstract = Name of the AVD being run

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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