• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.app;
17 
18 import android.content.Context;
19 import android.content.pm.ActivityInfo;
20 import android.content.pm.PackageManager;
21 import android.content.res.AssetManager;
22 import android.content.res.Configuration;
23 import android.graphics.PixelFormat;
24 import android.os.Build;
25 import android.os.Bundle;
26 import android.os.Environment;
27 import android.os.Looper;
28 import android.os.MessageQueue;
29 import android.util.AttributeSet;
30 import android.view.InputQueue;
31 import android.view.KeyEvent;
32 import android.view.Surface;
33 import android.view.SurfaceHolder;
34 import android.view.View;
35 import android.view.WindowManager;
36 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
37 import android.view.inputmethod.InputMethodManager;
38 
39 import java.io.File;
40 
41 /**
42  * Convenience for implementing an activity that will be implemented
43  * purely in native code.  That is, a game (or game-like thing).  There
44  * is no need to derive from this class; you can simply declare it in your
45  * manifest, and use the NDK APIs from there.
46  *
47  * <p>A typical manifest would look like:
48  *
49  * {@sample development/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml
50  *      manifest}
51  *
52  * <p>A very simple example of native code that is run by NativeActivity
53  * follows.  This reads input events from the user and uses OpenGLES to
54  * draw into the native activity's window.
55  *
56  * {@sample development/ndk/platforms/android-9/samples/native-activity/jni/main.c all}
57  */
58 public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
59         InputQueue.Callback, OnGlobalLayoutListener {
60     /**
61      * Optional meta-that can be in the manifest for this component, specifying
62      * the name of the native shared library to load.  If not specified,
63      * "main" is used.
64      */
65     public static final String META_DATA_LIB_NAME = "android.app.lib_name";
66 
67     /**
68      * Optional meta-that can be in the manifest for this component, specifying
69      * the name of the main entry point for this native activity in the
70      * {@link #META_DATA_LIB_NAME} native code.  If not specified,
71      * "ANativeActivity_onCreate" is used.
72      */
73     public static final String META_DATA_FUNC_NAME = "android.app.func_name";
74 
75     private static final String KEY_NATIVE_SAVED_STATE = "android:native_state";
76 
77     private NativeContentView mNativeContentView;
78     private InputMethodManager mIMM;
79 
80     private int mNativeHandle;
81 
82     private InputQueue mCurInputQueue;
83     private SurfaceHolder mCurSurfaceHolder;
84 
85     final int[] mLocation = new int[2];
86     int mLastContentX;
87     int mLastContentY;
88     int mLastContentWidth;
89     int mLastContentHeight;
90 
91     private boolean mDispatchingUnhandledKey;
92 
93     private boolean mDestroyed;
94 
loadNativeCode(String path, String funcname, MessageQueue queue, String internalDataPath, String obbPath, String externalDataPath, int sdkVersion, AssetManager assetMgr, byte[] savedState)95     private native int loadNativeCode(String path, String funcname, MessageQueue queue,
96             String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
97             AssetManager assetMgr, byte[] savedState);
unloadNativeCode(int handle)98     private native void unloadNativeCode(int handle);
99 
onStartNative(int handle)100     private native void onStartNative(int handle);
onResumeNative(int handle)101     private native void onResumeNative(int handle);
onSaveInstanceStateNative(int handle)102     private native byte[] onSaveInstanceStateNative(int handle);
onPauseNative(int handle)103     private native void onPauseNative(int handle);
onStopNative(int handle)104     private native void onStopNative(int handle);
onConfigurationChangedNative(int handle)105     private native void onConfigurationChangedNative(int handle);
onLowMemoryNative(int handle)106     private native void onLowMemoryNative(int handle);
onWindowFocusChangedNative(int handle, boolean focused)107     private native void onWindowFocusChangedNative(int handle, boolean focused);
onSurfaceCreatedNative(int handle, Surface surface)108     private native void onSurfaceCreatedNative(int handle, Surface surface);
onSurfaceChangedNative(int handle, Surface surface, int format, int width, int height)109     private native void onSurfaceChangedNative(int handle, Surface surface,
110             int format, int width, int height);
onSurfaceRedrawNeededNative(int handle, Surface surface)111     private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
onSurfaceDestroyedNative(int handle)112     private native void onSurfaceDestroyedNative(int handle);
onInputQueueCreatedNative(int handle, int queuePtr)113     private native void onInputQueueCreatedNative(int handle, int queuePtr);
onInputQueueDestroyedNative(int handle, int queuePtr)114     private native void onInputQueueDestroyedNative(int handle, int queuePtr);
onContentRectChangedNative(int handle, int x, int y, int w, int h)115     private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
116 
117     static class NativeContentView extends View {
118         NativeActivity mActivity;
119 
NativeContentView(Context context)120         public NativeContentView(Context context) {
121             super(context);
122         }
123 
NativeContentView(Context context, AttributeSet attrs)124         public NativeContentView(Context context, AttributeSet attrs) {
125             super(context, attrs);
126         }
127     }
128 
129     @Override
onCreate(Bundle savedInstanceState)130     protected void onCreate(Bundle savedInstanceState) {
131         String libname = "main";
132         String funcname = "ANativeActivity_onCreate";
133         ActivityInfo ai;
134 
135         mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
136 
137         getWindow().takeSurface(this);
138         getWindow().takeInputQueue(this);
139         getWindow().setFormat(PixelFormat.RGB_565);
140         getWindow().setSoftInputMode(
141                 WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
142                 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
143 
144         mNativeContentView = new NativeContentView(this);
145         mNativeContentView.mActivity = this;
146         setContentView(mNativeContentView);
147         mNativeContentView.requestFocus();
148         mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
149 
150         try {
151             ai = getPackageManager().getActivityInfo(
152                     getIntent().getComponent(), PackageManager.GET_META_DATA);
153             if (ai.metaData != null) {
154                 String ln = ai.metaData.getString(META_DATA_LIB_NAME);
155                 if (ln != null) libname = ln;
156                 ln = ai.metaData.getString(META_DATA_FUNC_NAME);
157                 if (ln != null) funcname = ln;
158             }
159         } catch (PackageManager.NameNotFoundException e) {
160             throw new RuntimeException("Error getting activity info", e);
161         }
162 
163         String path = null;
164 
165         File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
166                 System.mapLibraryName(libname));
167         if (libraryFile.exists()) {
168             path = libraryFile.getPath();
169         }
170 
171         if (path == null) {
172             throw new IllegalArgumentException("Unable to find native library: " + libname);
173         }
174 
175         byte[] nativeSavedState = savedInstanceState != null
176                 ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
177 
178         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
179                  getFilesDir().toString(), getObbDir().toString(),
180                  Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
181                  Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
182 
183         if (mNativeHandle == 0) {
184             throw new IllegalArgumentException("Unable to load native library: " + path);
185         }
186         super.onCreate(savedInstanceState);
187     }
188 
189     @Override
onDestroy()190     protected void onDestroy() {
191         mDestroyed = true;
192         if (mCurSurfaceHolder != null) {
193             onSurfaceDestroyedNative(mNativeHandle);
194             mCurSurfaceHolder = null;
195         }
196         if (mCurInputQueue != null) {
197             onInputQueueDestroyedNative(mNativeHandle, mCurInputQueue.getNativePtr());
198             mCurInputQueue = null;
199         }
200         unloadNativeCode(mNativeHandle);
201         super.onDestroy();
202     }
203 
204     @Override
onPause()205     protected void onPause() {
206         super.onPause();
207         onPauseNative(mNativeHandle);
208     }
209 
210     @Override
onResume()211     protected void onResume() {
212         super.onResume();
213         onResumeNative(mNativeHandle);
214     }
215 
216     @Override
onSaveInstanceState(Bundle outState)217     protected void onSaveInstanceState(Bundle outState) {
218         super.onSaveInstanceState(outState);
219         byte[] state = onSaveInstanceStateNative(mNativeHandle);
220         if (state != null) {
221             outState.putByteArray(KEY_NATIVE_SAVED_STATE, state);
222         }
223     }
224 
225     @Override
onStart()226     protected void onStart() {
227         super.onStart();
228         onStartNative(mNativeHandle);
229     }
230 
231     @Override
onStop()232     protected void onStop() {
233         super.onStop();
234         onStopNative(mNativeHandle);
235     }
236 
237     @Override
onConfigurationChanged(Configuration newConfig)238     public void onConfigurationChanged(Configuration newConfig) {
239         super.onConfigurationChanged(newConfig);
240         if (!mDestroyed) {
241             onConfigurationChangedNative(mNativeHandle);
242         }
243     }
244 
245     @Override
onLowMemory()246     public void onLowMemory() {
247         super.onLowMemory();
248         if (!mDestroyed) {
249             onLowMemoryNative(mNativeHandle);
250         }
251     }
252 
253     @Override
onWindowFocusChanged(boolean hasFocus)254     public void onWindowFocusChanged(boolean hasFocus) {
255         super.onWindowFocusChanged(hasFocus);
256         if (!mDestroyed) {
257             onWindowFocusChangedNative(mNativeHandle, hasFocus);
258         }
259     }
260 
surfaceCreated(SurfaceHolder holder)261     public void surfaceCreated(SurfaceHolder holder) {
262         if (!mDestroyed) {
263             mCurSurfaceHolder = holder;
264             onSurfaceCreatedNative(mNativeHandle, holder.getSurface());
265         }
266     }
267 
surfaceChanged(SurfaceHolder holder, int format, int width, int height)268     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
269         if (!mDestroyed) {
270             mCurSurfaceHolder = holder;
271             onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height);
272         }
273     }
274 
surfaceRedrawNeeded(SurfaceHolder holder)275     public void surfaceRedrawNeeded(SurfaceHolder holder) {
276         if (!mDestroyed) {
277             mCurSurfaceHolder = holder;
278             onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface());
279         }
280     }
281 
surfaceDestroyed(SurfaceHolder holder)282     public void surfaceDestroyed(SurfaceHolder holder) {
283         mCurSurfaceHolder = null;
284         if (!mDestroyed) {
285             onSurfaceDestroyedNative(mNativeHandle);
286         }
287     }
288 
onInputQueueCreated(InputQueue queue)289     public void onInputQueueCreated(InputQueue queue) {
290         if (!mDestroyed) {
291             mCurInputQueue = queue;
292             onInputQueueCreatedNative(mNativeHandle, queue.getNativePtr());
293         }
294     }
295 
onInputQueueDestroyed(InputQueue queue)296     public void onInputQueueDestroyed(InputQueue queue) {
297         if (!mDestroyed) {
298             onInputQueueDestroyedNative(mNativeHandle, queue.getNativePtr());
299             mCurInputQueue = null;
300         }
301     }
302 
onGlobalLayout()303     public void onGlobalLayout() {
304         mNativeContentView.getLocationInWindow(mLocation);
305         int w = mNativeContentView.getWidth();
306         int h = mNativeContentView.getHeight();
307         if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY
308                 || w != mLastContentWidth || h != mLastContentHeight) {
309             mLastContentX = mLocation[0];
310             mLastContentY = mLocation[1];
311             mLastContentWidth = w;
312             mLastContentHeight = h;
313             if (!mDestroyed) {
314                 onContentRectChangedNative(mNativeHandle, mLastContentX,
315                         mLastContentY, mLastContentWidth, mLastContentHeight);
316             }
317         }
318     }
319 
setWindowFlags(int flags, int mask)320     void setWindowFlags(int flags, int mask) {
321         getWindow().setFlags(flags, mask);
322     }
323 
setWindowFormat(int format)324     void setWindowFormat(int format) {
325         getWindow().setFormat(format);
326     }
327 
showIme(int mode)328     void showIme(int mode) {
329         mIMM.showSoftInput(mNativeContentView, mode);
330     }
331 
hideIme(int mode)332     void hideIme(int mode) {
333         mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode);
334     }
335 }
336