From 1aa3218800a9d98c7b62450a3821b99b8b9588e0 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 9 Jul 2010 11:48:23 -0700 Subject: [PATCH] Add new native-plasma sample code. This shows direct drawing to an ANativeWindow's bits. Update the NDK API, and fix a bug in the native-activity app where it would hang while exiting. Change-Id: I4fa98d083405eb0d1b22b10a73a2ef18d45fdb59 --- .../usr/include/android/native_activity.h | 5 + .../usr/include/android/native_window.h | 43 +- .../usr/include/android/native_window_jni.h | 40 ++ .../arch-arm/usr/include/android/rect.h | 36 ++ .../arch-arm/usr/include/android/window.h | 58 ++ .../usr/include/android_glue/threaded_app.h | 13 +- .../android-9/arch-arm/usr/lib/libandroid.so | Bin 9524 -> 13652 bytes .../arch-arm/usr/lib/libthreaded_app.a | Bin 50768 -> 50808 bytes ndk/samples/bitmap-plasma/default.properties | 2 +- ndk/samples/bitmap-plasma/jni/Application.mk | 1 + .../native-activity/AndroidManifest.xml | 2 +- ndk/samples/native-activity/jni/main.c | 28 +- ndk/samples/native-plasma/AndroidManifest.xml | 19 + ndk/samples/native-plasma/default.properties | 11 + ndk/samples/native-plasma/jni/Android.mk | 9 + ndk/samples/native-plasma/jni/Application.mk | 3 + ndk/samples/native-plasma/jni/plasma.c | 498 ++++++++++++++++++ .../native-plasma/res/values/strings.xml | 4 + .../src/Dummy.java | 0 19 files changed, 745 insertions(+), 27 deletions(-) create mode 100644 ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h create mode 100644 ndk/platforms/android-9/arch-arm/usr/include/android/rect.h create mode 100644 ndk/platforms/android-9/arch-arm/usr/include/android/window.h create mode 100644 ndk/samples/native-plasma/AndroidManifest.xml create mode 100644 ndk/samples/native-plasma/default.properties create mode 100644 ndk/samples/native-plasma/jni/Android.mk create mode 100644 ndk/samples/native-plasma/jni/Application.mk create mode 100644 ndk/samples/native-plasma/jni/plasma.c create mode 100644 ndk/samples/native-plasma/res/values/strings.xml rename ndk/samples/{native-activity => native-plasma}/src/Dummy.java (100%) diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h index a31c5af74..d0ff05277 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h @@ -192,6 +192,11 @@ typedef void ANativeActivity_createFunc(ANativeActivity* activity, */ extern ANativeActivity_createFunc ANativeActivity_onCreate; +void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); + +void ANativeActivity_setWindowFlags(ANativeActivity* activity, + uint32_t addFlags, uint32_t removeFlags); + #ifdef __cplusplus }; #endif diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h index 678ba3d7c..7599d7e55 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h @@ -14,10 +14,11 @@ * limitations under the License. */ - #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +35,27 @@ enum { struct ANativeWindow; typedef struct ANativeWindow ANativeWindow; +typedef struct ANativeWindow_Buffer { + int32_t width; + int32_t height; + int32_t stride; + int32_t format; + void* bits; + + uint32_t reserved[6]; +} ANativeWindow_Buffer; + +/** + * Acquire a reference on the given ANativeWindow object. This prevents the object + * from being deleted until the reference is removed. + */ +void ANativeWindow_acquire(ANativeWindow* window); + +/** + * Remove a reference that was previously acquired with ANativeWindow_acquire(). + */ +void ANativeWindow_release(ANativeWindow* window); + /* * Return the current width in pixels of the window surface. Returns a * negative value on error. @@ -60,13 +82,22 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * window's physical size, then it buffer will be scaled to match that size * when compositing it to the screen. * - * The format may be one of the window format constants above. - * - * For all of these parameters, if 0 is supplied than the window's base + * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. */ -int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, - int32_t height, int32_t format); +int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height); + +/** + * Lock the window's next drawing surface for writing. + */ +int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, + ARect* inOutDirtyBounds); + +/** + * Unlock the window's drawing surface after previously locking it, + * posting the new buffer to the display. + */ +int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); #ifdef __cplusplus }; diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h new file mode 100644 index 000000000..b9e72efb7 --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h @@ -0,0 +1,40 @@ +/* + * 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_NATIVE_WINDOW_JNI_H +#define ANDROID_NATIVE_WINDOW_JNI_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return the ANativeWindow associated with a Java Surface object, + * for interacting with it through native code. This acquires a reference + * on the ANativeWindow that is returned; be sure to use ANativeWindow_release() + * when done with it so that it doesn't leak. + */ +ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_WINDOW_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h b/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h new file mode 100644 index 000000000..3e81f531d --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h @@ -0,0 +1,36 @@ +/* + * 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_RECT_H +#define ANDROID_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ARect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} ARect; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_RECT_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/window.h b/ndk/platforms/android-9/arch-arm/usr/include/android/window.h new file mode 100644 index 000000000..2ab192b74 --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/window.h @@ -0,0 +1,58 @@ +/* + * 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_WINDOW_H +#define ANDROID_WINDOW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Window flags, as per the Java API at android.view.WindowManager.LayoutParams. + */ +enum { + AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + AWINDOW_FLAG_DIM_BEHIND = 0x00000002, + AWINDOW_FLAG_BLUR_BEHIND = 0x00000004, + AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008, + AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010, + AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020, + AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080, + AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100, + AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200, + AWINDOW_FLAG_FULLSCREEN = 0x00000400, + AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + AWINDOW_FLAG_DITHER = 0x00001000, + AWINDOW_FLAG_SECURE = 0x00002000, + AWINDOW_FLAG_SCALED = 0x00004000, + AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000, + AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000, + AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000, + AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000, + AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000, + AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000, +}; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_WINDOW_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h b/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h index 80de3bf2b..491389bb0 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h @@ -52,10 +52,6 @@ struct android_app { // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. int activityState; - // This is non-zero when the application's NativeActivity is being - // destroyed and waiting for the app thread to complete. - int destroyRequested; - // ------------------------------------------------- // Below are "private" implementation of the glue code. @@ -67,6 +63,10 @@ struct android_app { pthread_t thread; + // This is non-zero when the application's NativeActivity is being + // destroyed and waiting for the app thread to complete. + int destroyRequested; + int running; int destroyed; AInputQueue* pendingInputQueue; @@ -158,8 +158,11 @@ int8_t android_app_read_cmd(struct android_app* android_app); /** * Call with the command returned by android_app_read_cmd() to do the * default processing of the given command. + * + * Important: returns 0 if the app should exit. You must ALWAYS check for + * a zero return and, if found, exit your android_main() function. */ -void android_app_exec_cmd(struct android_app* android_app, int8_t cmd); +int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd); /** * This is the function that application code must implement, representing diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so index 002b9294696903b1ddcf5465d444a3c282843e1d..ba26010a72fdfbbc1899f8c82892dba55cac5881 100644 GIT binary patch literal 13652 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 c82z9%VB}1;e}~_zBq_x|0bAihr~m)} delta 3893 zcmb_fZBSI#89sMmzhD;MOWdY}nd3sBhrlmL4HAFvCc(gM@~4J1%R-~g}>r~t|U zbc(qFDw`RTb>lJor$)a7?9@Gs9WkVv59B#5WN?PT zSzw1@FEcnvv_@2x1G&1D__vO;$@BtMfCpFwJPa5`Ic;*vnTGfR7)#I60UMA8_<@Z8 z6?TYy^KVhme~Z3P;EZ2%S8W4nRXKsE3v@Cd+{FGDmZ9Lh`R1FiCItOT{0iCvhS zaH>N6qn&gBaaweW(?UMMX53;?tY+UHUY;s9yr)9p^tO=2J}g2 zni%T9J#ZhV?HIw!TzwJx6;5x49^`Zj^!FB@mo2Otjtg+mXsLmhpu^k)KZ1^M`XclU zr+)_><+KX@4yV(wT`of>2T%fi1zK-UMuVH+xCsaT^bYKSz7J7s=r-s)tV>cKgWdw2 ztbZDMAE!s4JD_RP(|~>p-3?7!oAlqIpEor2poNv;HF*UN+JmGIKwp5Sx1aQJ=qRTL zq5sO&pN3XB{d?$Sp;7)5`XRh1WEUe}5pAYKN!Oj*;3&;iE?J(;{4wf@h*3QcHuO8W zO0~68K8bgY4mRq}o3zi3LMbmoUq&2FF@btbT&q4N2f5w`tuuT z#73c<0q7o2!r{Vp*++3Psnb}S4HIEobfmMRs6bZ|6&Jg!Jr7NnT~fac-MN_Xu6AaL zzOY1(EzuXDL)`P1Y`DaD$JHej{kGdpTQ_L%CkL5bflaVZ6j%jDr|=p_drf)>>kmhCX7P^nT(>9LU5t@h<7s9PP`kJRld@@+$GOC zF{|%>=N9|*z^&QOXFpEb)0{oQ*{^Z-dCnf<>;cX`#o4`_{cOUP^@a~~fp*Rga&`-6 zH*?Fozdd`F)!*2;3+Nsu4b7lEh7D`m_=gV z8z0C~_Vy&srZ<6}h_f?QDhhig%GweWjr@-*`wH@e!^+bIdFvWt?nZZ$1^F#T{(zpj zL2u;+t#r;dwte2=tVM>sO1Pk)z9g2>n4$M5g`W7n78heaL`(E1p46ycC9%iuXg*=i z{DX=%`{bRd7rp5K=5S0OOi?llt4$d(rM|FY$0fDAs8bStsKqlhcJ8p`lk&Q>_&v1~ zS(a(Suq!N#Y4K^b7voy@iMHJ$Ii%&%u#_^G7q&?$h>a*eEzA+lE0+t`$g`>|niWYs z&xW-4tXddN*_GP#&44R%wpELtKx_o>(t@UGy#H(P_Z$8mtb$Xb%rs-IYI4R7s-Hf9kFw4|h=|9oG35n+!;=)Scn(bVnRi4oIkT)$1(+1usF9R#cq=GoCLj1Mb=?v2?w z5>w2cQ{C0l8fj!F6RGA@|H^hjes5lrCnrZk@9R7n>ikzi_k+img+mLv9uH;z8~!(J zp(6^a@4?usY4UY& z3wRFP3cj7F5Sj{mZlrwI=Wy3$e>g@5KDI1#c@n>1hGFAIWvl< z=URK>gEI)GZ-IXRm>YHrTZ?$!U=!k`ml<4Ou-D)!gEtv0f$1w}4;c3z4s-q2NVT;r&$!v`SYBkp^L(o&&WBj7?} zB1SIeE3elSTUv2hw-zW@Yl`iQKP8pVYDBY0^%S>%l?@ibp?LgRO3?50L1Y8-?0-9t zC1S?_YJ~>i@FWn_`#0ftSm;xt$D{n*UuGtAg&tV&yG;EaC1XRG`7Jm{^k$kj*!~MA CcvRT{ diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a b/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a index 9b6e7dd8cbdc17120138b776867f284246965c07..a21c7e5532722c7337b4efd769829c13b9469eca 100644 GIT binary patch delta 3298 zcmZuz4Nz3q6~6buLs4+oC@uylZ{_EKLRl3ABgm?_^#@xW!Az!-8qvmRFl0uJ3b+^q zQ4k?VjHWQLR;f+Z(5xoJ${43Qu~8=IXs`{=U@O)p+TaAopAqeM?ryebrf=qc=bm%F zbM86!-uK?^tPOZj8&Dq^l8OHeZ^o+?yn#18h-{F{)nrc8xOK-T5 zpjkJ1hRI)P@+;5kfCh(*{U|kE`}y!;LWI0yMuC#!K7=j47?n$1=Av%{ zJN_yF`WQqXD-lGD*~l|5qtzJ^?qy6X0K=Qka!$uA9F6f;7flqRil;N?vA&zTA`@*d zdT*tnOjW^dcKH;hgu6c^&n;HL;uB4V(RAop}YQG8?Ke zE{8*Zs{E3m7r@xdeyY%?TxS`(eZY(Ql-*jC+c}_ohTUq|?XwX~<5PP~xwWGw zTa_Cx?==`x(!o=^(#n+#z~tSP)*?5yB?1dAj3_={*Ogxa^vN*3$bM>huk&;-DPAe_ zy8XPjV08O=-OPJe@eYQ7cgfE?4&(3ryi3fx!mh%o;S=29Cw>p>mwsXg6G!0X6GkFH z@`(~+KH7K~?=w#o_9+*(K=Dd=!_O&REO>9g7>$+i7IKc`?POk}>;}?1Q(~SUD=+hz zoFvy{HTdaA`xc}vbbdgvOi4V`G0&*XC0cT?lp~_;$@aOLF7OKKm|2K` zuYA^AZO}8;`}Di1iE;~dOr0$MNrSSZY>iSH_UM#XztDo7;r)iDWJky+v@d&K^Ukv1$RJ@~z9jH&I4zi#ZZnpya1}0ndjH8& zX=|J) zlJaLX*uwQ;t^~!pS!lSVor5xaV8&mEhUIwbm^)JZFH&TWZT2{qjmLsEMPu^9GWR=*cGyjn6_iR{1u{5;gI0&apVq`4!mYDLF6k2M^lavO0Oa;I- zR0+hIDZB!#rGZjYH=KBz>6OwElv!q#O*F5})SOOQT{4PlVQ^A&nJJIaS>P=mpNF(9K+38nBuQ z6jlOv(UHxjUJt({<#&6tRUV*$&8Bv8x=JeZZ7UXN-rHQ!T7}KP%XAjlM|Tv4RhYci z6{rq@GE|__3ab|QG1XPXYmONz(uE4EbkH?$V@cm)$_z>drcyp|8I>tK2+X67EvEkZ zj2}`8skCA|s?yZ;67>x?xJ2`CxuoqrU8#pL6xarMIdiVO;uJD zaiq%BtT`&9+b~#Z0Mr{4x0Sbj9WBP+PHwaE=XIN@b$SDZY_}r& zsO=_pVJ7e@6#r83H`v1%c0^m0wSmN!!s*HmLg0!M00 zoQ*5M#WVoSq_|p>&#%I@z%|rdYw8COsb59vuH}^O)MB|^Dp1l6Uhb?N?7SSfk9Gia z={WE*T?6)zUT4bJDH(W+@`2q{2HZji>rB0St`L{#VqJ{he?o{Q^sp{Q9;K+AygoC5 zCKUk}QzP&`weK{w$TM_vXT1D`LhDWa>>ENnM{kylpxk;ZuBQdCb-|XbY)$nzX2o>0 zJ{~)ErQVbd&p`dEV0ppw+Ixioc<(!!7lyg>@h8+8a2xQ+0+#qp{hH+;g(&vvZlA33 z*&A3k3(@G4dwt{kedC9H`e#19!zX{L!4DU*9G1g{=Y7vZ-Cd54))3rucC-9Yh$fb} zKJ({t$Z32PeD({F0ii;4vIP0EPru6YT_N}iz~enE_uwk%({HidE5vP|-pBGi0G_c8 r!ecveIyiAN?ghLOl|IS$1g>z8Pww-{10>Jbf=~Ihzj%h9$=3c0+_`mC delta 3438 zcmZuz3s6+o89wL2#TU41$^E{j|+5I}iI0`d?@jF93eT4y9hsS}cjrX3%nfFObo z9>V%deT-y$C#Gmj)>o}e$W)CnIARCVm|}wyP3;7nvFJ!zG5!9t>yFO2Gxz(?|DEsu z&f}hY_YO69bTxQ12YDsNO-Y!NXb;_QQLU*KOI%XYv}8*{Y-}vrv9XEq@fKtWQ|-4R zw4pVQvGTW?{F`H$hdox>K8sJ%-Xt#}yp!965Snd*Y1~+3)6d3m7G$z($kKXMW-;ye zK$hWDhMBxQk!3ow2-7}aWLdwCrP{=sk+&q=L=Xdhf$>6E^G!m?TR+7KVPP)R^aAo8 zYDx;U^f3DtNb4hj?D3u=M7a`mv1k=tP717C#iGA}wZ)GEx%vo9!@eAY=DMvsJ$q4D z`bcE8S+ShGE=GF31D{DUa5Pv=su`U@{dHXbMRB;AktW&qXK>-~W3AFd=As<{b@;ac zE%Ec@zgu*$UVxEpsJQ4j%=1mo1BM)cE<9s_eMGCH6Xsu4b zGSv#UbIG4UMHH9*4zf~=^LJIY8Mi?0R%O#rCNZyL?y}unW~~HgJ*Bg*5UWf>DlFX- zkPoZ6DCC78Z*!em=rFIdg3CVUO!>a5OP!74v&La&VWw+dALtN(LAx2@i zA9?c+Qgd>^{DVBHc{m+bUadTs4%G^z!qS36A_v{(+d$U2%?H{1Gk4h_m;FPPjrK>` zU3#1xP?WCqaJb)^)M2hf9T}o=@=CZs8!TMD_t4i@QX?p2HkRyA=nA$LN2mj6YC;nFOasqYV(hj-Fzk!RZTzG zpCG8BtFI>cZW)2clB?AyQ9Q~K$FEX~w16L^93Nthw$9RYfyYnBs6u#jlYP3Md_W&g zkCfGPZF;i2Nn_H214v4XH6-Tk%bM3y>RptU7WncbI7M4StSe_d)A>-9ST{V&9#AF! zd49>jb4&h3*V6ndk4hO69b-|)N_D+c|`btKA%9*sW^7lD$rdROG7n5gtS|(!|LG)=(aGnjB?Ts~A zYqMC}SF*1}glaZ!`}Dntz86`kKk0Wlzh_wlPvIQvg+Bk8FXi|v$B@_j7C3q5PK@mH zfrpRVUt0GqdcR$K{sB(tUR*V}HsV@}YZkO^mX|xnXKUJ(VWIP=L-lr?TEP4QJqu@%$ zY~Xn+tu*u#8A7Bhqqa)3?56fgL%W}$X7mWeee$U?q$ed*8QLSzRpFRqEvRX96qrRl z3WuuOy%}rETW@GJnaZgFL=CmBH)J_o05;HoLceN5o}pBQOMq?ESZ(MX zFp5$}oz-S}j&4+AZBC=04ZODK4TkKc0^ohB*nrNHba+F!jG`-`qUZt8n}TZ$J$}X$ zr-e0U>}Y9?p%u+gQ)&ZIMC~=axwnBODw*3kFBC{|6Wzt)UJ z4A&Z3r_(59qgi%R-bTJND}mkA3T&ebKyMmQ=(ov$CUujc`)1*9O&OJMGGh^qn+z=_ zOUcZ*EnFD9#nARRofd-FL#0~` z+=Uk4L23ssrQ5(x@~LA?05(uzouPNbD4(va^QG206Y7rE8CqDjno@tAS%%Rtq_=2N zJ&&AMkK=KgR@H~gd};-iPZxkVxb=qqo9riNDXM`BQyUCzr_-q%#7=5#;3=JKF!a5U z_S4M<8>Xc<@>HS~768MjqS4T|=Liw6cIsTC8AtgFxJ%%?73aN`4{PvNL(ZjaU@w&d zyQl@Yl-jo%de{+XF71 zj)Ln0*P*!nCbM?`uk^SnT<)bw&4xTidCi8_vD|sCo6WL=T0smfr;E+uGJ*!04X+8U zLJWFPm3;z@EgS7fv1g5v=N;>J7kl6xal3Vn-#fGM_R#D?6u9C7j)#R<%<)fn>ACVU zSFCpNjU3@_cf}T0{|B!Ak6igVSN@e_pTp!;xef2J(VqyhlOsOh_jCLLZxD|77CYnW zKac3)Bg7?+e-xtAm3ML6Aw;(;|CS@n_~V52eH?e;Bh{7P;kX-s-( - + app); switch (cmd) { case APP_CMD_WINDOW_CHANGED: engine_term_display(engine); - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); if (engine->app->window != NULL) { engine_init_display(engine); engine_draw_frame(engine); } break; case APP_CMD_LOST_FOCUS: - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); engine->animating = 0; engine_draw_frame(engine); break; default: - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); break; } + + return res; } void android_main(struct android_app* state) { @@ -185,10 +188,15 @@ void android_main(struct android_app* state) { int events; void* data; while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) { - LOGI("Poll returned: %d", (int)data); switch ((int)data) { case LOOPER_ID_MAIN: - engine_do_main_cmd(&engine); + if (!engine_do_main_cmd(&engine)) { + LOGI("Engine thread destroy requested!"); + engine_term_display(&engine); + android_app_destroy(state); + // Can't touch android_app object after this. + return; + } break; case LOOPER_ID_EVENT: engine_do_ui_event(&engine); @@ -196,14 +204,6 @@ void android_main(struct android_app* state) { } } - if (state->destroyRequested) { - LOGI("Engine thread destroy requested!"); - engine_term_display(&engine); - android_app_destroy(state); - // Can't touch android_app object after this. - return; - } - if (engine.animating) { // Done with events; draw next animation frame. engine.angle += .01f; diff --git a/ndk/samples/native-plasma/AndroidManifest.xml b/ndk/samples/native-plasma/AndroidManifest.xml new file mode 100644 index 000000000..28408b9b0 --- /dev/null +++ b/ndk/samples/native-plasma/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/ndk/samples/native-plasma/default.properties b/ndk/samples/native-plasma/default.properties new file mode 100644 index 000000000..9d135cb85 --- /dev/null +++ b/ndk/samples/native-plasma/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/ndk/samples/native-plasma/jni/Android.mk b/ndk/samples/native-plasma/jni/Android.mk new file mode 100644 index 000000000..e9dcaea70 --- /dev/null +++ b/ndk/samples/native-plasma/jni/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := native-plasma +LOCAL_SRC_FILES := plasma.c +LOCAL_LDLIBS := -lthreaded_app -lm -llog -landroid + +include $(BUILD_SHARED_LIBRARY) diff --git a/ndk/samples/native-plasma/jni/Application.mk b/ndk/samples/native-plasma/jni/Application.mk new file mode 100644 index 000000000..23fa139dd --- /dev/null +++ b/ndk/samples/native-plasma/jni/Application.mk @@ -0,0 +1,3 @@ +# The ARMv7 is significanly faster due to the use of the hardware FPU +APP_ABI := armeabi armeabi-v7a +APP_PLATFORM := android-9 diff --git a/ndk/samples/native-plasma/jni/plasma.c b/ndk/samples/native-plasma/jni/plasma.c new file mode 100644 index 000000000..3ccb6058c --- /dev/null +++ b/ndk/samples/native-plasma/jni/plasma.c @@ -0,0 +1,498 @@ +/* + * 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 + +#define LOG_TAG "libplasma" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) + +/* Set to 1 to enable debug log traces. */ +#define DEBUG 0 + +/* Set to 1 to optimize memory stores when generating plasma. */ +#define OPTIMIZE_WRITES 1 + +/* Return current time in milliseconds */ +static double now_ms(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000. + tv.tv_usec/1000.; +} + +/* We're going to perform computations for every pixel of the target + * bitmap. floating-point operations are very slow on ARMv5, and not + * too bad on ARMv7 with the exception of trigonometric functions. + * + * For better performance on all platforms, we're going to use fixed-point + * arithmetic and all kinds of tricks + */ + +typedef int32_t Fixed; + +#define FIXED_BITS 16 +#define FIXED_ONE (1 << FIXED_BITS) +#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1) + +#define FIXED_FROM_INT(x) ((x) << FIXED_BITS) +#define FIXED_TO_INT(x) ((x) >> FIXED_BITS) + +#define FIXED_FROM_FLOAT(x) ((Fixed)((x)*FIXED_ONE)) +#define FIXED_TO_FLOAT(x) ((x)/(1.*FIXED_ONE)) + +#define FIXED_MUL(x,y) (((int64_t)(x) * (y)) >> FIXED_BITS) +#define FIXED_DIV(x,y) (((int64_t)(x) * FIXED_ONE) / (y)) + +#define FIXED_DIV2(x) ((x) >> 1) +#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1) + +#define FIXED_FRAC(x) ((x) & ((1 << FIXED_BITS)-1)) +#define FIXED_TRUNC(x) ((x) & ~((1 << FIXED_BITS)-1)) + +#define FIXED_FROM_INT_FLOAT(x,f) (Fixed)((x)*(FIXED_ONE*(f))) + +typedef int32_t Angle; + +#define ANGLE_BITS 9 + +#if ANGLE_BITS < 8 +# error ANGLE_BITS must be at least 8 +#endif + +#define ANGLE_2PI (1 << ANGLE_BITS) +#define ANGLE_PI (1 << (ANGLE_BITS-1)) +#define ANGLE_PI2 (1 << (ANGLE_BITS-2)) +#define ANGLE_PI4 (1 << (ANGLE_BITS-3)) + +#define ANGLE_FROM_FLOAT(x) (Angle)((x)*ANGLE_PI/M_PI) +#define ANGLE_TO_FLOAT(x) ((x)*M_PI/ANGLE_PI) + +#if ANGLE_BITS <= FIXED_BITS +# define ANGLE_FROM_FIXED(x) (Angle)((x) >> (FIXED_BITS - ANGLE_BITS)) +# define ANGLE_TO_FIXED(x) (Fixed)((x) << (FIXED_BITS - ANGLE_BITS)) +#else +# define ANGLE_FROM_FIXED(x) (Angle)((x) << (ANGLE_BITS - FIXED_BITS)) +# define ANGLE_TO_FIXED(x) (Fixed)((x) >> (ANGLE_BITS - FIXED_BITS)) +#endif + +static Fixed angle_sin_tab[ANGLE_2PI+1]; + +static void init_angles(void) +{ + int nn; + for (nn = 0; nn < ANGLE_2PI+1; nn++) { + double radians = nn*M_PI/ANGLE_PI; + angle_sin_tab[nn] = FIXED_FROM_FLOAT(sin(radians)); + } +} + +static __inline__ Fixed angle_sin( Angle a ) +{ + return angle_sin_tab[(uint32_t)a & (ANGLE_2PI-1)]; +} + +static __inline__ Fixed angle_cos( Angle a ) +{ + return angle_sin(a + ANGLE_PI2); +} + +static __inline__ Fixed fixed_sin( Fixed f ) +{ + return angle_sin(ANGLE_FROM_FIXED(f)); +} + +static __inline__ Fixed fixed_cos( Fixed f ) +{ + return angle_cos(ANGLE_FROM_FIXED(f)); +} + +/* Color palette used for rendering the plasma */ +#define PALETTE_BITS 8 +#define PALETTE_SIZE (1 << PALETTE_BITS) + +#if PALETTE_BITS > FIXED_BITS +# error PALETTE_BITS must be smaller than FIXED_BITS +#endif + +static uint16_t palette[PALETTE_SIZE]; + +static uint16_t make565(int red, int green, int blue) +{ + return (uint16_t)( ((red << 8) & 0xf800) | + ((green << 2) & 0x03e0) | + ((blue >> 3) & 0x001f) ); +} + +static void init_palette(void) +{ + int nn, mm = 0; + /* fun with colors */ + for (nn = 0; nn < PALETTE_SIZE/4; nn++) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(255, jj, 255-jj); + } + + for ( mm = nn; nn < PALETTE_SIZE/2; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(255-jj, 255, jj); + } + + for ( mm = nn; nn < PALETTE_SIZE*3/4; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(0, 255-jj, 255); + } + + for ( mm = nn; nn < PALETTE_SIZE; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(jj, 0, 255); + } +} + +static __inline__ uint16_t palette_from_fixed( Fixed x ) +{ + if (x < 0) x = -x; + if (x >= FIXED_ONE) x = FIXED_ONE-1; + int idx = FIXED_FRAC(x) >> (FIXED_BITS - PALETTE_BITS); + return palette[idx & (PALETTE_SIZE-1)]; +} + +/* Angles expressed as fixed point radians */ + +static void init_tables(void) +{ + init_palette(); + init_angles(); +} + +static void fill_plasma(ANativeWindow_Buffer* buffer, double t) +{ + Fixed ft = FIXED_FROM_FLOAT(t/1000.); + Fixed yt1 = FIXED_FROM_FLOAT(t/1230.); + Fixed yt2 = yt1; + Fixed xt10 = FIXED_FROM_FLOAT(t/3000.); + Fixed xt20 = xt10; + +#define YT1_INCR FIXED_FROM_FLOAT(1/100.) +#define YT2_INCR FIXED_FROM_FLOAT(1/163.) + + void* pixels = buffer->bits; + LOGI("width=%d height=%d stride=%d format=%d", buffer->width, buffer->height, + buffer->stride, buffer->format); + + int yy; + for (yy = 0; yy < buffer->height; yy++) { + uint16_t* line = (uint16_t*)pixels; + Fixed base = fixed_sin(yt1) + fixed_sin(yt2); + Fixed xt1 = xt10; + Fixed xt2 = xt20; + + yt1 += YT1_INCR; + yt2 += YT2_INCR; + +#define XT1_INCR FIXED_FROM_FLOAT(1/173.) +#define XT2_INCR FIXED_FROM_FLOAT(1/242.) + +#if OPTIMIZE_WRITES + /* optimize memory writes by generating one aligned 32-bit store + * for every pair of pixels. + */ + uint16_t* line_end = line + buffer->width; + + if (line < line_end) { + if (((uint32_t)line & 3) != 0) { + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + line[0] = palette_from_fixed(ii >> 2); + line++; + } + + while (line + 2 <= line_end) { + Fixed i1 = base + fixed_sin(xt1) + fixed_sin(xt2); + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + Fixed i2 = base + fixed_sin(xt1) + fixed_sin(xt2); + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + uint32_t pixel = ((uint32_t)palette_from_fixed(i1 >> 2) << 16) | + (uint32_t)palette_from_fixed(i2 >> 2); + + ((uint32_t*)line)[0] = pixel; + line += 2; + } + + if (line < line_end) { + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + line[0] = palette_from_fixed(ii >> 2); + line++; + } + } +#else /* !OPTIMIZE_WRITES */ + int xx; + for (xx = 0; xx < buffer->width; xx++) { + + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + line[xx] = palette_from_fixed(ii / 4); + } +#endif /* !OPTIMIZE_WRITES */ + + // go to next line + pixels = (uint16_t*)pixels + buffer->stride; + } +} + +/* simple stats management */ +typedef struct { + double renderTime; + double frameTime; +} FrameStats; + +#define MAX_FRAME_STATS 200 +#define MAX_PERIOD_MS 1500 + +typedef struct { + double firstTime; + double lastTime; + double frameTime; + + int firstFrame; + int numFrames; + FrameStats frames[ MAX_FRAME_STATS ]; +} Stats; + +static void +stats_init( Stats* s ) +{ + s->lastTime = now_ms(); + s->firstTime = 0.; + s->firstFrame = 0; + s->numFrames = 0; +} + +static void +stats_startFrame( Stats* s ) +{ + s->frameTime = now_ms(); +} + +static void +stats_endFrame( Stats* s ) +{ + double now = now_ms(); + double renderTime = now - s->frameTime; + double frameTime = now - s->lastTime; + int nn; + + if (now - s->firstTime >= MAX_PERIOD_MS) { + if (s->numFrames > 0) { + double minRender, maxRender, avgRender; + double minFrame, maxFrame, avgFrame; + int count; + + nn = s->firstFrame; + minRender = maxRender = avgRender = s->frames[nn].renderTime; + minFrame = maxFrame = avgFrame = s->frames[nn].frameTime; + for (count = s->numFrames; count > 0; count-- ) { + nn += 1; + if (nn >= MAX_FRAME_STATS) + nn -= MAX_FRAME_STATS; + double render = s->frames[nn].renderTime; + if (render < minRender) minRender = render; + if (render > maxRender) maxRender = render; + double frame = s->frames[nn].frameTime; + if (frame < minFrame) minFrame = frame; + if (frame > maxFrame) maxFrame = frame; + avgRender += render; + avgFrame += frame; + } + avgRender /= s->numFrames; + avgFrame /= s->numFrames; + + LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) " + "render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n", + 1000./avgFrame, 1000./maxFrame, 1000./minFrame, + avgRender, minRender, maxRender); + } + s->numFrames = 0; + s->firstFrame = 0; + s->firstTime = now; + } + + nn = s->firstFrame + s->numFrames; + if (nn >= MAX_FRAME_STATS) + nn -= MAX_FRAME_STATS; + + s->frames[nn].renderTime = renderTime; + s->frames[nn].frameTime = frameTime; + + if (s->numFrames < MAX_FRAME_STATS) { + s->numFrames += 1; + } else { + s->firstFrame += 1; + if (s->firstFrame >= MAX_FRAME_STATS) + s->firstFrame -= MAX_FRAME_STATS; + } + + s->lastTime = now; +} + +// ---------------------------------------------------------------------- + +struct engine { + struct android_app* app; + + Stats stats; + + int animating; +}; + +static void engine_draw_frame(struct engine* engine) { + if (engine->app->window == NULL) { + // No window. + return; + } + + ANativeWindow_Buffer buffer; + if (ANativeWindow_lock(engine->app->window, &buffer, NULL) < 0) { + LOGW("Unable to lock window buffer"); + return; + } + + stats_startFrame(&engine->stats); + + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + int64_t time_ms = (((int64_t)t.tv_sec)*1000000000LL + t.tv_nsec)/1000000; + + /* Now fill the values with a nice little plasma */ + fill_plasma(&buffer, time_ms); + + ANativeWindow_unlockAndPost(engine->app->window); + + stats_endFrame(&engine->stats); +} + +static int engine_term_display(struct engine* engine) { + engine->animating = 0; +} + +static int engine_do_ui_event(struct engine* engine) { + AInputEvent* event = NULL; + if (AInputQueue_getEvent(engine->app->inputQueue, &event) >= 0) { + if (AInputEvent_getType(event) == INPUT_EVENT_TYPE_MOTION) { + engine->animating = 1; + AInputQueue_finishEvent(engine->app->inputQueue, event, 1); + } else { + AInputQueue_finishEvent(engine->app->inputQueue, event, 0); + } + } else { + LOGI("Failure reading next input event: %s\n", strerror(errno)); + } + + return 1; +} + +static int32_t engine_do_main_cmd(struct engine* engine) { + int32_t res; + int8_t cmd = android_app_read_cmd(engine->app); + switch (cmd) { + case APP_CMD_WINDOW_CHANGED: + engine_term_display(engine); + res = android_app_exec_cmd(engine->app, cmd); + if (engine->app->window != NULL) { + engine_draw_frame(engine); + } + break; + case APP_CMD_LOST_FOCUS: + res = android_app_exec_cmd(engine->app, cmd); + engine->animating = 0; + engine_draw_frame(engine); + break; + default: + res = android_app_exec_cmd(engine->app, cmd); + break; + } + + return res; +} + +void android_main(struct android_app* state) { + static int init; + + struct engine engine; + + memset(&engine, 0, sizeof(engine)); + state->userData = &engine; + engine.app = state; + + if (!init) { + init_tables(); + init = 1; + } + + stats_init(&engine.stats); + + // loop waiting for stuff to do. + + while (1) { + // Read all pending events. + int fd; + int events; + void* data; + while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) { + switch ((int)data) { + case LOOPER_ID_MAIN: + if (!engine_do_main_cmd(&engine)) { + LOGI("Engine thread destroy requested!"); + engine_term_display(&engine); + android_app_destroy(state); + // Can't touch android_app object after this. + return; + } + break; + case LOOPER_ID_EVENT: + engine_do_ui_event(&engine); + break; + } + } + + if (engine.animating) { + engine_draw_frame(&engine); + } + } +} diff --git a/ndk/samples/native-plasma/res/values/strings.xml b/ndk/samples/native-plasma/res/values/strings.xml new file mode 100644 index 000000000..269ec3dda --- /dev/null +++ b/ndk/samples/native-plasma/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Native Plasma + diff --git a/ndk/samples/native-activity/src/Dummy.java b/ndk/samples/native-plasma/src/Dummy.java similarity index 100% rename from ndk/samples/native-activity/src/Dummy.java rename to ndk/samples/native-plasma/src/Dummy.java