Commit 073c7aed authored by kenan's avatar kenan

Merge branch 'dev_click'

parents 7c69e0e2 17fddcba
...@@ -1800,6 +1800,12 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) { ...@@ -1800,6 +1800,12 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
return true; return true;
break; break;
} }
case BUTTON_REPORT:{
#ifdef _IRR_ANDROID_PLATFORM_
mainGame->onReportProblem();
#endif
break;
}
} }
break; break;
} }
...@@ -1837,6 +1843,7 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) { ...@@ -1837,6 +1843,7 @@ bool ClientField::OnCommonEvent(const irr::SEvent& event) {
return true; return true;
break; break;
} }
case CHECKBOX_DRAW_FIELD_SPELL: { case CHECKBOX_DRAW_FIELD_SPELL: {
mainGame->gameConf.draw_field_spell = mainGame->chkDrawFieldSpell->isChecked() ? 1 : 0; mainGame->gameConf.draw_field_spell = mainGame->chkDrawFieldSpell->isChecked() ? 1 : 0;
return true; return true;
......
...@@ -495,10 +495,10 @@ bool Game::Initialize() { ...@@ -495,10 +495,10 @@ bool Game::Initialize() {
scrTabSystem->setSmallStep(1); scrTabSystem->setSmallStep(1);
scrTabSystem->setVisible(false); scrTabSystem->setVisible(false);
posY = 0; posY = 0;
chkIgnore1 = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260, posY + 30 * yScale), tabSystem, CHECKBOX_DISABLE_CHAT, dataManager.GetSysString(1290)); chkIgnore1 = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260* xScale, posY + 30 * yScale), tabSystem, CHECKBOX_DISABLE_CHAT, dataManager.GetSysString(1290));
chkIgnore1->setChecked(gameConf.chkIgnore1 != 0); chkIgnore1->setChecked(gameConf.chkIgnore1 != 0);
posY += 60; posY += 60;
chkIgnore2 = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260, posY + 30 * yScale), tabSystem, -1, dataManager.GetSysString(1291)); chkIgnore2 = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260* xScale, posY + 30 * yScale), tabSystem, -1, dataManager.GetSysString(1291));
chkIgnore2->setChecked(gameConf.chkIgnore2 != 0); chkIgnore2->setChecked(gameConf.chkIgnore2 != 0);
posY += 60; posY += 60;
chkIgnoreDeckChanges = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, -1, dataManager.GetSysString(1357)); chkIgnoreDeckChanges = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, -1, dataManager.GetSysString(1357));
...@@ -512,10 +512,13 @@ bool Game::Initialize() { ...@@ -512,10 +512,13 @@ bool Game::Initialize() {
posY += 60; posY += 60;
chkQuickAnimation = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, CHECKBOX_QUICK_ANIMATION, dataManager.GetSysString(1299)); chkQuickAnimation = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, CHECKBOX_QUICK_ANIMATION, dataManager.GetSysString(1299));
chkQuickAnimation->setChecked(gameConf.quick_animation != 0); chkQuickAnimation->setChecked(gameConf.quick_animation != 0);
posY += 60; posY += 60;
chkPreferExpansionScript = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, CHECKBOX_PREFER_EXPANSION, dataManager.GetSysString(1379)); chkPreferExpansionScript = env->addCheckBox(false, rect<s32>(posX, posY, posX + 260 * xScale, posY + 30 * yScale), tabSystem, CHECKBOX_PREFER_EXPANSION, dataManager.GetSysString(1379));
chkPreferExpansionScript->setChecked(gameConf.prefer_expansion_script != 0); chkPreferExpansionScript->setChecked(gameConf.prefer_expansion_script != 0);
elmTabSystemLast = chkPreferExpansionScript; posY += 60;
btnReport = env->addButton(rect<s32>(posX, posY, posX + 100 * xScale, posY + 30 * yScale), tabSystem, BUTTON_REPORT, dataManager.GetSysString(1800));
elmTabSystemLast = btnReport;
//show scroll //show scroll
s32 tabSystemLastY = elmTabSystemLast->getRelativePosition().LowerRightCorner.Y; s32 tabSystemLastY = elmTabSystemLast->getRelativePosition().LowerRightCorner.Y;
s32 tabSystemHeight = 300 * yScale; s32 tabSystemHeight = 300 * yScale;
...@@ -1806,6 +1809,10 @@ JNIEnv* Game::getJniEnv(){ ...@@ -1806,6 +1809,10 @@ JNIEnv* Game::getJniEnv(){
return android::getJniEnv(appMain); return android::getJniEnv(appMain);
} }
void Game::onReportProblem(){
gameUI->onReportProblem(getJniEnv());
}
#endif #endif
void Game::refreshTexture(){ void Game::refreshTexture(){
gMutex.lock(); gMutex.lock();
......
...@@ -278,6 +278,7 @@ public: ...@@ -278,6 +278,7 @@ public:
irr::gui::IGUIButton* btnReplayMode; irr::gui::IGUIButton* btnReplayMode;
irr::gui::IGUIButton* btnTestMode; irr::gui::IGUIButton* btnTestMode;
irr::gui::IGUIButton* btnDeckEdit; irr::gui::IGUIButton* btnDeckEdit;
irr::gui::IGUIButton* btnReport;
irr::gui::IGUIButton* btnModeExit; irr::gui::IGUIButton* btnModeExit;
//lan //lan
irr::gui::IGUIWindow* wLanWindow; irr::gui::IGUIWindow* wLanWindow;
...@@ -593,6 +594,7 @@ public: ...@@ -593,6 +594,7 @@ public:
#ifdef _IRR_ANDROID_PLATFORM_ #ifdef _IRR_ANDROID_PLATFORM_
ygo::AndroidGameHost *gameHost; ygo::AndroidGameHost *gameHost;
ygo::AndroidGameUI *gameUI; ygo::AndroidGameUI *gameUI;
void onReportProblem();
#endif #endif
private: private:
int touchLeft; int touchLeft;
...@@ -629,6 +631,7 @@ private: ...@@ -629,6 +631,7 @@ private:
#define BUTTON_TEST_MODE 103 #define BUTTON_TEST_MODE 103
#define BUTTON_DECK_EDIT 104 #define BUTTON_DECK_EDIT 104
#define BUTTON_MODE_EXIT 105 #define BUTTON_MODE_EXIT 105
#define BUTTON_REPORT 106
#define LISTBOX_LAN_HOST 110 #define LISTBOX_LAN_HOST 110
#define BUTTON_JOIN_HOST 111 #define BUTTON_JOIN_HOST 111
#define BUTTON_JOIN_CANCEL 112 #define BUTTON_JOIN_CANCEL 112
......
...@@ -430,6 +430,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -430,6 +430,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->deckBuilder.Initialize(); mainGame->deckBuilder.Initialize();
break; break;
} }
case BUTTON_YES: { case BUTTON_YES: {
mainGame->HideElement(mainGame->wQuery); mainGame->HideElement(mainGame->wQuery);
if(prev_operation == BUTTON_DELETE_REPLAY) { if(prev_operation == BUTTON_DELETE_REPLAY) {
......
...@@ -30,6 +30,7 @@ void AndroidGameUI::initMethods(JNIEnv *env) { ...@@ -30,6 +30,7 @@ void AndroidGameUI::initMethods(JNIEnv *env) {
java_attachNativeDevice = env->GetMethodID(clazz, "attachNativeDevice", "(I)V"); java_attachNativeDevice = env->GetMethodID(clazz, "attachNativeDevice", "(I)V");
java_getJoinOptions = env->GetMethodID(clazz, "getJoinOptions", "()Ljava/nio/ByteBuffer;"); java_getJoinOptions = env->GetMethodID(clazz, "getJoinOptions", "()Ljava/nio/ByteBuffer;");
java_playSoundEffect = env->GetMethodID(clazz, "playSoundEffect", "(Ljava/lang/String;)V"); java_playSoundEffect = env->GetMethodID(clazz, "playSoundEffect", "(Ljava/lang/String;)V");
java_onReportProblem = env->GetMethodID(clazz, "onReportProblem", "()V");
env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz);
} }
...@@ -142,4 +143,11 @@ void AndroidGameUI::playSoundEffect(JNIEnv *env, const char *_name) { ...@@ -142,4 +143,11 @@ void AndroidGameUI::playSoundEffect(JNIEnv *env, const char *_name) {
if (name) { if (name) {
env->DeleteLocalRef(name); env->DeleteLocalRef(name);
} }
} }
\ No newline at end of file
void AndroidGameUI::onReportProblem(JNIEnv *env) {
if (!java_onReportProblem) {
return;
}
env->CallVoidMethod(app->activity->clazz, java_onReportProblem);
}
...@@ -25,6 +25,7 @@ namespace ygo { ...@@ -25,6 +25,7 @@ namespace ygo {
jmethodID java_attachNativeDevice; jmethodID java_attachNativeDevice;
jmethodID java_getJoinOptions; jmethodID java_getJoinOptions;
jmethodID java_playSoundEffect; jmethodID java_playSoundEffect;
jmethodID java_onReportProblem;
ANDROID_APP app; ANDROID_APP app;
public: public:
...@@ -58,6 +59,8 @@ namespace ygo { ...@@ -58,6 +59,8 @@ namespace ygo {
void playSoundEffect(JNIEnv *env, const char *name); void playSoundEffect(JNIEnv *env, const char *name);
void onReportProblem(JNIEnv *env);
}; };
} }
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="cn.garymb.ygomobile.lib">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<application>
<activity
android:name="cn.garymb.ygomobile.YGOMobileActivity"
android:clearTaskOnLaunch="true"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="YGOMobile"
android:process=":game"
android:launchMode="singleTop"
android:screenOrientation="sensorLandscape"
android:taskAffinity="cn.garymb.ygomobile.game"
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
android:windowSoftInputMode="adjustPan"
tools:targetApi="honeycomb">
<meta-data
android:name="android.app.lib_name"
android:value="YGOMobile"/>
</activity>
</application>
</manifest>
package cn.garymb.ygodata;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.nio.ByteBuffer;
/**
* @author mabin
*/
public class YGOGameOptions implements Parcelable {
public static final long TIME_OUT = 8 * 1000;
public static final String YGO_GAME_OPTIONS_BUNDLE_TIME = "cn.garymb.ygomobile.ygogameoptions.time";
public static final String YGO_GAME_OPTIONS_BUNDLE_KEY = "cn.garymb.ygomobile.ygogameoptions";
public static final int MAX_BYTE_BUFFER_SIZE = 8192;
public String mServerAddr;
//用户名字
public String mUserName;
public String mRoomName;
public String mRoomPasswd;
//用户密码
public String mUserPassword;
public int mPort;
public int mMode = 0;
public int mRule = 0;
public int mStartLP = 8000;
public int mStartHand = 5;
public int mDrawCount = 1;
public boolean mEnablePriority = false;
public boolean mNoDeckCheck = false;
public boolean mNoDeckShuffle = false;
private boolean isCompleteOptions;
public YGOGameOptions() {
}
public boolean isCompleteOptions() {
return isCompleteOptions;
}
public void setCompleteOptions(boolean isCompleteOptions) {
this.isCompleteOptions = isCompleteOptions;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mServerAddr);
dest.writeString(mUserName);
dest.writeString(mRoomName);
dest.writeString(mRoomPasswd);
dest.writeString(mUserPassword);
dest.writeInt(mPort);
dest.writeInt(mMode);
dest.writeInt(isCompleteOptions ? 1 : 0);
dest.writeInt(mRule);
dest.writeInt(mStartLP);
dest.writeInt(mStartHand);
dest.writeInt(mDrawCount);
dest.writeInt(mEnablePriority ? 1 : 0);
dest.writeInt(mNoDeckCheck ? 1 : 0);
dest.writeInt(mNoDeckShuffle ? 1 : 0);
}
public static final Creator<YGOGameOptions> CREATOR = new Creator<YGOGameOptions>() {
@Override
public YGOGameOptions createFromParcel(Parcel source) {
YGOGameOptions options = new YGOGameOptions();
options.mServerAddr = source.readString();
options.mUserName = source.readString();
options.mRoomName = source.readString();
options.mRoomPasswd = source.readString();
options.mUserPassword = source.readString();
options.mPort = source.readInt();
options.mMode = source.readInt();
options.isCompleteOptions = source.readInt() == 1;
options.mRule = source.readInt();
options.mStartLP = source.readInt();
options.mStartHand = source.readInt();
options.mDrawCount = source.readInt();
options.mEnablePriority = source.readInt() == 1;
options.mNoDeckCheck = source.readInt() == 1;
options.mNoDeckShuffle = source.readInt() == 1;
return options;
}
@Override
public YGOGameOptions[] newArray(int size) {
return new YGOGameOptions[size];
}
};
public String toString() {
StringBuilder builder = new StringBuilder("YGOGameOptions: ");
builder.append("serverAddr: ").append(mServerAddr == null ? "(unspecified)" : mServerAddr).
append(", port: ").append(mPort).
append(", roomName: ").append(mRoomName == null ? "(unspecified)" : mRoomName.toString()).
append(", roomPassword: ").append(mRoomPasswd == null ? "(unspecified)" : mRoomPasswd.toString()).
append(", userName: ").append(mUserName == null ? "(unspecified)" : mUserName.toString()).
append(", mode: ").append(mMode).
append(", isCompleteRequest").append(isCompleteOptions).
append(", rule: ").append(mRule).
append(", startlp: ").append(mStartLP).
append(", startHand: ").append(mStartHand).
append(", drawCount: ").append(mDrawCount).
append(", enablePriority: ").append(mEnablePriority).
append(", noDeckCheck: ").append(mNoDeckCheck).
append(", noDeckShuffle: ").append(mNoDeckShuffle);
return builder.toString();
}
public ByteBuffer toByteBuffer() {
ByteBuffer buffer = ByteBuffer.allocateDirect(MAX_BYTE_BUFFER_SIZE);
putString(buffer, mServerAddr);
putString(buffer, mUserName);
putString(buffer, mRoomName);
putString(buffer, mRoomPasswd);
putString(buffer, mUserPassword);
buffer.putInt(Integer.reverseBytes(mPort));
buffer.putInt(Integer.reverseBytes(mMode));
buffer.putInt(Integer.reverseBytes(isCompleteOptions ? 1 : 0));
if (isCompleteOptions) {
buffer.putInt(Integer.reverseBytes(mRule));
buffer.putInt(Integer.reverseBytes(mStartLP));
buffer.putInt(Integer.reverseBytes(mStartHand));
buffer.putInt(Integer.reverseBytes(mDrawCount));
buffer.putInt(Integer.reverseBytes(mEnablePriority ? 1 : 0));
buffer.putInt(Integer.reverseBytes(mNoDeckCheck ? 1 : 0));
buffer.putInt(Integer.reverseBytes(mNoDeckShuffle ? 1 : 0));
}
return buffer;
}
private void putString(ByteBuffer buffer, String str) {
if (TextUtils.isEmpty(str)) {
buffer.putInt(Integer.reverseBytes(0));
} else {
buffer.putInt(Integer.reverseBytes(str.getBytes().length));
buffer.put(str.getBytes());
}
}
}
package cn.garymb.ygomobile;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import androidx.annotation.Keep;
import java.lang.reflect.Method;
import cn.garymb.ygomobile.interfaces.GameHost;
public abstract class GameApplication extends Application {
private static GameApplication sGameApplication;
private static String sProcessName;
@Override
public void onCreate() {
super.onCreate();
sProcessName = getCurrentProcessName();
sGameApplication = this;
}
public static boolean isGameProcess(){
return sProcessName != null && sProcessName.endsWith(":game");
}
public static String getAppProcessName() {
return sProcessName;
}
@SuppressLint({"PrivateApi", "DiscouragedPrivateApi"})
protected String getCurrentProcessName() {
if (Build.VERSION.SDK_INT >= 28) {
return getProcessName();
}
try {
Class<?> clazz = Class.forName("android.app.ActivityThread");
Method currentProcessName = clazz.getDeclaredMethod("currentProcessName");
return (String) currentProcessName.invoke(null);
} catch (Throwable e) {
Log.w("kk", "currentProcessName", e);
}
int pid = android.os.Process.myPid();
String processName = getPackageName();
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {
if (info.pid == pid) {
processName = info.processName;
break;
}
}
return processName;
}
public static GameApplication get() {
return sGameApplication;
}
@Keep
public abstract GameHost getGameHost();
public static boolean isDebug(){
return get().getGameHost().isDebugMode();
}
/**
* @deprecated
*/
@Keep
public boolean canNdkCash() {
return true;
}
}
package cn.garymb.ygomobile;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.Keep;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public final class NativeInitOptions implements Parcelable {
private static final int BUFFER_MAX_SIZE = 8192;
public int mOpenglVersion;
public boolean mIsSoundEffectEnabled;
//工作目录
public String mWorkPath;
// /data/data/cards.cdb;a.cdb;b.cdb
public final List<String> mDbList;
//pics.zip;scripts.zip;a.zip;b.zip
public final List<String> mArchiveList;
public int mCardQuality;
public boolean mIsFontAntiAliasEnabled;
public boolean mIsPendulumScaleEnabled;
public String mFontFile;
public String mResDir;
public String mImageDir;
public NativeInitOptions() {
mDbList = new ArrayList<>();
mArchiveList = new ArrayList<>();
}
public ByteBuffer toNativeBuffer() {
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_MAX_SIZE);
putInt(buffer, mOpenglVersion);
putInt(buffer, mIsSoundEffectEnabled ? 1 : 0);
putInt(buffer, mCardQuality);
putInt(buffer, mIsFontAntiAliasEnabled ? 1 : 0);
putInt(buffer, mIsPendulumScaleEnabled ? 1 : 0);
putString(buffer, mWorkPath);
putInt(buffer, mDbList.size());
for(String str:mDbList){
putString(buffer, str);
}
putInt(buffer, mArchiveList.size());
for (String str : mArchiveList) {
putString(buffer, str);
}
putString(buffer, mFontFile);
putString(buffer, mResDir);
putString(buffer, mImageDir);
return buffer;
}
@Override
public String toString() {
return "NativeInitOptions{" +
"mOpenglVersion=" + mOpenglVersion +
", mIsSoundEffectEnabled=" + mIsSoundEffectEnabled +
", mWorkPath='" + mWorkPath + '\'' +
", mDbList='" + mDbList + '\'' +
", mArchiveList='" + mArchiveList + '\'' +
", mCardQuality=" + mCardQuality +
", mIsFontAntiAliasEnabled=" + mIsFontAntiAliasEnabled +
", mIsPendulumScaleEnabled=" + mIsPendulumScaleEnabled +
'}';
}
private void putString(ByteBuffer buffer, String str) {
if (TextUtils.isEmpty(str)) {
buffer.putInt(Integer.reverseBytes(0));
} else {
buffer.putInt(Integer.reverseBytes(str.getBytes().length));
buffer.put(str.getBytes());
}
}
@SuppressWarnings("unused")
private void putChar(ByteBuffer buffer, char value) {
Short svalue = (short) value;
buffer.putShort((Short.reverseBytes(svalue)));
}
private void putInt(ByteBuffer buffer, int value) {
buffer.putInt((Integer.reverseBytes(value)));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NativeInitOptions options = (NativeInitOptions) o;
return mOpenglVersion == options.mOpenglVersion &&
mIsSoundEffectEnabled == options.mIsSoundEffectEnabled &&
mCardQuality == options.mCardQuality &&
mIsFontAntiAliasEnabled == options.mIsFontAntiAliasEnabled &&
mIsPendulumScaleEnabled == options.mIsPendulumScaleEnabled &&
Objects.equals(mWorkPath, options.mWorkPath) &&
Objects.equals(mDbList, options.mDbList) &&
Objects.equals(mArchiveList, options.mArchiveList) &&
Objects.equals(mFontFile, options.mFontFile) &&
Objects.equals(mResDir, options.mResDir) &&
Objects.equals(mImageDir, options.mImageDir);
}
@Override
public int hashCode() {
return Objects.hash(mOpenglVersion, mIsSoundEffectEnabled, mWorkPath, mDbList, mArchiveList, mCardQuality, mIsFontAntiAliasEnabled, mIsPendulumScaleEnabled, mFontFile, mResDir, mImageDir);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.mOpenglVersion);
dest.writeByte(this.mIsSoundEffectEnabled ? (byte) 1 : (byte) 0);
dest.writeString(this.mWorkPath);
dest.writeStringList(this.mDbList);
dest.writeStringList(this.mArchiveList);
dest.writeInt(this.mCardQuality);
dest.writeByte(this.mIsFontAntiAliasEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(this.mIsPendulumScaleEnabled ? (byte) 1 : (byte) 0);
dest.writeString(this.mFontFile);
dest.writeString(this.mResDir);
dest.writeString(this.mImageDir);
}
protected NativeInitOptions(Parcel in) {
this.mOpenglVersion = in.readInt();
this.mIsSoundEffectEnabled = in.readByte() != 0;
this.mWorkPath = in.readString();
this.mDbList = in.createStringArrayList();
this.mArchiveList = in.createStringArrayList();
this.mCardQuality = in.readInt();
this.mIsFontAntiAliasEnabled = in.readByte() != 0;
this.mIsPendulumScaleEnabled = in.readByte() != 0;
this.mFontFile = in.readString();
this.mResDir = in.readString();
this.mImageDir = in.readString();
}
public static final Parcelable.Creator<NativeInitOptions> CREATOR = new Parcelable.Creator<NativeInitOptions>() {
@Override
public NativeInitOptions createFromParcel(Parcel source) {
return new NativeInitOptions(source);
}
@Override
public NativeInitOptions[] newArray(int size) {
return new NativeInitOptions[size];
}
};
}
package cn.garymb.ygomobile.core;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;
import androidx.annotation.Keep;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import cn.garymb.ygomobile.GameApplication;
import static android.content.ContentValues.TAG;
public class BpgImage {
@Keep
public static Bitmap getBpgImage(InputStream inputStream, Bitmap.Config config) {
ByteArrayOutputStream outputStream = null;
try {
outputStream = new ByteArrayOutputStream();
byte[] tmp = new byte[4096];
int len = 0;
while ((len = inputStream.read(tmp)) != -1) {
outputStream.write(tmp, 0, len);
}
//解码前
byte[] bpg = outputStream.toByteArray();
return getBpgImage(bpg, config);
} catch (Exception e) {
Log.e(TAG, "zip bpg image", e);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
@Keep
public static Bitmap getBpgImage(byte[] bpg, Bitmap.Config config) {
try {
//解码后
byte[] data = nativeBpgImage(bpg);
int start = 8;
int w = byte2int(Arrays.copyOfRange(data, 0, 4));
int h = byte2int(Arrays.copyOfRange(data, 4, 8));
if (w < 0 || h < 0) {
if (GameApplication.isDebug()) {
Log.e(TAG, "zip image:w=" + w + ",h=" + h);
}
return null;
}
int index = 0;
int[] colors = new int[(data.length - start) / 3];
for (int i = 0; i < colors.length; i++) {
index = start + i * 3;
colors[i] = Color.rgb(byte2uint(data[index + 0]), byte2uint(data[index + 1]), byte2uint(data[index + 2]));
}
return Bitmap.createBitmap(colors, w, h, config);
} catch (Throwable e) {
Log.e(TAG, "zip bpg image", e);
return null;
}
}
private static int byte2uint(byte b) {
int i = b;
if (b < 0) {
i = 0xff + 1 + b;
}
return i;
}
private static int byte2int(byte[] res) {
String str = String.format("%02x%02x%02x%02x", res[3], res[2], res[1], res[0]);
return Integer.parseInt(str, 16);
}
//显示卡图
private static native byte[] nativeBpgImage(byte[] data);
}
package cn.garymb.ygomobile.core;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.nio.ByteBuffer;
import cn.garymb.ygodata.YGOGameOptions;
import cn.garymb.ygomobile.YGOMobileActivity;
import cn.garymb.ygomobile.interfaces.GameConfig;
public class YGOCore {
public static final float GAME_WIDTH = 1024.0f;
public static final float GAME_HEIGHT = 640.0f;
private static final String TAG = "ygomobile";
public static final String CONF_LAST_DECK = "lastdeck";
public static final String CONF_LAST_CATEGORY = "lastcategory";
private static YGOCore sYGOCore;
private static final boolean DISABLE_THREAD = true;
public static YGOCore getInstance() {
if (sYGOCore == null) {
synchronized (YGOCore.class) {
if (sYGOCore == null) {
sYGOCore = new YGOCore();
}
}
}
return sYGOCore;
}
static {
try {
System.loadLibrary("YGOMobile");
} catch (Throwable e) {
//ignore
}
}
private int nativeAndroidDevice = 0;
private HandlerThread mWorker;
private Handler H;
private YGOCore() {
if (!DISABLE_THREAD) {
mWorker = new HandlerThread("ygopro_core_work");
mWorker.start();
H = new Handler(mWorker.getLooper());
}
}
@Keep
public void release() {
if (!DISABLE_THREAD) {
if (mWorker != null) {
mWorker.quitSafely();
mWorker = null;
}
}
}
@Keep
public void setNativeAndroidDevice(int nativeAndroidDevice) {
Log.i(TAG, "setNativeAndroidDevice:" + nativeAndroidDevice);
this.nativeAndroidDevice = nativeAndroidDevice;
}
@Keep
public boolean sendTouchEvent(final int action, final int x, final int y, final int id) {
if (nativeAndroidDevice == 0) {
Log.w(TAG, "sendTouchEvent fail nativeAndroidDevice = 0");
return false;
}
final int eventType = action & MotionEvent.ACTION_MASK;
boolean touchReceived = true;
switch (eventType) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
break;
default:
touchReceived = false;
break;
}
if (!touchReceived) {
return false;
}
if (id != 0) {
return false;
}
if (!DISABLE_THREAD) {
H.post(new Runnable() {
@Override
public void run() {
sendTouchInner(action, x, y, id);
}
});
} else {
sendTouchInner(action, x, y, id);
}
return true;
}
private void sendTouchInner(int action, int x, int y, int id) {
if (nativeAndroidDevice != 0) {
nativeSendTouch(nativeAndroidDevice, action, x, y, id);
}
}
@Keep
public void cancelChain() {
if (nativeAndroidDevice != 0) {
nativeCancelChain(nativeAndroidDevice);
}
}
@Keep
public void ignoreChain(boolean begin) {
if (nativeAndroidDevice != 0) {
nativeIgnoreChain(nativeAndroidDevice, begin);
}
}
@Keep
public void reactChain(boolean begin) {
if (nativeAndroidDevice != 0) {
nativeReactChain(nativeAndroidDevice, begin);
}
}
@Keep
public void insertText(String text) {
if (nativeAndroidDevice != 0) {
nativeInsertText(nativeAndroidDevice, text);
}
}
@Keep
public void setComboBoxSelection(int idx) {
if (nativeAndroidDevice != 0) {
nativeSetComboBoxSelection(nativeAndroidDevice, idx);
}
}
@Keep
public void refreshTexture() {
if (nativeAndroidDevice != 0) {
nativeRefreshTexture(nativeAndroidDevice);
}
}
@Keep
public void setCheckBoxesSelection(int idx) {
if (nativeAndroidDevice != 0) {
nativeSetCheckBoxesSelection(nativeAndroidDevice, idx);
}
}
@Keep
public void joinGame(ByteBuffer options, int length) {
if (nativeAndroidDevice != 0) {
nativeJoinGame(nativeAndroidDevice, options, length);
}
}
public static void startGame(Context activity, @Nullable YGOGameOptions options, @NonNull GameConfig gameConfig) {
Intent intent = new Intent(activity, YGOMobileActivity.class);
if (options != null) {
intent.putExtra(YGOGameOptions.YGO_GAME_OPTIONS_BUNDLE_KEY, options);
intent.putExtra(YGOGameOptions.YGO_GAME_OPTIONS_BUNDLE_TIME, System.currentTimeMillis());
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(GameConfig.EXTRA_CONFIG, gameConfig);
activity.startActivity(intent);
}
//插入文本(大概是发送消息)
private native void nativeInsertText(int device, String text);
//刷新文字
private native void nativeRefreshTexture(int device);
//忽略时点
private native void nativeIgnoreChain(int device, boolean begin);
//强制时点
private native void nativeReactChain(int device, boolean begin);
//取消连锁
private native void nativeCancelChain(int device);
private native void nativeSetCheckBoxesSelection(int device, int idx);
private native void nativeSetComboBoxSelection(int device, int idx);
private native void nativeJoinGame(int device, ByteBuffer buffer, int length);
private native boolean nativeSendTouch(int device, int action, int x, int y, int id);
}
package cn.garymb.ygomobile.interfaces;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.Keep;
import java.util.Objects;
import cn.garymb.ygomobile.NativeInitOptions;
@Keep
public class GameConfig implements Parcelable {
public static final String EXTRA_CONFIG = "ygo_config";
private NativeInitOptions nativeInitOptions;
private boolean lockScreenOrientation;
private boolean sensorRefresh;
private boolean keepScale;
/***
* 隐藏底部导航栏
*/
private boolean immerSiveMode;
private boolean enableSoundEffect;
private int notchHeight;
public int getNotchHeight() {
return notchHeight;
}
public void setNotchHeight(int notchHeight) {
this.notchHeight = notchHeight;
}
public NativeInitOptions getNativeInitOptions() {
return nativeInitOptions;
}
public void setNativeInitOptions(NativeInitOptions nativeInitOptions) {
this.nativeInitOptions = nativeInitOptions;
}
public boolean isLockScreenOrientation() {
return lockScreenOrientation;
}
public void setLockScreenOrientation(boolean lockScreenOrientation) {
this.lockScreenOrientation = lockScreenOrientation;
}
public boolean isSensorRefresh() {
return sensorRefresh;
}
public void setSensorRefresh(boolean sensorRefresh) {
this.sensorRefresh = sensorRefresh;
}
public boolean isImmerSiveMode() {
return immerSiveMode;
}
public void setImmerSiveMode(boolean immerSiveMode) {
this.immerSiveMode = immerSiveMode;
}
public boolean isEnableSoundEffect() {
return enableSoundEffect;
}
public void setEnableSoundEffect(boolean enableSoundEffect) {
this.enableSoundEffect = enableSoundEffect;
}
public boolean isKeepScale() {
return keepScale;
}
public void setKeepScale(boolean keepScale) {
this.keepScale = keepScale;
}
public GameConfig() {
nativeInitOptions = new NativeInitOptions();
lockScreenOrientation = false;
sensorRefresh = true;
immerSiveMode = false;
enableSoundEffect = true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GameConfig config = (GameConfig) o;
return lockScreenOrientation == config.lockScreenOrientation &&
sensorRefresh == config.sensorRefresh &&
keepScale == config.keepScale &&
immerSiveMode == config.immerSiveMode &&
enableSoundEffect == config.enableSoundEffect &&
Objects.equals(nativeInitOptions, config.nativeInitOptions);
}
@Override
public int hashCode() {
return Objects.hash(nativeInitOptions, lockScreenOrientation, sensorRefresh, keepScale, immerSiveMode, enableSoundEffect);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(this.nativeInitOptions, flags);
dest.writeByte(this.lockScreenOrientation ? (byte) 1 : (byte) 0);
dest.writeByte(this.sensorRefresh ? (byte) 1 : (byte) 0);
dest.writeByte(this.keepScale ? (byte) 1 : (byte) 0);
dest.writeByte(this.immerSiveMode ? (byte) 1 : (byte) 0);
dest.writeByte(this.enableSoundEffect ? (byte) 1 : (byte) 0);
dest.writeInt(this.notchHeight);
}
protected GameConfig(Parcel in) {
this.nativeInitOptions = in.readParcelable(NativeInitOptions.class.getClassLoader());
this.lockScreenOrientation = in.readByte() != 0;
this.sensorRefresh = in.readByte() != 0;
this.keepScale = in.readByte() != 0;
this.immerSiveMode = in.readByte() != 0;
this.enableSoundEffect = in.readByte() != 0;
this.notchHeight = in.readInt();
}
public static final Creator<GameConfig> CREATOR = new Creator<GameConfig>() {
@Override
public GameConfig createFromParcel(Parcel source) {
return new GameConfig(source);
}
@Override
public GameConfig[] newArray(int size) {
return new GameConfig[size];
}
};
@Override
public String toString() {
return "GameConfig{" +
"nativeInitOptions=" + nativeInitOptions +
", lockScreenOrientation=" + lockScreenOrientation +
", sensorRefresh=" + sensorRefresh +
", keepScale=" + keepScale +
", immerSiveMode=" + immerSiveMode +
", enableSoundEffect=" + enableSoundEffect +
", notchHeight=" + notchHeight +
'}';
}
}
package cn.garymb.ygomobile.interfaces;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import androidx.annotation.Keep;
import cn.garymb.ygomobile.NativeInitOptions;
import cn.garymb.ygomobile.tool.GameSoundPlayer;
import cn.garymb.ygomobile.tool.NetworkController;
@Keep
public abstract class GameHost implements IGameHost{
private final NetworkController mNetworkController;
public GameHost(Context context) {
mNetworkController = new NetworkController(context);
}
@Override
public int getLocalAddr() {
return mNetworkController.getIPAddress();
}
public abstract AssetManager getGameAsset();
public abstract GameSize getGameSize(Activity activity, GameConfig config);
public boolean isDebugMode(){
return false;
}
public void onBeforeCreate(Activity activity){
}
public void onAfterCreate(Activity activity){
}
public void onGameExit(Activity activity){
}
public void onGameReport(Activity activity, GameConfig config){
}
public abstract void initWindbot(NativeInitOptions options, GameConfig config);
}
package cn.garymb.ygomobile.interfaces;
public class GameSize {
private int width;
private int height;
private int touchX;
private int touchY;
private int fullW;
private int fullH;
private int actW;
private int actH;
public void update(GameSize size) {
synchronized (this) {
this.width = size.width;
this.height = size.height;
this.touchX = size.touchX;
this.touchY = size.touchY;
}
}
public void setTouch(int touchX, int touchY) {
synchronized (this) {
this.touchX = touchX;
this.touchY = touchY;
}
}
public int getWidth() {
synchronized (this) {
return width;
}
}
public int getHeight() {
synchronized (this) {
return height;
}
}
public int getTouchX() {
synchronized (this) {
return touchX;
}
}
public int getTouchY() {
synchronized (this) {
return touchY;
}
}
public int getFullW() {
return fullW;
}
public int getFullH() {
return fullH;
}
public int getActW() {
return actW;
}
public int getActH() {
return actH;
}
public void setScreen(int fullW, int fullH, int actW, int actH) {
this.fullW = fullW;
this.fullH = fullH;
this.actW = actW;
this.actH = actH;
}
public GameSize() {
}
public GameSize(int width, int height, int touchX, int touchY) {
this.width = width;
this.height = height;
this.touchX = touchX < 0 ? 0 : touchX;
this.touchY = touchY < 0 ? 0 : touchY;
}
@Override
public String toString() {
return "GameSize{" +
"width=" + width +
", height=" + height +
", touchX=" + touchX +
", touchY=" + touchY +
", fullW=" + fullW +
", fullH=" + fullH +
", actW=" + actW +
", actH=" + actH +
'}';
}
}
package cn.garymb.ygomobile.interfaces;
import androidx.annotation.Keep;
@Keep
public interface IGameActivity extends IGameUI, IGameHost{
}
package cn.garymb.ygomobile.interfaces;
public interface IGameHost {
String getSetting(String key);
int getIntSetting(String key, int def);
void saveIntSetting(String key, int value);
void saveSetting(String key, String value);
void runWindbot(String cmd);
int getLocalAddr();
}
package cn.garymb.ygomobile.interfaces;
import androidx.annotation.Keep;
import java.nio.ByteBuffer;
@Keep
public interface IGameUI {
int getWindowLeft();
int getWindowTop();
int getWindowWidth();
int getWindowHeight();
void toggleIME(boolean show, String message);
void performHapticFeedback();
void showComboBoxCompat(String[] items, boolean isShow, int mode);
ByteBuffer getInitOptions();
void attachNativeDevice(int device);
ByteBuffer getJoinOptions();
void playSoundEffect(String path);
void onReportProblem();
}
package cn.garymb.ygomobile.tool;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class GameSoundPlayer {
private AssetManager mAssetManager;
private SoundPool mSoundEffectPool;
private final Map<String, Integer> mSoundIdMap;
private boolean mInit = false;
public GameSoundPlayer(AssetManager mAssetManager) {
this.mAssetManager = mAssetManager;
mSoundIdMap = new HashMap<>();
}
@SuppressWarnings("deprecation")
public void initSoundEffectPool() {
synchronized (this) {
if (mInit) {
return;
}
mInit = true;
}
mSoundEffectPool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
AssetManager am = mAssetManager;
String[] sounds = null;
try {
sounds = am.list("sound");
} catch (IOException e) {
e.printStackTrace();
}
if (sounds != null) {
int ret = 0;
String path = null;
for (String sound : sounds) {
path = "sound" + File.separator + sound;
AssetFileDescriptor fd = null;
ret = 0;
try {
fd = am.openFd(path);
ret = mSoundEffectPool.load(fd, 1);
} catch (Throwable e) {
//ignore
} finally {
if (fd != null) {
try {
fd.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ret != 0) {
mSoundIdMap.put(path, ret);
}
}
}
}
}
public void playSoundEffect(String path) {
if (mSoundEffectPool == null) {
return;
}
Integer id = mSoundIdMap.get(path);
if (id != null) {
mSoundEffectPool.play(id, 0.5f, 0.5f, 2, 0, 1.0f);
}
}
public void release() {
synchronized (this) {
if (!mInit) {
return;
}
mInit = false;
}
mSoundIdMap.clear();
if (mSoundEffectPool != null) {
mSoundEffectPool.release();
mSoundEffectPool = null;
}
}
}
package cn.garymb.ygomobile.tool;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
/**
* @author mabin
*/
public final class NetworkController {
private WifiManager mWM;
private ConnectivityManager mCM;
/**
*
*/
public NetworkController(Context context) {
mWM = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mCM = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
}
/**
* @return
* @author: mabin
**/
public boolean isWifiConnected() {
boolean isWifiEnabled = mWM.isWifiEnabled();
NetworkInfo ni = mCM.getActiveNetworkInfo();
if (isWifiEnabled && null != ni && ni.isConnected()
&& ni.getType() == ConnectivityManager.TYPE_WIFI) {
return true;
}
return false;
}
public int getIPAddress() {
if (!isWifiConnected()) {
return -1;
}
WifiInfo wi = mWM.getConnectionInfo();
return wi.getIpAddress();
}
}
package cn.garymb.ygomobile.tool;
import android.content.Context;
import android.os.PowerManager;
public class ScreenKeeper {
//电池管理
private PowerManager mPM;
private PowerManager.WakeLock mLock;
private String TAG = "ScreenKeeper";
public ScreenKeeper(Context context){
mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
}
public void keep(){
if (mLock == null) {
mLock = mPM.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
}
mLock.acquire();
}
public void release(){
if (mLock != null) {
if (mLock.isHeld()) {
mLock.release();
}
}
}
}
/*
* ComboBoxCompat.java
*
* Created on: 2014年3月15日
* Author: mabin
*/
package cn.garymb.ygomobile.widget;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.ViewFlipper;
import cn.garymb.ygomobile.lib.R;
import cn.garymb.ygomobile.widget.wheelview.ArrayWheelAdapter;
import cn.garymb.ygomobile.widget.wheelview.WheelView;
public class ComboBoxCompat extends PopupWindow {
/*change this will affect C++ code, be careful!*/
public static final int COMPAT_GUI_MODE_COMBOBOX = 0;
/*change this will affect C++ code, be careful!*/
public static final int COMPAT_GUI_MODE_CHECKBOXES_PANEL = 1;
private Context mContext;
private WheelView mComboBoxContent;
private Button mSubmitButton;
private Button mCancelButton;
private ViewFlipper mFlipper;
private ArrayWheelAdapter<String> mAdapter;
public ComboBoxCompat(Context context) {
// TODO Auto-generated constructor stub
super(context);
mContext = context;
View menuView = LayoutInflater.from(mContext).inflate(R.layout.combobox_compat_layout, null);
mComboBoxContent = (WheelView) menuView.findViewById(R.id.combobox_content);
mSubmitButton = (Button) menuView.findViewById(R.id.submit);
mCancelButton = (Button) menuView.findViewById(R.id.cancel);
mFlipper = new ViewFlipper(context);
mFlipper.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mFlipper.addView(menuView);
mFlipper.setFlipInterval(6000000);
setContentView(mFlipper);
}
public void setButtonListener(OnClickListener listener) {
mSubmitButton.setOnClickListener(listener);
mCancelButton.setOnClickListener(listener);
}
public void fillContent(String[] items) {
mAdapter = new ArrayWheelAdapter<String>(mContext, items);
mComboBoxContent.setViewAdapter(mAdapter);
this.setWidth(LayoutParams.MATCH_PARENT);
this.setHeight(LayoutParams.WRAP_CONTENT);
this.setFocusable(true);
ColorDrawable dw = new ColorDrawable(0x00000000);
this.setBackgroundDrawable(dw);
this.update();
}
public int getCurrentSelection() {
return mComboBoxContent.getCurrentItem();
}
@Override
public void showAtLocation(View parent, int gravity, int x, int y) {
super.showAtLocation(parent, gravity, x, y);
mFlipper.startFlipping();
}
@Override
public void dismiss() {
// TODO Auto-generated method stub
super.dismiss();
}
}
/*
* EditWindowCompat.java
*
* Created on: 2014年3月15日
* Author: mabin
*/
package cn.garymb.ygomobile.widget;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.PopupWindow;
import android.widget.TextView.OnEditorActionListener;
import cn.garymb.ygomobile.lib.R;
/**
* @author mabin
*
*/
public class EditWindowCompat extends PopupWindow {
private Context mContext;
private ViewGroup mContentView;
private EditText mEditText;
private InputMethodManager mIM;
public EditWindowCompat(Context context) {
super(context);
mContext = context;
mContentView = (ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.text_input_compat_layout, null);
mEditText = (EditText) mContentView.findViewById(R.id.global_input);
mIM = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
setContentView(mContentView);
}
public void fillContent(String hint) {
mEditText.setText(hint);
this.setWidth(LayoutParams.MATCH_PARENT);
this.setHeight(LayoutParams.WRAP_CONTENT);
this.setFocusable(true);
this.update();
}
/* (non-Javadoc)
* @see android.widget.PopupWindow#showAtLocation(android.view.View, int, int, int)
*/
@Override
public void showAtLocation(View parent, int gravity, int x, int y) {
// TODO Auto-generated method stub
mEditText.requestFocus();
mIM.showSoftInput(mEditText, 0);
super.showAtLocation(parent, gravity, x, y);
}
/* (non-Javadoc)
* @see android.widget.PopupWindow#dismiss()
*/
@Override
public void dismiss() {
// TODO Auto-generated method stub
mEditText.clearFocus();
mIM.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
super.dismiss();
}
public void setEditActionListener(OnEditorActionListener listener) {
mEditText.setOnEditorActionListener(listener);
}
}
/*
Copyright 2011 jawsware international
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cn.garymb.ygomobile.widget.overlay;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import cn.garymb.ygomobile.lib.R;
public class OverlayOvalView extends OverlayView implements View.OnClickListener {
/**
* @author mabin
*
*/
public interface OnDuelOptionsSelectListener {
void onDuelOptionsSelected(int mode, boolean action);
}
private TextView mInfo;
private OnDuelOptionsSelectListener mListener;
public OverlayOvalView(Context context) {
super(context, R.layout.overlay_oval);
}
@Override
protected void onInflateView() {
mInfo = (TextView) this.findViewById(R.id.textview_info);
mInfo.setOnClickListener(this);
}
public void setDuelOpsListener(OnDuelOptionsSelectListener listener) {
mListener = listener;
}
@Override
public void onClick(View v) {
mListener.onDuelOptionsSelected(MODE_CANCEL_CHAIN_OPTIONS, true);
}
}
package cn.garymb.ygomobile.widget.overlay;
import android.content.Context;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;
import cn.garymb.ygomobile.lib.R;
import cn.garymb.ygomobile.widget.overlay.OverlayOvalView.OnDuelOptionsSelectListener;
public class OverlayRectView extends OverlayView implements OnCheckedChangeListener {
private ToggleButton mReactButton;
private ToggleButton mIgnoreButton;
private OnDuelOptionsSelectListener mListener;
public OverlayRectView(Context context) {
super(context, R.layout.overlay_rect);
}
@Override
protected void onInflateView() {
super.onInflateView();
mIgnoreButton= (ToggleButton) findViewById(R.id.overlay_ignore);
mIgnoreButton.setOnCheckedChangeListener(this);
mReactButton = (ToggleButton) findViewById(R.id.overlay_react);
mReactButton.setOnCheckedChangeListener(this);
}
public void setDuelOpsListener(OnDuelOptionsSelectListener listener) {
mListener = listener;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.equals(mIgnoreButton)) {
if (isChecked && mReactButton.isChecked()) {
mReactButton.setChecked(false);
mListener.onDuelOptionsSelected(MODE_REACT_CHAIN_OPTION, false);
}
mListener.onDuelOptionsSelected(MODE_IGNORE_CHAIN_OPTION, isChecked);
} else {
if (isChecked && mIgnoreButton.isChecked()) {
mIgnoreButton.setChecked(false);
mListener.onDuelOptionsSelected(MODE_IGNORE_CHAIN_OPTION, false);
}
mListener.onDuelOptionsSelected(MODE_REACT_CHAIN_OPTION, isChecked);
}
}
}
/*
Copyright 2011 jawsware international
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cn.garymb.ygomobile.widget.overlay;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;
public abstract class OverlayView extends RelativeLayout {
public static final int MODE_CANCEL_CHAIN_OPTIONS = 0;
public static final int MODE_REFRESH_OPTION = 1;
public static final int MODE_IGNORE_CHAIN_OPTION = 2;
public static final int MODE_REACT_CHAIN_OPTION = 3;
protected WindowManager.LayoutParams layoutParams;
private int layoutResId;
private boolean mIsAdded = false;
public OverlayView(Context context, int layoutResId) {
super(context);
this.layoutResId = layoutResId;
this.setLongClickable(true);
this.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return onTouchEvent_LongPress();
}
});
inflateView();
}
/*
* (non-Javadoc)
*
* @see android.view.View#getLayoutParams()
*/
@Override
public android.view.ViewGroup.LayoutParams getLayoutParams() {
// TODO Auto-generated method stub
return layoutParams;
}
private void setupLayoutParams(int x, int y) {
layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT>=19?
WindowManager.LayoutParams.TYPE_TOAST:WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
layoutParams.y = y;
layoutParams.x = x;
onSetupLayoutParams();
}
protected void onSetupLayoutParams() {
// Override this to modify the initial LayoutParams. Be sure to call
// super.setupLayoutParams() first.
}
private void inflateView() {
// Inflates the layout resource, sets up the LayoutParams and adds the
// View to the WindowManager service.
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(layoutResId, this);
onInflateView();
}
protected void onInflateView() {
// Override this to make calls to findViewById() to setup references to
// the views that were inflated.
// This is called automatically when the object is created right after
// the resource is inflated.
}
public boolean isVisible() {
// Override this method to control when the Overlay is visible without
// destroying it.
return true;
}
public void refreshLayout() {
// Call this to force the updating of the view's layout.
if (isVisible()) {
removeAllViews();
inflateView();
onSetupLayoutParams();
((WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE)).updateViewLayout(this,
layoutParams);
refresh();
}
}
protected void addView(int x, int y) {
setupLayoutParams(x, y);
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
.addView(this, layoutParams);
super.setVisibility(View.GONE);
}
public void showAtScreen(int x, int y) {
if (!mIsAdded) {
addView(x, y);
refresh();
mIsAdded = true;
}
}
public void removeFromScreen() {
if (mIsAdded) {
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
.removeView(this);
mIsAdded = false;
}
}
public void refresh() {
// Call this to update the contents of the Overlay.
if (!isVisible()) {
setVisibility(View.GONE);
} else {
setVisibility(View.VISIBLE);
refreshViews();
}
}
protected void refreshViews() {
// Override this method to refresh the views inside of the Overlay. Only
// called when Overlay is visible.
}
protected boolean showNotificationHidden() {
// Override this to configure the notification to remain even when the
// overlay is invisible.
return true;
}
protected boolean onVisibilityToChange(int visibility) {
// Catch changes to the Overlay's visibility in order to animate
return true;
}
protected View animationView() {
return this;
}
public void hide() {
// Set visibility, but bypass onVisibilityToChange()
super.setVisibility(View.GONE);
}
public void show() {
// Set visibility, but bypass onVisibilityToChange()
super.setVisibility(View.VISIBLE);
}
@Override
public void setVisibility(int visibility) {
if (getVisibility() != visibility) {
if (onVisibilityToChange(visibility)) {
super.setVisibility(visibility);
}
}
}
protected int getLeftOnScreen() {
int[] location = new int[2];
getLocationOnScreen(location);
return location[0];
}
protected int getTopOnScreen() {
int[] location = new int[2];
getLocationOnScreen(location);
return location[1];
}
protected boolean isInside(View view, int x, int y) {
// Use this to test if the X, Y coordinates of the MotionEvent are
// inside of the View specified.
int[] location = new int[2];
view.getLocationOnScreen(location);
if (x >= location[0]) {
if (x <= location[0] + view.getWidth()) {
if (y >= location[1]) {
if (y <= location[1] + view.getHeight()) {
return true;
}
}
}
}
return false;
}
protected void onTouchEvent_Up(MotionEvent event) {
}
protected void onTouchEvent_Move(MotionEvent event) {
}
protected void onTouchEvent_Press(MotionEvent event) {
}
protected void onTouchEvent_Cancel(MotionEvent event) {
}
public boolean onTouchEvent_LongPress() {
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
onTouchEvent_Press(event);
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
onTouchEvent_Up(event);
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
onTouchEvent_Move(event);
} else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
onTouchEvent_Cancel(event);
}
return super.onTouchEvent(event);
}
}
package cn.garymb.ygomobile.widget.wheelview;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import java.util.LinkedList;
import java.util.List;
/**
* Abstract Wheel adapter.
*/
public abstract class AbstractWheelAdapter implements WheelViewAdapter {
// Observers
private List<DataSetObserver> datasetObservers;
public View getEmptyItem(View convertView, ViewGroup parent) {
return null;
}
public void registerDataSetObserver(DataSetObserver observer) {
if (datasetObservers == null) {
datasetObservers = new LinkedList<DataSetObserver>();
}
datasetObservers.add(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
if (datasetObservers != null) {
datasetObservers.remove(observer);
}
}
/**
* Notifies observers about data changing
*/
protected void notifyDataChangedEvent() {
if (datasetObservers != null) {
for (DataSetObserver observer : datasetObservers) {
observer.onChanged();
}
}
}
/**
* Notifies observers about invalidating data
*/
protected void notifyDataInvalidatedEvent() {
if (datasetObservers != null) {
for (DataSetObserver observer : datasetObservers) {
observer.onInvalidated();
}
}
}
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
/*
* Copyright 2011 Yuri Kanivets
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Abstract wheel adapter provides common functionality for adapters.
*/
public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {
/** Text view resource. Used as a default view for adapter. */
public static final int TEXT_VIEW_ITEM_RESOURCE = -1;
/** No resource constant. */
protected static final int NO_RESOURCE = 0;
/** Default text color */
public static final int DEFAULT_TEXT_COLOR = 0xFF101010;
/** Default text color */
public static final int LABEL_COLOR = 0xFF700070;
public static final int CONFIG_TEXT_COLOR = 0xFF6699ff;
/** Default text size */
public static final int DEFAULT_TEXT_SIZE = 24;
// Text settings
private int textColor = DEFAULT_TEXT_COLOR;
private int textSize = DEFAULT_TEXT_SIZE;
private String textType = "";
// Current context
protected Context context;
// Layout inflater
protected LayoutInflater inflater;
// Items resources
protected int itemResourceId;
protected int itemTextResourceId;
// Empty items resources
protected int emptyItemResourceId;
public String getTextType() {
return textType;
}
public void setTextType(String textType) {
this.textType = textType;
}
/**
* Constructor
*
* @param context
* the current context
*/
protected AbstractWheelTextAdapter(Context context) {
this(context, TEXT_VIEW_ITEM_RESOURCE);
}
/**
* Constructor
*
* @param context
* the current context
* @param itemResource
* the resource ID for a layout file containing a TextView to use
* when instantiating items views
*/
protected AbstractWheelTextAdapter(Context context, int itemResource) {
this(context, itemResource, NO_RESOURCE);
}
/**
* Constructor
*
* @param context
* the current context
* @param itemResource
* the resource ID for a layout file containing a TextView to use
* when instantiating items views
* @param itemTextResource
* the resource ID for a text view in the item layout
*/
protected AbstractWheelTextAdapter(Context context, int itemResource,
int itemTextResource) {
this.context = context;
itemResourceId = itemResource;
itemTextResourceId = itemTextResource;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* Gets text color
*
* @return the text color
*/
public int getTextColor() {
return textColor;
}
/**
* Sets text color
*
* @param textColor
* the text color to set
*/
public void setTextColor(int textColor) {
this.textColor = textColor;
}
/**
* Gets text size
*
* @return the text size
*/
public int getTextSize() {
return textSize;
}
/**
* Sets text size
*
* @param textSize
* the text size to set
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
/**
* Gets resource Id for items views
*
* @return the item resource Id
*/
public int getItemResource() {
return itemResourceId;
}
/**
* Sets resource Id for items views
*
* @param itemResourceId
* the resource Id to set
*/
public void setItemResource(int itemResourceId) {
this.itemResourceId = itemResourceId;
}
/**
* Gets resource Id for text view in item layout
*
* @return the item text resource Id
*/
public int getItemTextResource() {
return itemTextResourceId;
}
/**
* Sets resource Id for text view in item layout
*
* @param itemTextResourceId
* the item text resource Id to set
*/
public void setItemTextResource(int itemTextResourceId) {
this.itemTextResourceId = itemTextResourceId;
}
/**
* Gets resource Id for empty items views
*
* @return the empty item resource Id
*/
public int getEmptyItemResource() {
return emptyItemResourceId;
}
/**
* Sets resource Id for empty items views
*
* @param emptyItemResourceId
* the empty item resource Id to set
*/
public void setEmptyItemResource(int emptyItemResourceId) {
this.emptyItemResourceId = emptyItemResourceId;
}
/**
* Returns text for specified item
*
* @param index
* the item index
* @return the text of specified items
*/
protected abstract CharSequence getItemText(int index);
public View getItem(int index, View convertView, ViewGroup parent) {
if (index >= 0 && index < getItemsCount()) {
if (convertView == null) {
convertView = getView(itemResourceId, parent);
}
TextView textView = getTextView(convertView, itemTextResourceId);
textView.setPadding(0, 6, 0, 6);
if (textView != null) {
CharSequence text = getItemText(index);
if (text == null) {
text = "";
}
textView.setText(text);
if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
configureTextView(textView);
}
}
return convertView;
}
return null;
}
@Override
public View getEmptyItem(View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getView(emptyItemResourceId, parent);
}
if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE
&& convertView instanceof TextView) {
configureTextView((TextView) convertView);
}
return convertView;
}
/**
* Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.
*
* @param view
* the text view to be configured
*/
protected void configureTextView(TextView view) {
view.setTextColor(textColor);
view.setGravity(Gravity.CENTER);
view.setTextSize(textSize);
view.setLines(1);
view.setText(view.getText()+textType);
view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
}
/**
* Loads a text view from view
*
* @param view
* the text view or layout containing it
* @param textResource
* the text resource Id in layout
* @return the loaded text view
*/
private TextView getTextView(View view, int textResource) {
TextView text = null;
try {
if (textResource == NO_RESOURCE && view instanceof TextView) {
text = (TextView) view;
} else if (textResource != NO_RESOURCE) {
text = (TextView) view.findViewById(textResource);
}
} catch (ClassCastException e) {
Log.e("AbstractWheelAdapter",
"You must supply a resource ID for a TextView");
throw new IllegalStateException(
"AbstractWheelAdapter requires the resource ID to be a TextView",
e);
}
return text;
}
/**
* Loads view from resources
*
* @param resource
* the resource Id
* @return the loaded view or null if resource is not set
*/
private View getView(int resource, ViewGroup parent) {
switch (resource) {
case NO_RESOURCE:
return null;
case TEXT_VIEW_ITEM_RESOURCE:
return new TextView(context);
default:
return inflater.inflate(resource, parent, false);
}
}
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
import android.content.Context;
/**
* Adapter class for old wheel adapter (deprecated WheelAdapter class).
*
* @deprecated Will be removed soon
*/
public class AdapterWheel extends AbstractWheelTextAdapter {
// Source adapter
private WheelAdapter adapter;
/**
* Constructor
*
* @param context
* the current context
* @param adapter
* the source adapter
*/
public AdapterWheel(Context context, WheelAdapter adapter) {
super(context);
this.adapter = adapter;
}
/**
* Gets original adapter
*
* @return the original adapter
*/
public WheelAdapter getAdapter() {
return adapter;
}
public int getItemsCount() {
return adapter.getItemsCount();
}
@Override
protected CharSequence getItemText(int index) {
return adapter.getItem(index);
}
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
import android.content.Context;
/**
* The simple Array wheel adapter
*
* @param <T>
* the element type
*/
public class ArrayWheelAdapter<T> extends AbstractWheelTextAdapter {
// items
private T items[];
/**
* Constructor
*
* @param context
* the current context
* @param items
* the items
*/
public ArrayWheelAdapter(Context context, T items[]) {
super(context);
// setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);
this.items = items;
}
@Override
public CharSequence getItemText(int index) {
if (index >= 0 && index < items.length) {
T item = items[index];
if (item instanceof CharSequence) {
return (CharSequence) item;
}
return item.toString();
}
return null;
}
public int getItemsCount() {
return items.length;
}
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
public class ItemsRange {
// First item number
private int first;
// Items count
private int count;
/**
* Default constructor. Creates an empty range
*/
public ItemsRange() {
this(0, 0);
}
/**
* Constructor
*
* @param first
* the number of first item
* @param count
* the count of items
*/
public ItemsRange(int first, int count) {
this.first = first;
this.count = count;
}
/**
* Gets number of first item
*
* @return the number of the first item
*/
public int getFirst() {
return first;
}
/**
* Gets number of last item
*
* @return the number of last item
*/
public int getLast() {
return getFirst() + getCount() - 1;
}
/**
* Get items count
*
* @return the count of items
*/
public int getCount() {
return count;
}
/**
* Tests whether item is contained by range
*
* @param index
* the item number
* @return true if item is contained
*/
public boolean contains(int index) {
return index >= getFirst() && index <= getLast();
}
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
public interface OnWheelChangedListener {
void onChanged(WheelView wheel, int oldValue, int newValue);
}
package cn.garymb.ygomobile.widget.wheelview;
public interface OnWheelClickedListener {
/**
* Callback method to be invoked when current item clicked
*
* @param wheel
* the wheel view
* @param itemIndex
* the index of clicked item
*/
void onItemClicked(WheelView wheel, int itemIndex);
}
package cn.garymb.ygomobile.widget.wheelview;
public interface OnWheelScrollListener {
/**
* Callback method to be invoked when scrolling started.
*
* @param wheel
* the wheel view whose state has changed.
*/
void onScrollingStarted(WheelView wheel);
/**
* Callback method to be invoked when scrolling ended.
*
* @param wheel
* the wheel view whose state has changed.
*/
void onScrollingFinished(WheelView wheel);
}
package cn.garymb.ygomobile.widget.wheelview;
public interface WheelAdapter {
/**
* Gets items count
*
* @return the count of wheel items
*/
public int getItemsCount();
/**
* Gets a wheel item by index.
*
* @param index
* the item index
* @return the wheel item text or null
*/
public String getItem(int index);
/**
* Gets maximum item length. It is used to determine the wheel width. If -1
* is returned there will be used the default wheel width.
*
* @return the maximum item length or -1
*/
public int getMaximumLength();
}
\ No newline at end of file
package cn.garymb.ygomobile.widget.wheelview;
import android.view.View;
import android.widget.LinearLayout;
import java.util.LinkedList;
import java.util.List;
/**
* Recycle stores wheel items to reuse.
*/
public class WheelRecycle {
// Cached items
private List<View> items;
// Cached empty items
private List<View> emptyItems;
// Wheel view
private WheelView wheel;
/**
* Constructor
*
* @param wheel
* the wheel view
*/
public WheelRecycle(WheelView wheel) {
this.wheel = wheel;
}
/**
* Recycles items from specified layout. There are saved only items not
* included to specified range. All the cached items are removed from
* original layout.
*
* @param layout
* the layout containing items to be cached
* @param firstItem
* the number of first item in layout
* @param range
* the range of current wheel items
* @return the new value of first item number
*/
public int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {
int index = firstItem;
for (int i = 0; i < layout.getChildCount();) {
if (!range.contains(index)) {
recycleView(layout.getChildAt(i), index);
layout.removeViewAt(i);
if (i == 0) { // first item
firstItem++;
}
} else {
i++; // go to next item
}
index++;
}
return firstItem;
}
/**
* Gets item view
*
* @return the cached view
*/
public View getItem() {
return getCachedView(items);
}
/**
* Gets empty item view
*
* @return the cached empty view
*/
public View getEmptyItem() {
return getCachedView(emptyItems);
}
/**
* Clears all views
*/
public void clearAll() {
if (items != null) {
items.clear();
}
if (emptyItems != null) {
emptyItems.clear();
}
}
/**
* Adds view to specified cache. Creates a cache list if it is null.
*
* @param view
* the view to be cached
* @param cache
* the cache list
* @return the cache list
*/
private List<View> addView(View view, List<View> cache) {
if (cache == null) {
cache = new LinkedList<View>();
}
cache.add(view);
return cache;
}
/**
* Adds view to cache. Determines view type (item view or empty one) by
* index.
*
* @param view
* the view to be cached
* @param index
* the index of view
*/
private void recycleView(View view, int index) {
int count = wheel.getViewAdapter().getItemsCount();
if ((index < 0 || index >= count) && !wheel.isCyclic()) {
// empty view
emptyItems = addView(view, emptyItems);
} else {
while (index < 0) {
index = count + index;
}
index %= count;
items = addView(view, items);
}
}
/**
* Gets view from specified cache.
*
* @param cache
* the cache
* @return the first view from cache.
*/
private View getCachedView(List<View> cache) {
if (cache != null && cache.size() > 0) {
View view = cache.get(0);
cache.remove(0);
return view;
}
return null;
}
}
package cn.garymb.ygomobile.widget.wheelview;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import android.widget.Scroller;
/**
* Scroller class handles scrolling events and updates the
*/
public class WheelScroller {
/**
* Scrolling listener interface
*/
public interface ScrollingListener {
/**
* Scrolling callback called when scrolling is performed.
*
* @param distance
* the distance to scroll
*/
void onScroll(int distance);
/**
* Starting callback called when scrolling is started
*/
void onStarted();
/**
* Finishing callback called after justifying
*/
void onFinished();
/**
* Justifying callback called to justify a view when scrolling is ended
*/
void onJustify();
}
/** Scrolling duration */
private static final int SCROLLING_DURATION = 400;
/** Minimum delta for scrolling */
public static final int MIN_DELTA_FOR_SCROLLING = 1;
// Listener
private ScrollingListener listener;
// Context
private Context context;
// Scrolling
private GestureDetector gestureDetector;
private Scroller scroller;
private int lastScrollY;
private float lastTouchedY;
private boolean isScrollingPerformed;
/**
* Constructor
*
* @param context
* the current context
* @param listener
* the scrolling listener
*/
public WheelScroller(Context context, ScrollingListener listener) {
gestureDetector = new GestureDetector(context, gestureListener);
gestureDetector.setIsLongpressEnabled(false);
scroller = new Scroller(context);
this.listener = listener;
this.context = context;
}
/**
* Set the the specified scrolling interpolator
*
* @param interpolator
* the interpolator
*/
public void setInterpolator(Interpolator interpolator) {
scroller.forceFinished(true);
scroller = new Scroller(context, interpolator);
}
/**
* Scroll the wheel
*
* @param distance
* the scrolling distance
* @param time
* the scrolling duration
*/
public void scroll(int distance, int time) {
scroller.forceFinished(true);
lastScrollY = 0;
scroller.startScroll(0, 0, 0, distance, time != 0 ? time
: SCROLLING_DURATION);
setNextMessage(MESSAGE_SCROLL);
startScrolling();
}
/**
* Stops scrolling
*/
public void stopScrolling() {
scroller.forceFinished(true);
}
/**
* Handles Touch event
*
* @param event
* the motion event
* @return
*/
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastTouchedY = event.getY();
scroller.forceFinished(true);
clearMessages();
break;
case MotionEvent.ACTION_MOVE:
// perform scrolling
int distanceY = (int) (event.getY() - lastTouchedY);
if (distanceY != 0) {
startScrolling();
listener.onScroll(distanceY);
lastTouchedY = event.getY();
}
break;
}
if (!gestureDetector.onTouchEvent(event)
&& event.getAction() == MotionEvent.ACTION_UP) {
justify();
}
return true;
}
// gesture listener
private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// Do scrolling in onTouchEvent() since onScroll() are not call
// immediately
// when user touch and move the wheel
return true;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
lastScrollY = 0;
final int maxY = 0x7FFFFFFF;
final int minY = -maxY;
scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY,
maxY);
setNextMessage(MESSAGE_SCROLL);
return true;
}
};
// Messages
private final int MESSAGE_SCROLL = 0;
private final int MESSAGE_JUSTIFY = 1;
/**
* Set next message to queue. Clears queue before.
*
* @param message
* the message to set
*/
private void setNextMessage(int message) {
clearMessages();
animationHandler.sendEmptyMessage(message);
}
/**
* Clears messages from queue
*/
private void clearMessages() {
animationHandler.removeMessages(MESSAGE_SCROLL);
animationHandler.removeMessages(MESSAGE_JUSTIFY);
}
// animation handler
private Handler animationHandler = new Handler() {
public void handleMessage(Message msg) {
scroller.computeScrollOffset();
int currY = scroller.getCurrY();
int delta = lastScrollY - currY;
lastScrollY = currY;
if (delta != 0) {
listener.onScroll(delta);
}
// scrolling is not finished when it comes to final Y
// so, finish it manually
if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
currY = scroller.getFinalY();
scroller.forceFinished(true);
}
if (!scroller.isFinished()) {
animationHandler.sendEmptyMessage(msg.what);
} else if (msg.what == MESSAGE_SCROLL) {
justify();
} else {
finishScrolling();
}
}
};
/**
* Justifies wheel
*/
private void justify() {
listener.onJustify();
setNextMessage(MESSAGE_JUSTIFY);
}
/**
* Starts scrolling
*/
private void startScrolling() {
if (!isScrollingPerformed) {
isScrollingPerformed = true;
listener.onStarted();
}
}
/**
* Finishes scrolling
*/
void finishScrolling() {
if (isScrollingPerformed) {
listener.onFinished();
isScrollingPerformed = false;
}
}
}
package cn.garymb.ygomobile.widget.wheelview;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
/**
* Wheel items adapter interface
*/
public interface WheelViewAdapter {
/**
* Gets items count
*
* @return the count of wheel items
*/
public int getItemsCount();
/**
* Get a View that displays the data at the specified position in the data
* set
*
* @param index
* the item index
* @param convertView
* the old view to reuse if possible
* @param parent
* the parent that this view will eventually be attached to
* @return the wheel item View
*/
public View getItem(int index, View convertView, ViewGroup parent);
/**
* Get a View that displays an empty wheel item placed before the first or
* after the last wheel item.
*
* @param convertView
* the old view to reuse if possible
* @param parent
* the parent that this view will eventually be attached to
* @return the empty item View
*/
public View getEmptyItem(View convertView, ViewGroup parent);
/**
* Register an observer that is called when changes happen to the data used
* by this adapter.
*
* @param observer
* the observer to be registered
*/
public void registerDataSetObserver(DataSetObserver observer);
/**
* Unregister an observer that has previously been registered
*
* @param observer
* the observer to be unregistered
*/
void unregisterDataSetObserver(DataSetObserver observer);
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@android:color/white" />
<item android:state_activated="true" android:color="@android:color/white" />
<item android:color="#585858" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@color/navigator_dir_text_color_selected" />
<item android:color="@android:color/white" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="@drawable/mm_title_act_btn_focused" />
<item android:state_pressed="true" android:drawable="@drawable/mm_title_act_btn_pressed" />
<item android:state_selected="true" android:drawable="@drawable/mm_title_act_btn_pressed" />
<item android:drawable="@drawable/mm_title_act_btn_normal" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:drawable="@drawable/mm_title_btn_focused" />
<item android:state_pressed="true" android:drawable="@drawable/mm_title_btn_pressed" />
<item android:state_selected="true" android:drawable="@drawable/mm_title_btn_pressed" />
<item android:drawable="@drawable/mm_title_btn_normal" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@drawable/overlay_internal_pressed" />
<item android:drawable="@drawable/overlay_internal_normal" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/less_trasparent_dark_purple"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/dark_purple"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@drawable/overlay_rect_state" />
<item android:state_selected="true" android:drawable="@drawable/overlay_rect_state" />
<item android:state_checked="true" android:drawable="@drawable/overlay_rect_state" />
<item android:drawable="@drawable/overlay_rect_normal" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="2dp"/>
<solid
android:color="@color/less_trasparent_dark_purple"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="2dp"/>
<solid
android:color="@color/dark_purple"/>
</shape>
<?xml version="1.0" encoding="UTF-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<gradient
android:angle="90.0"
android:centerColor="#ffdddddd"
android:endColor="#ff333333"
android:startColor="#ff333333"/>
<stroke
android:width="1.0dip"
android:color="#ff333333"/>
</shape>
</item>
<item
android:bottom="1.0dip"
android:left="4.0dip"
android:right="4.0dip"
android:top="1.0dip">
<shape android:shape="rectangle">
<gradient
android:angle="90.0"
android:centerColor="#ffFCFCFC"
android:endColor="#ffFCFCFC"
android:startColor="#ffFCFCFC"/>
</shape>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/combobox_content_layout"
android:background="#ff424542"
android:orientation="horizontal" >
<TextView
android:id="@+id/combobox_category_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:text="@string/combobox_choose_item"
android:textColor="@android:color/white" />
<Button
android:id="@+id/cancel"
android:layout_width="80dip"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="@drawable/mm_title_btn_right"
android:text="@android:string/cancel"
android:textColor="@android:color/white" />
<Button
android:id="@+id/submit"
android:layout_width="80dip"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_gravity="right"
android:background="@drawable/mm_title_act_btn"
android:text="@android:string/ok"
android:textColor="@android:color/white" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/combobox_content_layout"
android:layout_width="fill_parent"
android:layout_height="220dip"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="220dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="15dip"
android:gravity="center"
android:orientation="horizontal" >
<cn.garymb.ygomobile.widget.wheelview.WheelView
android:id="@+id/combobox_content"
android:layout_width="0.0dip"
android:layout_height="fill_parent"
android:layout_weight="1" />
</LinearLayout>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="220.0dip"
android:layout_gravity="center"
android:background="@drawable/com_ttshrk_view_scroll_picker_background" >
</FrameLayout>
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp" >
<TextView
android:id="@+id/textview_info"
android:layout_width="60dip"
android:layout_height="60dip"
android:layout_centerInParent="true"
android:background="@drawable/overlay_internal"
android:clickable="false"
android:gravity="center"
android:text="@android:string/cancel"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/text_color_list" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp" >
<ToggleButton
android:id="@+id/overlay_ignore"
android:layout_width="@dimen/chain_control_button_width"
android:layout_height="@dimen/chain_control_button_height"
android:layout_alignParentTop="true"
android:background="@drawable/overlay_rect"
android:textSize="12sp"
android:clickable="true"
android:textOn="@string/ignore_chain"
android:textOff="@string/ignore_chain"
android:textColor="@color/text_color_list"
android:gravity="center" >
</ToggleButton>
<ToggleButton
android:id="@+id/overlay_react"
android:layout_width="@dimen/chain_control_button_width"
android:layout_height="@dimen/chain_control_button_height"
android:layout_marginTop="@dimen/chain_control_margin"
android:layout_below="@id/overlay_ignore"
android:background="@drawable/overlay_rect"
android:textSize="12sp"
android:clickable="true"
android:textOn="@string/react_chain"
android:textOff="@string/react_chain"
android:textColor="@color/text_color_list"
android:gravity="center" >
</ToggleButton>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:orientation="vertical" >
<EditText
android:id="@+id/global_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLength="128"
android:singleLine="true"
android:textColor="#FFFFFF"
android:textCursorDrawable="@null" >
</EditText>
</LinearLayout>
</ScrollView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="combobox_choose_item">请选择其中一个</string>
<string name="ignore_chain">忽略时点</string>
<string name="react_chain">显示时点</string>
<string name="refresh_textures">刷新界面</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="combobox_choose_item">请选择其中一个</string>
<string name="ignore_chain">忽略时点</string>
<string name="react_chain">显示时点</string>
<string name="refresh_textures">刷新界面</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="trasparent_dark_purple">#669933CC</color>
<color name="dark_purple">#9933CC</color>
<color name="navigator_dir_text_color">#666666</color>
<color name="navigator_dir_text_color_selected">#ff8a00</color>
<color name="less_trasparent_dark_purple">#339933CC</color>
<color name="dark_trasparent_dark_purple">#999933CC</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="chain_control_button_width">70dip</dimen>
<dimen name="chain_control_button_height">30dip</dimen>
<dimen name="chain_control_margin">10dip</dimen>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="combobox_choose_item">Select one item</string>
<string name="ignore_chain">Ignore All Timing</string>
<string name="react_chain">Show All Timing</string>
<string name="refresh_textures">Refresh Textures</string>
</resources>
\ No newline at end of file
...@@ -500,6 +500,7 @@ ...@@ -500,6 +500,7 @@
!system 1624 投掷骰子结果: !system 1624 投掷骰子结果:
#tips #tips
!system 1700 可以用鼠标右键%ls !system 1700 可以用鼠标右键%ls
!system 1800 问题反馈
#victory reason #victory reason
!victory 0x0 投降 !victory 0x0 投降
!victory 0x1 基本分变成0 !victory 0x1 基本分变成0
......
...@@ -8,8 +8,8 @@ android { ...@@ -8,8 +8,8 @@ android {
applicationId "cn.garymb.ygomobile" applicationId "cn.garymb.ygomobile"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
versionCode 352001017 versionCode 352001025
versionName "3.5.2" versionName "3.5.2.2"
flavorDimensions "versionCode" flavorDimensions "versionCode"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
ndk { ndk {
......
...@@ -195,7 +195,6 @@ ...@@ -195,7 +195,6 @@
<!--android:priority="1000"--> <!--android:priority="1000"-->
<service <service
android:name="cn.garymb.ygomobile.ui.plus.ServiceDuelAssistant" android:name="cn.garymb.ygomobile.ui.plus.ServiceDuelAssistant"
android:process=":game"
android:priority="1000" /> android:priority="1000" />
</application> </application>
......
...@@ -16,6 +16,7 @@ import com.yuyh.library.imgsel.common.ImageLoader; ...@@ -16,6 +16,7 @@ import com.yuyh.library.imgsel.common.ImageLoader;
import cn.garymb.ygomobile.interfaces.GameConfig; import cn.garymb.ygomobile.interfaces.GameConfig;
import cn.garymb.ygomobile.interfaces.GameHost; import cn.garymb.ygomobile.interfaces.GameHost;
import cn.garymb.ygomobile.utils.CrashHandler; import cn.garymb.ygomobile.utils.CrashHandler;
import cn.garymb.ygomobile.utils.ScreenUtil;
import libwindbot.windbot.WindBot; import libwindbot.windbot.WindBot;
public class App extends GameApplication { public class App extends GameApplication {
...@@ -30,12 +31,20 @@ public class App extends GameApplication { ...@@ -30,12 +31,20 @@ public class App extends GameApplication {
initImgsel(); initImgsel();
// QbSdk.initX5Environment(this, null); // QbSdk.initX5Environment(this, null);
// QbSdk.setCurrentID(""); // QbSdk.setCurrentID("");
AppsSettings.init(this);
} }
AppsSettings.init(this);
//初始化异常工具类 //初始化异常工具类
CrashHandler crashHandler = CrashHandler.getInstance(); CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext()); crashHandler.init(getApplicationContext());
if(getPackageName().equals(getAppProcessName())){
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String args = intent.getStringExtra("args");
WindBot.runAndroid(args);
}
}, new IntentFilter(Constants.ACTION_WINDBOT));
}
} }
private void initImgsel() { private void initImgsel() {
...@@ -62,6 +71,7 @@ public class App extends GameApplication { ...@@ -62,6 +71,7 @@ public class App extends GameApplication {
public static GameConfig genConfig() { public static GameConfig genConfig() {
GameConfig config = new GameConfig(); GameConfig config = new GameConfig();
config.setNotchHeight(AppsSettings.get().getNotchHeight());
config.setNativeInitOptions(AppsSettings.get().getNativeInitOptions()); config.setNativeInitOptions(AppsSettings.get().getNativeInitOptions());
config.setLockScreenOrientation(AppsSettings.get().isLockScreenOrientation()); config.setLockScreenOrientation(AppsSettings.get().isLockScreenOrientation());
config.setSensorRefresh(AppsSettings.get().isSensorRefresh()); config.setSensorRefresh(AppsSettings.get().isSensorRefresh());
......
...@@ -5,6 +5,7 @@ import android.view.Gravity; ...@@ -5,6 +5,7 @@ import android.view.Gravity;
import cn.garymb.ygomobile.lite.BuildConfig; import cn.garymb.ygomobile.lite.BuildConfig;
public interface Constants { public interface Constants {
String ACTION_WINDBOT = "RUN_WINDBOT";
boolean DEBUG = BuildConfig.DEBUG; boolean DEBUG = BuildConfig.DEBUG;
String PREF_START = "game_pref_"; String PREF_START = "game_pref_";
String PREF_LAST_DECK_PATH = "pref_last_deck_path"; String PREF_LAST_DECK_PATH = "pref_last_deck_path";
......
package cn.garymb.ygomobile.ui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class SquareFrameLayout extends FrameLayout {
public SquareFrameLayout(@NonNull Context context) {
super(context);
}
public SquareFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public SquareFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment