/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2011 Sam Lantinga Java source code (C) 2009-2011 Sergii Pylypenko This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. */ package net.sourceforge.clonekeenplus; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.MotionEvent; import android.view.KeyEvent; import android.view.Window; import android.view.WindowManager; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.EditText; import android.text.Editable; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.FrameLayout; import android.content.res.Configuration; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.view.View.OnKeyListener; import android.text.method.TextKeyListener; import java.util.LinkedList; import java.io.SequenceInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileOutputStream; import java.io.File; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import android.text.SpannedString; import java.io.BufferedReader; import java.io.BufferedInputStream; import java.io.InputStreamReader; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // fullscreen mode requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); if(Globals.InhibitSuspend) getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); System.out.println("libSDL: Creating startup screen"); _layout = new LinearLayout(this); _layout.setOrientation(LinearLayout.VERTICAL); _layout.setLayoutParams(new LinearLayout.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); _layout2 = new LinearLayout(this); _layout2.setLayoutParams(new LinearLayout.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); _btn = new Button(this); _btn.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); _btn.setText(getResources().getString(R.string.device_change_cfg)); class onClickListener implements View.OnClickListener { public MainActivity p; onClickListener( MainActivity _p ) { p = _p; } public void onClick(View v) { setUpStatusLabel(); System.out.println("libSDL: User clicked change phone config button"); Settings.showConfig(p, false); } }; _btn.setOnClickListener(new onClickListener(this)); _layout2.addView(_btn); _layout.addView(_layout2); ImageView img = new ImageView(this); img.setScaleType(ImageView.ScaleType.FIT_CENTER /* FIT_XY */ ); img.setImageResource(R.drawable.publisherlogo); img.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); _layout.addView(img); _videoLayout = new FrameLayout(this); _videoLayout.addView(_layout); setContentView(_videoLayout); if(mAudioThread == null) // Starting from background (should not happen) { System.out.println("libSDL: Loading libraries"); LoadLibraries(); mAudioThread = new AudioThread(this); System.out.println("libSDL: Loading settings"); Settings.Load(this); } if( !Settings.settingsChanged ) { System.out.println("libSDL: 3-second timeout in startup screen"); class Callback implements Runnable { MainActivity p; Callback( MainActivity _p ) { p = _p; } public void run() { try { Thread.sleep(3000); } catch( InterruptedException e ) {}; if( Settings.settingsChanged ) return; System.out.println("libSDL: Timeout reached in startup screen, process with downloader"); p.startDownloader(); } }; Thread changeConfigAlertThread = null; changeConfigAlertThread = new Thread(new Callback(this)); changeConfigAlertThread.start(); } } public void setUpStatusLabel() { MainActivity Parent = this; // Too lazy to rename if( Parent._btn != null ) { Parent._layout2.removeView(Parent._btn); Parent._btn = null; } if( Parent._tv == null ) { Parent._tv = new TextView(Parent); Parent._tv.setMaxLines(1); Parent._tv.setText(R.string.init); Parent._layout2.addView(Parent._tv); } } public void startDownloader() { System.out.println("libSDL: Starting data downloader"); class Callback implements Runnable { public MainActivity Parent; public void run() { setUpStatusLabel(); System.out.println("libSDL: Starting downloader"); if( Parent.downloader == null ) Parent.downloader = new DataDownloader(Parent, Parent._tv); } } Callback cb = new Callback(); cb.Parent = this; this.runOnUiThread(cb); } public void initSDL() { if(sdlInited) return; System.out.println("libSDL: Initializing video and SDL application"); sdlInited = true; if(Globals.UseAccelerometerAsArrowKeys) getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); _videoLayout.removeView(_layout); _layout = null; _layout2 = null; _btn = null; _tv = null; _videoLayout = new FrameLayout(this); setContentView(_videoLayout); mGLView = new DemoGLSurfaceView(this); _videoLayout.addView(mGLView); // Receive keyboard events mGLView.setFocusableInTouchMode(true); mGLView.setFocusable(true); mGLView.requestFocus(); } @Override protected void onPause() { if( downloader != null ) { synchronized( downloader ) { downloader.setStatusField(null); } } _isPaused = true; if( mGLView != null ) mGLView.onPause(); super.onPause(); } @Override protected void onResume() { super.onResume(); if( mGLView != null ) mGLView.onResume(); else if( downloader != null ) { synchronized( downloader ) { downloader.setStatusField(_tv); if( downloader.DownloadComplete ) initSDL(); } } _isPaused = false; } public boolean isPaused() { return _isPaused; } @Override protected void onDestroy() { if( downloader != null ) { synchronized( downloader ) { downloader.setStatusField(null); } } if( mGLView != null ) mGLView.exitApp(); super.onDestroy(); System.exit(0); } public void hideScreenKeyboard() { if(_screenKeyboard == null) return; synchronized(textInput) { String text = _screenKeyboard.getText().toString(); for(int i = 0; i < text.length(); i++) { DemoRenderer.nativeTextInput( (int)text.charAt(i), (int)text.codePointAt(i) ); } } DemoRenderer.nativeTextInputFinished(); _videoLayout.removeView(_screenKeyboard); _screenKeyboard = null; mGLView.setFocusableInTouchMode(true); mGLView.setFocusable(true); mGLView.requestFocus(); }; public void showScreenKeyboard(final String oldText, boolean sendBackspace) { if(_screenKeyboard != null) return; class myKeyListener implements OnKeyListener { MainActivity _parent; boolean sendBackspace; myKeyListener(MainActivity parent, boolean sendBackspace) { _parent = parent; this.sendBackspace = sendBackspace; }; public boolean onKey(View v, int keyCode, KeyEvent event) { if ((event.getAction() == KeyEvent.ACTION_UP) && ((keyCode == KeyEvent.KEYCODE_ENTER) || (keyCode == KeyEvent.KEYCODE_BACK))) { _parent.hideScreenKeyboard(); return true; } if ((sendBackspace && event.getAction() == KeyEvent.ACTION_UP) && (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_CLEAR)) { synchronized(textInput) { DemoRenderer.nativeTextInput( 8, 0 ); // Send backspace to native code } return false; // and proceed to delete text in keyboard input field } return false; } }; _screenKeyboard = new EditText(this); _videoLayout.addView(_screenKeyboard); _screenKeyboard.setOnKeyListener(new myKeyListener(this, sendBackspace)); _screenKeyboard.setHint(R.string.text_edit_click_here); _screenKeyboard.setText(oldText); final Window window = getWindow(); _screenKeyboard.setOnFocusChangeListener(new View.OnFocusChangeListener() { public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); } }); _screenKeyboard.setKeyListener(new TextKeyListener(TextKeyListener.Capitalize.NONE, false)); _screenKeyboard.setFocusableInTouchMode(true); _screenKeyboard.setFocusable(true); _screenKeyboard.requestFocus(); }; @Override public boolean onKeyDown(int keyCode, final KeyEvent event) { // Overrides Back key to use in our app if(_screenKeyboard != null) _screenKeyboard.onKeyDown(keyCode, event); else if( mGLView != null ) mGLView.nativeKey( keyCode, 1 ); else if( keyCode == KeyEvent.KEYCODE_BACK && downloader != null ) { if( downloader.DownloadFailed ) System.exit(1); if( !downloader.DownloadComplete ) onStop(); } else if( keyListener != null ) { keyListener.onKeyEvent(keyCode); } return true; } @Override public boolean onKeyUp(int keyCode, final KeyEvent event) { if(_screenKeyboard != null) _screenKeyboard.onKeyUp(keyCode, event); else if( mGLView != null ) mGLView.nativeKey( keyCode, 0 ); return true; } @Override public boolean dispatchTouchEvent(final MotionEvent ev) { if(_screenKeyboard != null) _screenKeyboard.dispatchTouchEvent(ev); else if(mGLView != null) mGLView.onTouchEvent(ev); else if( _btn != null ) return _btn.dispatchTouchEvent(ev); else if( touchListener != null ) touchListener.onTouchEvent(ev); return true; } @Override public boolean dispatchGenericMotionEvent (final MotionEvent ev) { return dispatchTouchEvent(ev); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Do nothing here } public void setText(final String t) { class Callback implements Runnable { MainActivity Parent; public SpannedString text; public void run() { Parent.setUpStatusLabel(); if(Parent._tv != null) Parent._tv.setText(text); } } Callback cb = new Callback(); cb.text = new SpannedString(t); cb.Parent = this; this.runOnUiThread(cb); } public void showTaskbarNotification() { showTaskbarNotification("SDL application paused", "SDL application", "Application is paused, click to activate"); } // Stolen from SDL port by Mamaich public void showTaskbarNotification(String text0, String text1, String text2) { NotificationManager NotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Intent intent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK); Notification n = new Notification(R.drawable.icon, text0, System.currentTimeMillis()); n.setLatestEventInfo(this, text1, text2, pendingIntent); NotificationManager.notify(NOTIFY_ID, n); } public void hideTaskbarNotification() { NotificationManager NotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager.cancel(NOTIFY_ID); } public void LoadLibraries() { try { for(String l : Globals.AppLibraries) { try { String libname = System.mapLibraryName(l); File libpath = new File(getFilesDir().getAbsolutePath() + "/../lib/" + libname); System.out.println("libSDL: loading lib " + libpath.getAbsolutePath()); System.load(libpath.getPath()); } catch( UnsatisfiedLinkError e ) { System.loadLibrary(l); } } } catch ( UnsatisfiedLinkError e ) { try { System.out.println("libSDL: Extracting APP2SD-ed libs"); InputStream in = null; try { for( int i = 0; ; i++ ) { InputStream in2 = getAssets().open("bindata" + String.valueOf(i)); if( in == null ) in = in2; else in = new SequenceInputStream( in, in2 ); } } catch( IOException ee ) { } if( in == null ) throw new RuntimeException("libSDL: Extracting APP2SD-ed libs failed, the .apk file packaged incorrectly"); ZipInputStream zip = new ZipInputStream(in); File cacheDir = getCacheDir(); try { cacheDir.mkdirs(); } catch( SecurityException ee ) { }; byte[] buf = new byte[16384]; while(true) { ZipEntry entry = null; entry = zip.getNextEntry(); /* if( entry != null ) System.out.println("Extracting lib " + entry.getName()); */ if( entry == null ) { System.out.println("Extracting libs finished"); break; } if( entry.isDirectory() ) { System.out.println("Warning '" + entry.getName() + "' is a directory"); continue; } OutputStream out = null; String path = cacheDir.getAbsolutePath() + "/" + entry.getName(); System.out.println("Saving to file '" + path + "'"); out = new FileOutputStream( path ); int len = zip.read(buf); while (len >= 0) { if(len > 0) out.write(buf, 0, len); len = zip.read(buf); } out.flush(); out.close(); } for(String l : Globals.AppLibraries) { String libname = System.mapLibraryName(l); File libpath = new File(cacheDir, libname); System.out.println("libSDL: loading lib " + libpath.getPath()); System.load(libpath.getPath()); libpath.delete(); } } catch ( Exception ee ) { System.out.println("libSDL: Error: " + e.toString()); } } }; public FrameLayout getVideoLayout() { return _videoLayout; } static int NOTIFY_ID = 12367098; // Random ID private static DemoGLSurfaceView mGLView = null; private static AudioThread mAudioThread = null; private static DataDownloader downloader = null; private TextView _tv = null; private Button _btn = null; private LinearLayout _layout = null; private LinearLayout _layout2 = null; private FrameLayout _videoLayout = null; private EditText _screenKeyboard = null; private boolean sdlInited = false; public Settings.TouchEventsListener touchListener = null; public Settings.KeyEventsListener keyListener = null; boolean _isPaused = false; public LinkedList textInput = new LinkedList (); }