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