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