[Android] Draw notification messages instead of using toaster
This commit is contained in:
parent
49dcce96e9
commit
9b1587992e
|
@ -1,20 +1,27 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* *
|
* *
|
||||||
* Project 64 - A Nintendo 64 emulator. *
|
* Project 64 - A Nintendo 64 emulator. *
|
||||||
* http://www.pj64-emu.com/ *
|
* http://www.pj64-emu.com/ *
|
||||||
* Copyright (C) 2012 Project64. All rights reserved. *
|
* Copyright (C) 2012 Project64. All rights reserved. *
|
||||||
* *
|
* *
|
||||||
* License: *
|
* License: *
|
||||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||||
* *
|
* *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
package emu.project64.game;
|
package emu.project64.game;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import emu.project64.input.TouchController;
|
import emu.project64.input.TouchController;
|
||||||
import emu.project64.input.map.VisibleTouchMap;
|
import emu.project64.input.map.VisibleTouchMap;
|
||||||
import emu.project64.util.DeviceUtil;
|
import emu.project64.util.DeviceUtil;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
@ -24,35 +31,84 @@ public class GameOverlay extends View implements TouchController.OnStateChangedL
|
||||||
private boolean mDrawingEnabled = true;
|
private boolean mDrawingEnabled = true;
|
||||||
private int mHatRefreshPeriod = 0;
|
private int mHatRefreshPeriod = 0;
|
||||||
private int mHatRefreshCount = 0;
|
private int mHatRefreshCount = 0;
|
||||||
|
private Paint mPaint = new Paint();
|
||||||
public GameOverlay( Context context, AttributeSet attribs )
|
private Rect mRectangle = new Rect();
|
||||||
|
private String mDisplayMessage = "";
|
||||||
|
private String mDisplayMessage2 = "";
|
||||||
|
private int mDisplayMessageDuration = 0;
|
||||||
|
private Timer mTimer = null;
|
||||||
|
|
||||||
|
public GameOverlay(Context context, AttributeSet attribs)
|
||||||
{
|
{
|
||||||
super( context, attribs );
|
super(context, attribs);
|
||||||
requestFocus();
|
requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize( VisibleTouchMap touchMap, boolean drawingEnabled, boolean fpsEnabled, boolean joystickAnimated )
|
public void initialize( VisibleTouchMap touchMap, boolean drawingEnabled, boolean fpsEnabled, boolean joystickAnimated )
|
||||||
{
|
{
|
||||||
mTouchMap = touchMap;
|
mTouchMap = touchMap;
|
||||||
mDrawingEnabled = drawingEnabled;
|
mDrawingEnabled = drawingEnabled;
|
||||||
mHatRefreshPeriod = joystickAnimated ? 3 : 0;
|
mHatRefreshPeriod = joystickAnimated ? 3 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void SetDisplayMessage(String Message, int Duratation)
|
||||||
public void onAnalogChanged( float axisFractionX, float axisFractionY )
|
|
||||||
{
|
{
|
||||||
if( mHatRefreshPeriod > 0 && mDrawingEnabled )
|
if (Duratation >= mDisplayMessageDuration)
|
||||||
|
{
|
||||||
|
mDisplayMessage = Message;
|
||||||
|
mDisplayMessageDuration = Duratation;
|
||||||
|
if (mTimer != null)
|
||||||
|
{
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer.purge();
|
||||||
|
}
|
||||||
|
if (Duratation == 0)
|
||||||
|
{
|
||||||
|
Duratation = 10;
|
||||||
|
}
|
||||||
|
TimerTask task = new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mDisplayMessage = "";
|
||||||
|
mDisplayMessageDuration = 0;
|
||||||
|
Timer CurrentTimer = mTimer;
|
||||||
|
mTimer = null;
|
||||||
|
CurrentTimer.cancel();
|
||||||
|
CurrentTimer.purge();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
mTimer = new Timer();
|
||||||
|
mTimer.schedule(task, Duratation * 1000);
|
||||||
|
}
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDisplayMessage2(String Message)
|
||||||
|
{
|
||||||
|
mDisplayMessage2 = Message;
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnalogChanged(float axisFractionX, float axisFractionY)
|
||||||
|
{
|
||||||
|
if (mHatRefreshPeriod > 0 && mDrawingEnabled)
|
||||||
{
|
{
|
||||||
// Increment the count since last refresh
|
// Increment the count since last refresh
|
||||||
mHatRefreshCount++;
|
mHatRefreshCount++;
|
||||||
|
|
||||||
// If stick re-centered, always refresh
|
// If stick re-centered, always refresh
|
||||||
if( axisFractionX == 0 && axisFractionY == 0 )
|
if (axisFractionX == 0 && axisFractionY == 0)
|
||||||
|
{
|
||||||
mHatRefreshCount = 0;
|
mHatRefreshCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the analog stick assets and redraw if required
|
// Update the analog stick assets and redraw if required
|
||||||
if( mHatRefreshCount % mHatRefreshPeriod == 0 && mTouchMap != null
|
if (mHatRefreshCount % mHatRefreshPeriod == 0 && mTouchMap != null
|
||||||
&& mTouchMap.updateAnalog( axisFractionX, axisFractionY ) )
|
&& mTouchMap.updateAnalog(axisFractionX, axisFractionY))
|
||||||
{
|
{
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
@ -60,40 +116,64 @@ public class GameOverlay extends View implements TouchController.OnStateChangedL
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAutoHold( boolean autoHold, int index )
|
public void onAutoHold(boolean autoHold, int index)
|
||||||
{
|
{
|
||||||
// Update the AutoHold mask, and redraw if required
|
// Update the AutoHold mask, and redraw if required
|
||||||
if( mTouchMap != null && mTouchMap.updateAutoHold( autoHold , index) )
|
if (mTouchMap != null && mTouchMap.updateAutoHold(autoHold, index))
|
||||||
{
|
{
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged( int w, int h, int oldw, int oldh )
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
{
|
{
|
||||||
// Recompute skin layout geometry
|
// Recompute skin layout geometry
|
||||||
if( mTouchMap != null )
|
if (mTouchMap != null)
|
||||||
mTouchMap.resize( w, h, DeviceUtil.getDisplayMetrics( this ) );
|
{
|
||||||
super.onSizeChanged( w, h, oldw, oldh );
|
mTouchMap.resize(w, h, DeviceUtil.getDisplayMetrics(this));
|
||||||
|
}
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw( Canvas canvas )
|
protected void onDraw(Canvas canvas)
|
||||||
{
|
{
|
||||||
if(canvas == null )
|
if (canvas == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if( mTouchMap != null && mDrawingEnabled )
|
|
||||||
|
if (mTouchMap != null && mDrawingEnabled)
|
||||||
{
|
{
|
||||||
// Redraw the static buttons
|
// Redraw the static buttons
|
||||||
mTouchMap.drawButtons( canvas );
|
mTouchMap.drawButtons(canvas);
|
||||||
|
|
||||||
// Redraw the dynamic analog stick
|
// Redraw the dynamic analog stick
|
||||||
mTouchMap.drawAnalog( canvas );
|
mTouchMap.drawAnalog(canvas);
|
||||||
|
|
||||||
// Redraw the autoHold mask
|
// Redraw the autoHold mask
|
||||||
mTouchMap.drawAutoHold( canvas );
|
mTouchMap.drawAutoHold(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
String txt = mDisplayMessage;
|
||||||
|
if (txt.length() > 0 && mDisplayMessage2.length() > 0)
|
||||||
|
{
|
||||||
|
txt += " - ";
|
||||||
|
}
|
||||||
|
txt += mDisplayMessage2;
|
||||||
|
if (txt.length() > 0)
|
||||||
|
{
|
||||||
|
mPaint.setStyle(Paint.Style.FILL);
|
||||||
|
mPaint.setColor(Color.parseColor("#DDDDDD"));
|
||||||
|
mPaint.setAntiAlias(true);
|
||||||
|
mPaint.setTextSize(25);
|
||||||
|
mPaint.setTextAlign(Paint.Align.CENTER);
|
||||||
|
Typeface typeface = Typeface.create(Typeface.SANS_SERIF,
|
||||||
|
Typeface.BOLD_ITALIC);
|
||||||
|
mPaint.setTypeface(typeface);
|
||||||
|
mPaint.getTextBounds(txt, 0, txt.length(), mRectangle);
|
||||||
|
canvas.drawText(txt, Math.abs(canvas.getWidth() / 2), Math.abs((int) (canvas.getHeight() * 0.95)) - Math.abs(mRectangle.height()), mPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,18 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
package emu.project64.util;
|
package emu.project64.util;
|
||||||
|
|
||||||
|
import emu.project64.game.GameOverlay;
|
||||||
|
import emu.project64.R;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A small class to encapsulate the notification process for Mupen64PlusAE.
|
* A small class to encapsulate the notification process for Mupen64PlusAE.
|
||||||
*/
|
*/
|
||||||
public final class Notifier
|
public final class Notifier
|
||||||
{
|
{
|
||||||
private static Toast sToast = null;
|
|
||||||
private static Runnable sToastMessager = null;
|
|
||||||
private static Runnable sDisplayMessager = null;
|
private static Runnable sDisplayMessager = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,50 +78,27 @@ public final class Notifier
|
||||||
Log.d("DisplayError", "Done");
|
Log.d("DisplayError", "Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static void showMessage( Activity activity, String message, int Duratation )
|
||||||
* Pop up a temporary message on the device.
|
|
||||||
*
|
|
||||||
* @param activity The activity to display from
|
|
||||||
* @param message The message string to display.
|
|
||||||
*/
|
|
||||||
public static void showToast( Activity activity, String message )
|
|
||||||
{
|
{
|
||||||
if( activity == null )
|
if( activity == null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create a messaging task if it doesn't already exist
|
|
||||||
if( sToastMessager == null )
|
|
||||||
{
|
|
||||||
final String ToastMessage = new String(message);
|
|
||||||
final Activity ToastActivity = activity;
|
|
||||||
|
|
||||||
sToastMessager = new Runnable()
|
GameOverlay overlay = (GameOverlay) activity.findViewById(R.id.gameOverlay);
|
||||||
{
|
if (overlay == null)
|
||||||
@Override
|
return;
|
||||||
public void run()
|
|
||||||
{
|
overlay.SetDisplayMessage(message, Duratation);
|
||||||
// Just show the toast message
|
|
||||||
if( sToast != null )
|
|
||||||
sToast.show();
|
|
||||||
|
|
||||||
if( sToast != null )
|
|
||||||
{
|
|
||||||
// Toast exists, just change the text
|
|
||||||
Notifier.sToast.setText( ToastMessage );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Message short in duration, and at the bottom of the screen
|
|
||||||
sToast = Toast.makeText( ToastActivity, ToastMessage, Toast.LENGTH_SHORT );
|
|
||||||
sToast.setGravity( Gravity.BOTTOM, 0, 0 );
|
|
||||||
}
|
|
||||||
sToastMessager = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
activity.runOnUiThread( sToastMessager );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void showMessage2( Activity activity, String message )
|
||||||
|
{
|
||||||
|
if( activity == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
GameOverlay overlay = (GameOverlay) activity.findViewById(R.id.gameOverlay);
|
||||||
|
overlay.SetDisplayMessage2(message);
|
||||||
|
}
|
||||||
|
|
||||||
private static Runnable runEmulationStopped = null;
|
private static Runnable runEmulationStopped = null;
|
||||||
public static void EmulationStopped (Activity activity)
|
public static void EmulationStopped (Activity activity)
|
||||||
{
|
{
|
||||||
|
|
|
@ -122,14 +122,26 @@ void JavaBridge::DisplayError(const char * Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaBridge::DisplayMessage(const char * Message)
|
void JavaBridge::DisplayMessage(const char * Message, int DisplayTime)
|
||||||
{
|
{
|
||||||
JNIEnv *env = Android_JNI_GetEnv();
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
if (env)
|
if (env)
|
||||||
{
|
{
|
||||||
jstring j_Message = env->NewStringUTF(Message);
|
jstring j_Message = env->NewStringUTF(Message);
|
||||||
jmethodID midShowToast = env->GetStaticMethodID(m_NotifierClass, "showToast", "(Landroid/app/Activity;Ljava/lang/String;)V");
|
jmethodID midshowMessage = env->GetStaticMethodID(m_NotifierClass, "showMessage", "(Landroid/app/Activity;Ljava/lang/String;I)V");
|
||||||
env->CallStaticVoidMethod(m_NotifierClass, midShowToast,g_Activity,j_Message);
|
env->CallStaticVoidMethod(m_NotifierClass, midshowMessage,g_Activity,j_Message,DisplayTime);
|
||||||
|
env->DeleteLocalRef(j_Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JavaBridge::DisplayMessage2(const char * Message)
|
||||||
|
{
|
||||||
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
if (env)
|
||||||
|
{
|
||||||
|
jstring j_Message = env->NewStringUTF(Message);
|
||||||
|
jmethodID midshowMessage2 = env->GetStaticMethodID(m_NotifierClass, "showMessage2", "(Landroid/app/Activity;Ljava/lang/String;)V");
|
||||||
|
env->CallStaticVoidMethod(m_NotifierClass, midshowMessage2,g_Activity,j_Message);
|
||||||
env->DeleteLocalRef(j_Message);
|
env->DeleteLocalRef(j_Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ public:
|
||||||
|
|
||||||
//Notification
|
//Notification
|
||||||
void DisplayError(const char * Message);
|
void DisplayError(const char * Message);
|
||||||
void DisplayMessage(const char * Message);
|
void DisplayMessage(const char * Message, int DisplayTime);
|
||||||
|
void DisplayMessage2(const char * Message);
|
||||||
void EmulationStopped(void);
|
void EmulationStopped(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -28,7 +28,7 @@ CNotificationImp & Notify(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
CNotificationImp::CNotificationImp() :
|
CNotificationImp::CNotificationImp() :
|
||||||
m_NextMsg(0)
|
m_NextMsg(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,26 +81,7 @@ void CNotificationImp::DisplayMessage(int DisplayTime, const char * Message) con
|
||||||
{
|
{
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
if (g_JavaBridge == NULL) { return; }
|
if (g_JavaBridge == NULL) { return; }
|
||||||
|
g_JavaBridge->DisplayMessage(Message, DisplayTime);
|
||||||
if (m_NextMsg > 0 || DisplayTime > 0)
|
|
||||||
{
|
|
||||||
time_t Now = time(NULL);
|
|
||||||
if (DisplayTime == 0 && Now < m_NextMsg)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (DisplayTime > 0)
|
|
||||||
{
|
|
||||||
m_NextMsg = Now + DisplayTime;
|
|
||||||
}
|
|
||||||
if (m_NextMsg == 0)
|
|
||||||
{
|
|
||||||
m_NextMsg = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_Message[0] = Message;
|
|
||||||
UpdateMessage();
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// ignore warning usage
|
// ignore warning usage
|
||||||
DisplayTime = DisplayTime;
|
DisplayTime = DisplayTime;
|
||||||
|
@ -112,9 +93,8 @@ void CNotificationImp::DisplayMessage2(const char * Message) const
|
||||||
{
|
{
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
if (g_JavaBridge == NULL) { return; }
|
if (g_JavaBridge == NULL) { return; }
|
||||||
m_Message[1] = Message;
|
|
||||||
|
|
||||||
UpdateMessage();
|
g_JavaBridge->DisplayMessage2(Message);
|
||||||
#else
|
#else
|
||||||
// ignore warning usage
|
// ignore warning usage
|
||||||
Message = Message;
|
Message = Message;
|
||||||
|
@ -151,19 +131,3 @@ bool CNotificationImp::ProcessGuiMessages(void) const
|
||||||
void CNotificationImp::ChangeFullScreen(void) const
|
void CNotificationImp::ChangeFullScreen(void) const
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNotificationImp::UpdateMessage(void) const
|
|
||||||
{
|
|
||||||
#ifdef ANDROID
|
|
||||||
std::string message = m_Message[0];
|
|
||||||
if (message.length() > 0 && m_Message[1].length())
|
|
||||||
{
|
|
||||||
message += " ";
|
|
||||||
}
|
|
||||||
message += m_Message[1];
|
|
||||||
if (message.length() > 0)
|
|
||||||
{
|
|
||||||
g_JavaBridge->DisplayMessage(message.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
|
@ -17,7 +17,7 @@ class CNotificationImp :
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CNotificationImp(void);
|
CNotificationImp(void);
|
||||||
virtual ~CNotificationImp();
|
virtual ~CNotificationImp();
|
||||||
|
|
||||||
//Error Messages
|
//Error Messages
|
||||||
void DisplayError(const char * Message) const;
|
void DisplayError(const char * Message) const;
|
||||||
|
@ -44,10 +44,7 @@ private:
|
||||||
CNotificationImp(const CNotificationImp&); // Disable copy constructor
|
CNotificationImp(const CNotificationImp&); // Disable copy constructor
|
||||||
CNotificationImp& operator=(const CNotificationImp&); // Disable assignment
|
CNotificationImp& operator=(const CNotificationImp&); // Disable assignment
|
||||||
|
|
||||||
void UpdateMessage(void) const;
|
|
||||||
|
|
||||||
mutable time_t m_NextMsg;
|
mutable time_t m_NextMsg;
|
||||||
mutable std::string m_Message[2];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CNotificationImp & Notify(void);
|
CNotificationImp & Notify(void);
|
Loading…
Reference in New Issue