summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/bootanimation/Android.mk48
-rw-r--r--cmds/bootanimation/BootAnimation.cpp95
-rw-r--r--cmds/bootanimation/BootAnimation.h86
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp106
-rw-r--r--cmds/hid/README.md145
-rw-r--r--cmds/hid/jni/Android.mk9
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.cpp125
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.h9
-rw-r--r--cmds/hid/src/com/android/commands/hid/Device.java26
-rw-r--r--cmds/hid/src/com/android/commands/hid/Hid.java13
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--cmds/screencap/screencap.cpp39
-rw-r--r--cmds/uiautomator/instrumentation/Android.mk1
-rw-r--r--cmds/uiautomator/library/Android.mk5
14 files changed, 485 insertions, 224 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 0e2c13ee1719..7ab402a2cd46 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -1,14 +1,49 @@
+bootanimation_CommonCFlags = -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+bootanimation_CommonCFlags += -Wall -Werror -Wunused -Wunreachable-code
+
+
+# bootanimation executable
+# =========================================================
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
bootanimation_main.cpp \
audioplay.cpp \
- BootAnimation.cpp
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += ${bootanimation_CommonCFlags}
+
+LOCAL_SHARED_LIBRARIES := \
+ libOpenSLES \
+ libandroidfw \
+ libbase \
+ libbinder \
+ libbootanimation \
+ libcutils \
+ liblog \
+ libutils \
+
+LOCAL_MODULE:= bootanimation
+
+LOCAL_INIT_RC := bootanim.rc
+
+ifdef TARGET_32_BIT_SURFACEFLINGER
+LOCAL_32_BIT_ONLY := true
+endif
+
+include $(BUILD_EXECUTABLE)
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
+# libbootanimation
+# ===========================================================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbootanimation
+LOCAL_CFLAGS += ${bootanimation_CommonCFlags}
+
+LOCAL_SRC_FILES:= \
+ BootAnimation.cpp
LOCAL_C_INCLUDES += \
external/tinyalsa/include \
@@ -25,16 +60,11 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv1_CM \
libgui \
- libOpenSLES \
libtinyalsa \
libbase
-LOCAL_MODULE:= bootanimation
-
-LOCAL_INIT_RC := bootanim.rc
-
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
-include $(BUILD_EXECUTABLE)
+include ${BUILD_SHARED_LIBRARY}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 7394490fc8d4..6b2de4b7f1ff 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -62,7 +62,6 @@
#include <EGL/eglext.h>
#include "BootAnimation.h"
-#include "audioplay.h"
namespace android {
@@ -92,26 +91,18 @@ static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS;
static const int TEXT_CENTER_VALUE = INT_MAX;
static const int TEXT_MISSING_VALUE = INT_MIN;
static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
-static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
static const int ANIM_ENTRY_NAME_MAX = 256;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
-static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
-static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
-// bootreasons list in "system/core/bootstat/bootstat.cpp".
-static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
- "kernel_panic",
- "Panic",
- "Watchdog",
-};
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
- mTimeFormat12Hour(false), mTimeCheckThread(NULL) {
+BootAnimation::BootAnimation(InitCallback initCallback,
+ PlayPartCallback partCallback)
+ : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
+ mTimeFormat12Hour(false), mTimeCheckThread(NULL),
+ mInitCallback(initCallback), mPlayPartCallback(partCallback) {
mSession = new SurfaceComposerClient();
- // If the system has already booted, the animation is not being used for a boot.
- mSystemBoot = !android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false);
std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
if (powerCtl.empty()) {
mShuttingDown = false;
@@ -142,7 +133,6 @@ void BootAnimation::binderDied(const wp<IBinder>&)
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
requestExit();
- audioplay::destroy();
}
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
@@ -158,10 +148,6 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
asset->close();
delete asset;
- // ensure we can call getPixels(). No need to call unlock, since the
- // bitmap will go out of scope when we return from this method.
- bitmap.lockPixels();
-
const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();
@@ -216,10 +202,6 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
// the packed resource can be released.
delete map;
- // ensure we can call getPixels(). No need to call unlock, since the
- // bitmap will go out of scope when we return from this method.
- bitmap.lockPixels();
-
const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();
@@ -712,7 +694,6 @@ bool BootAnimation::preloadZip(Animation& animation)
return false;
}
- Animation::Part* partWithAudio = NULL;
ZipEntryRO entry;
char name[ANIM_ENTRY_NAME_MAX];
while ((entry = zip->nextEntry(cookie)) != NULL) {
@@ -747,7 +728,6 @@ bool BootAnimation::preloadZip(Animation& animation)
// a part may have at most one audio file
part.audioData = (uint8_t *)map->getDataPtr();
part.audioLength = map->getDataLength();
- partWithAudio = &part;
} else if (leaf == "trim.txt") {
part.trimData.setTo((char const*)map->getDataPtr(),
map->getDataLength());
@@ -797,13 +777,8 @@ bool BootAnimation::preloadZip(Animation& animation)
}
}
- // Create and initialize audioplay if there is a wav file in any of the animations.
- // Do it on a separate thread so we don't hold up the animation intro.
- if (partWithAudio != NULL) {
- ALOGD("found audio.wav, creating playback engine");
- mInitAudioThread = new InitAudioThread(partWithAudio->audioData,
- partWithAudio->audioLength);
- mInitAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
+ if (mInitCallback != nullptr) {
+ mInitCallback(animation.parts);
}
zip->endIteration(cookie);
@@ -876,11 +851,6 @@ bool BootAnimation::movie()
mTimeCheckThread = nullptr;
}
- // We should have joined mInitAudioThread thread in playAnimation
- if (mInitAudioThread != nullptr) {
- mInitAudioThread = nullptr;
- }
-
releaseAnimation(animation);
if (clockFontInitialized) {
@@ -917,14 +887,8 @@ bool BootAnimation::playAnimation(const Animation& animation)
if(exitPending() && !part.playUntilComplete)
break;
- // only play audio file the first time we animate the part
- if (r == 0 && part.audioData && playSoundsAllowed()) {
- ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
- // Block until the audio engine is finished initializing.
- if (mInitAudioThread != nullptr) {
- mInitAudioThread->join();
- }
- audioplay::playClip(part.audioData, part.audioLength);
+ if (mPlayPartCallback != nullptr) {
+ mPlayPartCallback(i, part, r);
}
glClearColor(
@@ -1013,10 +977,6 @@ bool BootAnimation::playAnimation(const Animation& animation)
}
}
- // we've finally played everything we're going to play
- audioplay::setPlaying(false);
- audioplay::destroy();
-
return true;
}
@@ -1062,32 +1022,6 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
return animation;
}
-bool BootAnimation::playSoundsAllowed() const {
- // Only play sounds for system boots, not runtime restarts.
- if (!mSystemBoot) {
- return false;
- }
- if (mShuttingDown) { // no audio while shutting down
- return false;
- }
- // Read the system property to see if we should play the sound.
- // If it's not present, default to allowed.
- if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
- return false;
- }
-
- // Don't play sounds if this is a reboot due to an error.
- char bootreason[PROPERTY_VALUE_MAX];
- if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
- for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
- if (strcasecmp(str.c_str(), bootreason) == 0) {
- return false;
- }
- }
- }
- return true;
-}
-
bool BootAnimation::updateIsTimeAccurate() {
static constexpr long long MAX_TIME_IN_PAST = 60000LL * 60LL * 24LL * 30LL; // 30 days
static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL; // 90 minutes
@@ -1219,17 +1153,6 @@ status_t BootAnimation::TimeCheckThread::readyToRun() {
return NO_ERROR;
}
-BootAnimation::InitAudioThread::InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
- : Thread(false),
- mExampleAudioData(exampleAudioData),
- mExampleAudioLength(exampleAudioLength) {}
-
-bool BootAnimation::InitAudioThread::threadLoop() {
- audioplay::create(mExampleAudioData, mExampleAudioLength);
- // Exit immediately
- return false;
-}
-
// ---------------------------------------------------------------------------
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 181ef1c596d1..3ebe7d6e4dff 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -39,44 +39,6 @@ class SurfaceControl;
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
- BootAnimation();
-
- sp<SurfaceComposerClient> session() const;
-
-private:
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
- virtual void binderDied(const wp<IBinder>& who);
-
- bool updateIsTimeAccurate();
-
- class TimeCheckThread : public Thread {
- public:
- TimeCheckThread(BootAnimation* bootAnimation);
- virtual ~TimeCheckThread();
- private:
- virtual status_t readyToRun();
- virtual bool threadLoop();
- bool doThreadLoop();
- void addTimeDirWatch();
-
- int mInotifyFd;
- int mSystemWd;
- int mTimeWd;
- BootAnimation* mBootAnimation;
- };
-
- class InitAudioThread : public Thread {
- public:
- InitAudioThread(uint8_t* exampleAudioData, int mExampleAudioLength);
- private:
- virtual bool threadLoop();
-
- uint8_t* mExampleAudioData;
- int mExampleAudioLength;
- };
-
struct Texture {
GLint w;
GLint h;
@@ -131,6 +93,49 @@ private:
Font clockFont;
};
+ // Callback will be called during initialization after we have loaded
+ // the animation and be provided with all parts in animation.
+ typedef std::function<void(const Vector<Animation::Part>& parts)> InitCallback;
+
+ // Callback will be called while animation is playing before each part is
+ // played. It will be provided with the part and play count for it.
+ // It will be provided with the partNumber for the part about to be played,
+ // as well as a reference to the part itself. It will also be provided with
+ // which play of that part is about to start, some parts are repeated
+ // multiple times.
+ typedef std::function<void(int partNumber, const Animation::Part& part, int playNumber)>
+ PlayPartCallback;
+
+ // Callbacks may be null and will be called from this class's internal
+ // thread.
+ BootAnimation(InitCallback initCallback, PlayPartCallback partCallback);
+
+ sp<SurfaceComposerClient> session() const;
+
+private:
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ virtual void binderDied(const wp<IBinder>& who);
+
+ bool updateIsTimeAccurate();
+
+ class TimeCheckThread : public Thread {
+ public:
+ TimeCheckThread(BootAnimation* bootAnimation);
+ virtual ~TimeCheckThread();
+ private:
+ virtual status_t readyToRun();
+ virtual bool threadLoop();
+ bool doThreadLoop();
+ void addTimeDirWatch();
+
+ int mInotifyFd;
+ int mSystemWd;
+ int mTimeWd;
+ BootAnimation* mBootAnimation;
+ };
+
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(FileMap* map, int* width, int* height);
status_t initFont(Font* font, const char* fallback);
@@ -144,7 +149,6 @@ private:
void releaseAnimation(Animation*) const;
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
- bool playSoundsAllowed() const;
void checkExit();
@@ -162,12 +166,12 @@ private:
bool mClockEnabled;
bool mTimeIsAccurate;
bool mTimeFormat12Hour;
- bool mSystemBoot;
bool mShuttingDown;
String8 mZipFileName;
SortedVector<String8> mLoadedFiles;
sp<TimeCheckThread> mTimeCheckThread = nullptr;
- sp<InitAudioThread> mInitAudioThread = nullptr;
+ InitCallback mInitCallback = nullptr;
+ PlayPartCallback mPlayPartCallback = nullptr;
};
// ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 3689d5ed937e..c11d90522ffd 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -27,13 +27,77 @@
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/threads.h>
+#include <android-base/properties.h>
#include "BootAnimation.h"
+#include "audioplay.h"
using namespace android;
// ---------------------------------------------------------------------------
+namespace {
+
+// Create a typedef for readability.
+typedef android::BootAnimation::Animation Animation;
+
+static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
+static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
+static const char POWER_CTL_PROP_NAME[] = "sys.powerctl";
+static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
+static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
+ "kernel_panic",
+ "Panic",
+ "Watchdog",
+};
+
+class InitAudioThread : public Thread {
+public:
+ InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
+ : Thread(false),
+ mExampleAudioData(exampleAudioData),
+ mExampleAudioLength(exampleAudioLength) {}
+private:
+ virtual bool threadLoop() {
+ audioplay::create(mExampleAudioData, mExampleAudioLength);
+ // Exit immediately
+ return false;
+ }
+
+ uint8_t* mExampleAudioData;
+ int mExampleAudioLength;
+};
+
+bool playSoundsAllowed() {
+ // Only play sounds for system boots, not runtime restarts.
+ if (android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false)) {
+ return false;
+ }
+ // no audio while shutting down
+ if (!android::base::GetProperty(POWER_CTL_PROP_NAME, "").empty()) {
+ return false;
+ }
+ // Read the system property to see if we should play the sound.
+ // If it's not present, default to allowed.
+ if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
+ return false;
+ }
+
+ // Don't play sounds if this is a reboot due to an error.
+ char bootreason[PROPERTY_VALUE_MAX];
+ if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
+ for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
+ if (strcasecmp(str.c_str(), bootreason) == 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
@@ -71,10 +135,50 @@ int main()
ALOGI("Waiting for SurfaceFlinger took %" PRId64 " ms", totalWaited);
}
+ // TODO: Move audio code to a new class that just exports the callbacks.
+ sp<InitAudioThread> initAudioThread = nullptr;
+
+ auto initCallback = [&](const Vector<Animation::Part>& parts) {
+ const Animation::Part* partWithAudio = nullptr;
+ for (const Animation::Part& part : parts) {
+ if (part.audioData != nullptr) {
+ partWithAudio = &part;
+ }
+ }
+
+ if (partWithAudio == nullptr) {
+ return;
+ }
+
+ ALOGD("found audio.wav, creating playback engine");
+ initAudioThread = new InitAudioThread(partWithAudio->audioData,
+ partWithAudio->audioLength);
+ initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
+
+ };
+
+ auto partCallback = [&](int partNumber, const Animation::Part& part,
+ int playNumber) {
+ // only play audio file the first time we animate the part
+ if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
+ ALOGD("playing clip for part%d, size=%d",
+ partNumber, part.audioLength);
+ // Block until the audio engine is finished initializing.
+ if (initAudioThread != nullptr) {
+ initAudioThread->join();
+ }
+ audioplay::playClip(part.audioData, part.audioLength);
+ }
+ };
+
// create the boot animation object
- sp<BootAnimation> boot = new BootAnimation();
+ sp<BootAnimation> boot = new BootAnimation(initCallback, partCallback);
IPCThreadState::self()->joinThreadPool();
+
+ // we've finally played everything we're going to play
+ audioplay::setPlaying(false);
+ audioplay::destroy();
}
return 0;
}
diff --git a/cmds/hid/README.md b/cmds/hid/README.md
new file mode 100644
index 000000000000..7e22d08eeaeb
--- /dev/null
+++ b/cmds/hid/README.md
@@ -0,0 +1,145 @@
+# Usage
+## Two options to use the hid command:
+### 1. Interactive through stdin:
+type `hid -` into the terminal, then type/paste commands to send to the binary.
+Use Ctrl+D to signal end of stream to the binary (EOF).
+
+This mode can be also used from an app to send HID events.
+For an example, see the cts test case at: [InputTestCase.java][2]
+
+When using another program to control hid in interactive mode, registering a
+new input device (for example, a bluetooth joystick) should be the first step.
+After the device is added, you need to wait for the _onInputDeviceAdded_
+(see [InputDeviceListener][1]) notification before issuing commands
+to the device.
+Failure to do so will cause missed events and inconsistent behaviour.
+In the current implementation of the hid command, the hid binary will wait
+for the file descriptor to the uhid node to send the UHID_START and UHID_OPEN
+signals before returning. However, this is not sufficient. These signals
+only notify the readiness of the kernel driver,
+but do not take into account the inputflinger framework.
+
+
+### 2. Using a file as an input:
+type `hid <filename>`, and the file will be used an an input to the binary.
+You must add a sufficient delay after a "register" command to ensure device
+is ready. The interactive mode is the recommended method of communicating
+with the hid binary.
+
+All of the input commands should be in pseudo-JSON format as documented below.
+See examples [here][3].
+
+The file can have multiple commands one after the other (which is not strictly
+legal JSON format, as this would imply multiple root elements).
+
+## Command description
+
+1. `register`
+Register a new uhid device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:--------------------------|
+| id | integer | Device id |
+| command | string | Must be set to "register" |
+| name | string | Device name |
+| vid | 16-bit integer| Vendor id |
+| pid | 16-bit integer| Product id |
+| descriptor | byte array | USB HID report descriptor |
+
+Device ID is used for matching the subsequent commands to a specific device
+to avoid ambiguity when multiple devices are registered.
+
+USB HID report descriptor should be generated according the the USB HID spec
+and can be checked by reverse parsing using a variety of tools, for example
+[usbdescreqparser][5].
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "register",
+ "name": "Odie (Test)",
+ "vid": 0x18d1,
+ "pid": 0x2c40,
+ "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
+ 0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
+ 0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
+ 0x23, 0x02, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0b, 0x81, 0x02, 0x75, 0x01, 0x95,
+ 0x01, 0x81, 0x03, 0x05, 0x01, 0x75, 0x04, 0x95, 0x01, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x66,
+ 0x14, 0x00, 0x09, 0x39, 0x81, 0x42, 0x66, 0x00, 0x00, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,
+ 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x05, 0x02, 0x09, 0xc5, 0x09, 0xc4, 0x15, 0x00, 0x26,
+ 0xff, 0x00, 0x35, 0x00, 0x46, 0xff, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0x85,
+ 0x02, 0x05, 0x08, 0x0a, 0x01, 0x00, 0x0a, 0x02, 0x00, 0x0a, 0x03, 0x00, 0x0a, 0x04, 0x00,
+ 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x91, 0x02, 0x75, 0x04, 0x95, 0x01, 0x91,
+ 0x03, 0xc0, 0x05, 0x0c, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x03, 0x05, 0x01, 0x09, 0x06, 0xa1,
+ 0x02, 0x05, 0x06, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81,
+ 0x02, 0x06, 0xbc, 0xff, 0x0a, 0xad, 0xbd, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0xc0]
+}
+```
+2. `delay`
+Add a delay to command processing
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "delay" |
+| duration | integer | Delay in milliseconds |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "delay",
+ "duration": 10
+}
+```
+
+3. `report`
+Send a report to the HID device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "report" |
+| report | byte array | Report data to send |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "report",
+ "report": [0x01, 0x01, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00]
+}
+```
+
+### Sending a joystick button press event
+To send a button press event on a joystick device:
+1. Register the joystick device
+2. Send button down event with coordinates ABS_X, ABS_Y, ABS_Z, and ABS_RZ
+at the center of the range. If the coordinates are not centered, this event
+will generate a motion event within the input framework, in addition to the
+button press event. The range can be determined from the uhid report descriptor.
+3. Send the button up event with the same coordinates as in 2.
+4. Check that the button press event was received.
+
+### Notes
+1. As soon as EOF is reached (either in interactive mode, or in file mode),
+the device that was created will be unregistered. There is no
+explicit command for unregistering a device.
+2. The linux input subsystem does not generate events for those values
+that remain unchanged. For example, if there are two events sent to the driver,
+and both events have the same value of ABS_X, then ABS_X coordinate
+will not be reported.
+3. The description of joystick actions is available [here][6].
+4. Joysticks are split axes. When an analog stick is in a resting state,
+the reported coordinates are at the center of the range.
+5. The `getevent` utility can used to print out the key events
+for debugging purposes.
+
+
+[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
+[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+[3]: ../../../../cts/tests/tests/hardware/res/raw/
+[4]: https://developer.android.com/training/game-controllers/controller-input.html#button
+[5]: http://eleccelerator.com/usbdescreqparser/
+[6]: https://developer.android.com/training/game-controllers/controller-input.html \ No newline at end of file
diff --git a/cmds/hid/jni/Android.mk b/cmds/hid/jni/Android.mk
index d41d39d27f5b..86f4e012a943 100644
--- a/cmds/hid/jni/Android.mk
+++ b/cmds/hid/jni/Android.mk
@@ -6,14 +6,9 @@ LOCAL_SRC_FILES := \
com_android_commands_hid_Device.cpp
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
- frameworks/base/core/jni
+ $(JNI_H_INCLUDE)
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- liblog \
- libnativehelper \
- libutils
+LOCAL_LDLIBS += -landroid -llog -lnativehelper
LOCAL_MODULE := libhidcommand_jni
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 1ea33ced7bbf..107dc863ef66 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -26,17 +26,17 @@
#include <memory>
#include <unistd.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/Log.h>
-#include <android_os_MessageQueue.h>
-#include <core_jni_helpers.h>
#include <jni.h>
#include <JNIHelp.h>
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
+#include <android/looper.h>
+#include <android/log.h>
+
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
namespace android {
namespace uhid {
@@ -56,59 +56,67 @@ static int handleLooperEvents(int /* fd */, int events, void* data) {
static void checkAndClearException(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
- ALOGE("An exception was thrown by callback '%s'.", methodName);
- LOGE_EX(env);
+ LOGE("An exception was thrown by callback '%s'.", methodName);
env->ExceptionClear();
}
}
DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
- mCallbackObject(env->NewGlobalRef(callback)) { }
+ mCallbackObject(env->NewGlobalRef(callback)) {
+ env->GetJavaVM(&mJavaVM);
+ }
DeviceCallback::~DeviceCallback() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->DeleteGlobalRef(mCallbackObject);
}
void DeviceCallback::onDeviceError() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
checkAndClearException(env, "onDeviceError");
}
void DeviceCallback::onDeviceOpen() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
checkAndClearException(env, "onDeviceOpen");
}
+JNIEnv* DeviceCallback::getJNIEnv() {
+ JNIEnv* env;
+ mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+}
+
Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
- std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) {
+ std::unique_ptr<DeviceCallback> callback) {
int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
if (fd < 0) {
- ALOGE("Failed to open uhid: %s", strerror(errno));
+ LOGE("Failed to open uhid: %s", strerror(errno));
return nullptr;
}
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
- ev.type = UHID_CREATE;
- strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH);
- ev.u.create.rd_data = descriptor.get();
- ev.u.create.rd_size = descriptorSize;
- ev.u.create.bus = BUS_BLUETOOTH;
- ev.u.create.vendor = vid;
- ev.u.create.product = pid;
- ev.u.create.version = 0;
- ev.u.create.country = 0;
+ ev.type = UHID_CREATE2;
+ strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH);
+ memcpy(&ev.u.create2.rd_data, descriptor.get(),
+ descriptorSize * sizeof(ev.u.create2.rd_data[0]));
+ ev.u.create2.rd_size = descriptorSize;
+ ev.u.create2.bus = BUS_BLUETOOTH;
+ ev.u.create2.vendor = vid;
+ ev.u.create2.product = pid;
+ ev.u.create2.version = 0;
+ ev.u.create2.country = 0;
errno = 0;
ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
if (ret < 0 || ret != sizeof(ev)) {
::close(fd);
- ALOGE("Failed to create uhid node: %s", strerror(errno));
+ LOGE("Failed to create uhid node: %s", strerror(errno));
return nullptr;
}
@@ -116,20 +124,30 @@ Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
if (ret < 0 || ev.type != UHID_START) {
::close(fd);
- ALOGE("uhid node failed to start: %s", strerror(errno));
+ LOGE("uhid node failed to start: %s", strerror(errno));
return nullptr;
}
-
- return new Device(id, fd, std::move(callback), looper);
+ return new Device(id, fd, std::move(callback));
}
-Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) :
- mId(id), mFd(fd), mDeviceCallback(std::move(callback)), mLooper(looper) {
- looper->addFd(fd, 0, Looper::EVENT_INPUT, handleLooperEvents, reinterpret_cast<void*>(this));
+Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
+ mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
+ ALooper* aLooper = ALooper_forThread();
+ if (aLooper == NULL) {
+ LOGE("Could not get ALooper, ALooper_forThread returned NULL");
+ aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ }
+ ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
+ reinterpret_cast<void*>(this));
}
Device::~Device() {
- mLooper->removeFd(mFd);
+ ALooper* looper = ALooper_forThread();
+ if (looper != NULL) {
+ ALooper_removeFd(looper, mFd);
+ } else {
+ LOGE("Could not remove fd, ALooper_forThread() returned NULL!");
+ }
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_DESTROY;
@@ -141,25 +159,25 @@ Device::~Device() {
void Device::sendReport(uint8_t* report, size_t reportSize) {
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
- ev.type = UHID_INPUT;
- ev.u.input.size = reportSize;
- memcpy(&ev.u.input.data, report, reportSize);
+ ev.type = UHID_INPUT2;
+ ev.u.input2.size = reportSize;
+ memcpy(&ev.u.input2.data, report, reportSize);
ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
if (ret < 0 || ret != sizeof(ev)) {
- ALOGE("Failed to send hid event: %s", strerror(errno));
+ LOGE("Failed to send hid event: %s", strerror(errno));
}
}
int Device::handleEvents(int events) {
- if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+ LOGE("uhid node was closed or an error occurred. events=0x%x", events);
mDeviceCallback->onDeviceError();
return 0;
}
struct uhid_event ev;
ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
if (ret < 0) {
- ALOGE("Failed to read from uhid node: %s", strerror(errno));
+ LOGE("Failed to read from uhid node: %s", strerror(errno));
mDeviceCallback->onDeviceError();
return 0;
}
@@ -184,7 +202,7 @@ std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& ou
}
static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
- jbyteArray rawDescriptor, jobject queue, jobject callback) {
+ jbyteArray rawDescriptor, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
@@ -194,20 +212,21 @@ static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint i
std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);
std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
- sp<Looper> looper = android_os_MessageQueue_getMessageQueue(env, queue)->getLooper();
uhid::Device* d = uhid::Device::open(
id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
- std::move(desc), size, std::move(cb), std::move(looper));
+ std::move(desc), size, std::move(cb));
return reinterpret_cast<jlong>(d);
}
-static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr,jbyteArray rawReport) {
+static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
size_t size;
std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
d->sendReport(report.get(), size);
+ } else {
+ LOGE("Could not send report, Device* is null!");
}
}
@@ -220,7 +239,7 @@ static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
static JNINativeMethod sMethods[] = {
{ "nativeOpenDevice",
- "(Ljava/lang/String;III[BLandroid/os/MessageQueue;"
+ "(Ljava/lang/String;III[B"
"Lcom/android/commands/hid/Device$DeviceCallback;)J",
reinterpret_cast<void*>(openDevice) },
{ "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
@@ -228,11 +247,21 @@ static JNINativeMethod sMethods[] = {
};
int register_com_android_commands_hid_Device(JNIEnv* env) {
- jclass clazz = FindClassOrDie(env, "com/android/commands/hid/Device$DeviceCallback");
+ jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback");
+ if (clazz == NULL) {
+ LOGE("Unable to find class 'DeviceCallback'");
+ return JNI_ERR;
+ }
uhid::gDeviceCallbackClassInfo.onDeviceOpen =
- GetMethodIDOrDie(env, clazz, "onDeviceOpen", "()V");
- uhid::gDeviceCallbackClassInfo.onDeviceError=
- GetMethodIDOrDie(env, clazz, "onDeviceError", "()V");
+ env->GetMethodID(clazz, "onDeviceOpen", "()V");
+ uhid::gDeviceCallbackClassInfo.onDeviceError =
+ env->GetMethodID(clazz, "onDeviceError", "()V");
+ if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
+ uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) {
+ LOGE("Unable to obtain onDeviceOpen or onDeviceError methods");
+ return JNI_ERR;
+ }
+
return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
sMethods, NELEM(sMethods));
}
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 6c5899eeb861..149456d8c10d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -17,8 +17,6 @@
#include <memory>
#include <jni.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
namespace android {
namespace uhid {
@@ -32,16 +30,18 @@ public:
void onDeviceError();
private:
+ JNIEnv* getJNIEnv();
jobject mCallbackObject;
+ JavaVM* mJavaVM;
};
class Device {
public:
static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
- std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+ std::unique_ptr<DeviceCallback> callback);
- Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+ Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
~Device();
void sendReport(uint8_t* report, size_t reportSize);
@@ -53,7 +53,6 @@ private:
int32_t mId;
int mFd;
std::unique_ptr<DeviceCallback> mDeviceCallback;
- sp<Looper> mLooper;
};
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index dbe883bd1136..8c52a8ed1e09 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -29,22 +29,14 @@ import com.android.internal.os.SomeArgs;
public class Device {
private static final String TAG = "HidDevice";
- // Minimum amount of time to wait before sending input events to a device. Even though we're
- // guaranteed that the device has been created and opened by the input system, there's still a
- // window in which the system hasn't started reading events out of it. If a stream of events
- // begins in during this window (like a button down event) and *then* we start reading, we're
- // liable to ignore the whole stream.
- private static final int MIN_WAIT_FOR_FIRST_EVENT = 150;
-
private static final int MSG_OPEN_DEVICE = 1;
private static final int MSG_SEND_REPORT = 2;
private static final int MSG_CLOSE_DEVICE = 3;
-
private final int mId;
private final HandlerThread mThread;
private final DeviceHandler mHandler;
- private long mEventTime;
+ private long mTimeToSend;
private final Object mCond = new Object();
@@ -53,7 +45,7 @@ public class Device {
}
private static native long nativeOpenDevice(String name, int id, int vid, int pid,
- byte[] descriptor, MessageQueue queue, DeviceCallback callback);
+ byte[] descriptor, DeviceCallback callback);
private static native void nativeSendReport(long ptr, byte[] data);
private static native void nativeCloseDevice(long ptr);
@@ -74,22 +66,22 @@ public class Device {
args.arg2 = descriptor;
args.arg3 = report;
mHandler.obtainMessage(MSG_OPEN_DEVICE, args).sendToTarget();
- mEventTime = SystemClock.uptimeMillis() + MIN_WAIT_FOR_FIRST_EVENT;
+ mTimeToSend = SystemClock.uptimeMillis();
}
public void sendReport(byte[] report) {
Message msg = mHandler.obtainMessage(MSG_SEND_REPORT, report);
- mHandler.sendMessageAtTime(msg, mEventTime);
+ // if two messages are sent at identical time, they will be processed in order received
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
}
public void addDelay(int delay) {
- mEventTime += delay;
+ mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
}
public void close() {
Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, mEventTime + 1);
+ mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1);
try {
synchronized (mCond) {
mCond.wait();
@@ -111,8 +103,7 @@ public class Device {
case MSG_OPEN_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
- (byte[]) args.arg2, getLooper().myQueue(), new DeviceCallback());
- nativeSendReport(mPtr, (byte[]) args.arg3);
+ (byte[]) args.arg2, new DeviceCallback());
pauseEvents();
break;
case MSG_SEND_REPORT:
@@ -155,6 +146,7 @@ public class Device {
}
public void onDeviceError() {
+ Log.e(TAG, "Device error occurred, closing /dev/uhid");
Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
msg.setAsynchronous(true);
msg.sendToTarget();
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index 976a78249bec..234e47f12dee 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -16,7 +16,6 @@
package com.android.commands.hid;
-import android.os.SystemClock;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
@@ -91,7 +90,6 @@ public class Hid {
}
}
-
private void process(Event e) {
final int index = mDevices.indexOfKey(e.getId());
if (index >= 0) {
@@ -101,10 +99,16 @@ public class Hid {
} else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
d.sendReport(e.getReport());
} else {
- error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ } else {
+ error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ }
}
- } else {
+ } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
registerDevice(e);
+ } else {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
}
}
@@ -124,7 +128,6 @@ public class Hid {
}
private static void error(String msg, Exception e) {
- System.out.println(msg);
Log.e(TAG, msg);
if (e != null) {
Log.e(TAG, Log.getStackTraceString(e));
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d71573f7ca50..c4193f647c32 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1473,7 +1473,7 @@ public final class Pm {
ClearDataObserver obs = new ClearDataObserver();
try {
mPm.freeStorageAndNotify(volumeUuid, sizeVal,
- StorageManager.FLAG_ALLOCATE_DEFY_RESERVED, obs);
+ StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
synchronized (obs) {
while (!obs.finished) {
try {
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index e5c246608a0f..23668786abee 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -33,17 +33,24 @@
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
+#include <system/graphics.h>
+
// TODO: Fix Skia.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <SkImageEncoder.h>
#include <SkData.h>
+#include <SkColorSpace.h>
#pragma GCC diagnostic pop
using namespace android;
static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
+#define COLORSPACE_UNKNOWN 0
+#define COLORSPACE_SRGB 1
+#define COLORSPACE_DISPLAY_P3 2
+
static void usage(const char* pname)
{
fprintf(stderr,
@@ -67,6 +74,31 @@ static SkColorType flinger2skia(PixelFormat f)
}
}
+static sk_sp<SkColorSpace> dataSpaceToColorSpace(android_dataspace d)
+{
+ switch (d) {
+ case HAL_DATASPACE_V0_SRGB:
+ return SkColorSpace::MakeSRGB();
+ case HAL_DATASPACE_DISPLAY_P3:
+ return SkColorSpace::MakeRGB(
+ SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
+ default:
+ return nullptr;
+ }
+}
+
+static uint32_t dataSpaceToInt(android_dataspace d)
+{
+ switch (d) {
+ case HAL_DATASPACE_V0_SRGB:
+ return COLORSPACE_SRGB;
+ case HAL_DATASPACE_DISPLAY_P3:
+ return COLORSPACE_DISPLAY_P3;
+ default:
+ return COLORSPACE_UNKNOWN;
+ }
+}
+
static status_t notifyMediaScanner(const char* fileName) {
String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
String8 fileUrl("\"");
@@ -139,6 +171,7 @@ int main(int argc, char** argv)
void const* base = NULL;
uint32_t w, s, h, f;
+ android_dataspace d;
size_t size = 0;
// Maps orientations from DisplayInfo to ISurfaceComposer
@@ -177,13 +210,15 @@ int main(int argc, char** argv)
h = screenshot.getHeight();
s = screenshot.getStride();
f = screenshot.getFormat();
+ d = screenshot.getDataSpace();
size = screenshot.getSize();
}
if (base != NULL) {
if (png) {
const SkImageInfo info =
- SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType);
+ SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,
+ dataSpaceToColorSpace(d));
SkPixmap pixmap(info, base, s * bytesPerPixel(f));
struct FDWStream final : public SkWStream {
size_t fBytesWritten = 0;
@@ -200,9 +235,11 @@ int main(int argc, char** argv)
notifyMediaScanner(fn);
}
} else {
+ uint32_t c = dataSpaceToInt(d);
write(fd, &w, 4);
write(fd, &h, 4);
write(fd, &f, 4);
+ write(fd, &c, 4);
size_t Bpp = bytesPerPixel(f);
for (size_t y=0 ; y<h ; y++) {
write(fd, base, w*Bpp);
diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk
index 0c93b4c7b970..e6cbdb4ec49b 100644
--- a/cmds/uiautomator/instrumentation/Android.mk
+++ b/cmds/uiautomator/instrumentation/Android.mk
@@ -22,6 +22,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \
$(call all-java-files-under, ../library/core-src)
LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
LOCAL_MODULE := uiautomator-instrumentation
# TODO: change this to 18 when it's available
LOCAL_SDK_VERSION := current
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index e70bd1162fbb..4bf856f8cbfa 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -64,10 +64,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE := android_uiautomator
LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries)
LOCAL_SOURCE_FILES_ALL_GENERATED := true
-include $(BUILD_STATIC_JAVA_LIBRARY)
# Make sure to run droiddoc first to generate the stub source files.
-$(full_classes_compiled_jar) : $(uiautomator_stubs_stamp)
-$(built_dex_intermediate) : $(uiautomator_stubs_stamp)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(uiautomator_stubs_stamp)
+include $(BUILD_STATIC_JAVA_LIBRARY)
###############################################
# API check