NativeActivity.java revision 3c80a4a044865bdf1289c7896baffa1c082d835c
1package android.app;
2
3import dalvik.system.PathClassLoader;
4
5import android.content.pm.ActivityInfo;
6import android.content.pm.ApplicationInfo;
7import android.content.pm.PackageManager;
8import android.os.Bundle;
9import android.os.Looper;
10import android.os.MessageQueue;
11import android.view.InputChannel;
12import android.view.InputQueue;
13import android.view.KeyEvent;
14import android.view.SurfaceHolder;
15import android.view.View;
16
17import java.io.File;
18
19/**
20 * Convenience for implementing an activity that will be implemented
21 * purely in native code.  That is, a game (or game-like thing).
22 */
23public class NativeActivity extends Activity implements SurfaceHolder.Callback,
24        InputQueue.Callback {
25    public static final String META_DATA_LIB_NAME = "android.app.lib_name";
26
27    private int mNativeHandle;
28
29    private InputQueue mCurInputQueue;
30    private SurfaceHolder mCurSurfaceHolder;
31
32    private boolean mDestroyed;
33
34    private native int loadNativeCode(String path, MessageQueue queue);
35    private native void unloadNativeCode(int handle);
36
37    private native void onStartNative(int handle);
38    private native void onResumeNative(int handle);
39    private native void onSaveInstanceStateNative(int handle);
40    private native void onPauseNative(int handle);
41    private native void onStopNative(int handle);
42    private native void onLowMemoryNative(int handle);
43    private native void onWindowFocusChangedNative(int handle, boolean focused);
44    private native void onSurfaceCreatedNative(int handle, SurfaceHolder holder);
45    private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
46            int format, int width, int height);
47    private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
48    private native void onInputChannelCreatedNative(int handle, InputChannel channel);
49    private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
50
51    @Override
52    protected void onCreate(Bundle savedInstanceState) {
53        String libname = "main";
54        ActivityInfo ai;
55
56        getWindow().takeSurface(this);
57        getWindow().takeInputQueue(this);
58
59        try {
60            ai = getPackageManager().getActivityInfo(
61                    getIntent().getComponent(), PackageManager.GET_META_DATA);
62            if (ai.metaData != null) {
63                String ln = ai.metaData.getString(META_DATA_LIB_NAME);
64                if (ln != null) libname = ln;
65            }
66        } catch (PackageManager.NameNotFoundException e) {
67            throw new RuntimeException("Error getting activity info", e);
68        }
69
70        String path = null;
71
72        if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) == 0) {
73            // If the application does not have (Java) code, then no ClassLoader
74            // has been set up for it.  We will need to do our own search for
75            // the native code.
76            path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname);
77            if (!(new File(path)).exists()) {
78                path = null;
79            }
80        }
81
82        if (path == null) {
83            path = ((PathClassLoader)getClassLoader()).findLibrary(libname);
84        }
85
86        if (path == null) {
87            throw new IllegalArgumentException("Unable to find native library: " + libname);
88        }
89
90        mNativeHandle = loadNativeCode(path, Looper.myQueue());
91        if (mNativeHandle == 0) {
92            throw new IllegalArgumentException("Unable to load native library: " + path);
93        }
94        super.onCreate(savedInstanceState);
95    }
96
97    @Override
98    protected void onDestroy() {
99        mDestroyed = true;
100        if (mCurSurfaceHolder != null) {
101            onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder);
102            mCurSurfaceHolder = null;
103        }
104        if (mCurInputQueue != null) {
105            onInputChannelDestroyedNative(mNativeHandle, mCurInputQueue.getInputChannel());
106            mCurInputQueue = null;
107        }
108        unloadNativeCode(mNativeHandle);
109        super.onDestroy();
110    }
111
112    @Override
113    protected void onPause() {
114        super.onPause();
115        onPauseNative(mNativeHandle);
116    }
117
118    @Override
119    protected void onResume() {
120        super.onResume();
121        onResumeNative(mNativeHandle);
122    }
123
124    @Override
125    protected void onSaveInstanceState(Bundle outState) {
126        super.onSaveInstanceState(outState);
127        onSaveInstanceStateNative(mNativeHandle);
128    }
129
130    @Override
131    protected void onStart() {
132        super.onStart();
133        onStartNative(mNativeHandle);
134    }
135
136    @Override
137    protected void onStop() {
138        super.onStop();
139        onStopNative(mNativeHandle);
140    }
141
142    @Override
143    public void onLowMemory() {
144        super.onLowMemory();
145        if (!mDestroyed) {
146            onLowMemoryNative(mNativeHandle);
147        }
148    }
149
150    @Override
151    public void onWindowFocusChanged(boolean hasFocus) {
152        super.onWindowFocusChanged(hasFocus);
153        if (!mDestroyed) {
154            onWindowFocusChangedNative(mNativeHandle, hasFocus);
155        }
156    }
157
158    public void surfaceCreated(SurfaceHolder holder) {
159        if (!mDestroyed) {
160            mCurSurfaceHolder = holder;
161            onSurfaceCreatedNative(mNativeHandle, holder);
162        }
163    }
164
165    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
166        if (!mDestroyed) {
167            mCurSurfaceHolder = holder;
168            onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
169        }
170    }
171
172    public void surfaceDestroyed(SurfaceHolder holder) {
173        mCurSurfaceHolder = null;
174        if (!mDestroyed) {
175            onSurfaceDestroyedNative(mNativeHandle, holder);
176        }
177    }
178
179    public void onInputQueueCreated(InputQueue queue) {
180        if (!mDestroyed) {
181            mCurInputQueue = queue;
182            onInputChannelCreatedNative(mNativeHandle, queue.getInputChannel());
183        }
184    }
185
186    public void onInputQueueDestroyed(InputQueue queue) {
187        mCurInputQueue = null;
188        if (!mDestroyed) {
189            onInputChannelDestroyedNative(mNativeHandle, queue.getInputChannel());
190        }
191    }
192
193    void dispatchUnhandledKeyEvent(KeyEvent event) {
194        View decor = getWindow().getDecorView();
195        if (decor != null) {
196            decor.dispatchKeyEvent(event);
197        }
198    }
199}
200