[Android] Draw notification messages instead of using toaster

This commit is contained in:
zilmar 2016-09-17 11:43:32 +10:00
parent 49dcce96e9
commit 9b1587992e
6 changed files with 157 additions and 128 deletions

View File

@ -1,20 +1,27 @@
/****************************************************************************
* *
* Project 64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2012 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
* *
* Project 64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2012 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
package emu.project64.game;
import java.util.Timer;
import java.util.TimerTask;
import emu.project64.input.TouchController;
import emu.project64.input.map.VisibleTouchMap;
import emu.project64.util.DeviceUtil;
import android.content.Context;
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.view.View;
@ -24,10 +31,16 @@ public class GameOverlay extends View implements TouchController.OnStateChangedL
private boolean mDrawingEnabled = true;
private int mHatRefreshPeriod = 0;
private int mHatRefreshCount = 0;
private Paint mPaint = new Paint();
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 )
public GameOverlay(Context context, AttributeSet attribs)
{
super( context, attribs );
super(context, attribs);
requestFocus();
}
@ -38,21 +51,64 @@ public class GameOverlay extends View implements TouchController.OnStateChangedL
mHatRefreshPeriod = joystickAnimated ? 3 : 0;
}
@Override
public void onAnalogChanged( float axisFractionX, float axisFractionY )
public void SetDisplayMessage(String Message, int Duratation)
{
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
mHatRefreshCount++;
// If stick re-centered, always refresh
if( axisFractionX == 0 && axisFractionY == 0 )
if (axisFractionX == 0 && axisFractionY == 0)
{
mHatRefreshCount = 0;
}
// Update the analog stick assets and redraw if required
if( mHatRefreshCount % mHatRefreshPeriod == 0 && mTouchMap != null
&& mTouchMap.updateAnalog( axisFractionX, axisFractionY ) )
if (mHatRefreshCount % mHatRefreshPeriod == 0 && mTouchMap != null
&& mTouchMap.updateAnalog(axisFractionX, axisFractionY))
{
postInvalidate();
}
@ -60,40 +116,64 @@ public class GameOverlay extends View implements TouchController.OnStateChangedL
}
@Override
public void onAutoHold( boolean autoHold, int index )
public void onAutoHold(boolean autoHold, int index)
{
// Update the AutoHold mask, and redraw if required
if( mTouchMap != null && mTouchMap.updateAutoHold( autoHold , index) )
if (mTouchMap != null && mTouchMap.updateAutoHold(autoHold, index))
{
postInvalidate();
}
}
@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
if( mTouchMap != null )
mTouchMap.resize( w, h, DeviceUtil.getDisplayMetrics( this ) );
super.onSizeChanged( w, h, oldw, oldh );
if (mTouchMap != null)
{
mTouchMap.resize(w, h, DeviceUtil.getDisplayMetrics(this));
}
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw( Canvas canvas )
protected void onDraw(Canvas canvas)
{
if(canvas == null )
if (canvas == null)
{
return;
}
if( mTouchMap != null && mDrawingEnabled )
if (mTouchMap != null && mDrawingEnabled)
{
// Redraw the static buttons
mTouchMap.drawButtons( canvas );
mTouchMap.drawButtons(canvas);
// Redraw the dynamic analog stick
mTouchMap.drawAnalog( canvas );
mTouchMap.drawAnalog(canvas);
// 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);
}
}
}

View File

@ -10,20 +10,18 @@
****************************************************************************/
package emu.project64.util;
import emu.project64.game.GameOverlay;
import emu.project64.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
/**
* A small class to encapsulate the notification process for Mupen64PlusAE.
*/
public final class Notifier
{
private static Toast sToast = null;
private static Runnable sToastMessager = null;
private static Runnable sDisplayMessager = null;
/**
@ -80,48 +78,25 @@ public final class Notifier
Log.d("DisplayError", "Done");
}
/**
* 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 )
public static void showMessage( Activity activity, String message, int Duratation )
{
if( activity == null )
return;
// Create a messaging task if it doesn't already exist
if( sToastMessager == null )
{
final String ToastMessage = new String(message);
final Activity ToastActivity = activity;
GameOverlay overlay = (GameOverlay) activity.findViewById(R.id.gameOverlay);
if (overlay == null)
return;
sToastMessager = new Runnable()
{
@Override
public void run()
{
// Just show the toast message
if( sToast != null )
sToast.show();
overlay.SetDisplayMessage(message, Duratation);
}
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;

View File

@ -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();
if (env)
{
jstring j_Message = env->NewStringUTF(Message);
jmethodID midShowToast = env->GetStaticMethodID(m_NotifierClass, "showToast", "(Landroid/app/Activity;Ljava/lang/String;)V");
env->CallStaticVoidMethod(m_NotifierClass, midShowToast,g_Activity,j_Message);
jmethodID midshowMessage = env->GetStaticMethodID(m_NotifierClass, "showMessage", "(Landroid/app/Activity;Ljava/lang/String;I)V");
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);
}
}

View File

@ -23,7 +23,8 @@ public:
//Notification
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);
private:

View File

@ -28,7 +28,7 @@ CNotificationImp & Notify(void)
}
CNotificationImp::CNotificationImp() :
m_NextMsg(0)
m_NextMsg(0)
{
}
@ -81,26 +81,7 @@ void CNotificationImp::DisplayMessage(int DisplayTime, const char * Message) con
{
#ifdef ANDROID
if (g_JavaBridge == NULL) { return; }
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();
g_JavaBridge->DisplayMessage(Message, DisplayTime);
#else
// ignore warning usage
DisplayTime = DisplayTime;
@ -112,9 +93,8 @@ void CNotificationImp::DisplayMessage2(const char * Message) const
{
#ifdef ANDROID
if (g_JavaBridge == NULL) { return; }
m_Message[1] = Message;
UpdateMessage();
g_JavaBridge->DisplayMessage2(Message);
#else
// ignore warning usage
Message = Message;
@ -151,19 +131,3 @@ bool CNotificationImp::ProcessGuiMessages(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
}

View File

@ -17,7 +17,7 @@ class CNotificationImp :
{
public:
CNotificationImp(void);
virtual ~CNotificationImp();
virtual ~CNotificationImp();
//Error Messages
void DisplayError(const char * Message) const;
@ -44,10 +44,7 @@ private:
CNotificationImp(const CNotificationImp&); // Disable copy constructor
CNotificationImp& operator=(const CNotificationImp&); // Disable assignment
void UpdateMessage(void) const;
mutable time_t m_NextMsg;
mutable std::string m_Message[2];
};
CNotificationImp & Notify(void);