From fc1f5e24bcd678a08221c8c01a364807edca6daf Mon Sep 17 00:00:00 2001 From: Dirk Dougherty Date: Tue, 2 Nov 2010 19:15:51 -0700 Subject: [PATCH 1/6] doc change: update uses-feature for gingerbread. Change-Id: I1af174da527a91e111d6bdecaad8c08bde050c24 --- .../topics/manifest/uses-feature-element.jd | 76 +++++++++++++++---- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 45f4a66b1c4a2..b5b30f632a1a6 100644 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -472,11 +472,11 @@ If you are developing in Eclipse with ADT, right-click the project and select Package. Select a destination filename and path and click OK.
  • Next, locate the aapt tool, if it is not already in your PATH. -If you are using SDK Tools r7 or earlier, you can find aapt in the -<SDK>/platforms/android-<platform>/tools/ directory. +If you are using SDK Tools r8 or higher, you can find aapt in the +<SDK>/platform-tools/ directory.

    Note: You must use the version of -aapt that is provided for the latest platform release available. If -you do not have the latest platform release, download it using the aapt that is provided for the latest Platform-Tools component available. If +you do not have the latest Platform-Tools component, download it using the Android SDK and AVD Manager.

  • Run aapt using this syntax:
  • @@ -521,6 +521,14 @@ in a separate <uses-feature> element.

    Description Comments + + Audio + android.hardware.audio.low_latency + The application uses a low-latency audio pipeline on the device and +is sensitive to delays or lag in sound input or output. + + + Bluetooth android.hardware.bluetooth @@ -529,7 +537,7 @@ in a separate <uses-feature> element.

    - Camera + Camera android.hardware.camera The application uses the device's camera. If the device supports multiple cameras, the application uses the camera that facing @@ -539,7 +547,7 @@ in a separate <uses-feature> element.

    android.hardware.camera.autofocus Subfeature. The application uses the device camera's autofocus capability. - If declared with the "android:required="true" + If declared with the "android:required="true" attribute, these subfeatures implicitly declare the android.hardware.camera parent feature. @@ -547,6 +555,10 @@ attribute, these subfeatures implicitly declare the android.hardware.camera.flash Subfeature. The application uses the device camera's flash. + + android.hardware.camera.front + Subfeature. The application uses a front-facing camera on the device. + Location @@ -568,20 +580,42 @@ attribute, these subfeatures implicitly declare the Subfeature. The application uses precise location coordinates obtained from a Global Positioning System receiver on the device. - - Sensors + Microphone + android.hardware.microphone + The application uses a microphone on the device. + + + + + Near Field Communications + android.hardware.nfc + The application uses NFC radio features in the device. + + + + Sensors android.hardware.sensor.accelerometer The application uses motion readings from an accelerometer on the device. + + android.hardware.sensor.barometer + The application uses the device's barometer. + + android.hardware.sensor.compass The application uses directional readings from a magnetometer (compass) on the device. + + android.hardware.sensor.gyroscope + The application uses the device's gyroscope sensor. + + android.hardware.sensor.light The application uses the device's light sensor. @@ -593,12 +627,20 @@ the device. - Microphone - android.hardware.microphone - The application uses a microphone on the device. + SIP/VOIP + android.hardware.sip + The application uses SIP service on the device. + + android.hardware.sip.voip + Subfeature. The application uses SIP-based VOIP service on the device. + + If declared with the "android:required="true" attribute, this +subfeature implicitly declares the android.hardware.sip +parent feature. + Telephony @@ -622,14 +664,14 @@ device. - Touchscreen + Touchscreen android.hardware.touchscreen The application uses touchscreen capabilities on the device. android.hardware.touchscreen.multitouch - The application uses basic two-point multitouch capabilities on the device + Subfeature. The application uses basic two-point multitouch capabilities on the device screen. If declared with the "android:required="true" attribute, this subfeature implicitly declares the android.hardware.touchscreen @@ -640,10 +682,16 @@ parent feature. Subfeature. The application uses advanced multipoint multitouch capabilities on the device screen, such as for tracking two or more points fully independently. - If declared with the "android:required="true" attribute, this + If declared with the "android:required="true" attribute, this subfeature implicitly declares the android.hardware.touchscreen.multitouch parent feature. + + android.hardware.touchscreen.multitouch.jazzhand + Subfeature. The application uses advanced multipoint multitouch +capabilities on the device screen, for tracking up to five points fully +independently. + Wifi From 2cbe92ea6d36adb721b0cb94f5dbecb9c9e71ad8 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Wed, 17 Nov 2010 18:14:58 -0800 Subject: [PATCH 2/6] docs: add better visibility to app install location doc Change-Id: Ib36a53c69a918eab4378d5ec7d25ec89be1b7070 --- docs/html/guide/topics/manifest/manifest-element.jd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd index a35c5a13c29ac..7f21e6bbb9fb1 100644 --- a/docs/html/guide/topics/manifest/manifest-element.jd +++ b/docs/html/guide/topics/manifest/manifest-element.jd @@ -159,6 +159,9 @@ multiple SD cards can be used with the same device. storage. However, the system will not allow the user to move the application to external storage if this attribute is set to {@code internalOnly}, which is the default setting.

    +

    Read App Install Location for +more information about using this attribute (including how to maintain backward compatibility).

    +

    Introduced in: API Level 8.

    @@ -173,7 +176,7 @@ this attribute is set to {@code internalOnly}, which is the default setting.

    see also:
    -
    App Install Location
    +
    <application>
    From bfc1cc2d1ea85cc754e63b422eb8cef8ae6a3667 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 17 Nov 2010 19:16:52 -0800 Subject: [PATCH 3/6] Fix stuck keys when released out of order. (DO NOT MERGE) Bug: 3208156 Change-Id: I14e4d54f4912de5e2fabcd8638120623aa2d16e0 --- libs/ui/InputReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index d1674390efd64..3197ab229ad71 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -934,7 +934,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, ssize_t keyDownIndex = findKeyDownLocked(scanCode); if (keyDownIndex >= 0) { // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mLocked.keyDowns.top().keyCode; + keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode; } else { // key down mLocked.keyDowns.push(); @@ -949,7 +949,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, ssize_t keyDownIndex = findKeyDownLocked(scanCode); if (keyDownIndex >= 0) { // key up, be sure to use same keycode as before in case of rotation - keyCode = mLocked.keyDowns.top().keyCode; + keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode; mLocked.keyDowns.removeAt(size_t(keyDownIndex)); } else { // key was not actually down From b27b8c0caf8ff23d10eea655085769f314050427 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 2 Nov 2010 17:58:22 -0700 Subject: [PATCH 4/6] Fix a key repeating bug. (DO NOT MERGE) This change fixes a bug in the dispatcher where the window manager policy would incorrectly receive a key repeat count of 0 in the case where the key repeat was generated by the hardware or driver. Long-press on HOME was broken as a result. Repeating keys could also get stuck down. Bug: 3159581 Bug: 3208156 Change-Id: I1145487cfcc41a7850dba4cafc63c4a5951ace5b --- libs/ui/InputDispatcher.cpp | 80 ++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index c0b27fe2cc430..28ccc43a67275 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -619,38 +619,8 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( bool InputDispatcher::dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Give the policy a chance to intercept the key. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindow) { - commandEntry->inputChannel = mFocusedWindow->inputChannel; - } - commandEntry->keyEntry = entry; - entry->refCount += 1; - return false; // wait for the command to run - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } - } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { - if (*dropReason == DROP_REASON_NOT_DROPPED) { - *dropReason = DROP_REASON_POLICY; - } - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - resetTargetsLocked(); - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - // Preprocessing. if (! entry->dispatchInProgress) { - logOutboundKeyDetailsLocked("dispatchKey - ", entry); - if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && (entry->policyFlags & POLICY_FLAG_TRUSTED) @@ -677,6 +647,36 @@ bool InputDispatcher::dispatchKeyLocked( entry->dispatchInProgress = true; resetTargetsLocked(); + + logOutboundKeyDetailsLocked("dispatchKey - ", entry); + } + + // Give the policy a chance to intercept the key. + if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { + if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { + CommandEntry* commandEntry = postCommandLocked( + & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); + if (mFocusedWindow) { + commandEntry->inputChannel = mFocusedWindow->inputChannel; + } + commandEntry->keyEntry = entry; + entry->refCount += 1; + return false; // wait for the command to run + } else { + entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; + } + } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { + if (*dropReason == DROP_REASON_NOT_DROPPED) { + *dropReason = DROP_REASON_POLICY; + } + } + + // Clean up if dropping the event. + if (*dropReason != DROP_REASON_NOT_DROPPED) { + resetTargetsLocked(); + setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY + ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); + return true; } // Identify targets. @@ -705,16 +705,24 @@ void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyE #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "downTime=%lld", + "repeatCount=%d, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->downTime); + entry->repeatCount, entry->downTime); #endif } bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { + // Preprocessing. + if (! entry->dispatchInProgress) { + entry->dispatchInProgress = true; + resetTargetsLocked(); + + logOutboundMotionDetailsLocked("dispatchMotion - ", entry); + } + // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { resetTargetsLocked(); @@ -723,14 +731,6 @@ bool InputDispatcher::dispatchMotionLocked( return true; } - // Preprocessing. - if (! entry->dispatchInProgress) { - logOutboundMotionDetailsLocked("dispatchMotion - ", entry); - - entry->dispatchInProgress = true; - resetTargetsLocked(); - } - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; // Identify targets. From 9b14d1d52a85d0f3a4789d85372ae18b34118ba6 Mon Sep 17 00:00:00 2001 From: Justin Ho Date: Thu, 18 Nov 2010 15:02:18 -0800 Subject: [PATCH 5/6] DO NOT MERGE - Updated ringtones for Crespo, fixing looping problem Change-Id: Id5947197bdb6599bb7a3a15ab1e1a9541a4d31b2 --- data/sounds/ringtones/Carina.ogg | Bin 15478 -> 15462 bytes data/sounds/ringtones/Eridani.ogg | Bin 34856 -> 36585 bytes 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 data/sounds/ringtones/Carina.ogg mode change 100755 => 100644 data/sounds/ringtones/Eridani.ogg diff --git a/data/sounds/ringtones/Carina.ogg b/data/sounds/ringtones/Carina.ogg old mode 100755 new mode 100644 index 25cf36e1907808d3ef695eeaa5855fc76ea7c3d6..aeb9b36bb6cdd48717761eeb9b4836f71394f235 GIT binary patch delta 14229 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 I|J&>T0jcu*>i_@% delta 14281 zcmaKSc|25a^#8dtV;Q@wS&A0BkX>j?toM1&bI$v`&lwJ#3B|3wymkW#{`XpMA-A7- zyYED(0=5P_9&qe{PZ0AD%;XO92Viak_V2eA``7Z{J@bp%l37wS?*5x6e&zqU_{slu zBZ*2KeFD8VSs(L~I_z^`53}>jI2VPC3NGKGv+h3@>=P7RG5?H$GbCc#lnXAIQ zXw#*_PYhP+Y8z6PPMd8In=J<|JKg_qp-bw4SvXZ#@`_|WI)~Wt+0J}kEMN82zvaO z;{P%2|N64;wX=8DvhS|ev8O&XQ%PjUH} z7V=*7h|BE7R~r8BgI!#-T^xG-U9`{c?TvJ^vv+ei^j3S%-kHdcvlSr&qNeuUA^7g& zXWT*#xz&ca?LFc$^04~i;e{7!KkC&NO@rNZQoF0=%Z_k9z4K%4$+*&kNkxOs%8*X` zkdJmQZfX9`tB<(s_}A;+IZKC`GtRvihk7EtR=cE?zPPJ$=k6V@nhEiz;|ovjzNB?^Ou(FWfSVgz+<@exIXt{N;&77K7DQMv%pZvy2eq%M=BEF=` zX}4d+Sz9O0yh=w4AGNAI9)2awv1-(-LAIMmZYA3~DdttC>h8!3x@60SOXpp&jo+9j zsyK4%V28~&satlo=L>HMddO{TzG8b}W1g6EoN|q55D)6h_Iw2@h?j2>_GshxprgLf z=<<1$dn|lQj#*i-N$0g1nWL_Dn#+5(nSYnM)n&AU*_F9Gn$}^|)lPG@YSEx0^3`G% zKBy}{bNOZ*^`%_>L65!UjNJjQyvDu*t@o?;`28FG&c?iV2kum%(Yf;)9c>GlO^Pde zMLk~0SMS>$uUR7+UaDN<8pLB*wI?V}zE{{|T&+gRukFzZKJ@O5q88^Xn)dj`tBuet zm@l%^yaJ8xU(&M%6);CHY!>yv+bWt}cl%XUi-ub%_v{NAf7C2-+P7pF^(9}O=~w!w z_d~Q2fcw9b7qgk}{mcTSH~>`7s*Ol#aOk4*$%+nX(iL4c>6qlrBT_M!Y)2$wt~mY3 zJWaRo%S%pnimyn%V(X_S3_u?Q;B!BHyYVxeIeUi!wiw`C2_Ad1yfTV>UnXoknI%_r zyZC$c`n_4QaYaQ%)&3{5+UMOtoHx$;wY-LP+uXjqq=mVPIa+4a039Y z{}_V;#@TLutGH$oC-+_|97L0BmO991`%EfE(AG>oCfOEgZB_{Y(k?mjzlq;OdUV~L zsvakg67&_%yz?u`OSZL;|NnhqU@O1_w!B*27D_z-t)vjnTuS-d5~sQJo+bx%n9FU< zLo1tk`iiYZN|3FEd0|x#Q)Zb9=*eg6quea!_eu&a>IJnKBt**1PC@MkNb=*WdOif9 zM~U!uBlaZQ;;LbZ7@ndkC%-n`IjLQK6+L3Xe8!?cbfO&ybAS4sU3R<2Ddwx-%uQgA zNj}huM%`wiHk=vMrhD$c#~>@UX7p&peuG&m6~kxDEHz@6j%h{vej1(2>p?um=#fwF zUn#qE@PCiSqs+>vpo3W%-Q8eTX5L{yu<#%or*$VG&{jj((Hlqd1ndCO?~W;{shjBz zD``=rS?=4L$v0Jcny&s@YtJElOXHxG+QD0mPCA|$Jmn*sZk1h zf);>LY%AaSvu6e;b5=>MyG!F<-Q!1P!C==zKaW z+dqlNh-c>Pw)-xHItJi@K@0|KVcoinr_Vb221h67fJ*&Wv>N6BbWDiY*kRSp8d^Gf z`i3;)|Fh-kjR!;I}&D=9_sR{BL8u;dP zTuD(`QCm~3B27_UQ}xz01@x$@rhX+|SzT>&e(Iv@zMGC*-Uf^*6*my4pKv*S{H4?e zuOoHO^0hJ1m4lbGn`2p3cK+b{&^x-)tRr{iYI%v6iGMw&eYGdR)V!Sc0uiSOUF>v! zwX_K3Pra3joAD%`vT0MQL)a+;T<;2ZX4x;rRVH4C8J-81zMDA9#gm;TB}gWiE6o5? z{iP)NDn$3*c?+s$D4q$LJNQo>U#j?=n6#6xRr;s9{Km{AR?0==J?~6dpc{j7-can% z28OhG_{C$tB?w*xvebECT#LHl;IAFCF(l3|{SG#^S7^zPb z{UTmdbg;7LCaJQ=$vO4TAX?`Rr*Jo(iB>fQSmU9;d`X0*yyd-{UkL_CvPayw4Vp!J zbLsA!=?AW;!3Lb3cToE)nRpxAke%wlNsvF>g}`^If5)6vBH+z0`Q&`IhVIyf+Yi=C z^}k+7d8)7C=*~91gOno#Gx?`t`S=Tqxod%D!d{X|f&M4^-n4FgRiM4>@nIX!^_B0B z-t>p7lynM#-lOdQa9T?>27M(!bQGOn0V2Br598)2xLC&yeP`BlF6iJTB|k}n@?S?V zP{j%w4l4<+YSk2v4JSy0f{TNxAz#Ba;=Zf&nLNgvCjC=@wQDyiM!k#Ur%N^qu_kYU z4xv*^r??*rM94gXMP4qq8~L%B8gUalzMGJpq%i(+!uP&yfNA8BO$6;q+Pw#I9k^k@ znmDL-?A|T5@>dBz`g;h1szKV?h+yU6Ecv;uAZM zr*;VKL??D>1`x1e{3QlAoXqWWf5$7P5&R()l76^qQ?Thgl)tb+gE{lr6>#w-> zM6H9Qgq;N3#^`lQg~23R;x+`+1N|a?I<)vz@KvciF>RY7P)+3*>W9_@YAIFjsOEI zAQNUTdAjs3P&pB2*JjpRI%3$T;?&oVuWz9S_V4f&@aZ$_l@o# zKFUIiG0xdkcK1Yzrpn{lV^ahAvu|e?5B#*<7d8>eO_HV@9eXreIUAL=a+MYI^}jt* zgwH*fjq)@}pt>yN6HU7Mbz~`AnMQu`$6kvOZbR_YvIaVnRl8HP0lxI#JNQS}I`>)2 zezFkIMk#=k3drtvd#eYx@Y0~77U2EX0?6#ZzVz>={Ml=r8=ABEQ3u++6Tsg=_-aY6 zC#)Y#!C=ctcGBSUn!>G*NduA3y#!1QYDhqNE4*G`BaT;%Occ$?(1N9C-DcGZl|y$( zI=J{FpH%`8!y=#OUE(h&^?96Sfd^R+*Z`-zWqtfuGp?N~24e1l1QtSdoH^y#)xMT^ zJj6I@!jgV9(*L88&{Vwhipi(0Lu`o_5PJv#pxCf?*$=oloE)+I@+D+Qt$BSmD|Da}$w9-NJ0f^@L(sX-Qg3DX8RWgwh;(2 z0NC~Nk>D^oqEh8SGiR?;Gwn#;4Ds5vn;6losWdVlwDuf1Srw6OYV*~cBm^1{F_54u zPwZ`AS$XVn=|=Us_YEV2cyt6g3g>|?yWQ3{h8dsKwLe8B0>9e7-@Rr~;ODZQtxE9v`G@!N_t2gAih7EE$u8c^g`lRJ&VMzW4c|Cg;wZQ z5mDbR_vP30&$su6%%r#pmxowzNB8whz)hztcgM1F9DkHtd)>-MwfQw(;rv=^rRy5N z;^$`53bCw?s<UbG` zK9H>_$yKZfHbCA=f4-v8&Hig^n&p4>HDoQweYn1ucXshK+5TJI-sXVYD!+?$(uYb0 z_%45RbIV^oB>vI1roL}O33!v$2`!jrv77rt0Y2wf2u5SzvEddnXOtT)^P0KJydGgr z&zJqRWm3hOm{>s6BiXd72Y2#=K{1aD;lhl+l4_>2qS(~M9%Q)zUVD5v{gsF|t!f{0 z_K?s3Ri|p%9BhhJNWqAt;~z{!pGfd$Ne3YhHnA7i2P>6nv=x3x-J7aXRCA`mLd0h| z=|{`>7tKGUgV(p*9oM2?2Y*mS^9w^Z+4~O(0%^9G6yP`V&O6ZEPWT*X7cpjkEc%T( z^x&t~j*wPO>SJtBkO>JS90c2wZH|nrG_6DxhMP1*oE$Q>zxbm7611RuZpr@aTZaKyCl@O~>#8ut{^;hAJ8At{hHHOhLzd8cTXWWgurFhU$w z0Y2B79xlYbT81T*f=0?{56Baog~fw-X0*vUF9-X4WmS@!J+@LP#sXv_GX2F`5mG+I`S#U0bYXh#hFlwaKD>*0aQbvXrO__ZeV zNdQcLvCT)7SC`eXJKx+NZHm?67!3p6UFN$T)u)>&NrpL$<7IN=Q))hEk--o$vOEtbc7HJ<3blKUKEo*5qnq3k!)NHm-q6daIO+iux0; zd#h=jeVmknt=w`@pfcM}HfK4AJsdWG>uU)1nI$gih1(8%6Wa@;g}i zFVpib6I?WM(W}6)@9XLo*PHB@-7o%7Q(oKi@S*hY-Q>oD9^0T1(Yt=GvM_mu0uydL@8-%GH#}2yz z+sMqy;N5YIQJ>ufkmC&Q`&M4PUyo^hJJkNtfqj#AcJ9R5)|EcixJ}1W<;S1DO|%xT zB{8ARSq^RxJgg~;aE>al8_`@gMf}?M+%UDOxIJFHx!5!m@qV;&bUnq_*_>lq137@P#52l3qX>*lUNfjPjw zuyHvoQ@r?c{tTRmvxv}mdx2w=gkJ&)-5YlfE&9i1uQqWe$JDL)V^bhGKOuXkxFOzN zOzdrw^^B&$(0uYJjnd+1nyO%(b3&-or!j)1FnTy1|wc3Z2QO5vzOqy)w^yu*SFbp^UJH8S?No{05g!9JNK&n2G;j?lSrf+-ZU|GsP^IhN13aY}&W zcINcleY!EmMI@_(N4!Y1b8^+%3WtZoBki>`8!3wha*E;%c`8BWga3^j6f@iW$3!5g z4@>%&iq({q6_vEK@y%t&PlpjoYMNPBWaQK}axW_?Dk-U}tG!9MmXV~Ox;gW*yt0N` zW`dHUQdiHB@Fw2^hurjc(ulR;z7DK*TPR!U8nU(|4bGc8S^C%p=Y%=L8X5pl-IGnm z1v_#>Bk}?O#Pl%s0)fHLC!P;h(Nr1h_%Il0(KD%4z)uBmt(xuX>B&4`@S()i#;p^B z9Lf>Yb3#xEcl3(L!AaZnFS4t`9R{^E8C&b2wJV-0ZilyXZtdY@#Q7vMxPd)~hq!2W zWbgw;@*x*HxV!G-(YjOM_<_{=X570;yg)PV`}2ye&;chvl+H$T&IP*6F)5*>KnPD-|>}HM)$}z5?6tjy8E{~(F+`np=M|J z7EM{^U(^;~W05ZHvsrk*N_^v#ndDZ1T>)ybBPCzEIs&UI3J&CBCbFXRc4ElXNB5kl zXV&M*mTf*y*DJH7yuCmoQnqHvERySV`*9V!P&e}ay@uWD)A-7gX=O%3qeuJn^hte# zC6h#CC8-P^RSaR5h&I|F8?+65LoE4wB47`|aIF_9wjQT&uRlwXB~>yY1#2GMar47VG>M*fHAM-UEux*d zC2FPsPsZl$^7EB14f{~xY%&W40@p}f0@&oR;!wZZu-Yb6y@USh__TP8=1R}>Yc@i= zWFPIc)?^LS-331W8~%)K0C_weFOa)i>$ojw>G;_CgJs1ACr?DKKR(Kmo=27pgjzA6 ztzhsFXNt3e7q=QZdLy%uWWLe9n?p_U5|k7W5CS4U2+y_qOLs@=liw zulUZ7ZhLx`f8coA+sn7C`p6AzIhu$@6ugz7<*opPv613xfb#=?k2FR0eaX(>^dlf! z%j3u~m&fu4R$&ANi5%cA3^ZhMaU$o;Llq-3D{5Zm=JyLmr5<-IJj}jH(mI-CH&5cA zmHkv=e4MhZUtO=cKEfkVoxgb|=Ul6bR^;?4+KV-6H>hTTr&cI5KlC1+-r{sBK-g5urcdT|hmID)940&v^zc6e2$Q!xlkY_X& z;49?>z7C>p6+`8SQkC^AbRhT9N*?sJ``j_$8e*-xTV?v|=z1kE5l%27n%lL9XO@< zYu3Ch9&POHt2HyZ{3;n$7jNaiCoUlHzQ3}E3C+NJ%yJ72l||nFy1pg7^LwP;S5l~M zzV8N@PJHSuc`0!VB~XtDx5M1Xu;;J;jyEbu{hoWW)J~3U_%!gz*lOhRpWd%YoDodE zWBeuXOS>0y<1h$Zz-9{D53+g8?k_sH=riG>$V2W3pOB6@NJX4^^ggqHabe1d2CXp; zderQg=`Z!EzM-ajokKbaLpnQTf`<^7;Y@`Ol4-5G%aw%*kAYLyTVMl?vA36J^iVN_ z_oy2O{QO*#-13IzBiPM*nj&Qk?lX>Sb8K+R_--;)9#%eJ-?iu_A6dQ(-cu2JNps8X zE6TS5*ofS8+LmkDHBG14okOzkb8v`E zbDzrkvUO&0LtX6$>~&28PbLhREqq>_Pb=mkeR;R3Qf$%p;^!KrLm0u@*9Z~mc&*bU zn@`vnY zXg#t`?Zv*QtZ^Qv^Z?MR64N~F(65u9b$;?{DS*kd zM-TM{k{xTP-UM6pDB%X>ipmk(5S_j?iw$_S(({6njPE?wv_^0 zGC8~AVO)AP)CO~Ri!%rBkxrV+#$hFbhi|7g zyHpc-=Ac0-J2dv(vyMA6Xq}t><}3=|C37eNNx@Rzn>}iRER@dis%DlUU{#yH4{%dx z>`Srq(q^qMZA?B(ZdFfUH7<}HjnxV?v{PR4J8&p8Z7mYZW&xKvG6L4 zFE}~L5~EnH*H<5g$Gu$NcJS8UV#+SB=*IhwTaQQz8@5WuW)Qyf3FZEmfsW{N-34OOr}2tsu_?>(iIERTMh)_u{f`J42Iw@zMIQI;=J%J7WgH|;x**%y4PCrj73Mb1qY^R6|F zn46pr3l`6GBlls1Rl(1~s7X;Om~%s4=kj|!w9_Qw2OBR*jg}aZVQAD5diGjcr+RmL z!yBYx{#pYZxS)nJ&9wIw59jtxe@b>FsF|`rj+5V5$w>Il1b!q005d$2lcGb*8)Jf3 z+A$x0UGPqadUwp6WaRE6# zyk!CWjQ7`I(4HMteXtGcPYPS#4*wK5nm6UP$btWy+4TSdlMq8J0fBCYMi=lxjL7Mh z0YV(5k?iLC-mECQO#%NVT7tPD8$B4xf(^ezM`c$Lnp**djSnVqj>HwWsdbO)?_^0n zBJp+obpir}nopQ9AnWL7SB!HIZoVv4>qsvTQ|)-AT3$l7AGq4M2Zee1`Egi2+2e5A zdMMk+emHyIO4XK#+Y8*+6m`S(94MA#1S!1946Cyo1J_vLRP_%;;2(AldivaAoSAh)ulet>jA8MyN{p3BsUN&*pZE+a4lFc zO>_3B-2irJNtBmtci z`n3A5yXckn-^h35>h4P1H^pjtTH!G0QM_qY(mrEe8YdDR!tHr|-aRWFjeSHb)1KM& z`|gwyma)2LBE@Uy#Mg@z=guulPq9>U&d`%%r$Y58Pmqn+C5y<*I$xY3gjDj?uGbu* z;$ZSUy5j}X!ygM)y-VLA)+~F%F5?INYve#L6B4LdHZnJIIDkdrL-uc5fJC*Zu<9O4 zUni2h4zelM`PxT{UY_sbQdoMt76Z*KSsiyuAEu|mty_rHR6Vs5FqjFL(2xbM<5bVG z_lPve#dQOg&I-MCEs~k+tRBnQ>eTXVmj?K|Go8g*y830noFCom)69YsXBEzd%BV79BMvN0TlIhSmOQCHC2ybOa|)!8W0mds zomxj8Hzs8Y@__rV5VAh1xDi#H@)6AELgc1iIYtn^H-eny>o=sHv6aeL_VRFL9bEXP zJ5|IBKl{a8EBNL+kr;rqq%9jE^91>H86YOt>&`e}c`5ykTj`^jnGG!K80I1~W--@6E8wYNqFF z9%Xq~duVpLrKC=AVd+m!!@-FyDJia*FYeFZDbeY^&2k4V<^~k7oZLfJTS8dXqu2mw z;&g6RDY_I+cet1Qp?mbg(!j9|k7M}0w*DN_L3+7aG&~n=x~2tl=X+dtW{P%B=5h1E zLF98HC@B4h9aQ-r0SDiZ!GG)kUBsBiqy}74 zgYSP#w!HH2R~OILGGTcCCH>)S`n5o>;WAUUqWp7aU=n3g&^X|c@^$QL zQ(C0VIyE!Wqv3JJ*A;6>)aEMZI=TF>WDJ43$#73+I_nk2b}-GGk6#x zK65p8jGt^07ke$YrppKUsMKI8kc8#ypfBN_9p=mC<}Bf1nLKNvd-;TD;kI)%aZbl=O-_=$lBO(B&=!8XK%p<%TDB( zF=T=Koiw>tKHI+6l|^iq`E{HVytR&WSBjRG-Z6>Z3ML*Mjnr;A!}_`&h}9u{Bm0S= zAc4X6^EZxtuKk0rtn{v|e6B2ep}4TF0oRP)qAsGpuy@Kvca=#1_4M+5{EzLb+H=Q% ztDw4X`|oE3S+{-ElD^762%A|}nV4WdAiqiX^vd|Y*^40PXRmul@&+Ci=3&3CXcGYI`66hE}*## zG}Iq|;HO7TQc~f@o3m{sq?$$7!UZ;q zJ8Ks=FkN)uzl_4+UI1sJ_k2e}%e(F4LKPm66!F%uB|Wd_sWV#v3PtB51m%R%tx)|{ zG`xt@tX%qbu?2d1^|n-jU5CT&I+;=C3GP%LD3?J)eqam7KU_vrQ9Ze*6gXgYMbygV^jSC@zrb;FcR&tVC*x@> zMTTL%&ll>ct|N%22+oc7+_GkV>u|s|!+Cb8i>hmlX$0pY#)J&8!T3EP`|tgS5x@K{ zls7jDKkNBKOgPcJ=Ek{7+xXa)VI61y&LPh(m@?0 zS%VYCh+GX9nCl>oU^sh;{zj0(uk?OVH*nz%s{iAsJ3ft8$Ks zzlF%?7Dr<~`1N`Va!^|M%g*mYWC2v2?R~qK#a*x-y_%yJ2vY`956bH}=FT~VToDES zHVt>00lczwqsD5(DV_BrhAqvDGPpSslp#v!*th_je4mB7=3%I-{mI0 z|292*J}PUUcyDh=h(V%SViJ|HMvjb>>fw!c!C5Hga}a5L0{M3am(5rhof@<@({4`7*bAVFYf6mCI(5g65$Vm$J}{4MQuW7{^$nmjn}QEdBeb*e*3 zd&IqUVinKx$}SJ!0b3SCJoY7?LvFByfbKE2!zoxf8^KdBnq9~SX1?gCEl0@$gA6~1 zPTN8AQ+>?XF7f@qtK0YAk4vbT9xCGoeWuA7^s2&zhgQaaU1aiZ$V3$Myi2=%_X{cl z8WV@j9xa#U^SH2}nwx-EHoVou|Ms;E)SsLhesxXTuQ@%HmXYP^;^ML-yAm8E#_0c) zLqmyV^Uu@%+%3w_4?!WCn=klarl`z{3*4V~g8M`u9p<(~gflPl^2t<{LOdY%Q-`*H zoZH!@Y4b?%%RX;PSfZ1e!wn6RQq4oFfR9$Zn*_BLR8SRyReaxNUJS7AAD?@Yp}axJ zC2wuE1zV^v+U&s->@<{H0w)phhMPA)1p*&R6Y;irW>TYbd1MgeYE|vwUo|ThLn@~g z<-a=jWP71_kIiiCl9}>%y8hy!IJx_m_IdC(UQYUl|9#Z`+lcii{_UuSd8> z$1Nj7d||AP0;nRZ#`b9R$DKKdxspGwF zVy%ZWcc@$^3zIeAE##dh`z$~IX#HTwp>D_K#?9aPPt!TYDp4*GE7)7|C$j*1^;Qf< zpIl=O6qG)z26{k=ac ziPGb9JD`wve#gAa`xS#h{OwX`oGoj$KZX94 zOm~=D{1-E&Qvv8>CFi1dJa~*&iE)4eIvxR*C_d>#YV911n141seSm|5G4`H$eP>=T ziqR#;LofXPN10?48XiXp#Iw#&SO&3?lTKHFI9ZibJ?YD(<8SyjrRGP2`@Z3+)b}f% zdg5|*!6r`=-kwJW0vE6PZXBVjCY_r2o}h>YvW`_2+k#WNXeWtI}M*P;Oi z{j%M?V>=RJ&mFI3TS@w>Cy>`N%~zm#R>pxH0bXWIiZ53HRI7cFzpF}?qEJdSfcCEK z*88i@nSVEC>xS>#iZ>MFB$OHhG;Cj*0votHBcu$_x((SbrsOl4N;fh8kZRSpB@!fK z=JNj}r#YP9j8P|rX5M3+Ji(qr-Ua=)HAZHNMJ`SMC@36&*wqymRrl$CRBto7przA5 zK`3k=zBcwUH=OR;?!u076ugX&Y}+5EurmNB4-PQj9}S>OiEC>1rBNqG5*zCEA9Su1 z-!CITb({2W`|<;2^`p`THp)5nA6HgW(f+z^1f7x943gt?3mZVxu>Pi+g;v3a_^mC9 zg$f!=2guapDDwzG8iQ3PCVe+}Vh{skw4vJsLl9x`U6^a~{b@#U!-44oeunA_89Q72 oJ_f}5KVBXS5Ck|eza{29@WNnX;%#IF$O}GuNd(U&!9XwgAB~{hfdBvi diff --git a/data/sounds/ringtones/Eridani.ogg b/data/sounds/ringtones/Eridani.ogg old mode 100755 new mode 100644 index a290a6e72ef1b2087af038c777eb0fbe1ec3502f..b665a29fd4a24d033bb6848fc1a5af35a01d8414 GIT binary patch literal 36585 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

    |4gUh*N>dd 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

    yLgeOX#h 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 CG=!A^ literal 34856 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

  • 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 XgM&&sBfnDkaq?y_vIEOU9pL`~hsm@i From 671a6ff4be11b3e2d8eb017e0c7a78e6133fb2b8 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 11 Nov 2010 17:58:51 -0800 Subject: [PATCH 6/6] Add support for virtual sensors. Rework sensorservice to allow "virtual sensors", that is sensors that report a synthetized value based on real sensors. the main change to sensorservice is around managing which real sensor need to be activated and which rate to use. The logic for all this has been moved into SensorDevice, which essentially wraps the sensor HAL but adds two features to it: - it keeps track of which sensors need to be activated - it keeps track of what rate needs to be used For this purpose an "identity" is associated with each real sensor activation, so we can track them. On start-up we check for gravity, linear-acceleration and rotation-vector sensors, if they're not present in the HAL, we synthetize them in sensor-service. Change-Id: I841db2c1b37ef127ed571efa21732ecc5adf1800 --- services/sensorservice/Android.mk | 8 +- services/sensorservice/GravitySensor.cpp | 112 ++++++ services/sensorservice/GravitySensor.h | 56 +++ .../LinearAccelerationSensor.cpp | 86 +++++ .../sensorservice/LinearAccelerationSensor.h | 53 +++ .../sensorservice/RotationVectorSensor.cpp | 174 +++++++++ services/sensorservice/RotationVectorSensor.h | 60 +++ .../SecondOrderLowPassFilter.cpp | 70 ++++ .../sensorservice/SecondOrderLowPassFilter.h | 61 +++ services/sensorservice/SensorDevice.cpp | 239 ++++++++++++ services/sensorservice/SensorDevice.h | 62 ++++ services/sensorservice/SensorInterface.cpp | 70 ++++ services/sensorservice/SensorInterface.h | 75 ++++ services/sensorservice/SensorService.cpp | 347 ++++++++---------- services/sensorservice/SensorService.h | 27 +- 15 files changed, 1296 insertions(+), 204 deletions(-) create mode 100644 services/sensorservice/GravitySensor.cpp create mode 100644 services/sensorservice/GravitySensor.h create mode 100644 services/sensorservice/LinearAccelerationSensor.cpp create mode 100644 services/sensorservice/LinearAccelerationSensor.h create mode 100644 services/sensorservice/RotationVectorSensor.cpp create mode 100644 services/sensorservice/RotationVectorSensor.h create mode 100644 services/sensorservice/SecondOrderLowPassFilter.cpp create mode 100644 services/sensorservice/SecondOrderLowPassFilter.h create mode 100644 services/sensorservice/SensorDevice.cpp create mode 100644 services/sensorservice/SensorDevice.h create mode 100644 services/sensorservice/SensorInterface.cpp create mode 100644 services/sensorservice/SensorInterface.h diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk index 75f690f1867bf..7e17fdd58eded 100644 --- a/services/sensorservice/Android.mk +++ b/services/sensorservice/Android.mk @@ -2,7 +2,13 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - SensorService.cpp + GravitySensor.cpp \ + LinearAccelerationSensor.cpp \ + RotationVectorSensor.cpp \ + SensorService.cpp \ + SensorInterface.cpp \ + SensorDevice.cpp \ + SecondOrderLowPassFilter.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp new file mode 100644 index 0000000000000..18bd359ea27d7 --- /dev/null +++ b/services/sensorservice/GravitySensor.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include + +#include + +#include + +#include "GravitySensor.h" + +namespace android { +// --------------------------------------------------------------------------- + +GravitySensor::GravitySensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mEnabled(false), mAccTime(0), + mLowPass(M_SQRT1_2, 1), + mX(mLowPass), mY(mLowPass), mZ(mLowPass) + +{ + for (size_t i=0 ; idata[0] = x; + outEvent->data[1] = y; + outEvent->data[2] = z; + outEvent->sensor = '_grv'; + outEvent->type = SENSOR_TYPE_GRAVITY; + return true; + } + return false; +} + +bool GravitySensor::isEnabled() const { + return mEnabled; +} + +status_t GravitySensor::activate(void* ident, bool enabled) { + status_t err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled); + if (err == NO_ERROR) { + mEnabled = enabled; + if (enabled) { + mAccTime = 0; + } + } + return err; +} + +status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) +{ + return mSensorDevice.setDelay(this, mAccelerometer.getHandle(), ns); +} + +Sensor GravitySensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Gravity Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_grv'; + hwSensor.type = SENSOR_TYPE_GRAVITY; + hwSensor.maxRange = mAccelerometer.getMaxValue(); + hwSensor.resolution = mAccelerometer.getResolution(); + hwSensor.power = mAccelerometer.getPowerUsage(); + hwSensor.minDelay = mAccelerometer.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h new file mode 100644 index 0000000000000..f9850b75f34ff --- /dev/null +++ b/services/sensorservice/GravitySensor.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_GRAVITY_SENSOR_H +#define ANDROID_GRAVITY_SENSOR_H + +#include +#include + +#include + +#include "SensorDevice.h" +#include "SensorInterface.h" +#include "SecondOrderLowPassFilter.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class GravitySensor : public SensorInterface { + SensorDevice& mSensorDevice; + Sensor mAccelerometer; + bool mEnabled; + double mAccTime; + + SecondOrderLowPassFilter mLowPass; + BiquadFilter mX, mY, mZ; + +public: + GravitySensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual bool isEnabled() const; + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GRAVITY_SENSOR_H diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp new file mode 100644 index 0000000000000..2dc12dc50a33f --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include + +#include + +#include + +#include "LinearAccelerationSensor.h" + +namespace android { +// --------------------------------------------------------------------------- + +LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mGravitySensor(list, count) +{ + mData[0] = mData[1] = mData[2] = 0; +} + +bool LinearAccelerationSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) +{ + bool result = mGravitySensor.process(outEvent, event); + if (result) { + if (event.type == SENSOR_TYPE_ACCELEROMETER) { + mData[0] = event.acceleration.x; + mData[1] = event.acceleration.y; + mData[2] = event.acceleration.z; + } + outEvent->data[0] = mData[0] - outEvent->data[0]; + outEvent->data[1] = mData[1] - outEvent->data[1]; + outEvent->data[2] = mData[2] - outEvent->data[2]; + outEvent->sensor = '_lin'; + outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION; + } + return result; +} + +bool LinearAccelerationSensor::isEnabled() const { + return mGravitySensor.isEnabled(); +} + +status_t LinearAccelerationSensor::activate(void* ident, bool enabled) { + return mGravitySensor.activate(ident, enabled); +} + +status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) { + return mGravitySensor.setDelay(ident, handle, ns); +} + +Sensor LinearAccelerationSensor::getSensor() const { + Sensor gsensor(mGravitySensor.getSensor()); + sensor_t hwSensor; + hwSensor.name = "Linear Acceleration Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_lin'; + hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION; + hwSensor.maxRange = gsensor.getMaxValue(); + hwSensor.resolution = gsensor.getResolution(); + hwSensor.power = gsensor.getPowerUsage(); + hwSensor.minDelay = gsensor.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h new file mode 100644 index 0000000000000..ee918ce1c4719 --- /dev/null +++ b/services/sensorservice/LinearAccelerationSensor.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_LINEAR_ACCELERATION_SENSOR_H +#define ANDROID_LINEAR_ACCELERATION_SENSOR_H + +#include +#include + +#include + +#include "SensorDevice.h" +#include "SensorInterface.h" +#include "GravitySensor.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class LinearAccelerationSensor : public SensorInterface { + SensorDevice& mSensorDevice; + GravitySensor mGravitySensor; + float mData[3]; + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); +public: + LinearAccelerationSensor(sensor_t const* list, size_t count); + virtual bool isEnabled() const; + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp new file mode 100644 index 0000000000000..6f4b8be45fded --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include + +#include + +#include + +#include "RotationVectorSensor.h" + +namespace android { +// --------------------------------------------------------------------------- + +template +static inline T clamp(T v) { + return v < 0 ? 0 : v; +} + +RotationVectorSensor::RotationVectorSensor(sensor_t const* list, size_t count) + : mSensorDevice(SensorDevice::getInstance()), + mEnabled(false), + mALowPass(M_SQRT1_2, 5.0f), + mAX(mALowPass), mAY(mALowPass), mAZ(mALowPass), + mMLowPass(M_SQRT1_2, 2.5f), + mMX(mMLowPass), mMY(mMLowPass), mMZ(mMLowPass) +{ + for (size_t i=0 ; i 100. + return false; + } + const float invH = 1.0f / normH; + const float invA = 1.0f / sqrtf(Ax*Ax + Ay*Ay + Az*Az); + Hx *= invH; + Hy *= invH; + Hz *= invH; + Ax *= invA; + Ay *= invA; + Az *= invA; + const float Mx = Ay*Hz - Az*Hy; + const float My = Az*Hx - Ax*Hz; + const float Mz = Ax*Hy - Ay*Hx; + + // matrix to rotation vector (normalized quaternion) + float qw = sqrtf( clamp( Hx + My + Az + 1) * 0.25f ); + float qx = sqrtf( clamp( Hx - My - Az + 1) * 0.25f ); + float qy = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f ); + float qz = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f ); + const float n = 1.0f / (qw*qw + qx*qx + qy*qy + qz*qz); + qx = copysignf(qx, Ay - Mz) * n; + qy = copysignf(qy, Hz - Ax) * n; + qz = copysignf(qz, Mx - Hy) * n; + + *outEvent = event; + outEvent->data[0] = qx; + outEvent->data[1] = qy; + outEvent->data[2] = qz; + outEvent->sensor = '_rov'; + outEvent->type = SENSOR_TYPE_ROTATION_VECTOR; + return true; + } + return false; +} + +bool RotationVectorSensor::isEnabled() const { + return mEnabled; +} + +status_t RotationVectorSensor::activate(void* ident, bool enabled) { + if (mEnabled != enabled) { + mSensorDevice.activate(this, mAcc.getHandle(), enabled); + mSensorDevice.activate(this, mMag.getHandle(), enabled); + mEnabled = enabled; + if (enabled) { + mMagTime = 0; + mAccTime = 0; + } + } + return NO_ERROR; +} + +status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) +{ + mSensorDevice.setDelay(this, mAcc.getHandle(), ns); + mSensorDevice.setDelay(this, mMag.getHandle(), ns); + return NO_ERROR; +} + +Sensor RotationVectorSensor::getSensor() const { + sensor_t hwSensor; + hwSensor.name = "Rotation Vector Sensor"; + hwSensor.vendor = "Google Inc."; + hwSensor.version = 1; + hwSensor.handle = '_rov'; + hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; + hwSensor.maxRange = 1; + hwSensor.resolution = 1.0f / (1<<24); + hwSensor.power = mAcc.getPowerUsage() + mMag.getPowerUsage(); + hwSensor.minDelay = mAcc.getMinDelay(); + Sensor sensor(&hwSensor); + return sensor; +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h new file mode 100644 index 0000000000000..e7f28c93a2328 --- /dev/null +++ b/services/sensorservice/RotationVectorSensor.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_ROTATION_VECTOR_SENSOR_H +#define ANDROID_ROTATION_VECTOR_SENSOR_H + +#include +#include + +#include + +#include "SensorDevice.h" +#include "SensorInterface.h" +#include "SecondOrderLowPassFilter.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class RotationVectorSensor : public SensorInterface { + SensorDevice& mSensorDevice; + Sensor mAcc; + Sensor mMag; + bool mEnabled; + float mMagData[3]; + double mAccTime; + double mMagTime; + SecondOrderLowPassFilter mALowPass; + BiquadFilter mAX, mAY, mAZ; + SecondOrderLowPassFilter mMLowPass; + BiquadFilter mMX, mMY, mMZ; + +public: + RotationVectorSensor(sensor_t const* list, size_t count); + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + virtual bool isEnabled() const; + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return true; } +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ROTATION_VECTOR_SENSOR_H diff --git a/services/sensorservice/SecondOrderLowPassFilter.cpp b/services/sensorservice/SecondOrderLowPassFilter.cpp new file mode 100644 index 0000000000000..e13e1362d6dd4 --- /dev/null +++ b/services/sensorservice/SecondOrderLowPassFilter.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include + +#include + +#include "SecondOrderLowPassFilter.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +SecondOrderLowPassFilter::SecondOrderLowPassFilter(float Q, float fc) + : iQ(1.0f / Q), fc(fc) +{ +} + +void SecondOrderLowPassFilter::setSamplingPeriod(float dT) +{ + K = tanf(float(M_PI) * fc * dT); + iD = 1.0f / (K*K + K*iQ + 1); + a0 = K*K*iD; + a1 = 2.0f * a0; + b1 = 2.0f*(K*K - 1)*iD; + b2 = (K*K - K*iQ + 1)*iD; +} + +// --------------------------------------------------------------------------- + +BiquadFilter::BiquadFilter(const SecondOrderLowPassFilter& s) + : s(s) +{ +} + +float BiquadFilter::init(float x) +{ + x1 = x2 = x; + y1 = y2 = x; + return x; +} + +float BiquadFilter::operator()(float x) +{ + float y = (x + x2)*s.a0 + x1*s.a1 - y1*s.b1 - y2*s.b2; + x2 = x1; + y2 = y1; + x1 = x; + y1 = y; + return y; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SecondOrderLowPassFilter.h b/services/sensorservice/SecondOrderLowPassFilter.h new file mode 100644 index 0000000000000..998ca35b9b660 --- /dev/null +++ b/services/sensorservice/SecondOrderLowPassFilter.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H +#define ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H + +#include +#include + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class BiquadFilter; + +/* + * State of a 2nd order low-pass IIR filter + */ +class SecondOrderLowPassFilter { + friend class BiquadFilter; + float iQ, fc; + float K, iD; + float a0, a1; + float b1, b2; +public: + SecondOrderLowPassFilter(float Q, float fc); + void setSamplingPeriod(float dT); +}; + +/* + * Implements a Biquad IIR filter + */ +class BiquadFilter { + float x1, x2; + float y1, y2; + const SecondOrderLowPassFilter& s; +public: + BiquadFilter(const SecondOrderLowPassFilter& s); + float init(float in); + float operator()(float in); +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SECOND_ORDER_LOW_PASS_FILTER_H diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp new file mode 100644 index 0000000000000..73f85ba35ca1b --- /dev/null +++ b/services/sensorservice/SensorDevice.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "SensorDevice.h" + +namespace android { +// --------------------------------------------------------------------------- +class BatteryService : public Singleton { + static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3; + static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4; + static const String16 DESCRIPTOR; + + friend class Singleton; + sp mBatteryStatService; + + BatteryService() { + const sp sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("batteryinfo"); + mBatteryStatService = sm->getService(name); + } + } + + status_t noteStartSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStartSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; + } + + status_t noteStopSensor(int uid, int handle) { + Parcel data, reply; + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt32(uid); + data.writeInt32(handle); + status_t err = mBatteryStatService->transact( + TRANSACTION_noteStopSensor, data, &reply, 0); + err = reply.readExceptionCode(); + return err; + } + +public: + void enableSensor(int handle) { + if (mBatteryStatService != 0) { + int uid = IPCThreadState::self()->getCallingUid(); + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStartSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } + void disableSensor(int handle) { + if (mBatteryStatService != 0) { + int uid = IPCThreadState::self()->getCallingUid(); + int64_t identity = IPCThreadState::self()->clearCallingIdentity(); + noteStopSensor(uid, handle); + IPCThreadState::self()->restoreCallingIdentity(identity); + } + } +}; + +const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats"); + +ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService) + +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice) + +SensorDevice::SensorDevice() + : mSensorDevice(0), + mSensorModule(0) +{ + status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, + (hw_module_t const**)&mSensorModule); + + LOGE_IF(err, "couldn't load %s module (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorModule) { + err = sensors_open(&mSensorModule->common, &mSensorDevice); + + LOGE_IF(err, "couldn't open device for module %s (%s)", + SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + + if (mSensorDevice) { + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + mActivationCount.setCapacity(count); + Info model; + for (size_t i=0 ; iactivate(mSensorDevice, list[i].handle, 0); + } + } + } +} + +void SensorDevice::dump(String8& result, char* buffer, size_t SIZE) +{ + if (!mSensorModule) return; + sensor_t const* list; + ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + + snprintf(buffer, SIZE, "%d h/w sensors:\n", int(count)); + result.append(buffer); + + Mutex::Autolock _l(mLock); + for (size_t i=0 ; iget_sensors_list(mSensorModule, list); + return count; +} + +status_t SensorDevice::initCheck() const { + return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT; +} + +ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { + if (!mSensorDevice) return NO_INIT; + return mSensorDevice->poll(mSensorDevice, buffer, count); +} + +status_t SensorDevice::activate(void* ident, int handle, int enabled) +{ + if (!mSensorDevice) return NO_INIT; + status_t err(NO_ERROR); + bool actuateHardware = false; + + Info& info( mActivationCount.editValueFor(handle) ); + int32_t& count(info.count); + if (enabled) { + if (android_atomic_inc(&count) == 0) { + actuateHardware = true; + } + Mutex::Autolock _l(mLock); + if (info.rates.indexOfKey(ident) < 0) { + info.rates.add(ident, DEFAULT_EVENTS_PERIOD); + } + } else { + if (android_atomic_dec(&count) == 1) { + actuateHardware = true; + } + Mutex::Autolock _l(mLock); + info.rates.removeItem(ident); + } + if (actuateHardware) { + err = mSensorDevice->activate(mSensorDevice, handle, enabled); + if (enabled) { + LOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err)); + if (err == 0) { + BatteryService::getInstance().enableSensor(handle); + } + } else { + if (err == 0) { + BatteryService::getInstance().disableSensor(handle); + } + } + } + + if (!actuateHardware || enabled) { + Mutex::Autolock _l(mLock); + nsecs_t ns = info.rates.valueAt(0); + for (size_t i=1 ; isetDelay(mSensorDevice, handle, ns); + } + + return err; +} + +status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns) +{ + if (!mSensorDevice) return NO_INIT; + Info& info( mActivationCount.editValueFor(handle) ); + { // scope for lock + Mutex::Autolock _l(mLock); + ssize_t index = info.rates.indexOfKey(ident); + if (index < 0) return BAD_INDEX; + info.rates.editValueAt(index) = ns; + ns = info.rates.valueAt(0); + for (size_t i=1 ; isetDelay(mSensorDevice, handle, ns); +} + +// --------------------------------------------------------------------------- +}; // namespace android + diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h new file mode 100644 index 0000000000000..63ecbcddecc40 --- /dev/null +++ b/services/sensorservice/SensorDevice.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_SENSOR_DEVICE_H +#define ANDROID_SENSOR_DEVICE_H + +#include +#include + +#include +#include +#include + +#include + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz + +class SensorDevice : public Singleton { + friend class Singleton; + struct sensors_poll_device_t* mSensorDevice; + struct sensors_module_t* mSensorModule; + Mutex mLock; // protect mActivationCount[].rates + // fixed-size array after construction + struct Info { + Info() : count(0) { } + int32_t count; + KeyedVector rates; + }; + DefaultKeyedVector mActivationCount; + + SensorDevice(); +public: + ssize_t getSensorList(sensor_t const** list); + status_t initCheck() const; + ssize_t poll(sensors_event_t* buffer, size_t count); + status_t activate(void* ident, int handle, int enabled); + status_t setDelay(void* ident, int handle, int64_t ns); + void dump(String8& result, char* buffer, size_t SIZE); +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_DEVICE_H diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp new file mode 100644 index 0000000000000..93d23d9a40d2e --- /dev/null +++ b/services/sensorservice/SensorInterface.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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. + */ + +#include +#include + +#include + +#include "SensorInterface.h" + +namespace android { +// --------------------------------------------------------------------------- + +SensorInterface::~SensorInterface() +{ +} + +// --------------------------------------------------------------------------- + +HardwareSensor::HardwareSensor(const sensor_t& sensor) + : mSensorDevice(SensorDevice::getInstance()), + mSensor(&sensor), mEnabled(false) +{ + LOGI("%s", sensor.name); +} + +HardwareSensor::~HardwareSensor() { +} + +bool HardwareSensor::process(sensors_event_t* outEvent, + const sensors_event_t& event) { + *outEvent = event; + return true; +} + +bool HardwareSensor::isEnabled() const { + return mEnabled; +} + +status_t HardwareSensor::activate(void* ident,bool enabled) { + status_t err = mSensorDevice.activate(ident, mSensor.getHandle(), enabled); + if (err == NO_ERROR) + mEnabled = enabled; + return err; +} + +status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) { + return mSensorDevice.setDelay(ident, handle, ns); +} + +Sensor HardwareSensor::getSensor() const { + return mSensor; +} + + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h new file mode 100644 index 0000000000000..eebd5638f5d0e --- /dev/null +++ b/services/sensorservice/SensorInterface.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef ANDROID_SENSOR_INTERFACE_H +#define ANDROID_SENSOR_INTERFACE_H + +#include +#include + +#include + +#include + +#include "SensorDevice.h" + +// --------------------------------------------------------------------------- + +namespace android { +// --------------------------------------------------------------------------- + +class SensorInterface { +public: + virtual ~SensorInterface(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event) = 0; + + virtual bool isEnabled() const = 0; + virtual status_t activate(void* ident, bool enabled) = 0; + virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0; + virtual Sensor getSensor() const = 0; + virtual bool isVirtual() const = 0; +}; + +// --------------------------------------------------------------------------- + +class HardwareSensor : public SensorInterface +{ + SensorDevice& mSensorDevice; + Sensor mSensor; + bool mEnabled; + +public: + HardwareSensor(const sensor_t& sensor); + + virtual ~HardwareSensor(); + + virtual bool process(sensors_event_t* outEvent, + const sensors_event_t& event); + + virtual bool isEnabled() const; + virtual status_t activate(void* ident, bool enabled); + virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual Sensor getSensor() const; + virtual bool isVirtual() const { return false; } +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_INTERFACE_H diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 22a45df0603c0..ea5e5ccd8e253 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -35,80 +36,15 @@ #include #include "SensorService.h" +#include "GravitySensor.h" +#include "LinearAccelerationSensor.h" +#include "RotationVectorSensor.h" namespace android { // --------------------------------------------------------------------------- -class BatteryService : public Singleton { - static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3; - static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4; - static const String16 DESCRIPTOR; - - friend class Singleton; - sp mBatteryStatService; - - BatteryService() { - const sp sm(defaultServiceManager()); - if (sm != NULL) { - const String16 name("batteryinfo"); - mBatteryStatService = sm->getService(name); - } - } - - status_t noteStartSensor(int uid, int handle) { - Parcel data, reply; - data.writeInterfaceToken(DESCRIPTOR); - data.writeInt32(uid); - data.writeInt32(handle); - status_t err = mBatteryStatService->transact( - TRANSACTION_noteStartSensor, data, &reply, 0); - err = reply.readExceptionCode(); - return err; - } - - status_t noteStopSensor(int uid, int handle) { - Parcel data, reply; - data.writeInterfaceToken(DESCRIPTOR); - data.writeInt32(uid); - data.writeInt32(handle); - status_t err = mBatteryStatService->transact( - TRANSACTION_noteStopSensor, data, &reply, 0); - err = reply.readExceptionCode(); - return err; - } - -public: - void enableSensor(int handle) { - if (mBatteryStatService != 0) { - int uid = IPCThreadState::self()->getCallingUid(); - int64_t identity = IPCThreadState::self()->clearCallingIdentity(); - noteStartSensor(uid, handle); - IPCThreadState::self()->restoreCallingIdentity(identity); - } - } - void disableSensor(int handle) { - if (mBatteryStatService != 0) { - int uid = IPCThreadState::self()->getCallingUid(); - int64_t identity = IPCThreadState::self()->clearCallingIdentity(); - noteStopSensor(uid, handle); - IPCThreadState::self()->restoreCallingIdentity(identity); - } - } -}; - -const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats"); - -ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService) - -// --------------------------------------------------------------------------- - -// 100 events/s max -static const nsecs_t MINIMUM_EVENT_PERIOD = ms2ns(10); - SensorService::SensorService() : Thread(false), - mSensorDevice(0), - mSensorModule(0), mDump("android.permission.DUMP"), mInitCheck(NO_INIT) { @@ -118,43 +54,66 @@ void SensorService::onFirstRef() { LOGD("nuSensorService starting..."); - status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, - (hw_module_t const**)&mSensorModule); - - LOGE_IF(err, "couldn't load %s module (%s)", - SENSORS_HARDWARE_MODULE_ID, strerror(-err)); - - if (mSensorModule) { - err = sensors_open(&mSensorModule->common, &mSensorDevice); - - LOGE_IF(err, "couldn't open device for module %s (%s)", - SENSORS_HARDWARE_MODULE_ID, strerror(-err)); + SensorDevice& dev(SensorDevice::getInstance()); - sensors_event_t event; - memset(&event, 0, sizeof(event)); - - struct sensor_t const* list; - int count = mSensorModule->get_sensors_list(mSensorModule, &list); + if (dev.initCheck() == NO_ERROR) { + uint32_t virtualSensorsNeeds = + (1<activate(mSensorDevice, sensor.getHandle(), 0); + registerSensor( new HardwareSensor(list[i]) ); + switch (list[i].type) { + case SENSOR_TYPE_GRAVITY: + case SENSOR_TYPE_LINEAR_ACCELERATION: + case SENSOR_TYPE_ROTATION_VECTOR: + virtualSensorsNeeds &= ~(1<getSensor()); + // add to the sensor list (returned to clients) + mSensorList.add(sensor); + // add to our handle->SensorInterface mapping + mSensorMap.add(sensor.getHandle(), s); + // create an entry in the mLastEventSeen array + mLastEventSeen.add(sensor.getHandle(), event); +} + +void SensorService::registerVirtualSensor(SensorInterface* s) +{ + registerSensor(s); + mVirtualSensorList.add( s ); +} + SensorService::~SensorService() { + for (size_t i=0 ; i& args) @@ -175,7 +134,7 @@ status_t SensorService::dump(int fd, const Vector& args) for (size_t i=0 ; i)\n", + snprintf(buffer, SIZE, "%-48s| %-32s | 0x%08x | maxRate=%7.2fHz | last=<%5.1f,%5.1f,%5.1f>\n", s.getName().string(), s.getVendor().string(), s.getHandle(), @@ -183,6 +142,7 @@ status_t SensorService::dump(int fd, const Vector& args) e.data[0], e.data[1], e.data[2]); result.append(buffer); } + SensorDevice::getInstance().dump(result, buffer, SIZE); snprintf(buffer, SIZE, "%d active connections\n", mActiveConnections.size()); @@ -191,7 +151,7 @@ status_t SensorService::dump(int fd, const Vector& args) result.append(buffer); for (size_t i=0 ; igetNumConnections()); @@ -206,13 +166,15 @@ bool SensorService::threadLoop() { LOGD("nuSensorService thread starting..."); - sensors_event_t buffer[16]; - sensors_event_t scratch[16]; - struct sensors_poll_device_t* device = mSensorDevice; - ssize_t count; + const size_t numEventMax = 16 * (1 + mVirtualSensorList.size()); + sensors_event_t buffer[numEventMax]; + sensors_event_t scratch[numEventMax]; + SensorDevice& device(SensorDevice::getInstance()); + const size_t vcount = mVirtualSensorList.size(); + ssize_t count; do { - count = device->poll(device, buffer, sizeof(buffer)/sizeof(*buffer)); + count = device.poll(buffer, numEventMax); if (count<0) { LOGE("sensor poll failed (%s)", strerror(-count)); break; @@ -220,19 +182,44 @@ bool SensorService::threadLoop() recordLastValue(buffer, count); + // handle virtual sensors + if (count && vcount) { + const DefaultKeyedVector virtualSensors( + getActiveVirtualSensors()); + const size_t activeVirtualSensorCount = virtualSensors.size(); + if (activeVirtualSensorCount) { + size_t k = 0; + for (size_t i=0 ; iprocess(&out, event[i])) { + buffer[count + k] = out; + k++; + } + } + } + if (k) { + // record the last synthesized values + recordLastValue(&buffer[count], k); + count += k; + // sort the buffer by time-stamps + sortEventBuffer(buffer, count); + } + } + } + + // send our events to clients... const SortedVector< wp > activeConnections( getActiveConnections()); - size_t numConnections = activeConnections.size(); - if (numConnections) { - for (size_t i=0 ; i connection(activeConnections[i].promote()); - if (connection != 0) { - connection->sendEvents(buffer, count, scratch); - } + for (size_t i=0 ; i connection( + activeConnections[i].promote()); + if (connection != 0) { + connection->sendEvents(buffer, count, scratch); } } - } while (count >= 0 || Thread::exitPending()); LOGW("Exiting SensorService::threadLoop!"); @@ -257,6 +244,18 @@ void SensorService::recordLastValue( mLastEventSeen.editValueFor(prev) = buffer[count-1]; } +void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) +{ + struct compar { + static int cmp(void const* lhs, void const* rhs) { + sensors_event_t const* l = static_cast(lhs); + sensors_event_t const* r = static_cast(rhs); + return r->timestamp - l->timestamp; + } + }; + qsort(buffer, count, sizeof(sensors_event_t), compar::cmp); +} + SortedVector< wp > SensorService::getActiveConnections() const { @@ -264,6 +263,13 @@ SensorService::getActiveConnections() const return mActiveConnections; } +DefaultKeyedVector +SensorService::getActiveVirtualSensors() const +{ + Mutex::Autolock _l(mLock); + return mActiveVirtualSensors; +} + String8 SensorService::getSensorName(int handle) const { size_t count = mSensorList.size(); for (size_t i=0 ; i& connectio for (size_t i=0 ; iremoveConnection(connection)) { - mSensorDevice->activate(mSensorDevice, mActiveSensors.keyAt(i), 0); + int handle = mActiveSensors.keyAt(i); + SensorInterface* sensor = mSensorMap.valueFor( handle ); + if (sensor) { + sensor->activate(connection.unsafe_get(), false); + } mActiveSensors.removeItemsAt(i, 1); + mActiveVirtualSensors.removeItem(handle); delete rec; size--; } else { @@ -311,39 +322,38 @@ status_t SensorService::enable(const sp& connection, if (mInitCheck != NO_ERROR) return mInitCheck; - status_t err = NO_ERROR; Mutex::Autolock _l(mLock); - SensorRecord* rec = mActiveSensors.valueFor(handle); - if (rec == 0) { - rec = new SensorRecord(connection); - mActiveSensors.add(handle, rec); - err = mSensorDevice->activate(mSensorDevice, handle, 1); - LOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err)); - if (err == 0) { - BatteryService::getInstance().enableSensor(handle); - } - } else { - if (rec->addConnection(connection)) { - // this sensor is already activated, but we are adding a - // connection that uses it. Immediately send down the last - // known value of the requested sensor. - sensors_event_t scratch; - sensors_event_t& event(mLastEventSeen.editValueFor(handle)); - if (event.version == sizeof(sensors_event_t)) { - connection->sendEvents(&event, 1); + SensorInterface* sensor = mSensorMap.valueFor(handle); + status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE); + if (err == NO_ERROR) { + SensorRecord* rec = mActiveSensors.valueFor(handle); + if (rec == 0) { + rec = new SensorRecord(connection); + mActiveSensors.add(handle, rec); + if (sensor->isVirtual()) { + mActiveVirtualSensors.add(handle, sensor); + } + } else { + if (rec->addConnection(connection)) { + // this sensor is already activated, but we are adding a + // connection that uses it. Immediately send down the last + // known value of the requested sensor. + sensors_event_t scratch; + sensors_event_t& event(mLastEventSeen.editValueFor(handle)); + if (event.version == sizeof(sensors_event_t)) { + connection->sendEvents(&event, 1); + } } } - } - if (err == NO_ERROR) { - // connection now active - if (connection->addSensor(handle)) { - // the sensor was added (which means it wasn't already there) - // so, see if this connection becomes active - if (mActiveConnections.indexOf(connection) < 0) { - mActiveConnections.add(connection); + if (err == NO_ERROR) { + // connection now active + if (connection->addSensor(handle)) { + // the sensor was added (which means it wasn't already there) + // so, see if this connection becomes active + if (mActiveConnections.indexOf(connection) < 0) { + mActiveConnections.add(connection); + } } - // this could change the sensor event delivery speed - recomputeEventsPeriodLocked(handle); } } return err; @@ -367,15 +377,11 @@ status_t SensorService::disable(const sp& connection, // see if this sensor becomes inactive if (rec->removeConnection(connection)) { mActiveSensors.removeItem(handle); + mActiveVirtualSensors.removeItem(handle); delete rec; - err = mSensorDevice->activate(mSensorDevice, handle, 0); - if (err == 0) { - BatteryService::getInstance().disableSensor(handle); - } } - } - if (err == NO_ERROR) { - recomputeEventsPeriodLocked(handle); + SensorInterface* sensor = mSensorMap.valueFor(handle); + err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); } return err; } @@ -392,30 +398,9 @@ status_t SensorService::setEventRate(const sp& connection if (ns < MINIMUM_EVENTS_PERIOD) ns = MINIMUM_EVENTS_PERIOD; - Mutex::Autolock _l(mLock); - status_t err = connection->setEventRateLocked(handle, ns); - if (err == NO_ERROR) { - recomputeEventsPeriodLocked(handle); - } - return err; -} - -status_t SensorService::recomputeEventsPeriodLocked(int32_t handle) -{ - status_t err = NO_ERROR; - nsecs_t wanted = ms2ns(1000); - size_t count = mActiveConnections.size(); - for (size_t i=0 ; i connection(mActiveConnections[i].promote()); - if (connection != NULL) { - nsecs_t ns = connection->getEventRateForSensor(handle); - if (ns) { - wanted = wanted < ns ? wanted : ns; - } - } - } - err = mSensorDevice->setDelay(mSensorDevice, handle, wanted); - return err; + SensorInterface* sensor = mSensorMap.valueFor(handle); + if (!sensor) return BAD_VALUE; + return sensor->setDelay(connection.get(), handle, ns); } // --------------------------------------------------------------------------- @@ -465,9 +450,8 @@ void SensorService::SensorEventConnection::onFirstRef() bool SensorService::SensorEventConnection::addSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); - if (mSensorInfo.indexOfKey(handle) <= 0) { - SensorInfo info; - mSensorInfo.add(handle, info); + if (mSensorInfo.indexOf(handle) <= 0) { + mSensorInfo.add(handle); return true; } return false; @@ -475,7 +459,7 @@ bool SensorService::SensorEventConnection::addSensor(int32_t handle) { bool SensorService::SensorEventConnection::removeSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); - if (mSensorInfo.removeItem(handle) >= 0) { + if (mSensorInfo.remove(handle) >= 0) { return true; } return false; @@ -483,7 +467,7 @@ bool SensorService::SensorEventConnection::removeSensor(int32_t handle) { bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const { Mutex::Autolock _l(mConnectionLock); - return mSensorInfo.indexOfKey(handle) >= 0; + return mSensorInfo.indexOf(handle) >= 0; } bool SensorService::SensorEventConnection::hasAnySensor() const { @@ -491,19 +475,6 @@ bool SensorService::SensorEventConnection::hasAnySensor() const { return mSensorInfo.size() ? true : false; } -status_t SensorService::SensorEventConnection::setEventRateLocked( - int handle, nsecs_t ns) -{ - Mutex::Autolock _l(mConnectionLock); - ssize_t index = mSensorInfo.indexOfKey(handle); - if (index >= 0) { - SensorInfo& info = mSensorInfo.editValueFor(handle); - info.ns = ns; - return NO_ERROR; - } - return status_t(index); -} - status_t SensorService::SensorEventConnection::sendEvents( sensors_event_t const* buffer, size_t numEvents, sensors_event_t* scratch) @@ -515,7 +486,7 @@ status_t SensorService::SensorEventConnection::sendEvents( size_t i=0; while (i= 0) { + if (mSensorInfo.indexOf(curr) >= 0) { do { scratch[count++] = buffer[i++]; } while ((i #include +#include "SensorInterface.h" + // --------------------------------------------------------------------------- struct sensors_poll_device_t; @@ -50,7 +52,6 @@ class SensorService : friend class BinderService; static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz - static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz SensorService(); virtual ~SensorService(); @@ -77,12 +78,8 @@ class SensorService : sp const mChannel; mutable Mutex mConnectionLock; - // protected mConnectionLock - struct SensorInfo { - SensorInfo() : ns(DEFAULT_EVENTS_PERIOD) { } - nsecs_t ns; - }; - DefaultKeyedVector mSensorInfo; + // protected by SensorService::mLock + SortedVector mSensorInfo; public: SensorEventConnection(const sp& service); @@ -93,10 +90,6 @@ class SensorService : bool hasAnySensor() const; bool addSensor(int32_t handle); bool removeSensor(int32_t handle); - status_t setEventRateLocked(int handle, nsecs_t ns); - nsecs_t getEventRateForSensor(int32_t handle) const { - return mSensorInfo.valueFor(handle).ns; - } }; class SensorRecord { @@ -109,21 +102,25 @@ class SensorService : }; SortedVector< wp > getActiveConnections() const; - String8 getSensorName(int handle) const; - status_t recomputeEventsPeriodLocked(int32_t handle); + DefaultKeyedVector getActiveVirtualSensors() const; + String8 getSensorName(int handle) const; void recordLastValue(sensors_event_t const * buffer, size_t count); + static void sortEventBuffer(sensors_event_t* buffer, size_t count); + void registerSensor(SensorInterface* sensor); + void registerVirtualSensor(SensorInterface* sensor); // constants Vector mSensorList; - struct sensors_poll_device_t* mSensorDevice; - struct sensors_module_t* mSensorModule; + DefaultKeyedVector mSensorMap; + Vector mVirtualSensorList; Permission mDump; status_t mInitCheck; // protected by mLock mutable Mutex mLock; DefaultKeyedVector mActiveSensors; + DefaultKeyedVector mActiveVirtualSensors; SortedVector< wp > mActiveConnections; // The size of this vector is constant, only the items are mutable