|
@@ -0,0 +1,408 @@
|
|
|
+package org.jmonkeyengine.jme3androidexamples;
|
|
|
+
|
|
|
+import android.app.Activity;
|
|
|
+import android.content.Intent;
|
|
|
+import android.content.pm.ApplicationInfo;
|
|
|
+import android.os.Bundle;
|
|
|
+import android.text.Editable;
|
|
|
+import android.text.TextWatcher;
|
|
|
+import android.util.Log;
|
|
|
+import android.view.Menu;
|
|
|
+import android.view.MenuInflater;
|
|
|
+import android.view.MenuItem;
|
|
|
+import android.view.View;
|
|
|
+import android.widget.AdapterView;
|
|
|
+import android.widget.AdapterView.OnItemClickListener;
|
|
|
+import android.widget.Button;
|
|
|
+import android.widget.EditText;
|
|
|
+import android.widget.ListView;
|
|
|
+import com.jme3.app.Application;
|
|
|
+import dalvik.system.DexFile;
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Enumeration;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+//TODO: Create onscreen virtual keypad for triggering normal mapped keys used by test apps or modify test apps for touch with onscreen keypad
|
|
|
+
|
|
|
+/**
|
|
|
+ * Main Activity started by the application. Users select different jME3 test
|
|
|
+ * applications that are started via TestsHarness Activity.
|
|
|
+ * @author iwgeric
|
|
|
+ */
|
|
|
+public class MainActivity extends Activity implements OnItemClickListener, View.OnClickListener, TextWatcher {
|
|
|
+ private static final String TAG = "MainActivity";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Static String to pass the key for the selected test app to the
|
|
|
+ * TestsHarness class to start the application. Also used to store the
|
|
|
+ * current selection to the savedInstanceState Bundle.
|
|
|
+ */
|
|
|
+ public static final String SELECTED_APP_CLASS = "Selected_App_Class";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Static String to pass the key for the selected list position to the
|
|
|
+ * savedInstanceState Bundle so the list position can be restored after
|
|
|
+ * exiting the test application.
|
|
|
+ */
|
|
|
+ public static final String SELECTED_LIST_POSITION = "Selected_List_Position";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Static String to pass the key for the setting for enabling mouse events to the
|
|
|
+ * savedInstanceState Bundle.
|
|
|
+ */
|
|
|
+ public static final String ENABLE_MOUSE_EVENTS = "Enable_Mouse_Events";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Static String to pass the key for the setting for enabling joystick events to the
|
|
|
+ * savedInstanceState Bundle.
|
|
|
+ */
|
|
|
+ public static final String ENABLE_JOYSTICK_EVENTS = "Enable_Joystick_Events";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Static String to pass the key for the setting for enabling key events to the
|
|
|
+ * savedInstanceState Bundle.
|
|
|
+ */
|
|
|
+ public static final String ENABLE_KEY_EVENTS = "Enable_Key_Events";
|
|
|
+
|
|
|
+ /* Fields to contain the current position and display contents of the spinner */
|
|
|
+ private int currentPosition = 0;
|
|
|
+ private String currentSelection = "";
|
|
|
+ private List<String> classNames = new ArrayList<String>();
|
|
|
+ private List<String> exclusions = new ArrayList<String>();
|
|
|
+ private String rootPackage;
|
|
|
+
|
|
|
+ /* ListView that displays the test application class names. */
|
|
|
+ private ListView listClasses;
|
|
|
+
|
|
|
+ /* ArrayAdapter connects the spinner widget to array-based data. */
|
|
|
+ private CustomArrayAdapter arrayAdapter;
|
|
|
+
|
|
|
+ /* Buttons to start application or stop the activity. */
|
|
|
+ private Button btnOK;
|
|
|
+ private Button btnCancel;
|
|
|
+
|
|
|
+ /* Filter Edit Box */
|
|
|
+ EditText editFilterText;
|
|
|
+
|
|
|
+ /* Custom settings for the test app */
|
|
|
+ private boolean enableMouseEvents = true;
|
|
|
+ private boolean enableJoystickEvents = false;
|
|
|
+ private boolean enableKeyEvents = true;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Called when the activity is first created.
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onCreate(Bundle savedInstanceState) {
|
|
|
+ super.onCreate(savedInstanceState);
|
|
|
+
|
|
|
+ if (savedInstanceState != null) {
|
|
|
+ Log.i(TAG, "Restoring selections in onCreate: "
|
|
|
+ + "position: " + savedInstanceState.getInt(SELECTED_LIST_POSITION, 0)
|
|
|
+ + "class: " + savedInstanceState.getString(SELECTED_APP_CLASS)
|
|
|
+ );
|
|
|
+ currentPosition = savedInstanceState.getInt(SELECTED_LIST_POSITION, 0);
|
|
|
+ currentSelection = savedInstanceState.getString(SELECTED_APP_CLASS);
|
|
|
+ enableMouseEvents = savedInstanceState.getBoolean(ENABLE_MOUSE_EVENTS, true);
|
|
|
+ enableJoystickEvents = savedInstanceState.getBoolean(ENABLE_JOYSTICK_EVENTS, false);
|
|
|
+ enableKeyEvents = savedInstanceState.getBoolean(ENABLE_KEY_EVENTS, true);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* Set content view and register views */
|
|
|
+ setContentView(R.layout.test_chooser_layout);
|
|
|
+ btnOK = (Button) findViewById(R.id.btnOK);
|
|
|
+ btnCancel = (Button) findViewById(R.id.btnCancel);
|
|
|
+ listClasses = (ListView) findViewById(R.id.listClasses);
|
|
|
+ editFilterText = (EditText) findViewById(R.id.txtFilter);
|
|
|
+
|
|
|
+
|
|
|
+ /* Define the root package to start with */
|
|
|
+ rootPackage = "jme3test";
|
|
|
+
|
|
|
+ /* Create an array of Strings to define which classes to exclude */
|
|
|
+ exclusions.add("$"); // inner classes
|
|
|
+ exclusions.add("TestChooser"); // Desktop test chooser class
|
|
|
+ exclusions.add("awt"); // Desktop test chooser class
|
|
|
+
|
|
|
+// mExclusions.add("");
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Read the class names from the dex file and filter based on
|
|
|
+ * name and super class.
|
|
|
+ */
|
|
|
+
|
|
|
+ Log.i(TAG, "Composing Test list...");
|
|
|
+
|
|
|
+ ApplicationInfo ai = this.getApplicationInfo();
|
|
|
+ String classPath = ai.sourceDir;
|
|
|
+ DexFile dex = null;
|
|
|
+ Enumeration<String> apkClassNames = null;
|
|
|
+ try {
|
|
|
+ dex = new DexFile(classPath);
|
|
|
+ apkClassNames = dex.entries();
|
|
|
+ while (apkClassNames.hasMoreElements()) {
|
|
|
+ String className = apkClassNames.nextElement();
|
|
|
+ if (checkClassName(className) && checkClassType(className)) {
|
|
|
+ classNames.add(className);
|
|
|
+ }
|
|
|
+// classNames.add(className);
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ dex.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Create a backing Adapter for the List View from a list of the
|
|
|
+ * classes. The list is defined by array of class names.
|
|
|
+ */
|
|
|
+ arrayAdapter = new CustomArrayAdapter(
|
|
|
+ this,
|
|
|
+ R.layout.test_chooser_row, // text view to display selection
|
|
|
+ classNames // array of strings to display
|
|
|
+ );
|
|
|
+
|
|
|
+ /* Set the resource id for selected and non selected backgrounds */
|
|
|
+ Log.i(TAG, "Setting Adapter Background Resource IDs");
|
|
|
+ arrayAdapter.setSelectedBackgroundResource(R.drawable.selected);
|
|
|
+ arrayAdapter.setNonSelectedBackgroundResource(R.drawable.nonselected);
|
|
|
+
|
|
|
+ /* Attach the Adapter to the spinner */
|
|
|
+ Log.i(TAG, "Setting ListView Adapter");
|
|
|
+ listClasses.setAdapter(arrayAdapter);
|
|
|
+
|
|
|
+ /* Set initial selection for the list */
|
|
|
+ setSelection(currentPosition);
|
|
|
+
|
|
|
+ /* Set Click and Text Changed listeners */
|
|
|
+ listClasses.setOnItemClickListener(this);
|
|
|
+ btnOK.setOnClickListener(this);
|
|
|
+ btnCancel.setOnClickListener(this);
|
|
|
+ editFilterText.addTextChangedListener(this);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * User selected an application. Sets the current selection and redraws
|
|
|
+ * the list view to highlight the selected item.
|
|
|
+ * @param parent AdapterView tied to the list
|
|
|
+ * @param view The ListView
|
|
|
+ * @param position Selection position in the list of class names
|
|
|
+ * @param id
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
|
+ setSelection(position);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * User clicked a view on the screen. Check for the OK and Cancel buttons
|
|
|
+ * and either start the applicaiton or exit.
|
|
|
+ * @param view
|
|
|
+ */
|
|
|
+ public void onClick(View view) {
|
|
|
+ if (view.equals(btnOK)) {
|
|
|
+ /* Get selected class, pack it in the intent and start the test app */
|
|
|
+ Log.i(TAG, "User selected OK for class: " + currentSelection);
|
|
|
+ Intent intent = new Intent(this, TestActivity.class);
|
|
|
+ intent.putExtra(SELECTED_APP_CLASS, currentSelection);
|
|
|
+ intent.putExtra(ENABLE_MOUSE_EVENTS, enableMouseEvents);
|
|
|
+ intent.putExtra(ENABLE_JOYSTICK_EVENTS, enableJoystickEvents);
|
|
|
+ startActivity(intent);
|
|
|
+ } else if (view.equals(btnCancel)) {
|
|
|
+ /* Exit */
|
|
|
+ Log.i(TAG, "User selected Cancel");
|
|
|
+ finish();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Check class name to see if the class is in the root package and if it
|
|
|
+ * contains any of the exclusion strings
|
|
|
+ * @param className Class name to check
|
|
|
+ * @return true if the check passes, false otherwise
|
|
|
+ */
|
|
|
+ private boolean checkClassName(String className) {
|
|
|
+ boolean include = true;
|
|
|
+ /* check to see if the class in inside the rootPackage package */
|
|
|
+ if (className.startsWith(rootPackage)) {
|
|
|
+ /* check to see if the class contains any of the exlusion strings */
|
|
|
+ for (int i = 0; i < exclusions.size(); i++) {
|
|
|
+ if (className.contains(exclusions.get(i))) {
|
|
|
+ Log.i(TAG, "Skipping Class " + className + ". Includes exclusion string: " + exclusions.get(i) + ".");
|
|
|
+ include = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ include = false;
|
|
|
+ Log.i(TAG, "Skipping Class " + className + ". Not in the root package: " + rootPackage + ".");
|
|
|
+ }
|
|
|
+ return include;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Check to see if the class extends Application or SimpleApplication
|
|
|
+ * @param className Class name to check
|
|
|
+ * @return true if the check passes, false otherwise
|
|
|
+ */
|
|
|
+ private boolean checkClassType(String className) {
|
|
|
+ boolean include = true;
|
|
|
+ try {
|
|
|
+ Class<?> clazz = (Class<?>)Class.forName(className);
|
|
|
+ if (Application.class.isAssignableFrom(clazz)) {
|
|
|
+ Log.i(TAG, "Class " + className + " is a jME Application");
|
|
|
+ } else {
|
|
|
+ include = false;
|
|
|
+ Log.i(TAG, "Skipping Class " + className + ". Not a jME Application");
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (ClassNotFoundException cnfe) {
|
|
|
+ include = false;
|
|
|
+ Log.i(TAG, "Skipping Class " + className + ". Class not found.");
|
|
|
+ }
|
|
|
+ return include;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setSelection(int position) {
|
|
|
+ if (position == -1) {
|
|
|
+ arrayAdapter.setSelectedPosition(-1);
|
|
|
+ currentPosition = -1;
|
|
|
+ currentSelection = "";
|
|
|
+ btnOK.setEnabled(false);
|
|
|
+ listClasses.invalidateViews();
|
|
|
+ } else {
|
|
|
+ arrayAdapter.setSelectedPosition(position);
|
|
|
+ currentPosition = position;
|
|
|
+ currentSelection = arrayAdapter.getItem(position);
|
|
|
+ btnOK.setEnabled(true);
|
|
|
+ listClasses.invalidateViews();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSaveInstanceState(Bundle savedInstanceState) {
|
|
|
+ super.onSaveInstanceState(savedInstanceState);
|
|
|
+ Log.i(TAG, "Saving selections in onSaveInstanceState: "
|
|
|
+ + "position: " + currentPosition + ", "
|
|
|
+ + "class: " + currentSelection + ", "
|
|
|
+ + "mouseEvents: " + enableMouseEvents + ", "
|
|
|
+ + "joystickEvents: " + enableJoystickEvents + ", "
|
|
|
+ );
|
|
|
+ // Save current selections to the savedInstanceState.
|
|
|
+ // This bundle will be passed to onCreate if the process is
|
|
|
+ // killed and restarted.
|
|
|
+ savedInstanceState.putString(SELECTED_APP_CLASS, currentSelection);
|
|
|
+ savedInstanceState.putInt(SELECTED_LIST_POSITION, currentPosition);
|
|
|
+ savedInstanceState.putBoolean(ENABLE_MOUSE_EVENTS, enableMouseEvents);
|
|
|
+ savedInstanceState.putBoolean(ENABLE_JOYSTICK_EVENTS, enableJoystickEvents);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
|
|
|
+ super.onRestoreInstanceState(savedInstanceState);
|
|
|
+// Log.i(TAG, "Restoring selections in onRestoreInstanceState: "
|
|
|
+// + "position: " + savedInstanceState.getInt(SELECTED_LIST_POSITION, 0)
|
|
|
+// + "class: " + savedInstanceState.getString(SELECTED_APP_CLASS)
|
|
|
+// );
|
|
|
+// //Restore selections from the savedInstanceState.
|
|
|
+// // This bundle has also been passed to onCreate.
|
|
|
+// currentPosition = savedInstanceState.getInt(SELECTED_LIST_POSITION, 0);
|
|
|
+// currentSelection = savedInstanceState.getString(SELECTED_APP_CLASS);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void beforeTextChanged(CharSequence cs, int i, int i1, int i2) {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onTextChanged(CharSequence cs, int startPos, int beforePos, int count) {
|
|
|
+ Log.i(TAG, "onTextChanged with cs: " + cs + ", startPos: " + startPos + ", beforePos: " + beforePos + ", count: " + count);
|
|
|
+ arrayAdapter.getFilter().filter(cs.toString());
|
|
|
+ setSelection(-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void afterTextChanged(Editable edtbl) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onDestroy() {
|
|
|
+ super.onDestroy();
|
|
|
+ editFilterText.removeTextChangedListener(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onCreateOptionsMenu(Menu menu) {
|
|
|
+ MenuInflater inflater = getMenuInflater();
|
|
|
+ inflater.inflate(R.menu.menu_items, menu);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onPrepareOptionsMenu (Menu menu) {
|
|
|
+ MenuItem item;
|
|
|
+
|
|
|
+ item = menu.findItem(R.id.optionMouseEvents);
|
|
|
+ if (item != null) {
|
|
|
+ Log.i(TAG, "Found EnableMouseEvents menu item");
|
|
|
+ if (enableMouseEvents) {
|
|
|
+ item.setTitle(R.string.strOptionDisableMouseEventsTitle);
|
|
|
+ } else {
|
|
|
+ item.setTitle(R.string.strOptionEnableMouseEventsTitle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ item = menu.findItem(R.id.optionJoystickEvents);
|
|
|
+ if (item != null) {
|
|
|
+ Log.i(TAG, "Found EnableJoystickEvents menu item");
|
|
|
+ if (enableJoystickEvents) {
|
|
|
+ item.setTitle(R.string.strOptionDisableJoystickEventsTitle);
|
|
|
+ } else {
|
|
|
+ item.setTitle(R.string.strOptionEnableJoystickEventsTitle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ item = menu.findItem(R.id.optionKeyEvents);
|
|
|
+ if (item != null) {
|
|
|
+ Log.i(TAG, "Found EnableKeyEvents menu item");
|
|
|
+ if (enableKeyEvents) {
|
|
|
+ item.setTitle(R.string.strOptionDisableKeyEventsTitle);
|
|
|
+ } else {
|
|
|
+ item.setTitle(R.string.strOptionEnableKeyEventsTitle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
+ switch (item.getItemId()) {
|
|
|
+ case R.id.optionMouseEvents:
|
|
|
+ enableMouseEvents = !enableMouseEvents;
|
|
|
+ Log.i(TAG, "enableMouseEvents set to: " + enableMouseEvents);
|
|
|
+ break;
|
|
|
+ case R.id.optionJoystickEvents:
|
|
|
+ enableJoystickEvents = !enableJoystickEvents;
|
|
|
+ Log.i(TAG, "enableJoystickEvents set to: " + enableJoystickEvents);
|
|
|
+ break;
|
|
|
+ case R.id.optionKeyEvents:
|
|
|
+ enableKeyEvents = !enableKeyEvents;
|
|
|
+ Log.i(TAG, "enableKeyEvents set to: " + enableKeyEvents);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return super.onOptionsItemSelected(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|