From 87d8c08b5f3f03f0348c6389c3f42f44ac00adf4 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Mon, 24 Mar 2025 17:21:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=BA=94=E7=94=A8=E4=BB=8B?= =?UTF-8?q?=E7=BB=8D=E6=A8=A1=E5=9D=97...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aes/build.properties | 4 +- .../main/java/cc/winboll/studio/aes/App.java | 2 +- .../cc/winboll/studio/aes/MainActivity.java | 46 +- libaes/build.gradle | 4 +- libaes/build.properties | 4 +- libaes/src/main/AndroidManifest.xml | 8 +- .../winboll/studio/libaes/beans/AESModel.java | 71 +++ .../unittests/SecondaryLibraryActivity.java | 10 +- .../unittests/TestDrawerFragmentActivity.java | 7 +- .../studio/libaes/winboll/APPInfo.java | 142 +++++ .../studio/libaes/winboll/AboutActivity.java | 62 ++ .../libaes/winboll/AboutActivityFactory.java | 54 ++ .../studio/libaes/winboll/AboutView.java | 391 ++++++++++++ .../libaes/winboll/IWinBollActivity.java | 6 +- .../winboll/WinBollActivityManager.java | 592 +++++++++--------- libaes/src/main/res/layout/activity_about.xml | 11 + libaes/src/main/res/layout/view_about_dev.xml | 64 ++ libaes/src/main/res/layout/view_about_www.xml | 22 + 18 files changed, 1160 insertions(+), 340 deletions(-) create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/beans/AESModel.java create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/winboll/APPInfo.java create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivity.java create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivityFactory.java create mode 100644 libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutView.java create mode 100644 libaes/src/main/res/layout/activity_about.xml create mode 100644 libaes/src/main/res/layout/view_about_dev.xml create mode 100644 libaes/src/main/res/layout/view_about_www.xml diff --git a/aes/build.properties b/aes/build.properties index c46a2df..0169943 100644 --- a/aes/build.properties +++ b/aes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Mon Mar 24 15:00:52 HKT 2025 +#Mon Mar 24 09:20:58 GMT 2025 stageCount=4 libraryProject=libaes baseVersion=15.0 publishVersion=15.0.3 -buildCount=0 +buildCount=11 baseBetaVersion=15.0.4 diff --git a/aes/src/main/java/cc/winboll/studio/aes/App.java b/aes/src/main/java/cc/winboll/studio/aes/App.java index 578f72d..9a764e2 100644 --- a/aes/src/main/java/cc/winboll/studio/aes/App.java +++ b/aes/src/main/java/cc/winboll/studio/aes/App.java @@ -14,7 +14,7 @@ public class App extends GlobalApplication { @Override public void onCreate() { super.onCreate(); - //setIsDebug(BuildConfig.DEBUG); + setIsDebuging(BuildConfig.DEBUG); } } diff --git a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java index 592e2ef..1438eae 100644 --- a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java +++ b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java @@ -25,37 +25,25 @@ import cc.winboll.studio.libaes.unittests.TestASupportToolbarActivity; import cc.winboll.studio.libaes.unittests.TestAToolbarActivity; import cc.winboll.studio.libaes.unittests.TestDrawerFragmentActivity; import cc.winboll.studio.libaes.unittests.TestViewPageFragment; +import cc.winboll.studio.libaes.winboll.APPInfo; +import cc.winboll.studio.libaes.winboll.AboutActivityFactory; import cc.winboll.studio.libaes.winboll.IWinBollActivity; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libapputils.app.AboutActivityFactory; -import cc.winboll.studio.libapputils.bean.APPInfo; import com.a4455jkjh.colorpicker.ColorPickerDialog; +import com.hjq.toast.ToastUtils; import java.util.ArrayList; public class MainActivity extends DrawerFragmentActivity implements IWinBollActivity { + public static final String TAG = "MainActivity"; TestAButtonFragment mTestAButtonFragment; TestViewPageFragment mTestViewPageFragment; - + @Override - public APPInfo getAppInfo() { - String szBranchName = "aes"; - - APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); - appInfo.setAppName("AES"); - appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); - appInfo.setAppDescription("AES Description"); - appInfo.setAppGitName("APP"); - appInfo.setAppGitOwner("Studio"); - appInfo.setAppGitAPPBranch(szBranchName); - appInfo.setAppGitAPPSubProjectFolder(szBranchName); - appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES"); - appInfo.setAppAPKName("AES"); - appInfo.setAppAPKFolderName("AES"); - return appInfo; - //return null; + public AppCompatActivity getActivity() { + return this; } @Override @@ -214,10 +202,28 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBollActi startActivity(intent); } else if (nItemId == R.id.item_about) { - AboutActivityFactory.showAboutActivity(this, getAppInfo()); + onAbout(); return true; } return super.onOptionsItemSelected(item); } + + public void onAbout() { + String szBranchName = "aes"; + + APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); + appInfo.setAppName("AES"); + appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); + appInfo.setAppDescription("AES Description"); + appInfo.setAppGitName("APP"); + appInfo.setAppGitOwner("Studio"); + appInfo.setAppGitAPPBranch(szBranchName); + appInfo.setAppGitAPPSubProjectFolder(szBranchName); + appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES"); + appInfo.setAppAPKName("AES"); + appInfo.setAppAPKFolderName("AES"); + AboutActivityFactory.showAboutActivity(this, appInfo); + ToastUtils.show("onAbout"); + } } diff --git a/libaes/build.gradle b/libaes/build.gradle index 39fee28..9be2d4c 100644 --- a/libaes/build.gradle +++ b/libaes/build.gradle @@ -43,7 +43,7 @@ dependencies { // 网络连接类库 api 'com.squareup.okhttp3:okhttp:4.4.1' // AndroidX 类库 - api 'androidx.appcompat:appcompat:1.0.0' + api 'androidx.appcompat:appcompat:1.1.0' api 'com.google.android.material:material:1.4.0' //api 'androidx.viewpager:viewpager:1.0.0' //api 'androidx.vectordrawable:vectordrawable:1.1.0' @@ -51,5 +51,5 @@ dependencies { //api 'androidx.fragment:fragment:1.1.0' api 'cc.winboll.studio:libappbase:15.0.9' - api 'cc.winboll.studio:libapputils:15.0.12' + api 'cc.winboll.studio:libapputils:15.0.15' } diff --git a/libaes/build.properties b/libaes/build.properties index 80f8a87..70bdd0b 100644 --- a/libaes/build.properties +++ b/libaes/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Mon Mar 24 15:00:41 HKT 2025 +#Mon Mar 24 09:19:18 GMT 2025 stageCount=4 libraryProject=libaes baseVersion=15.0 publishVersion=15.0.3 -buildCount=0 +buildCount=11 baseBetaVersion=15.0.4 diff --git a/libaes/src/main/AndroidManifest.xml b/libaes/src/main/AndroidManifest.xml index 74ac142..2d3330c 100644 --- a/libaes/src/main/AndroidManifest.xml +++ b/libaes/src/main/AndroidManifest.xml @@ -7,14 +7,14 @@ - - - + - + + + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/beans/AESModel.java b/libaes/src/main/java/cc/winboll/studio/libaes/beans/AESModel.java new file mode 100644 index 0000000..330538e --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/beans/AESModel.java @@ -0,0 +1,71 @@ +package cc.winboll.studio.libaes.beans; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/24 15:27:16 + * @Describe AES数据实例化模型 + */ +import cc.winboll.studio.libappbase.BaseBean; +import android.util.JsonWriter; +import java.io.IOException; +import android.util.JsonReader; + +public class AESModel extends BaseBean { + + public static final String TAG = "AESModel"; + + boolean isInDebugMode; + + public AESModel() { + this.isInDebugMode = false; + } + + public AESModel(boolean isInDebugMode) { + this.isInDebugMode = isInDebugMode; + } + + public void setIsInDebugMode(boolean isInDebugMode) { + this.isInDebugMode = isInDebugMode; + } + + public boolean isInDebugMode() { + return isInDebugMode; + } + + @Override + public String getName() { + return AESModel.class.getName(); + } + + @Override + public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { + super.writeThisToJsonWriter(jsonWriter); + jsonWriter.name("isInDebugMode").value(isInDebugMode()); + } + + @Override + public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { + if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { + if (name.equals("isInDebugMode")) { + setIsInDebugMode(jsonReader.nextBoolean()); + } else { + return false; + } + } + return true; + } + + @Override + public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { + jsonReader.beginObject(); + while (jsonReader.hasNext()) { + String name = jsonReader.nextName(); + if (!initObjectsFromJsonReader(jsonReader, name)) { + jsonReader.skipValue(); + } + } + // 结束 JSON 对象 + jsonReader.endObject(); + return this; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java index f2fd465..a4d4f8e 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java @@ -4,11 +4,11 @@ import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; +import android.widget.Toolbar; +import androidx.appcompat.app.AppCompatActivity; import cc.winboll.studio.libaes.R; import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; -import cc.winboll.studio.libapputils.bean.APPInfo; -import androidx.appcompat.app.AppCompatActivity; -import android.widget.Toolbar; +import cc.winboll.studio.libaes.winboll.APPInfo; import cc.winboll.studio.libaes.winboll.IWinBollActivity; /** @@ -23,8 +23,8 @@ public class SecondaryLibraryActivity extends DrawerFragmentActivity implements SecondaryLibraryFragment mSecondaryLibraryFragment; @Override - public APPInfo getAppInfo() { - return null; + public AppCompatActivity getActivity() { + return this; } @Override diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java index 5bc35ad..469b047 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java @@ -4,7 +4,6 @@ package cc.winboll.studio.libaes.unittests; * @Author ZhanGSKen@QQ.COM * @Date 2024/06/30 15:00:51 */ -import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -12,20 +11,20 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; +import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import cc.winboll.studio.libaes.R; import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; import cc.winboll.studio.libaes.beans.DrawerMenuBean; import cc.winboll.studio.libaes.winboll.IWinBollActivity; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libapputils.bean.APPInfo; import java.util.ArrayList; public class TestDrawerFragmentActivity extends DrawerFragmentActivity implements IWinBollActivity { @Override - public APPInfo getAppInfo() { - return null; + public AppCompatActivity getActivity() { + return this; } @Override diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/APPInfo.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/APPInfo.java new file mode 100644 index 0000000..73c4328 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/APPInfo.java @@ -0,0 +1,142 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/01/20 14:19:02 + * @Describe 应用信息类 + */ +import cc.winboll.studio.libapputils.R; +import java.io.Serializable; + +public class APPInfo implements Serializable { + + public static final String TAG = "APPInfo"; + + // 应用名称 + String appName; + // 应用图标 + int appIcon; + // 应用描述 + String appDescription; + // 应用Git仓库地址 + String appGitName; + // 应用Git仓库拥有者 + String appGitOwner; + // 应用Git仓库分支 + String appGitAPPBranch; + // 应用Git仓库子项目文件夹 + String appGitAPPSubProjectFolder; + // 应用主页 + String appHomePage; + // 应用包名称 + String appAPKName; + // 应用包存储文件夹名称 + String appAPKFolderName; + + public APPInfo(String appName, int appIcon, String appDescription, String appGitName, String appGitOwner, String appGitAPPBranch, String appGitAPPSubProjectFolder, String appHomePage, String appAPKName, String appAPKFolderName) { + this.appName = appName; + this.appIcon = appIcon; + this.appDescription = appDescription; + this.appGitName = appGitName; + this.appGitOwner = appGitOwner; + this.appGitAPPBranch = appGitAPPBranch; + this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder; + this.appHomePage = appHomePage; + this.appAPKName = appAPKName; + this.appAPKFolderName = appAPKFolderName; + } + + public APPInfo() { + this.appName = "WinBoll-APP"; + this.appIcon = R.drawable.ic_launcher; + this.appDescription = "WinBoll APP"; + this.appGitName = "APP"; + this.appGitOwner = "Studio"; + this.appGitAPPBranch = "app"; + this.appGitAPPSubProjectFolder = "app"; + this.appHomePage = "https://www.winboll.cc/studio/details.php?app=APP"; + this.appAPKName = "APP"; + this.appAPKFolderName = "APP"; + } + + public void setAppGitOwner(String appGitOwner) { + this.appGitOwner = appGitOwner; + } + + public String getAppGitOwner() { + return appGitOwner; + } + + public void setAppGitAPPBranch(String appGitAPPBranch) { + this.appGitAPPBranch = appGitAPPBranch; + } + + public String getAppGitAPPBranch() { + return appGitAPPBranch; + } + + public void setAppGitAPPSubProjectFolder(String appGitAPPSubProjectFolder) { + this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder; + } + + public String getAppGitAPPSubProjectFolder() { + return appGitAPPSubProjectFolder; + } + + public void setAppIcon(int appIcon) { + this.appIcon = appIcon; + } + + public int getAppIcon() { + return appIcon; + } + + public void setAppDescription(String appDescription) { + this.appDescription = appDescription; + } + + public String getAppDescription() { + return appDescription; + } + + public void setAppAPKFolderName(String appAPKFolderName) { + this.appAPKFolderName = appAPKFolderName; + } + + public String getAppAPKFolderName() { + return appAPKFolderName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppName() { + return appName; + } + + public void setAppGitName(String appGitName) { + this.appGitName = appGitName; + } + + public String getAppGitName() { + return appGitName; + } + + public void setAppHomePage(String appHomePage) { + this.appHomePage = appHomePage; + } + + public String getAppHomePage() { + return appHomePage; + } + + public void setAppAPKName(String appAPKName) { + this.appAPKName = appAPKName; + } + + public String getAppAPKName() { + return appAPKName; + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivity.java new file mode 100644 index 0000000..c245544 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivity.java @@ -0,0 +1,62 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/24 16:39:29 + * @Describe WinBoll Android 应用介绍窗口 + */ +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.LinearLayout; +import cc.winboll.studio.libaes.R; + +final public class AboutActivity extends Activity { + + public static final String TAG = "AboutActivity"; + + public static final String EXTRA_APPINFO = "EXTRA_APPINFO"; + + APPInfo mAPPInfo; + + @Override + public Context getApplicationContext() { + return this; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + Intent intent = getIntent(); + if (intent != null) { + mAPPInfo = (APPInfo)intent.getSerializableExtra(EXTRA_APPINFO); + } + if (mAPPInfo == null) { + mAPPInfo = new APPInfo(); + } + + AboutView aboutView = new AboutView(this, mAPPInfo); + LinearLayout llMain = findViewById(R.id.aboutroot_ll); + llMain.addView(aboutView); + + //ToastUtils.show(TAG); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.toolbar_winboll_shared_about, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { +// if (item.getItemId() == R.id.item_help) { +// WinBollActivityManager.getInstance(this).startWinBollActivity(this, AssetsHtmlActivity.class); +// } + return super.onOptionsItemSelected(item); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivityFactory.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivityFactory.java new file mode 100644 index 0000000..10b21f5 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutActivityFactory.java @@ -0,0 +1,54 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/06 08:45:23 + * @Describe 关于活动窗口的介绍窗口工厂 + */ + +import android.content.Context; +import android.content.Intent; +import cc.winboll.studio.libaes.winboll.AboutActivityFactory; + +public class AboutActivityFactory { + + public static final String TAG = "AboutActivityFactory"; + + public static APPInfo buildDefaultAPPInfo() { + String szBranchName = ""; + + APPInfo appInfo = new APPInfo(); + appInfo.setAppName("APP"); + appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); + appInfo.setAppDescription("APP Description"); + appInfo.setAppGitName("APP"); + appInfo.setAppGitOwner("Studio"); + appInfo.setAppGitAPPBranch(szBranchName); + appInfo.setAppGitAPPSubProjectFolder(szBranchName); + appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=APP"); + appInfo.setAppAPKName("APP"); + appInfo.setAppAPKFolderName("APP"); + return appInfo; + } + + public static void showAboutActivity(Context context, APPInfo appInfo) { + /*String szPN = ((IWinBollActivity)context).getActivityPackageName(); + //String szPN = context.getPackageName(); + String szBranchName = ""; + if (szPN != null) { + //String szPN = "cc.winboll.studio.apputils.beta"; + String regex = "cc\\.winboll\\.studio\\.([^.]+)\\.*"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(szPN); + if (matcher.find()) { + szBranchName = matcher.group(1); + } + }*/ + //ToastUtils.show(szPN); + + Intent intent = new Intent(context, AboutActivity.class); + intent.putExtra(AboutActivity.EXTRA_APPINFO, (appInfo == null) ? AboutActivityFactory.buildDefaultAPPInfo():appInfo); + context.startActivity(intent); + //WinBollActivityManager.getInstance(context).startWinBollActivity(context, intent, AboutActivity.class); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutView.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutView.java new file mode 100644 index 0000000..d4c38b3 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/AboutView.java @@ -0,0 +1,391 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/24 15:08:52 + * @Describe WinBoll应用介绍视图 + */ +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.net.Uri; +import android.os.Message; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.LinearLayout; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.beans.AESModel; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.utils.ToastUtils; +import cc.winboll.studio.libapputils.app.AppVersionUtils; +import cc.winboll.studio.libapputils.util.PrefUtils; +import cc.winboll.studio.libapputils.view.WinBollServiceStatusView; +import cc.winboll.studio.libapputils.view.YesNoAlertDialog; +import java.io.IOException; +import mehdi.sakout.aboutpage.AboutPage; +import mehdi.sakout.aboutpage.Element; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Credentials; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class AboutView extends LinearLayout { + + public static final String TAG = "AboutView"; + + public static final int MSG_APPUPDATE_CHECKED = 0; + + Context mContext; + APPInfo mAPPInfo; + + WinBollServiceStatusView mWinBollServiceStatusView; + OnRequestDevUserInfoAutofillListener mOnRequestDevUserInfoAutofillListener; + String mszAppName = ""; + String mszAppAPKFolderName = ""; + String mszAppAPKName = ""; + String mszAppGitName = ""; + String mszAppVersionName = ""; + String mszCurrentAppPackageName = ""; + volatile String mszNewestAppPackageName = ""; + String mszAppDescription = ""; + String mszHomePage = ""; + String mszGitea = ""; + int mnAppIcon = 0; + String mszWinBollServerHost; + String mszReleaseAPKName; + EditText metDevUserName; + EditText metDevUserPassword; + + public AboutView(Context context, APPInfo appInfo) { + super(context); + mContext = context; + + setAPPInfo(appInfo); + initView(context); + } + + public AboutView(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + + initView(context, attrs); + } + + public void setAPPInfo(APPInfo appInfo) { + mAPPInfo = appInfo; + } + + APPInfo createAppInfo(Context context, AttributeSet attrs) { + APPInfo appInfo = new APPInfo(); + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AboutView); + appInfo.setAppName(typedArray.getString(R.styleable.AboutView_app_name)); + appInfo.setAppAPKFolderName(typedArray.getString(R.styleable.AboutView_app_apkfoldername)); + appInfo.setAppAPKName(typedArray.getString(R.styleable.AboutView_app_apkname)); + appInfo.setAppGitName(typedArray.getString(R.styleable.AboutView_app_gitname)); + appInfo.setAppGitOwner(typedArray.getString(R.styleable.AboutView_app_gitowner)); + appInfo.setAppGitAPPBranch(typedArray.getString(R.styleable.AboutView_app_gitappbranch)); + appInfo.setAppGitAPPSubProjectFolder(typedArray.getString(R.styleable.AboutView_app_gitappsubprojectfolder)); + appInfo.setAppDescription(typedArray.getString(R.styleable.AboutView_appdescription)); + appInfo.setAppIcon(typedArray.getResourceId(R.styleable.AboutView_appicon, R.drawable.ic_winboll)); + // 返回一个绑定资源结束的信号给资源 + typedArray.recycle(); + return appInfo; + } + + void initView(Context context) { + mszAppName = mAPPInfo.getAppName(); + mszAppAPKFolderName = mAPPInfo.getAppAPKFolderName(); + mszAppAPKName = mAPPInfo.getAppAPKName(); + mszAppGitName = mAPPInfo.getAppGitName(); + mszAppDescription = mAPPInfo.getAppDescription(); + mnAppIcon = mAPPInfo.getAppIcon(); + + mszWinBollServerHost = GlobalApplication.isDebuging() ? "https://dev.winboll.cc": "https://www.winboll.cc"; + + try { + mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + mszCurrentAppPackageName = mszAppAPKName + "_" + mszAppVersionName + ".apk"; + mszHomePage = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; + if (mAPPInfo.getAppGitAPPBranch().equals("")) { + mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName; + } else { + mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName + "/src/branch/" + mAPPInfo.getAppGitAPPBranch() + "/" + mAPPInfo.getAppGitAPPSubProjectFolder(); + } + + if (GlobalApplication.isDebuging()) { + LayoutInflater inflater = LayoutInflater.from(mContext); + View addedView = inflater.inflate(R.layout.view_about_dev, this, false); + LinearLayout llMain = addedView.findViewById(R.id.viewaboutdevLinearLayout1); + metDevUserName = addedView.findViewById(R.id.viewaboutdevEditText1); + metDevUserPassword = addedView.findViewById(R.id.viewaboutdevEditText2); + metDevUserName.setText(PrefUtils.getString(mContext, "metDevUserName", "")); + metDevUserPassword.setText(PrefUtils.getString(mContext, "metDevUserPassword", "")); + //mDevelopHostConnectionStatusView = new DevelopHostConnectionStatusView(context); + mWinBollServiceStatusView = addedView.findViewById(R.id.viewaboutdevWinBollServiceStatusView1); + mWinBollServiceStatusView.setServerHost(mszWinBollServerHost); + mWinBollServiceStatusView.setAuthInfo(metDevUserName.getText().toString(), metDevUserPassword.getText().toString()); + //llMain.addView(mDevelopHostConnectionStatusView); + llMain.addView(createAboutPage()); + addView(addedView); + } else { + LayoutInflater inflater = LayoutInflater.from(mContext); + View addedView = inflater.inflate(R.layout.view_about_www, this, false); + LinearLayout llMain = addedView.findViewById(R.id.viewaboutwwwLinearLayout1); + //mDevelopHostConnectionStatusView = new DevelopHostConnectionStatusView(context); + mWinBollServiceStatusView = addedView.findViewById(R.id.viewaboutwwwWinBollServiceStatusView1); + mWinBollServiceStatusView.setServerHost(mszWinBollServerHost); + mWinBollServiceStatusView.setAuthInfo("", ""); + //llMain.addView(mDevelopHostConnectionStatusView); + llMain.addView(createAboutPage()); + addView(addedView); + } + + // 初始化标题栏 + //setSubtitle(getContext().getString(R.string.text_about)); + +// LinearLayout llMain = findViewById(R.id.viewaboutLinearLayout1); +// llMain.addView(createAboutPage()); + + // 就读取正式版应用包版本号,设置 Release 应用包文件名 + String szReleaseAppVersionName = ""; + try { + //LogUtils.d(TAG, String.format("mContext.getPackageName() %s", mContext.getPackageName())); + String szSubBetaSuffix = subBetaSuffix(mContext.getPackageName()); + //LogUtils.d(TAG, String.format("szSubBetaSuffix : %s", szSubBetaSuffix)); + szReleaseAppVersionName = mContext.getPackageManager().getPackageInfo(szSubBetaSuffix, 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + mszReleaseAPKName = mszAppAPKName + "_" + szReleaseAppVersionName + ".apk"; + + } + + void initView(Context context, AttributeSet attrs) { + mAPPInfo = createAppInfo(context, attrs); + initView(context); + } + + public static String subBetaSuffix(String input) { + if (input.endsWith(".beta")) { + return input.substring(0, input.length() - ".beta".length()); + } + return input; + } + + android.os.Handler mHandler = new android.os.Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case MSG_APPUPDATE_CHECKED : { + /*//检查当前应用包文件名是否是测试版,如果是就忽略检查 + if(mszCurrentAppPackageName.matches(".*_\\d+\\.\\d+\\.\\d+-beta.*\\.apk")) { + ToastUtils.show("APP is the beta Version. Version check ignore."); + return; + }*/ + +// if (!AppVersionUtils.isHasNewStageReleaseVersion(mszReleaseAPKName, mszNewestAppPackageName)) { +// ToastUtils.delayedShow("Current app is the newest.", 5000); +// } + if (!AppVersionUtils.isHasNewVersion2(mszCurrentAppPackageName, mszNewestAppPackageName)) { + ToastUtils.show("Current app is the newest."); + } else { + String szMsg = "Current app is :\n[ " + mszCurrentAppPackageName + + " ]\nThe last app is :\n[ " + mszNewestAppPackageName + + " ]\nIs download the last app?"; + YesNoAlertDialog.show(mContext, "Application Update Prompt", szMsg, mIsDownlaodUpdateListener); + } + break; + } + } + } + }; + + protected View createAboutPage() { + // 定义应用调试按钮 + // + Element elementAppMode; + if (GlobalApplication.isDebuging()) { + elementAppMode = new Element(mContext.getString(R.string.app_normal), R.drawable.ic_winboll); + elementAppMode.setOnClickListener(mAppNormalOnClickListener); + } else { + elementAppMode = new Element(mContext.getString(R.string.app_debug), R.drawable.ic_winboll); + elementAppMode.setOnClickListener(mAppDebugOnClickListener); + } + // 定义 GitWeb 按钮 + // + Element elementGitWeb = new Element(mContext.getString(R.string.gitea_home), R.drawable.ic_winboll); + elementGitWeb.setOnClickListener(mGitWebOnClickListener); + // 定义检查更新按钮 + // + Element elementAppUpdate = new Element(mContext.getString(R.string.app_update), R.drawable.ic_winboll); + elementAppUpdate.setOnClickListener(mAppUpdateOnClickListener); + + String szAppInfo = ""; + try { + szAppInfo = mszAppName + " " + + mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName + + "\n" + mszAppDescription; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + View aboutPage = new AboutPage(mContext) + .setDescription(szAppInfo) + //.isRTL(false) + //.setCustomFont(String) // or Typeface + .setImage(mnAppIcon) + //.addItem(versionElement) + //.addItem(adsElement) + //.addGroup("Connect with us") + .addEmail("ZhanGSKen@AliYun.Com") + .addWebsite(mszHomePage) + .addItem(elementAppMode) + .addItem(elementGitWeb) + .addItem(elementAppUpdate) + //.addFacebook("the.medy") + //.addTwitter("medyo80") + //.addYoutube("UCdPQtdWIsg7_pi4mrRu46vA") + //.addPlayStore("com.ideashower.readitlater.pro") + //.addGitHub("medyo") + //.addInstagram("medyo80") + .create(); + return aboutPage; + } + + View.OnClickListener mAppDebugOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + setApp2DebugMode(mContext); + } + }; + + View.OnClickListener mAppNormalOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + setApp2NormalMode(mContext); + } + }; + + public static void setApp2DebugMode(Context context) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + if (intent != null) { + intent.setAction(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + GlobalApplication.setIsDebuging(context, true); + AESModel.saveBean(context, new AESModel(true)); + + WinBollActivityManager.getInstance(context).finishAll(); + context.startActivity(intent); + } + } + + public static void setApp2NormalMode(Context context) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + GlobalApplication.setIsDebuging(context, false); + AESModel.saveBean(context, new AESModel(false)); + + WinBollActivityManager.getInstance(context).finishAll(); + context.startActivity(intent); + } + } + + View.OnClickListener mGitWebOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mszGitea)); + mContext.startActivity(browserIntent); + } + }; + + View.OnClickListener mAppUpdateOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + ToastUtils.show("Start app update checking."); + new Thread(new Runnable() { + @Override + public void run() { + String szUrl = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; + // 构建包含认证信息的请求 + String credential = ""; + if (GlobalApplication.isDebuging()) { + credential = Credentials.basic(metDevUserName.getText().toString(), metDevUserPassword.getText().toString()); + PrefUtils.saveString(mContext, "metDevUserName", metDevUserName.getText().toString()); + PrefUtils.saveString(mContext, "metDevUserPassword", metDevUserPassword.getText().toString()); + } + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(szUrl) + .header("Accept", "text/plain") // 设置正确的Content-Type头 + .header("Authorization", credential) + .build(); + Call call = client.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + // 处理网络请求失败 + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if (!response.isSuccessful()) { + LogUtils.d(TAG, "Unexpected code " + response, Thread.currentThread().getStackTrace()); + return; + } + + try { + // 读取响应体作为字符串,注意这里可能需要解码 + String text = response.body().string(); + org.jsoup.nodes.Document doc = org.jsoup.Jsoup.parse(text); + LogUtils.v(TAG, doc.text()); + + // 使用id选择器找到具有特定id的元素 + org.jsoup.nodes.Element elementWithId = doc.select("#LastRelease").first(); // 获取第一个匹配的元素 + + // 提取并打印元素的文本内容 + mszNewestAppPackageName = elementWithId.text(); + //ToastUtils.delayedShow(text + "\n" + mszNewestAppPackageName, 5000); + + mHandler.sendMessage(mHandler.obtainMessage(MSG_APPUPDATE_CHECKED)); + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + }); + } + }).start(); + } + }; + + YesNoAlertDialog.OnDialogResultListener mIsDownlaodUpdateListener = new YesNoAlertDialog.OnDialogResultListener() { + @Override + public void onYes() { + String szUrl = mszWinBollServerHost + "/studio/download.php?appname=" + mszAppAPKFolderName + "&apkname=" + mszNewestAppPackageName; + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(szUrl)); + mContext.startActivity(browserIntent); + } + + @Override + public void onNo() { + } + }; + + public interface OnRequestDevUserInfoAutofillListener { + void requestAutofill(EditText etDevUserName, EditText etDevUserPassword); + } + + public void setOnRequestDevUserInfoAutofillListener(OnRequestDevUserInfoAutofillListener l) { + mOnRequestDevUserInfoAutofillListener = l; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/IWinBollActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/IWinBollActivity.java index 33cbc6d..d4cb61c 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/IWinBollActivity.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/IWinBollActivity.java @@ -5,17 +5,15 @@ package cc.winboll.studio.libaes.winboll; * @Date 2025/03/24 08:23:40 * @Describe WinBoll 活动窗口通用接口 */ -import android.content.Context; import android.widget.Toolbar; -import cc.winboll.studio.libapputils.bean.APPInfo; +import androidx.appcompat.app.AppCompatActivity; public interface IWinBollActivity { public static final String TAG = "IWinBollActivity"; // 获取应用资源上下文 - abstract public Context getApplicationContext(); - abstract public APPInfo getAppInfo(); + abstract public AppCompatActivity getActivity(); abstract public String getTag(); abstract public Toolbar initToolBar(); abstract public boolean isEnableDisplayHomeAsUp(); diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/WinBollActivityManager.java b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/WinBollActivityManager.java index 3e78f6d..a975aed 100644 --- a/libaes/src/main/java/cc/winboll/studio/libaes/winboll/WinBollActivityManager.java +++ b/libaes/src/main/java/cc/winboll/studio/libaes/winboll/WinBollActivityManager.java @@ -19,300 +19,300 @@ import java.util.Map; public class WinBollActivityManager { -// public static final String TAG = "WinBollActivityManager"; -// public static final String EXTRA_TAG = "EXTRA_TAG"; -// -// public static enum WinBollUI_TYPE { -// Aplication, // 退出应用后,保持最近任务栏任务记录主窗口 -// Service // 退出应用后,清理所有最近任务栏任务记录窗口 -// }; -// -// // 应用类型标志 -// volatile static WinBollUI_TYPE _mWinBollUI_TYPE = WinBollUI_TYPE.Service; -// -// Context mContext; -// MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks; -// static WinBollActivityManager _mWinBollActivityManager; -// static Map _mapIWinBollList; -// IWinBollActivity firstIWinBollActivity; -// -// public WinBollActivityManager(Context context) { -// mContext = context; -// LogUtils.d(TAG, "WinBollActivityManager()"); -// _mapIWinBollList = new HashMap(); -// } -// -// public static synchronized WinBollActivityManager getInstance(Context context) { -// LogUtils.d(TAG, "getInstance"); -// if (_mWinBollActivityManager == null) { -// LogUtils.d(TAG, "_mWinBollActivityManager == null"); -// _mWinBollActivityManager = new WinBollActivityManager(context); -// } -// return _mWinBollActivityManager; -// } -// -// // -// // 设置 WinBoll 应用 UI 类型 -// // -// public synchronized static void setWinBollUI_TYPE(WinBollUI_TYPE mWinBollUI_TYPE) { -// _mWinBollUI_TYPE = mWinBollUI_TYPE; -// } -// -// // -// // 获取 WinBoll 应用 UI 类型 -// // -// public synchronized static WinBollUI_TYPE getWinBollUI_TYPE() { -// return _mWinBollUI_TYPE; -// } -// -// // -// // 把Activity添加到管理中 -// // -// public void add(T iWinBoll) { -// if (isActive(iWinBoll.getTag())) { -// LogUtils.d(TAG, String.format("add(...) %s is active.", iWinBoll.getTag())); -// } else { -// // 设置起始活动窗口,以便最后退出时提问 -// if (firstIWinBollActivity == null && _mapIWinBollList.size() == 0) { -// firstIWinBollActivity = iWinBoll; -// } -// -// // 添加到活动窗口列表 -// _mapIWinBollList.put(iWinBoll.getTag(), iWinBoll); -// LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", iWinBoll.getTag(), _mapIWinBollList.size())); -// } -// } -// -// -// // -// // activity: 为 null 时, -// // intent.putExtra 函数 EXTRA_TAG 参数为 tag -// // activity: 不为 null 时, -// // intent.putExtra 函数 "tag" 参数为 activity.getTag() -// // -// public void startWinBollActivity(Context context, Class clazz) { -// try { -// // 如果窗口已存在就重启窗口 -// String tag = clazz.newInstance().getTag(); -// if (isActive(tag)) { -// resumeActivity(context, tag); -// return; -// } -// -// // 新建一个任务窗口 -// Intent intent = new Intent(context, clazz); -// //打开多任务窗口 flags -// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); -// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); -// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); -// intent.putExtra(EXTRA_TAG, tag); -// mContext.startActivity(intent); -// } catch (InstantiationException | IllegalAccessException e) { -// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); -// } -// } -// -// public void startWinBollActivity(Context context, Intent intent, Class clazz) { -// try { -// // 如果窗口已存在就重启窗口 -// String tag = clazz.newInstance().getTag(); -// if (isActive(tag)) { -// resumeActivity(context, tag); -// return; -// } -// -// // 新建一个任务窗口 -// //Intent intent = new Intent(context, clazz); -// //打开多任务窗口 flags -// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); -// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); -// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); -// intent.putExtra(EXTRA_TAG, tag); -// mContext.startActivity(intent); -// } catch (InstantiationException | IllegalAccessException e) { -// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); -// } -// } -// -// public boolean isFirstIWinBollActivity(IWinBollActivity iWinBollActivity) { -// return firstIWinBollActivity != null && firstIWinBollActivity == iWinBollActivity; -// } -// -// // -// // 判断 tag绑定的 MyActivity是否存在 -// // -// public boolean isActive(String tag) { -// //printAvtivityListInfo(); -// IWinBollActivity iWinBoll = getIWinBoll(tag); -// if (iWinBoll != null) { -// LogUtils.d(TAG, "isActive(...) activity != null tag " + tag); -// //ToastUtils.show("activity != null tag " + tag); -// //判断是否为 BaseActivity,如果已经销毁,则移除 -// if (iWinBoll.getActivity().isFinishing() || iWinBoll.getActivity().isDestroyed()) { -// _mapIWinBollList.remove(iWinBoll.getTag()); -// //_mWinBollActivityList.remove(activity); -// LogUtils.d(TAG, String.format("isActive(...) remove activity.\ntag : %s", tag)); -// return false; -// } else { -// LogUtils.d(TAG, String.format("isActive(...) activity is exist.\ntag : %s", tag)); -// return true; -// } -// } else { -// LogUtils.d(TAG, String.format("isActive(...) activity == null\ntag : %s", tag)); -// return false; -// } -// } -// -// static IWinBollActivity getIWinBoll(String tag) { -// return _mapIWinBollList.get(tag); -// } -// -// // -// // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 -// // -// public void resumeActivity(Context context, String tag) { -// LogUtils.d(TAG, "resumeActivty"); -// T iWinBoll = (T)getIWinBoll(tag); -// //LogUtils.d(TAG, "activity " + activity.getTag()); -// if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { -// resumeActivity(context, iWinBoll); -// } -// } -// -// // -// // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 -// // -// public void resumeActivity(Context context, T iWinBoll) { -// ActivityManager am = (ActivityManager) iWinBoll.getActivity().getSystemService(Context.ACTIVITY_SERVICE); -// //返回启动它的根任务(home 或者 MainActivity) -// Intent intent = new Intent(context, iWinBoll.getClass()); -// TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); -// stackBuilder.addNextIntentWithParentStack(intent); -// stackBuilder.startActivities(); -// //moveTaskToFront(YourTaskId, 0); -// LogUtils.d(TAG, "am.moveTaskToFront"); -// //ToastUtils.show("resumeActivity am.moveTaskToFront"); -// am.moveTaskToFront(iWinBoll.getActivity().getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); -// } -// -// -// // -// // 结束所有 Activity -// // -// public void finishAll() { -// try { -// for (String key : _mapIWinBollList.keySet()) { -// //System.out.println("Key: " + key + ", Value: " + _mapActivityList.get(key)); -// IWinBollActivity iWinBoll = _mapIWinBollList.get(key); -// //ToastUtils.show("finishAll() activity"); -// if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { -// //ToastUtils.show("activity != null ..."); -// if (getWinBollUI_TYPE() == WinBollUI_TYPE.Service) { -// // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 -// iWinBoll.getActivity().finishAndRemoveTask(); -// //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); -// } else if (getWinBollUI_TYPE() == WinBollUI_TYPE.Aplication) { -// // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 -// iWinBoll.getActivity().finish(); -// //ToastUtils.show("finishAll() activity.finish();"); -// } else { -// LogUtils.d(TAG, "WinBollApplication.WinBollUI_TYPE error."); -// //ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); -// } -// } -// } -// } catch (Exception e) { -// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); -// } -// } -// -// // -// // 结束指定Activity -// // -// public void finish(T iWinBoll) { -// try { -// if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { -// //根据tag 移除 MyActivity -// //String tag= activity.getTag(); -// //_mWinBollActivityList.remove(tag); -// //ToastUtils.show("remove"); -// //ToastUtils.show("_mWinBollActivityArrayMap.size() " + Integer.toString(_mWinBollActivityArrayMap.size())); -// -// // 窗口回调规则: -// // [] 当前窗口位置 >> 调度出的窗口位置 -// // ★:[0] 1 2 3 4 >> 1 -// // ★:0 1 [2] 3 4 >> 1 -// // ★:0 1 2 [3] 4 >> 2 -// // ★:0 1 2 3 [4] >> 3 -// // ★:[0] >> 直接关闭当前窗口 -// LogUtils.d(TAG, "finish no yet."); -// IWinBollActivity preIWinBoll = getPreIWinBoll(iWinBoll); -// iWinBoll.getActivity().finish(); -// if (preIWinBoll != null) { -// resumeActivity(mContext, preIWinBoll); -// } -// } -// -// } catch (Exception e) { -// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); -// } -// } -// -// // -// // 获取窗口队列中的前一个窗口 -// // -// IWinBollActivity getPreIWinBoll(IWinBollActivity iWinBoll) { -// try { -// boolean bingo = false; -// IWinBollActivity preIWinBoll = null; -// for (Map.Entry entity : _mapIWinBollList.entrySet()) { -// if (entity.getKey().equals(iWinBoll.getTag())) { -// bingo = true; -// LogUtils.d(TAG, "bingo"); -// break; -// } -// preIWinBoll = entity.getValue(); -// } -// -// if (bingo) { -// return preIWinBoll; -// } -// } catch (Exception e) { -// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); -// } -// -// return null; -// } -// -// // -// // 从管理列表中移除管理项 -// // -// public boolean registeRemove(T activity) { -// IWinBollActivity iWinBollTest = _mapIWinBollList.get(activity.getTag()); -// if (iWinBollTest != null) { -// _mapIWinBollList.remove(activity.getTag()); -// return true; -// } -// return false; -// } -// -// // -// // 打印管理列表项列表里的信息 -// // -// public static void printIWinBollListInfo() { -// //LogUtils.d(TAG, "printAvtivityListInfo"); -// if (!_mapIWinBollList.isEmpty()) { -// StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(_mapIWinBollList.size())); -// Iterator> iterator = _mapIWinBollList.entrySet().iterator(); -// while (iterator.hasNext()) { -// Map.Entry entry = iterator.next(); -// sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); -// //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); -// } -// sb.append("\nMap entries end."); -// LogUtils.d(TAG, sb.toString()); -// } else { -// LogUtils.d(TAG, "The map is empty."); -// } -// } + public static final String TAG = "WinBollActivityManager"; + public static final String EXTRA_TAG = "EXTRA_TAG"; + + public static enum WinBollUI_TYPE { + Aplication, // 退出应用后,保持最近任务栏任务记录主窗口 + Service // 退出应用后,清理所有最近任务栏任务记录窗口 + }; + + // 应用类型标志 + volatile static WinBollUI_TYPE _mWinBollUI_TYPE = WinBollUI_TYPE.Service; + + Context mContext; + MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks; + static WinBollActivityManager _mWinBollActivityManager; + static Map _mapIWinBollList; + IWinBollActivity firstIWinBollActivity; + + public WinBollActivityManager(Context context) { + mContext = context; + LogUtils.d(TAG, "WinBollActivityManager()"); + _mapIWinBollList = new HashMap(); + } + + public static synchronized WinBollActivityManager getInstance(Context context) { + LogUtils.d(TAG, "getInstance"); + if (_mWinBollActivityManager == null) { + LogUtils.d(TAG, "_mWinBollActivityManager == null"); + _mWinBollActivityManager = new WinBollActivityManager(context); + } + return _mWinBollActivityManager; + } + + // + // 设置 WinBoll 应用 UI 类型 + // + public synchronized static void setWinBollUI_TYPE(WinBollUI_TYPE mWinBollUI_TYPE) { + _mWinBollUI_TYPE = mWinBollUI_TYPE; + } + + // + // 获取 WinBoll 应用 UI 类型 + // + public synchronized static WinBollUI_TYPE getWinBollUI_TYPE() { + return _mWinBollUI_TYPE; + } + + // + // 把Activity添加到管理中 + // + public void add(T iWinBoll) { + if (isActive(iWinBoll.getTag())) { + LogUtils.d(TAG, String.format("add(...) %s is active.", iWinBoll.getTag())); + } else { + // 设置起始活动窗口,以便最后退出时提问 + if (firstIWinBollActivity == null && _mapIWinBollList.size() == 0) { + firstIWinBollActivity = iWinBoll; + } + + // 添加到活动窗口列表 + _mapIWinBollList.put(iWinBoll.getTag(), iWinBoll); + LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", iWinBoll.getTag(), _mapIWinBollList.size())); + } + } + + + // + // activity: 为 null 时, + // intent.putExtra 函数 EXTRA_TAG 参数为 tag + // activity: 不为 null 时, + // intent.putExtra 函数 "tag" 参数为 activity.getTag() + // + public void startWinBollActivity(Context context, Class clazz) { + try { + // 如果窗口已存在就重启窗口 + String tag = clazz.newInstance().getTag(); + if (isActive(tag)) { + resumeActivity(context, tag); + return; + } + + // 新建一个任务窗口 + Intent intent = new Intent(context, clazz); + //打开多任务窗口 flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(EXTRA_TAG, tag); + mContext.startActivity(intent); + } catch (InstantiationException | IllegalAccessException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + public void startWinBollActivity(Context context, Intent intent, Class clazz) { + try { + // 如果窗口已存在就重启窗口 + String tag = clazz.newInstance().getTag(); + if (isActive(tag)) { + resumeActivity(context, tag); + return; + } + + // 新建一个任务窗口 + //Intent intent = new Intent(context, clazz); + //打开多任务窗口 flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(EXTRA_TAG, tag); + mContext.startActivity(intent); + } catch (InstantiationException | IllegalAccessException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + public boolean isFirstIWinBollActivity(IWinBollActivity iWinBollActivity) { + return firstIWinBollActivity != null && firstIWinBollActivity == iWinBollActivity; + } + + // + // 判断 tag绑定的 MyActivity是否存在 + // + public boolean isActive(String tag) { + //printAvtivityListInfo(); + IWinBollActivity iWinBoll = getIWinBoll(tag); + if (iWinBoll != null) { + LogUtils.d(TAG, "isActive(...) activity != null tag " + tag); + //ToastUtils.show("activity != null tag " + tag); + //判断是否为 BaseActivity,如果已经销毁,则移除 + if (iWinBoll.getActivity().isFinishing() || iWinBoll.getActivity().isDestroyed()) { + _mapIWinBollList.remove(iWinBoll.getTag()); + //_mWinBollActivityList.remove(activity); + LogUtils.d(TAG, String.format("isActive(...) remove activity.\ntag : %s", tag)); + return false; + } else { + LogUtils.d(TAG, String.format("isActive(...) activity is exist.\ntag : %s", tag)); + return true; + } + } else { + LogUtils.d(TAG, String.format("isActive(...) activity == null\ntag : %s", tag)); + return false; + } + } + + static IWinBollActivity getIWinBoll(String tag) { + return _mapIWinBollList.get(tag); + } + + // + // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 + // + public void resumeActivity(Context context, String tag) { + LogUtils.d(TAG, "resumeActivty"); + T iWinBoll = (T)getIWinBoll(tag); + //LogUtils.d(TAG, "activity " + activity.getTag()); + if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { + resumeActivity(context, iWinBoll); + } + } + + // + // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 + // + public void resumeActivity(Context context, T iWinBoll) { + ActivityManager am = (ActivityManager) iWinBoll.getActivity().getSystemService(Context.ACTIVITY_SERVICE); + //返回启动它的根任务(home 或者 MainActivity) + Intent intent = new Intent(context, iWinBoll.getClass()); + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + stackBuilder.addNextIntentWithParentStack(intent); + stackBuilder.startActivities(); + //moveTaskToFront(YourTaskId, 0); + LogUtils.d(TAG, "am.moveTaskToFront"); + //ToastUtils.show("resumeActivity am.moveTaskToFront"); + am.moveTaskToFront(iWinBoll.getActivity().getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); + } + + + // + // 结束所有 Activity + // + public void finishAll() { + try { + for (String key : _mapIWinBollList.keySet()) { + //System.out.println("Key: " + key + ", Value: " + _mapActivityList.get(key)); + IWinBollActivity iWinBoll = _mapIWinBollList.get(key); + //ToastUtils.show("finishAll() activity"); + if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { + //ToastUtils.show("activity != null ..."); + if (getWinBollUI_TYPE() == WinBollUI_TYPE.Service) { + // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 + iWinBoll.getActivity().finishAndRemoveTask(); + //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); + } else if (getWinBollUI_TYPE() == WinBollUI_TYPE.Aplication) { + // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 + iWinBoll.getActivity().finish(); + //ToastUtils.show("finishAll() activity.finish();"); + } else { + LogUtils.d(TAG, "WinBollApplication.WinBollUI_TYPE error."); + //ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); + } + } + } + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + // + // 结束指定Activity + // + public void finish(T iWinBoll) { + try { + if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { + //根据tag 移除 MyActivity + //String tag= activity.getTag(); + //_mWinBollActivityList.remove(tag); + //ToastUtils.show("remove"); + //ToastUtils.show("_mWinBollActivityArrayMap.size() " + Integer.toString(_mWinBollActivityArrayMap.size())); + + // 窗口回调规则: + // [] 当前窗口位置 >> 调度出的窗口位置 + // ★:[0] 1 2 3 4 >> 1 + // ★:0 1 [2] 3 4 >> 1 + // ★:0 1 2 [3] 4 >> 2 + // ★:0 1 2 3 [4] >> 3 + // ★:[0] >> 直接关闭当前窗口 + LogUtils.d(TAG, "finish no yet."); + IWinBollActivity preIWinBoll = getPreIWinBoll(iWinBoll); + iWinBoll.getActivity().finish(); + if (preIWinBoll != null) { + resumeActivity(mContext, preIWinBoll); + } + } + + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + // + // 获取窗口队列中的前一个窗口 + // + IWinBollActivity getPreIWinBoll(IWinBollActivity iWinBoll) { + try { + boolean bingo = false; + IWinBollActivity preIWinBoll = null; + for (Map.Entry entity : _mapIWinBollList.entrySet()) { + if (entity.getKey().equals(iWinBoll.getTag())) { + bingo = true; + LogUtils.d(TAG, "bingo"); + break; + } + preIWinBoll = entity.getValue(); + } + + if (bingo) { + return preIWinBoll; + } + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + + return null; + } + + // + // 从管理列表中移除管理项 + // + public boolean registeRemove(T activity) { + IWinBollActivity iWinBollTest = _mapIWinBollList.get(activity.getTag()); + if (iWinBollTest != null) { + _mapIWinBollList.remove(activity.getTag()); + return true; + } + return false; + } + + // + // 打印管理列表项列表里的信息 + // + public static void printIWinBollListInfo() { + //LogUtils.d(TAG, "printAvtivityListInfo"); + if (!_mapIWinBollList.isEmpty()) { + StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(_mapIWinBollList.size())); + Iterator> iterator = _mapIWinBollList.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); + //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); + } + sb.append("\nMap entries end."); + LogUtils.d(TAG, sb.toString()); + } else { + LogUtils.d(TAG, "The map is empty."); + } + } } diff --git a/libaes/src/main/res/layout/activity_about.xml b/libaes/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..540c689 --- /dev/null +++ b/libaes/src/main/res/layout/activity_about.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libaes/src/main/res/layout/view_about_dev.xml b/libaes/src/main/res/layout/view_about_dev.xml new file mode 100644 index 0000000..1f19c03 --- /dev/null +++ b/libaes/src/main/res/layout/view_about_dev.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/layout/view_about_www.xml b/libaes/src/main/res/layout/view_about_www.xml new file mode 100644 index 0000000..69c02d9 --- /dev/null +++ b/libaes/src/main/res/layout/view_about_www.xml @@ -0,0 +1,22 @@ + + + + + + + + + +