blob: 35cc3248f45630c615b26f500f03d2977e702db8 [file] [log] [blame]
Dianne Hackborn69969e42010-05-04 11:40:40 -07001package android.app;
2
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07003import com.android.internal.view.IInputMethodCallback;
4import com.android.internal.view.IInputMethodSession;
5
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07006import android.content.Context;
Dianne Hackborn69969e42010-05-04 11:40:40 -07007import android.content.pm.ActivityInfo;
Dianne Hackborn69969e42010-05-04 11:40:40 -07008import android.content.pm.PackageManager;
Christopher Tate6cce32b2010-07-12 18:21:36 -07009import android.content.res.AssetManager;
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070010import android.content.res.Configuration;
Dianne Hackborn54a181b2010-06-30 18:35:14 -070011import android.graphics.PixelFormat;
Dianne Hackborn68267412010-07-02 18:52:01 -070012import android.os.Build;
Dianne Hackborn69969e42010-05-04 11:40:40 -070013import android.os.Bundle;
Dianne Hackborn68267412010-07-02 18:52:01 -070014import android.os.Environment;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070015import android.os.Looper;
16import android.os.MessageQueue;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070017import android.util.AttributeSet;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -070018import android.view.InputChannel;
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -070019import android.view.InputQueue;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070020import android.view.KeyEvent;
Dianne Hackborn54a181b2010-06-30 18:35:14 -070021import android.view.Surface;
Dianne Hackborn74323fd2010-05-18 17:56:23 -070022import android.view.SurfaceHolder;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070023import android.view.View;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070024import android.view.WindowManager;
25import android.view.ViewTreeObserver.OnGlobalLayoutListener;
26import android.view.inputmethod.InputMethodManager;
Dianne Hackborn69969e42010-05-04 11:40:40 -070027
28import java.io.File;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -070029import java.lang.ref.WeakReference;
Dianne Hackborn69969e42010-05-04 11:40:40 -070030
31/**
32 * Convenience for implementing an activity that will be implemented
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070033 * purely in native code. That is, a game (or game-like thing). There
34 * is no need to derive from this class; you can simply declare it in your
35 * manifest, and use the NDK APIs from there.
36 *
37 * <p>A typical manifest would look like:
38 *
39 * {@sample development/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
40 * manifest}
41 *
42 * <p>A very simple example of native code that is run by NativeActivity
43 * follows. This reads input events from the user and uses OpenGLES to
44 * draw into the native activity's window.
45 *
46 * {@sample development/ndk/platforms/android-9/samples/native-activity/jni/main.c all}
Dianne Hackborn69969e42010-05-04 11:40:40 -070047 */
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070048public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
49 InputQueue.Callback, OnGlobalLayoutListener {
Dianne Hackborne21d91c62010-10-24 14:56:38 -070050 /**
51 * Optional meta-that can be in the manifest for this component, specifying
52 * the name of the native shared library to load. If not specified,
53 * "main" is used.
54 */
Dianne Hackborn69969e42010-05-04 11:40:40 -070055 public static final String META_DATA_LIB_NAME = "android.app.lib_name";
56
Dianne Hackborne21d91c62010-10-24 14:56:38 -070057 /**
58 * Optional meta-that can be in the manifest for this component, specifying
59 * the name of the main entry point for this native activity in the
60 * {@link #META_DATA_LIB_NAME} native code. If not specified,
61 * "ANativeActivity_onCreate" is used.
62 */
63 public static final String META_DATA_FUNC_NAME = "android.app.func_name";
64
65 private static final String KEY_NATIVE_SAVED_STATE = "android:native_state";
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070066
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070067 private NativeContentView mNativeContentView;
68 private InputMethodManager mIMM;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -070069 private InputMethodCallback mInputMethodCallback;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070070
Dianne Hackborn69969e42010-05-04 11:40:40 -070071 private int mNativeHandle;
72
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070073 private InputQueue mCurInputQueue;
74 private SurfaceHolder mCurSurfaceHolder;
75
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070076 final int[] mLocation = new int[2];
77 int mLastContentX;
78 int mLastContentY;
79 int mLastContentWidth;
80 int mLastContentHeight;
81
82 private boolean mDispatchingUnhandledKey;
83
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070084 private boolean mDestroyed;
85
Dianne Hackborne21d91c62010-10-24 14:56:38 -070086 private native int loadNativeCode(String path, String funcname, MessageQueue queue,
Dianne Hackborn805fd7e2011-01-16 18:30:29 -080087 String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070088 AssetManager assetMgr, byte[] savedState);
Dianne Hackborn69969e42010-05-04 11:40:40 -070089 private native void unloadNativeCode(int handle);
90
91 private native void onStartNative(int handle);
92 private native void onResumeNative(int handle);
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070093 private native byte[] onSaveInstanceStateNative(int handle);
Dianne Hackborn69969e42010-05-04 11:40:40 -070094 private native void onPauseNative(int handle);
95 private native void onStopNative(int handle);
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -070096 private native void onConfigurationChangedNative(int handle);
Dianne Hackborn69969e42010-05-04 11:40:40 -070097 private native void onLowMemoryNative(int handle);
98 private native void onWindowFocusChangedNative(int handle, boolean focused);
Dianne Hackborn54a181b2010-06-30 18:35:14 -070099 private native void onSurfaceCreatedNative(int handle, Surface surface);
100 private native void onSurfaceChangedNative(int handle, Surface surface,
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700101 int format, int width, int height);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700102 private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700103 private native void onSurfaceDestroyedNative(int handle);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700104 private native void onInputChannelCreatedNative(int handle, InputChannel channel);
105 private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700106 private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
107 private native void dispatchKeyEventNative(int handle, KeyEvent event);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700108 private native void finishPreDispatchKeyEventNative(int handle, int seq, boolean handled);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700109
110 static class NativeContentView extends View {
111 NativeActivity mActivity;
112
113 public NativeContentView(Context context) {
114 super(context);
115 }
116
117 public NativeContentView(Context context, AttributeSet attrs) {
118 super(context, attrs);
119 }
120 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700121
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700122 static class InputMethodCallback extends IInputMethodCallback.Stub {
123 WeakReference<NativeActivity> mNa;
124
125 InputMethodCallback(NativeActivity na) {
126 mNa = new WeakReference<NativeActivity>(na);
127 }
128
129 @Override
130 public void finishedEvent(int seq, boolean handled) {
131 NativeActivity na = mNa.get();
132 if (na != null) {
133 na.finishPreDispatchKeyEventNative(na.mNativeHandle, seq, handled);
134 }
135 }
136
137 @Override
138 public void sessionCreated(IInputMethodSession session) {
139 // Stub -- not for use in the client.
140 }
141 }
142
Dianne Hackborn69969e42010-05-04 11:40:40 -0700143 @Override
144 protected void onCreate(Bundle savedInstanceState) {
145 String libname = "main";
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700146 String funcname = "ANativeActivity_onCreate";
Dianne Hackborn69969e42010-05-04 11:40:40 -0700147 ActivityInfo ai;
148
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700149 mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700150 mInputMethodCallback = new InputMethodCallback(this);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700151
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700152 getWindow().takeSurface(this);
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700153 getWindow().takeInputQueue(this);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700154 getWindow().setFormat(PixelFormat.RGB_565);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700155 getWindow().setSoftInputMode(
156 WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
157 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
158
159 mNativeContentView = new NativeContentView(this);
160 mNativeContentView.mActivity = this;
161 setContentView(mNativeContentView);
162 mNativeContentView.requestFocus();
163 mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700164
Dianne Hackborn69969e42010-05-04 11:40:40 -0700165 try {
166 ai = getPackageManager().getActivityInfo(
167 getIntent().getComponent(), PackageManager.GET_META_DATA);
168 if (ai.metaData != null) {
169 String ln = ai.metaData.getString(META_DATA_LIB_NAME);
170 if (ln != null) libname = ln;
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700171 ln = ai.metaData.getString(META_DATA_FUNC_NAME);
172 if (ln != null) funcname = ln;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700173 }
174 } catch (PackageManager.NameNotFoundException e) {
175 throw new RuntimeException("Error getting activity info", e);
176 }
177
178 String path = null;
179
Dianne Hackborn74b1ed32010-10-20 10:22:45 -0700180 File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
181 System.mapLibraryName(libname));
182 if (libraryFile.exists()) {
183 path = libraryFile.getPath();
Dianne Hackborn69969e42010-05-04 11:40:40 -0700184 }
185
186 if (path == null) {
Dianne Hackborn69969e42010-05-04 11:40:40 -0700187 throw new IllegalArgumentException("Unable to find native library: " + libname);
188 }
189
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700190 byte[] nativeSavedState = savedInstanceState != null
191 ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
192
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700193 mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800194 getFilesDir().toString(), getObbDir().toString(),
Dianne Hackborn68267412010-07-02 18:52:01 -0700195 Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700196 Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
Dianne Hackborn68267412010-07-02 18:52:01 -0700197
Dianne Hackborn69969e42010-05-04 11:40:40 -0700198 if (mNativeHandle == 0) {
199 throw new IllegalArgumentException("Unable to load native library: " + path);
200 }
201 super.onCreate(savedInstanceState);
202 }
203
204 @Override
205 protected void onDestroy() {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700206 mDestroyed = true;
207 if (mCurSurfaceHolder != null) {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700208 onSurfaceDestroyedNative(mNativeHandle);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700209 mCurSurfaceHolder = null;
210 }
211 if (mCurInputQueue != null) {
212 onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel());
213 mCurInputQueue = null;
214 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700215 unloadNativeCode(mNativeHandle);
216 super.onDestroy();
217 }
218
219 @Override
Dianne Hackborn69969e42010-05-04 11:40:40 -0700220 protected void onPause() {
221 super.onPause();
222 onPauseNative(mNativeHandle);
223 }
224
225 @Override
226 protected void onResume() {
227 super.onResume();
228 onResumeNative(mNativeHandle);
229 }
230
231 @Override
232 protected void onSaveInstanceState(Bundle outState) {
233 super.onSaveInstanceState(outState);
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700234 byte[] state = onSaveInstanceStateNative(mNativeHandle);
235 if (state != null) {
236 outState.putByteArray(KEY_NATIVE_SAVED_STATE, state);
237 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700238 }
239
240 @Override
241 protected void onStart() {
242 super.onStart();
243 onStartNative(mNativeHandle);
244 }
245
246 @Override
247 protected void onStop() {
248 super.onStop();
249 onStopNative(mNativeHandle);
250 }
251
252 @Override
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700253 public void onConfigurationChanged(Configuration newConfig) {
254 super.onConfigurationChanged(newConfig);
255 if (!mDestroyed) {
256 onConfigurationChangedNative(mNativeHandle);
257 }
258 }
259
260 @Override
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700261 public void onLowMemory() {
262 super.onLowMemory();
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700263 if (!mDestroyed) {
264 onLowMemoryNative(mNativeHandle);
265 }
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700266 }
267
268 @Override
Dianne Hackborn69969e42010-05-04 11:40:40 -0700269 public void onWindowFocusChanged(boolean hasFocus) {
270 super.onWindowFocusChanged(hasFocus);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700271 if (!mDestroyed) {
272 onWindowFocusChangedNative(mNativeHandle, hasFocus);
273 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700274 }
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700275
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700276 @Override
277 public boolean dispatchKeyEvent(KeyEvent event) {
278 if (mDispatchingUnhandledKey) {
279 return super.dispatchKeyEvent(event);
280 } else {
281 // Key events from the IME do not go through the input channel;
282 // we need to intercept them here to hand to the application.
283 dispatchKeyEventNative(mNativeHandle, event);
284 return true;
285 }
286 }
287
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700288 public void surfaceCreated(SurfaceHolder holder) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700289 if (!mDestroyed) {
290 mCurSurfaceHolder = holder;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700291 onSurfaceCreatedNative(mNativeHandle, holder.getSurface());
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700292 }
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700293 }
294
295 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700296 if (!mDestroyed) {
297 mCurSurfaceHolder = holder;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700298 onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700299 }
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700300 }
301
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700302 public void surfaceRedrawNeeded(SurfaceHolder holder) {
303 if (!mDestroyed) {
304 mCurSurfaceHolder = holder;
305 onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface());
306 }
307 }
308
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700309 public void surfaceDestroyed(SurfaceHolder holder) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700310 mCurSurfaceHolder = null;
311 if (!mDestroyed) {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700312 onSurfaceDestroyedNative(mNativeHandle);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700313 }
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700314 }
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700315
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700316 public void onInputQueueCreated(InputQueue queue) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700317 if (!mDestroyed) {
318 mCurInputQueue = queue;
319 onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
320 }
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700321 }
322
Dianne Hackborn1e4b9f32010-06-23 14:10:57 -0700323 public void onInputQueueDestroyed(InputQueue queue) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700324 mCurInputQueue = null;
325 if (!mDestroyed) {
326 onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
327 }
328 }
329
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700330 public void onGlobalLayout() {
331 mNativeContentView.getLocationInWindow(mLocation);
332 int w = mNativeContentView.getWidth();
333 int h = mNativeContentView.getHeight();
334 if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY
335 || w != mLastContentWidth || h != mLastContentHeight) {
336 mLastContentX = mLocation[0];
337 mLastContentY = mLocation[1];
338 mLastContentWidth = w;
339 mLastContentHeight = h;
340 if (!mDestroyed) {
341 onContentRectChangedNative(mNativeHandle, mLastContentX,
342 mLastContentY, mLastContentWidth, mLastContentHeight);
343 }
344 }
345 }
346
Jeff Brown3915bb82010-11-05 15:02:16 -0700347 boolean dispatchUnhandledKeyEvent(KeyEvent event) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700348 try {
349 mDispatchingUnhandledKey = true;
350 View decor = getWindow().getDecorView();
351 if (decor != null) {
Jeff Brown3915bb82010-11-05 15:02:16 -0700352 return decor.dispatchKeyEvent(event);
353 } else {
354 return false;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700355 }
356 } finally {
357 mDispatchingUnhandledKey = false;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700358 }
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700359 }
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700360
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700361 void preDispatchKeyEvent(KeyEvent event, int seq) {
362 mIMM.dispatchKeyEvent(this, seq, event,
363 mInputMethodCallback);
364 }
365
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700366 void setWindowFlags(int flags, int mask) {
367 getWindow().setFlags(flags, mask);
368 }
369
370 void setWindowFormat(int format) {
371 getWindow().setFormat(format);
372 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700373
374 void showIme(int mode) {
375 mIMM.showSoftInput(mNativeContentView, mode);
376 }
377
378 void hideIme(int mode) {
379 mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode);
380 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700381}