mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-23 12:56:20 +02:00
369 lines
12 KiB
Java
369 lines
12 KiB
Java
package com.henrikrydgard.libnative;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.RandomAccessFile;
|
|
import java.lang.reflect.Field;
|
|
import java.util.UUID;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.Activity;
|
|
import android.app.ActivityManager;
|
|
import android.app.AlertDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.pm.ActivityInfo;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.ConfigurationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.PackageManager.NameNotFoundException;
|
|
import android.content.res.Configuration;
|
|
import android.media.AudioManager;
|
|
import android.net.Uri;
|
|
import android.opengl.GLSurfaceView;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.os.Environment;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
import android.view.Display;
|
|
import android.view.Gravity;
|
|
import android.view.KeyEvent;
|
|
import android.view.View;
|
|
import android.view.Window;
|
|
import android.view.WindowManager;
|
|
import android.widget.EditText;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.Toast;
|
|
|
|
class Installation {
|
|
private static String sID = null;
|
|
private static final String INSTALLATION = "INSTALLATION";
|
|
|
|
public synchronized static String id(Context context) {
|
|
if (sID == null) {
|
|
File installation = new File(context.getFilesDir(), INSTALLATION);
|
|
try {
|
|
if (!installation.exists())
|
|
writeInstallationFile(installation);
|
|
sID = readInstallationFile(installation);
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
return sID;
|
|
}
|
|
|
|
private static String readInstallationFile(File installation) throws IOException {
|
|
RandomAccessFile f = new RandomAccessFile(installation, "r");
|
|
byte[] bytes = new byte[(int) f.length()];
|
|
f.readFully(bytes);
|
|
f.close();
|
|
return new String(bytes);
|
|
}
|
|
|
|
private static void writeInstallationFile(File installation) throws IOException {
|
|
FileOutputStream out = new FileOutputStream(installation);
|
|
String id = UUID.randomUUID().toString();
|
|
out.write(id.getBytes());
|
|
out.close();
|
|
}
|
|
}
|
|
|
|
|
|
public class NativeActivity extends Activity {
|
|
// Remember to loadLibrary your JNI .so in a static {} block
|
|
|
|
// Adjust these as necessary
|
|
private static String TAG = "NativeActivity";
|
|
|
|
// Graphics and audio interfaces
|
|
private GLSurfaceView mGLSurfaceView;
|
|
private NativeAudioPlayer audioPlayer;
|
|
|
|
boolean useOpenSL = false;
|
|
|
|
public static String runCommand;
|
|
public static String commandParameter;
|
|
public static String installID;
|
|
|
|
String getApplicationLibraryDir(ApplicationInfo application) {
|
|
String libdir = null;
|
|
try {
|
|
// Starting from Android 2.3, nativeLibraryDir is available:
|
|
Field field = ApplicationInfo.class.getField("nativeLibraryDir");
|
|
libdir = (String) field.get(application);
|
|
} catch (SecurityException e1) {
|
|
} catch (NoSuchFieldException e1) {
|
|
} catch (IllegalArgumentException e) {
|
|
} catch (IllegalAccessException e) {
|
|
}
|
|
if (libdir == null) {
|
|
// Fallback for Android < 2.3:
|
|
libdir = application.dataDir + "/lib";
|
|
}
|
|
return libdir;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
if (Build.VERSION.SDK_INT >= 9) {
|
|
// Native OpenSL is available. Let's use it!
|
|
useOpenSL = true;
|
|
}
|
|
|
|
if (NativeApp.isLandscape()) {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
} else {
|
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
}
|
|
super.onCreate(savedInstanceState);
|
|
Log.i(TAG, "onCreate");
|
|
installID = Installation.id(this);
|
|
// Get system information
|
|
ApplicationInfo appInfo = null;
|
|
PackageManager packMgmr = getPackageManager();
|
|
String packageName = getPackageName();
|
|
try {
|
|
appInfo = packMgmr.getApplicationInfo(packageName, 0);
|
|
} catch (NameNotFoundException e) {
|
|
e.printStackTrace();
|
|
throw new RuntimeException("Unable to locate assets, aborting...");
|
|
}
|
|
String libraryDir = getApplicationLibraryDir(appInfo);
|
|
File sdcard = Environment.getExternalStorageDirectory();
|
|
Display display = ((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
|
int scrPixelFormat = display.getPixelFormat();
|
|
@SuppressWarnings("deprecation")
|
|
int scrWidth = display.getWidth();
|
|
@SuppressWarnings("deprecation")
|
|
int scrHeight = display.getHeight();
|
|
float scrRefreshRate = (float)display.getRefreshRate();
|
|
String externalStorageDir = sdcard.getAbsolutePath();
|
|
String dataDir = this.getFilesDir().getAbsolutePath();
|
|
String apkFilePath = appInfo.sourceDir;
|
|
NativeApp.sendMessage("Message from Java", "Hot Coffee");
|
|
DisplayMetrics metrics = new DisplayMetrics();
|
|
getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
|
int dpi = metrics.densityDpi;
|
|
|
|
// INIT!
|
|
NativeApp.init(scrWidth, scrHeight, dpi, apkFilePath, dataDir, externalStorageDir, libraryDir, installID, useOpenSL);
|
|
|
|
// Keep the screen bright - very annoying if it goes dark when tilting away
|
|
Window window = this.getWindow();
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
|
Log.i(TAG, "W : " + scrWidth + " H: " + scrHeight + " rate: " + scrRefreshRate + " fmt: " + scrPixelFormat);
|
|
|
|
// Initialize Graphics
|
|
|
|
if (!detectOpenGLES20()) {
|
|
Log.i(TAG, "OpenGL ES 2.0 NOT detected.");
|
|
} else {
|
|
Log.i(TAG, "OpenGL ES 2.0 detected.");
|
|
}
|
|
|
|
mGLSurfaceView = new NativeGLView(this);
|
|
mGLSurfaceView.setRenderer(new NativeRenderer(this));
|
|
setContentView(mGLSurfaceView);
|
|
if (!useOpenSL)
|
|
audioPlayer = new NativeAudioPlayer();
|
|
lightsOut();
|
|
|
|
/*
|
|
editText = new EditText(this);
|
|
editText.setText("Hello world");
|
|
|
|
addContentView(editText, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
|
*/
|
|
// inputBox("Please ener a s", "", "Save");
|
|
// Toast.makeText(this, "Value: " + input.getText().toString(), Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
public void lightsOut() {
|
|
if (Build.VERSION.SDK_INT >= 11) {
|
|
// mGLSurfaceView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
|
}
|
|
}
|
|
|
|
private boolean detectOpenGLES20() {
|
|
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
|
ConfigurationInfo info = am.getDeviceConfigurationInfo();
|
|
return info.reqGlEsVersion >= 0x20000;
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
Log.i(TAG, "onPause");
|
|
if (audioPlayer != null) {
|
|
audioPlayer.stop();
|
|
}
|
|
NativeApp.pause();
|
|
mGLSurfaceView.onPause();
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
Log.i(TAG, "onResume");
|
|
mGLSurfaceView.onResume();
|
|
if (audioPlayer != null) {
|
|
audioPlayer.play();
|
|
}
|
|
NativeApp.resume();
|
|
}
|
|
|
|
@Override
|
|
protected void onStop() {
|
|
super.onStop();
|
|
Log.i(TAG, "onStop - do nothing");
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
Log.e(TAG, "onDestroy");
|
|
NativeApp.shutdown();
|
|
audioPlayer = null;
|
|
mGLSurfaceView = null;
|
|
}
|
|
|
|
public boolean overrideKeys() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
// Eat these keys, to avoid accidental exits / other screwups.
|
|
// Maybe there's even more we need to eat on tablets?
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
if (event.isAltPressed()) {
|
|
NativeApp.keyDown(1004); // special custom keycode
|
|
} else {
|
|
NativeApp.keyDown(1);
|
|
}
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
|
NativeApp.keyDown(2);
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
|
NativeApp.keyDown(3);
|
|
}
|
|
else {
|
|
// send the rest of the keys through.
|
|
// TODO: get rid of the three special cases above by adjusting the native side of the code.
|
|
NativeApp.keyDown(keyCode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
// Eat these keys, to avoid accidental exits / other screwups.
|
|
// Maybe there's even more we need to eat on tablets?
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
if (event.isAltPressed()) {
|
|
NativeApp.keyUp(1004); // special custom keycode
|
|
}
|
|
else if (NativeApp.isAtTopLevel()) {
|
|
return false;
|
|
} else {
|
|
NativeApp.keyUp(1);
|
|
}
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
|
// Menu should be ignored from SDK 11 forwards. We send it to the app.
|
|
NativeApp.keyUp(2);
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
|
// Search probably should also be ignored. We send it to the app.
|
|
NativeApp.keyUp(3);
|
|
}
|
|
else {
|
|
// send the rest of the keys through.
|
|
// TODO: get rid of the three special cases above by adjusting the native side of the code.
|
|
NativeApp.keyUp(keyCode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Prevent destroying and recreating the main activity when the device rotates etc,
|
|
// since this would stop the sound.
|
|
@Override
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
// Ignore orientation change
|
|
super.onConfigurationChanged(newConfig);
|
|
}
|
|
|
|
public static boolean inputBoxCancelled;
|
|
@SuppressWarnings("deprecation")
|
|
public String inputBox(String title, String defaultText, String defaultAction) {
|
|
final FrameLayout fl = new FrameLayout(this);
|
|
final EditText input = new EditText(this);
|
|
input.setGravity(Gravity.CENTER);
|
|
|
|
inputBoxCancelled = false;
|
|
FrameLayout.LayoutParams editBoxLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
|
editBoxLayout.setMargins(2, 20, 2, 20);
|
|
fl.addView(input, editBoxLayout);
|
|
|
|
input.setText(defaultText);
|
|
input.selectAll();
|
|
|
|
AlertDialog dlg = new AlertDialog.Builder(this)
|
|
.setView(fl)
|
|
.setTitle(title)
|
|
.setPositiveButton(defaultAction, new DialogInterface.OnClickListener(){
|
|
public void onClick(DialogInterface d, int which) {
|
|
d.dismiss();
|
|
}
|
|
})
|
|
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
|
|
public void onClick(DialogInterface d, int which) {
|
|
d.cancel();
|
|
NativeActivity.inputBoxCancelled = false;
|
|
}
|
|
}).create();
|
|
dlg.setCancelable(false);
|
|
dlg.show();
|
|
if (inputBoxCancelled)
|
|
return null;
|
|
return input.getText().toString();
|
|
}
|
|
|
|
public void processCommand(String command, String params) {
|
|
if (command.equals("launchBrowser")) {
|
|
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(params));
|
|
startActivity(i);
|
|
} else if (command.equals("launchEmail")) {
|
|
Intent send = new Intent(Intent.ACTION_SENDTO);
|
|
String uriText;
|
|
uriText = "mailto:email@gmail.com" +
|
|
"?subject=Your app is..." +
|
|
"&body=great! Or?";
|
|
uriText = uriText.replace(" ", "%20");
|
|
Uri uri = Uri.parse(uriText);
|
|
send.setData(uri);
|
|
startActivity(Intent.createChooser(send, "E-mail the app author!"));
|
|
} else if (command.equals("launchMarket")) {
|
|
// http://stackoverflow.com/questions/3442366/android-link-to-market-from-inside-another-app
|
|
// http://developer.android.com/guide/publishing/publishing.html#marketintent
|
|
} else if (command.equals("toast")) {
|
|
Toast toast = Toast.makeText(this, params, Toast.LENGTH_SHORT);
|
|
toast.show();
|
|
} else if (command.equals("showkeyboard")) {
|
|
//InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
//inputMethodManager.toggleSoftInputFromWindow(this, InputMethodManager.SHOW_FORCED, 0);
|
|
} else if (command.equals("gettext")) {
|
|
inputBox("Enter text", params, "OK");
|
|
} else {
|
|
Log.e(TAG, "Unsupported command " + command + " , param: " + params);
|
|
}
|
|
}
|
|
}
|