Compare commits

..

16 Commits

Author SHA1 Message Date
ZhanGSKen
c22946f0a5 <appbase>APK 15.0.7 release Publish. 2025-03-24 07:44:12 +08:00
ZhanGSKen
1363a7dcce <appbase>APK 15.0.6 release Publish. 2025-03-24 07:43:28 +08:00
ZhanGSKen
e0ca5725f1 保持与旧版Gradle插件的兼容 2025-03-24 07:39:20 +08:00
ZhanGSKen
3c4988532f 函数命名更新 2025-03-24 07:30:59 +08:00
ZhanGSKen
b0a34579fa 命名空间重构 2025-03-24 07:17:22 +08:00
ZhanGSKen
dd08747edb 更新WinBoll maven库下载顺序 2025-03-21 00:42:41 +08:00
ZhanGSKen
603640b3cb <libappbase>Library Release 15.0.5 2025-03-18 10:15:14 +08:00
ZhanGSKen
5b06ce9699 <appbase>APK 15.0.5 release Publish. 2025-03-18 10:14:53 +08:00
ZhanGSKen
363fc6c7c1 修复编译参数 2025-03-18 10:13:01 +08:00
ZhanGSKen
7f43f8b5c5 <libappbase>Library Release 15.0.4 2025-03-18 10:09:49 +08:00
ZhanGSKen
a117e6e110 <appbase>APK 15.0.4 release Publish. 2025-03-18 10:09:21 +08:00
ZhanGSKen
c1f576e343 分开APP应用主题设置与类库主题预定设置。 2025-03-18 10:08:31 +08:00
ZhanGSKen
1dad84b65e <libappbase>Library Release 15.0.3 2025-03-17 09:51:28 +08:00
ZhanGSKen
1ae377e665 <appbase>APK 15.0.3 release Publish. 2025-03-17 09:51:04 +08:00
ZhanGSKen
02fa0a4134 优化调试窗口 2025-03-17 09:40:03 +08:00
ZhanGSKen
a730aa3f92 优化日志UI 2025-03-17 09:37:12 +08:00
88 changed files with 3085 additions and 1539 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sat Mar 15 15:30:02 HKT 2025 #Mon Mar 24 07:44:12 HKT 2025
stageCount=3 stageCount=8
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.2 publishVersion=15.0.7
buildCount=0 buildCount=0
baseBetaVersion=15.0.3 baseBetaVersion=15.0.8

View File

@@ -7,7 +7,7 @@
android:name=".App" android:name=".App"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/MyAppTheme" android:theme="@style/MyAPPBaseTheme"
android:resizeableActivity="true"> android:resizeableActivity="true">
<activity <activity
@@ -49,6 +49,12 @@
android:name=".services.MainService" android:name=".services.MainService"
android:exported="true"/> android:exported="true"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoBindService"
android:exported="true"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoService"
android:exported="true"/>
<service android:name=".services.AssistantService"/> <service android:name=".services.AssistantService"/>
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver"> <receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver">
@@ -81,13 +87,13 @@
</receiver> </receiver>
<receiver android:name=".widgets.APPNewsWidgetClickListener"> <receiver android:name=".receivers.APPNewsWidgetClickListener">
<intent-filter> <intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidgetClickListener.ACTION_PRE"/> <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidgetClickListener.ACTION_NEXT"/> <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/>
</intent-filter> </intent-filter>
@@ -97,12 +103,6 @@
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="4.0"/> android:value="4.0"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoBindService"
android:exported="true"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoService"
android:exported="true"/>
</application> </application>
</manifest> </manifest>

View File

@@ -89,7 +89,7 @@ public class MainActivity extends Activity {
startService(intentService); startService(intentService);
} }
public void onTestSOS(View view) { public void onTestDemoServiceSOS(View view) {
Intent intent = new Intent(this, TestDemoService.class); Intent intent = new Intent(this, TestDemoService.class);
stopService(intent); stopService(intent);
if (App.isDebuging()) { if (App.isDebuging()) {

View File

@@ -7,7 +7,7 @@ package cc.winboll.studio.appbase;
import android.content.Context; import android.content.Context;
import android.service.quicksettings.Tile; import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService; import android.service.quicksettings.TileService;
import cc.winboll.studio.appbase.beans.MainServiceBean; import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
public class MyTileService extends TileService { public class MyTileService extends TileService {

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.appbase.beans; package cc.winboll.studio.appbase.models;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.appbase.beans; package cc.winboll.studio.appbase.models;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.appbase.beans; package cc.winboll.studio.appbase.models;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.appbase.beans; package cc.winboll.studio.appbase.models;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com

View File

@@ -1,13 +1,13 @@
package cc.winboll.studio.appbase.widgets; package cc.winboll.studio.appbase.receivers;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 17:20:46 * @Date 2025/03/24 07:11:44
* @Describe WidgetButtonClickListener
*/ */
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
public class APPNewsWidgetClickListener extends BroadcastReceiver { public class APPNewsWidgetClickListener extends BroadcastReceiver {

View File

@@ -10,7 +10,7 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import cc.winboll.studio.appbase.beans.WinBollNewsBean; import cc.winboll.studio.appbase.models.WinBollNewsBean;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.widgets.APPNewsWidget; import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.libappbase.AppUtils; import cc.winboll.studio.libappbase.AppUtils;

View File

@@ -11,7 +11,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.appbase.beans.MainServiceBean; import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.services.AssistantService; import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;

View File

@@ -18,7 +18,7 @@ import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.appbase.MyTileService; import cc.winboll.studio.appbase.MyTileService;
import cc.winboll.studio.appbase.beans.MainServiceBean; import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.handlers.MainServiceHandler; import cc.winboll.studio.appbase.handlers.MainServiceHandler;
import cc.winboll.studio.appbase.receivers.MainReceiver; import cc.winboll.studio.appbase.receivers.MainReceiver;
import cc.winboll.studio.appbase.services.AssistantService; import cc.winboll.studio.appbase.services.AssistantService;

View File

@@ -10,7 +10,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.appbase.beans.TestDemoBindServiceBean; import cc.winboll.studio.appbase.models.TestDemoBindServiceBean;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.WinBoll; import cc.winboll.studio.libappbase.sos.WinBoll;
import cc.winboll.studio.appbase.App; import cc.winboll.studio.appbase.App;

View File

@@ -10,7 +10,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.appbase.beans.TestDemoServiceBean; import cc.winboll.studio.appbase.models.TestDemoServiceBean;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.WinBoll; import cc.winboll.studio.libappbase.sos.WinBoll;

View File

@@ -12,15 +12,16 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.beans.WinBollNewsBean; import cc.winboll.studio.appbase.models.WinBollNewsBean;
import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener;
import cc.winboll.studio.libappbase.AppUtils; import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.APPModel;
import cc.winboll.studio.libappbase.sos.WinBoll;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import cc.winboll.studio.libappbase.sos.APPModel;
import cc.winboll.studio.libappbase.sos.WinBoll;
public class APPNewsWidget extends AppWidgetProvider { public class APPNewsWidget extends AppWidgetProvider {

View File

@@ -72,6 +72,26 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="right"> android:gravity="right">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
</LinearLayout>
<HorizontalScrollView <HorizontalScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@@ -140,19 +160,6 @@
</HorizontalScrollView> </HorizontalScrollView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -171,24 +178,24 @@
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="TestSOS" android:text="TestDemoServiceSOS"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onTestSOS"/> android:onClick="onTestDemoServiceSOS"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
<cc.winboll.studio.libappbase.LogView <cc.winboll.studio.libappbase.LogView
android:layout_height="500dp" android:layout_height="300dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:id="@+id/activitymainLogView1"/> android:id="@+id/activitymainLogView1"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout> </LinearLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#005800FF</color> <color name="colorPrimary">#FF00B322</color>
<color name="colorPrimaryDark">#005800FF</color> <color name="colorPrimaryDark">#FF005C12</color>
<color name="colorAccent">#005800FF</color> <color name="colorAccent">#FF8DFFA2</color>
<color name="colorText">#FFFFFB8D</color>
</resources> </resources>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="MyAppTheme" parent="APPBaseTheme"> <style name="MyAPPBaseTheme" parent="APPBaseTheme">
<item name="attrColorPrimary">@color/colorPrimary</item> <item name="attrColorPrimary">@color/colorPrimary</item>
<item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item> <item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item>
</style> </style>

View File

@@ -18,18 +18,18 @@ def genVersionName(def versionName){
} }
android { android {
compileSdkVersion 30 compileSdkVersion 32
buildToolsVersion "30.0.3" buildToolsVersion "33.0.3"
defaultConfig { defaultConfig {
applicationId "cc.winboll.studio.apputils" applicationId "cc.winboll.studio.apputils"
minSdkVersion 26 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0 // 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.0" versionName "9.2"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }
@@ -41,26 +41,15 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
} }
dependencies { dependencies {
api project(':libapputils') api project(':libapputils')
api 'cc.winboll.studio:libappbase:1.0.3'
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
implementation 'cc.winboll.studio:libappbase:15.0.3'
// 二维码类库
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
// 网络连接类库
//implementation 'com.squareup.okhttp3:okhttp:4.4.1'
// Html 解析
//implementation 'org.jsoup:jsoup:1.13.1'
// SSH
//implementation 'com.jcraft:jsch:0.1.55'
// 应用介绍页类库
//implementation 'io.github.medyo:android-about-page:2.0.0'
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue Mar 18 09:52:37 HKT 2025 #Sat Jan 18 13:03:10 HKT 2025
stageCount=2 stageCount=2
libraryProject=libapputils libraryProject=libapputils
baseVersion=15.0 baseVersion=9.2
publishVersion=15.0.1 publishVersion=9.2.1
buildCount=0 buildCount=0
baseBetaVersion=15.0.2 baseBetaVersion=9.2.2

View File

@@ -8,7 +8,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@drawable/ic_winboll" android:icon="@drawable/ic_winboll"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/UtilsTheme" android:theme="@style/WinBoll.SupportThemeNoActionBar"
android:supportsRtl="true"> android:supportsRtl="true">
<activity <activity
@@ -27,6 +27,8 @@
</activity> </activity>
<activity android:name=".TestWinBollActivity"/>
<activity android:name=".TestStringToQrCodeViewActivity"/> <activity android:name=".TestStringToQrCodeViewActivity"/>
</application> </application>

View File

@@ -5,83 +5,27 @@ package cc.winboll.studio.apputils;
* @Date 2024/12/08 15:10:51 * @Date 2024/12/08 15:10:51
* @Describe 全局应用类 * @Describe 全局应用类
*/ */
import android.app.Application; import android.view.Gravity;
import android.content.Context; import cc.winboll.studio.libapputils.app.WinBollApplication;
import android.widget.Toast; import com.hjq.toast.ToastUtils;
import cc.winboll.studio.libappbase.GlobalApplication; import com.hjq.toast.style.WhiteToastStyle;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libapputils.app.MyActivityLifecycleCallbacks;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.DebugBean;
public class App extends GlobalApplication { public class App extends WinBollApplication {
public static final String TAG = "App"; public static final String TAG = "App";
public static final String _ACTION_DEBUGVIEW = App.class.getName() + "_ACTION_DEBUGVIEW"; public static final String _ACTION_DEBUGVIEW = WinBollApplication.class.getName() + "_ACTION_DEBUGVIEW";
//static volatile WinBollApplication _WinBollApplication = null;
MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks;
// 标记当前应用是否处于调试状态
static volatile boolean isDebug = false;
public synchronized static void setIsDebug(boolean isDebug) {
App.isDebug = isDebug;
}
public static boolean isDebug() {
return isDebug;
}
MyActivityLifecycleCallbacks getMyActivityLifecycleCallbacks() {
return mMyActivityLifecycleCallbacks;
}
@Override
public Context getApplicationContext() {
return super.getApplicationContext();
}
@Override
public Application getApplication() {
return this;
}
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// 应用环境初始化, 基本调试环境
//
// 初始化日志模块
//LogUtils.init(this);
try {
// 初始化 Toast 框架 // 初始化 Toast 框架
// ToastUtils.init(this);
// // 设置 Toast 布局样式
// //ToastUtils.setView(R.layout.view_toast);
// ToastUtils.setStyle(new WhiteToastStyle());
// ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
// 设置应用调试标志
DebugBean debugBean = DebugBean.loadBean(this, DebugBean.class);
if (debugBean == null) {
//ToastUtils.show("debugBean == null");
setIsDebug(false);
} else {
//ToastUtils.show("saveDebugStatus(" + String.valueOf(debugBean.isDebuging()) + ")");
setIsDebug(debugBean.isDebuging());
}
// 应用窗口管理模块参数设置
// //
mMyActivityLifecycleCallbacks = new MyActivityLifecycleCallbacks(); ToastUtils.init(this);
registerActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks); // 设置 Toast 布局样式
// 设置默认 WinBoll 应用 UI 类型 //ToastUtils.setView(R.layout.view_toast);
WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Service); ToastUtils.setStyle(new WhiteToastStyle());
//ToastUtils.show("WinBollUI_TYPE " + getWinBollUI_TYPE()); ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
} }
} }

View File

@@ -1,83 +1,28 @@
package cc.winboll.studio.apputils; package cc.winboll.studio.apputils;
import cc.winboll.studio.apputils.R;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import android.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.utils.ToastUtils;
import cc.winboll.studio.libapputils.activities.AssetsHtmlActivity; import cc.winboll.studio.libapputils.activities.AssetsHtmlActivity;
import cc.winboll.studio.libapputils.activities.LogActivity;
import cc.winboll.studio.libapputils.activities.QRCodeDecodeActivity; import cc.winboll.studio.libapputils.activities.QRCodeDecodeActivity;
import cc.winboll.studio.libapputils.app.AboutActivityFactory; import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.app.IWinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.APPInfo; import cc.winboll.studio.libapputils.log.LogActivity;
import cc.winboll.studio.libapputils.view.AboutView; import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.view.YesNoAlertDialog; import com.hjq.toast.ToastUtils;
import java.util.List;
import java.util.Set;
final public class MainActivity extends Activity implements IWinBollActivity { final public class MainActivity extends WinBollActivity {
public static final String TAG = "MainActivity"; public static final String TAG = "MainActivity";
public static final int REQUEST_QRCODEDECODE_ACTIVITY = 0; public static final int REQUEST_QRCODEDECODE_ACTIVITY = 0;
Toolbar mToolbar;
LogView mLogView;
@Override @Override
public Activity getActivity() { protected boolean isEnableDisplayHomeAsUp() {
return this;
}
@Override
public APPInfo getAppInfo() {
String szBranchName = "apputils";
APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo();
appInfo.setAppName("APPUtils");
appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll);
appInfo.setAppDescription("APPUtils 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("APPUtils");
appInfo.setAppAPKFolderName("APPUtils");
return appInfo;
//return null;
}
@Override
public String getTag() {
return TAG;
}
@Override
public boolean isAddWinBollToolBar() {
return true;
}
@Override
public Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false; return false;
} }
@@ -86,22 +31,8 @@ final public class MainActivity extends Activity implements IWinBollActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
mLogView = findViewById(R.id.logview); //Toolbar toolbar = findViewById(R.id.activitymainToolbar1);
mLogView.start(); //setActionBar(toolbar);
// 初始化工具栏
mToolbar = findViewById(R.id.activitymainToolbar1);
setActionBar(mToolbar);
if (isEnableDisplayHomeAsUp()) {
// 显示后退按钮
getActionBar().setDisplayHomeAsUpEnabled(true);
}
getActionBar().setSubtitle(getTag());
checkResolveActivity();
archiveInstance();
// 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回 // 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回
//if (prosessIntents(getIntent())) return; //if (prosessIntents(getIntent())) return;
@@ -113,94 +44,44 @@ final public class MainActivity extends Activity implements IWinBollActivity {
// LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); // LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG));
} }
boolean checkResolveActivity() {
PackageManager packageManager = getPackageManager();
//Intent intent = new Intent("your_action_here");
Intent intent = getIntent();
if (intent != null) {
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfoList.size() > 0) {
// 传入的Intent action在Activity清单的intent-filter的action节点里有定义
if (intent.getAction() != null) {
if (intent.getAction().equals(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW)) {
App.setIsDebug(true);
//ToastUtils.show!("WinBollApplication.setIsDebug(true) by action : " + intent.getAction());
}
}
return true;
} else {
// 传入的Intent action在Activity清单的intent-filter的action节点里没有定义
//ToastUtils.show("false : " + intent.getAction());
return false;
}
}
// action在清单文件中没有声明
ToastUtils.show("false");
return false;
}
void archiveInstance() {
Intent intent = getIntent();
StringBuilder sb = new StringBuilder("\n### Archive Instance ###\n");
if (intent != null) {
ComponentName componentName = intent.getComponent();
if (componentName != null) {
String packageName = componentName.getPackageName();
//Log.d("AppStarter", "启动本应用的应用包名: " + packageName);
sb.append("启动本应用的应用包名: \n" + packageName);
}
sb.append("\nImplicit Intent Tracker \n接收到的 Intent 动作: \n" + intent.getAction());
Set<String> categories = intent.getCategories();
if (categories != null) {
for (String category : categories) {
sb.append("\n接收到的 Intent 类别 :\n" + category);
}
}
Uri data = intent.getData();
if (data != null) {
sb.append("\n接收到的 Intent 数据 :\n" + data.toString());
}
} else {
sb.append("Intent is null.");
}
sb.append("\n\n");
LogUtils.d(TAG, sb.toString());
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// 缓存当前 activity
WinBollActivityManager.getInstance(this).add(this);
}
@Override
public void onDestroy() {
WinBollActivityManager.getInstance(this).registeRemove(this);
super.onDestroy();
}
public void onTestLogClick(View view) { public void onTestLogClick(View view) {
LogUtils.d(TAG, "onTestLogClick"); LogUtils.d(TAG, "onTestLogClick");
Toast.makeText(getApplication(), "onTestLogClick", Toast.LENGTH_SHORT).show(); Toast.makeText(getApplication(), "onTestLogClick", Toast.LENGTH_SHORT).show();
} }
public void onLogUtilsClick(View view) { public void onLogUtilsClick(View view) {
// Intent intent = new Intent(this, LogActivity.class); Intent intent = new Intent(this, LogActivity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
// startActivity(intent); startActivity(intent);
//WinBollActivityManager.getInstance().printAvtivityListInfo();
WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class);
} }
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// setSubTitle("");
}
@Override
public void onBackPressed() {
// exit();
}
// void exit() {
// YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
//
// @Override
// public void onYes() {
// WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
// }
//
// @Override
// public void onNo() {
// }
// };
// YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
// }
// //
// 处理传入的 Intent 数据 // 处理传入的 Intent 数据
// //
@@ -245,87 +126,39 @@ final public class MainActivity extends Activity implements IWinBollActivity {
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public String getTag() {
//ToastUtils.show("onCreateOptionsMenu"); return TAG;
getMenuInflater().inflate(R.menu.toolbar_main, menu);
if (isAddWinBollToolBar()) {
//ToastUtils.show("mIWinBoll.isAddWinBollToolBar()");
getMenuInflater().inflate(R.menu.toolbar_winboll_shared_main, menu);
}
if (App.isDebug()) {
getMenuInflater().inflate(R.menu.toolbar_studio_debug, menu);
} }
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_exit) { if (item.getItemId() == R.id.item_testwinboll) {
exit(); WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestWinBollActivity.class);
return true;
} else if (item.getItemId() == R.id.item_about) {
AboutActivityFactory.showAboutActivity(this, getAppInfo());
return true;
} else if (item.getItemId() == R.id.item_teststringtoqrcodeview) { } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) {
WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestStringToQrCodeViewActivity.class); WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestStringToQrCodeViewActivity.class);
} else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) { } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) {
Intent intent = new Intent(this, QRCodeDecodeActivity.class); Intent intent = new Intent(this, QRCodeDecodeActivity.class);
startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
} else if (item.getItemId() == R.id.item_testcrashreport) {
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
getString(i);
}
return true;
} else if (item.getItemId() == R.id.item_log) {
WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class);
return true;
} else if (item.getItemId() == R.id.item_exitdebug) {
//AboutView.setApp2NormalMode(this);
return true;
} else if (item.getItemId() == android.R.id.home) {
WinBollActivityManager.getInstance(this).finish(this);
return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
void about() {
// Intent intent = new Intent(this, AboutActivity.class);
// intent.putExtra(AboutActivity.EXTRA_APPINFO, AboutActivityFactory.buildAPPBranchInfo(this));
// WinBollActivityManager.getInstance(this).startWinBollActivity(this, intent, AboutActivity.class);
}
void exit() {
YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
}
@Override
public void onNo() {
}
};
YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
}
@Override
public void onBackPressed() {
if (WinBollActivityManager.getInstance(getApplicationContext()).isFirstIWinBollActivity(this)) {
exit();
} else {
WinBollActivityManager.getInstance(this).finish(this);
super.onBackPressed();
}
}
public void onTestAboutActivity(View view) {
about();
}
public void onTestJavascriptHtmlActivity(View view) { public void onTestJavascriptHtmlActivity(View view) {
Intent intent = new Intent(this, AssetsHtmlActivity.class); Intent intent = new Intent(this, AssetsHtmlActivity.class);
intent.putExtra(AssetsHtmlActivity.EXTRA_HTMLFILENAME, "javascript_test.html"); intent.putExtra(AssetsHtmlActivity.EXTRA_HTMLFILENAME, "javascript_test.html");
@@ -333,25 +166,17 @@ final public class MainActivity extends Activity implements IWinBollActivity {
} }
@Override @Override
protected void onResume() { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onResume();
mLogView.start();
}
/*@Override
protected void onActivithyResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { switch (requestCode) {
case REQUEST_QRCODEDECODE_ACTIVITY : { case REQUEST_QRCODEDECODE_ACTIVITY : {
if (data != null) {
String text = data.getStringExtra(QRCodeDecodeActivity.EXTRA_RESULT); String text = data.getStringExtra(QRCodeDecodeActivity.EXTRA_RESULT);
ToastUtils.show(text); ToastUtils.show(text);
}
break; break;
} }
default : { default : {
//ToastUtils.show(String.format("%d, %d", requestCode, resultCode)); ToastUtils.show(String.format("%d, %d", requestCode, resultCode));
super.prosessActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
}
} }
} }
}*/
} }

View File

@@ -1,50 +1,37 @@
package cc.winboll.studio.apputils; package cc.winboll.studio.apputils;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.view.StringToQrCodeView;
/** /**
* @Author ZhanGSKen@QQ.COM * @Author ZhanGSKen@QQ.COM
* @Date 2025/01/17 19:50:46 * @Date 2025/01/17 19:50:46
*/ */
import cc.winboll.studio.apputils.R; public class TestStringToQrCodeViewActivity extends WinBollActivity {
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toolbar;
import cc.winboll.studio.libapputils.app.IWinBollActivity;
import cc.winboll.studio.libapputils.bean.APPInfo;
import cc.winboll.studio.libapputils.view.StringToQrCodeView;
public class TestStringToQrCodeViewActivity extends Activity implements IWinBollActivity {
public static final String TAG = "TestStringToQrCodeViewActivity"; public static final String TAG = "TestStringToQrCodeViewActivity";
StringToQrCodeView mStringToQrCodeView; StringToQrCodeView mStringToQrCodeView;
@Override
public Activity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override @Override
public String getTag() { public String getTag() {
return TAG; return TAG;
} }
@Override @Override
public Toolbar initToolBar() { protected Toolbar initToolBar() {
return findViewById(R.id.activityteststringtoqrcodeviewToolbar1); return findViewById(R.id.activityteststringtoqrcodeviewToolbar1);
} }
@Override @Override
public boolean isEnableDisplayHomeAsUp() { protected boolean isEnableDisplayHomeAsUp() {
return true; return true;
} }
@Override @Override
public boolean isAddWinBollToolBar() { protected boolean isAddWinBollToolBar() {
return true; return true;
} }
@@ -54,4 +41,10 @@ public class TestStringToQrCodeViewActivity extends Activity implements IWinBoll
setContentView(R.layout.activity_teststringtoqrcodeview); setContentView(R.layout.activity_teststringtoqrcodeview);
mStringToQrCodeView = findViewById(R.id.activityteststringtoqrcodeviewStringToQrCodeView1); mStringToQrCodeView = findViewById(R.id.activityteststringtoqrcodeviewStringToQrCodeView1);
} }
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setSubTitle(TAG);
}
} }

View File

@@ -0,0 +1,52 @@
package cc.winboll.studio.apputils;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.activities.AssetsHtmlActivity;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/13 15:09:46
*/
public class TestWinBollActivity extends WinBollActivity {
public static final String TAG = "TestWinBollActivity";
@Override
public String getTag() {
return TAG;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activitytestwinbollToolbar1);
}
@Override
protected boolean isEnableDisplayHomeAsUp() {
return true;
}
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testwinboll);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setSubTitle(TAG);
}
}

View File

@@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitymainToolbar1"/> android:id="@+id/activitymainToolbar1"/>
@@ -54,13 +54,6 @@
</LinearLayout> </LinearLayout>
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Button"
android:id="@+id/logview"
android:layout_weight="1.0"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activityteststringtoqrcodeviewToolbar1"/> android:id="@+id/activityteststringtoqrcodeviewToolbar1"/>

View File

@@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#FF36B5B3"> android:background="#FF36B5B3">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitytestwinbollToolbar1"/> android:id="@+id/activitytestwinbollToolbar1"/>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@@ -3,14 +3,14 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/item_testwinboll" android:id="@+id/item_testwinboll"
android:title="TestWinBollActivity"/> android:title="TestWinBollActivity"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/item_teststringtoqrcodeview" android:id="@+id/item_teststringtoqrcodeview"
android:title="TestStringToQrCodeViewActivity"/> android:title="TestStringToQrCodeViewActivity"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/item_testqrcodedecodeactivity" android:id="@+id/item_testqrcodedecodeactivity"
android:title="TestQRCodeDecodeActivity"/> android:title="TestQRCodeDecodeActivity"
<item app:showAsAction="ifRoom"/>
android:id="@+id/item_testcrashreport"
android:title="TestCrashReportActivity"/>
</menu> </menu>

View File

@@ -4,4 +4,7 @@
<color name="colorPrimary">#FF196ABC</color> <color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color> <color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color> <color name="colorAccent">#FF80BFFF</color>
<color name="colorToastFrame">#FFA9A9A9</color>
<color name="colorToastShadow">#FF000000</color>
<color name="colorToastBackgroung">#FFFFFFFF</color>
</resources> </resources>

View File

@@ -1,14 +1,3 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="UtilsTheme" parent="APPBaseTheme">
<item name="attrColorPrimary">@color/colorPrimary</item>
<item name="themeGlobalCrashActivity">@style/UtilsGlobalCrashActivityTheme</item>
</style>
<style name="UtilsGlobalCrashActivityTheme" parent="GlobalCrashActivityTheme">
<item name="colorTittle">#FFFFFFFF</item>
<item name="colorTittleBackgound">#FF00A4B3</item>
<item name="colorText">#FFFFFFFF</item>
<item name="colorTextBackgound">#FF000000</item>
</style>
</resources> </resources>

View File

@@ -1,6 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
repositories { repositories {
// Nexus Maven 库地址
// "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' } maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
@@ -9,13 +15,6 @@ buildscript {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
mavenCentral() mavenCentral()
google() google()
// Nexus Maven 库地址
// "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
mavenLocal() mavenLocal()
} }
dependencies { dependencies {
@@ -27,6 +26,12 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
// Nexus Maven 库地址
// "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' } maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
@@ -35,13 +40,6 @@ allprojects {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
mavenCentral() mavenCentral()
google() google()
// Nexus Maven 库地址
// "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
mavenLocal() mavenLocal()
} }
ext { ext {

View File

@@ -17,3 +17,5 @@ org.gradle.jvmargs=-Xmx2048m
android.useAndroidX=false android.useAndroidX=false
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=false android.enableJetifier=false
# 保持与旧版Gradle插件的兼容
android.disableAutomaticComponentCreation=true

View File

@@ -17,3 +17,5 @@ org.gradle.jvmargs=-Xmx2048m
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
# 保持与旧版Gradle插件的兼容
android.disableAutomaticComponentCreation=true

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sat Mar 15 15:29:07 HKT 2025 #Mon Mar 24 07:44:12 HKT 2025
stageCount=3 stageCount=8
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.2 publishVersion=15.0.7
buildCount=0 buildCount=0
baseBetaVersion=15.0.3 baseBetaVersion=15.0.8

View File

@@ -190,6 +190,7 @@ public class LogView extends RelativeLayout {
// 加载标签表 // 加载标签表
mListViewTags = findViewById(cc.winboll.studio.libappbase.R.id.tags_listview); mListViewTags = findViewById(cc.winboll.studio.libappbase.R.id.tags_listview);
mListViewTags.setVerticalOffset(10);
mTAGListAdapter = new TAGListAdapter(mContext, mapTAGList); mTAGListAdapter = new TAGListAdapter(mContext, mapTAGList);
mListViewTags.setAdapter(mTAGListAdapter); mListViewTags.setAdapter(mTAGListAdapter);

View File

@@ -12,7 +12,9 @@ import android.widget.ListView;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
public class HorizontalListView extends ListView { public class HorizontalListView extends ListView {
public static final String TAG = "HorizontalListView"; public static final String TAG = "HorizontalListView";
int verticalOffset = 0;
public HorizontalListView(Context context) { public HorizontalListView(Context context) {
super(context); super(context);
@@ -25,25 +27,10 @@ public class HorizontalListView extends ListView {
public HorizontalListView(Context context, AttributeSet attrs, int defStyle) { public HorizontalListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
} }
// @Override
// protected void onLayout(boolean changed, int l, int t, int r, int b) { public void setVerticalOffset(int verticalOffset) {
// super.onLayout(changed, l, t, r, b); this.verticalOffset = verticalOffset;
// int childCount = getChildCount(); }
// int left = getPaddingLeft();
// // 获取HorizontalListView的高度
// int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
// for (int i = 0; i < childCount; i++) {
// View child = getChildAt(i);
// int width = child.getMeasuredWidth();
// int height = child.getMeasuredHeight();
// // 计算子项在垂直方向上的居中偏移量
// int verticalOffset = (viewHeight - height) / 2;
// // 设置子视图的位置,实现水平布局并垂直居中
// child.layout(left, getPaddingTop() + verticalOffset, left + width, getPaddingTop() + verticalOffset + height);
// left += width;
// }
// }
//
@Override @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { protected void onLayout(boolean changed, int l, int t, int r, int b) {
@@ -52,7 +39,7 @@ public class HorizontalListView extends ListView {
int left = getPaddingLeft(); int left = getPaddingLeft();
int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
LogUtils.d(TAG, String.format("HorizontalListView的高度 %d", viewHeight)); LogUtils.d(TAG, String.format("HorizontalListView的高度 %d", viewHeight));
int verticalOffset = 20;
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
View child = getChildAt(i); View child = getChildAt(i);
// 计算每个子视图的宽度和高度 // 计算每个子视图的宽度和高度
@@ -68,15 +55,11 @@ public class HorizontalListView extends ListView {
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
//super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); //super.onMeasure(widthMeasureSpec, newHeightMeasureSpec);
int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
//LogUtils.d(TAG, String.format("newWidthMeasureSpec %d, newHeightMeasureSpec %d", newWidthMeasureSpec, newHeightMeasureSpec)); //LogUtils.d(TAG, String.format("newWidthMeasureSpec %d, newHeightMeasureSpec %d", newWidthMeasureSpec, newHeightMeasureSpec));
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
// ViewGroup.LayoutParams params = getLayoutParams();
// params.width = getMeasuredWidth();
} }
} }

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#000000" /> <!-- 这里可调整边框宽度和颜色 -->
<solid android:color="@android:color/transparent" />
<corners
android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip"
android:topLeftRadius="6dip"
android:topRightRadius="6dip" />
</shape>

View File

@@ -10,8 +10,8 @@
<shape android:shape="rectangle" > <shape android:shape="rectangle" >
<gradient <gradient
android:angle="270" android:angle="270"
android:endColor="#0F000000" android:endColor="@color/colorAccent"
android:startColor="#0F000000" /> android:startColor="@color/colorAccent" />
<corners <corners
android:bottomLeftRadius="6dip" android:bottomLeftRadius="6dip"
android:bottomRightRadius="6dip" android:bottomRightRadius="6dip"

View File

@@ -5,17 +5,17 @@
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#FFEEEEEE"> android:background="@drawable/bg_border_round">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="24dp" android:layout_height="@dimen/button_height"
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:id="@+id/viewlogtagTextView1"/> android:id="@+id/viewlogtagTextView1"/>
<CheckBox <CheckBox
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="24dp" android:layout_height="@dimen/button_height"
android:id="@+id/viewlogtagCheckBox1"/> android:id="@+id/viewlogtagCheckBox1"/>
</LinearLayout> </LinearLayout>

View File

@@ -72,27 +72,29 @@
android:layout_below="@+id/viewlogRelativeLayoutToolbar" android:layout_below="@+id/viewlogRelativeLayoutToolbar"
android:id="@+id/viewlogLinearLayout1" android:id="@+id/viewlogLinearLayout1"
android:gravity="center_vertical" android:gravity="center_vertical"
android:background="#FFC0F4C2"> android:background="@drawable/bg_shadow">
<CheckBox <CheckBox
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="@dimen/button_height"
android:text="ALL" android:text="ALL"
android:id="@+id/viewlogCheckBox1"/> android:id="@+id/viewlogCheckBox1"
android:background="@drawable/bg_border_round"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<HorizontalScrollView <HorizontalScrollView
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/bg_border"
android:scrollbars="none" android:scrollbars="none"
android:layout_weight="1.0" android:padding="5dp"
android:background="#FF97F2E3"> android:layout_weight="1.0">
<cc.winboll.studio.libappbase.views.HorizontalListView <cc.winboll.studio.libappbase.views.HorizontalListView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/view_border" android:id="@+id/tags_listview"/>
android:id="@+id/tags_listview"
android:paddingLeft="10dp"/>
</HorizontalScrollView> </HorizontalScrollView>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 定义一个名为text_size_normal的尺寸值为16sp -->
<dimen name="text_size_normal">16sp</dimen>
<!-- 定义一个名为margin_small的尺寸值为8dp -->
<dimen name="margin_small">8dp</dimen>
<!-- 定义一个名为image_width的尺寸值为200dp -->
<dimen name="button_height">24dp</dimen>
</resources>

View File

@@ -4,12 +4,12 @@ apply from: '../.winboll/winboll_lib_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle' apply from: '../.winboll/winboll_lint_build.gradle'
android { android {
compileSdkVersion 30 compileSdkVersion 32
buildToolsVersion "30.0.3" buildToolsVersion "33.0.3"
defaultConfig { defaultConfig {
minSdkVersion 26 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
} }
buildTypes { buildTypes {
release { release {
@@ -17,22 +17,28 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
} }
dependencies { dependencies {
// 二维码使用的类库
api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0'
api 'io.github.medyo:android-about-page:2.0.0'
api 'com.github.getActivity:ToastUtils:10.5'
api 'com.jcraft:jsch:0.1.55'
api 'org.jsoup:jsoup:1.13.1'
api 'com.squareup.okhttp3:okhttp:4.4.1'
api 'androidx.appcompat:appcompat:1.0.0'
api 'androidx.fragment:fragment:1.0.0'
api 'com.google.android.material:material:1.0.0'
api 'cc.winboll.studio:libappbase:1.0.3'
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
implementation 'cc.winboll.studio:libappbase:15.0.3'
// 二维码类库
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
// 网络连接类库
//implementation 'com.squareup.okhttp3:okhttp:4.4.1'
// Html 解析
//implementation 'org.jsoup:jsoup:1.13.1'
// SSH
//implementation 'com.jcraft:jsch:0.1.55'
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue Mar 18 09:52:37 HKT 2025 #Sat Jan 18 13:02:39 HKT 2025
stageCount=2 stageCount=2
libraryProject=libapputils libraryProject=libapputils
baseVersion=15.0 baseVersion=9.2
publishVersion=15.0.1 publishVersion=9.2.1
buildCount=0 buildCount=0
baseBetaVersion=15.0.2 baseBetaVersion=9.2.2

View File

@@ -18,9 +18,6 @@
<!-- 拍摄照片和视频 --> <!-- 拍摄照片和视频 -->
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:networkSecurityConfig="@xml/network_security_config"> <application android:networkSecurityConfig="@xml/network_security_config">
<activity <activity
@@ -29,7 +26,7 @@
android:launchMode="standard"/> android:launchMode="standard"/>
<activity <activity
android:name=".activities.LogActivity" android:name=".log.LogActivity"
android:label="LogActivity" android:label="LogActivity"
android:launchMode="standard"/> android:launchMode="standard"/>

View File

@@ -1,41 +1,24 @@
package cc.winboll.studio.libapputils.activities; package cc.winboll.studio.libapputils.activities;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/07/14 13:20:33
* @Describe 应用介绍页
*/
import cc.winboll.studio.libapputils.R;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.LinearLayout; import androidx.appcompat.widget.Toolbar;
import android.widget.Toolbar; import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.APPInfo; import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.view.AboutView;
final public class AboutActivity extends Activity implements IWinBollActivity { /**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/07/14 13:20:33
* @Describe AboutFragment Test
*/
final public class AboutActivity extends WinBollActivity {
public static final String TAG = "AboutActivity"; public static final String TAG = "AboutActivity";
public static final String EXTRA_APPINFO = "EXTRA_APPINFO";
APPInfo mAPPInfo;
@Override
public Activity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override @Override
public String getTag() { public String getTag() {
@@ -43,37 +26,45 @@ final public class AboutActivity extends Activity implements IWinBollActivity {
} }
@Override @Override
public boolean isEnableDisplayHomeAsUp() { protected boolean isEnableDisplayHomeAsUp() {
return true; return true;
} }
@Override
public boolean isAddWinBollToolBar() {
return false;
}
@Override
public Toolbar initToolBar() {
return findViewById(R.id.activityaboutToolbar1);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about); setContentView(R.layout.activity_about);
Intent intent = getIntent();
if (intent != null) { /*AboutView aboutView = findViewById(R.id.activityaboutAboutView1);
mAPPInfo = (APPInfo)intent.getSerializableExtra(EXTRA_APPINFO); aboutView.setOnRequestDevUserInfoAutofillListener(new AboutView.OnRequestDevUserInfoAutofillListener(){
@Override
public void requestAutofill(EditText etDevUserName, EditText etDevUserPassword) {
AutofillManager autofillManager = (AutofillManager) getSystemService(AutofillManager.class);
if (autofillManager!= null) {
//ToastUtils.show("0");
autofillManager.requestAutofill(findViewById(R.id.usernameEditText));
autofillManager.requestAutofill(findViewById(R.id.passwordEditText));
} }
if (mAPPInfo == null) { }
mAPPInfo = new APPInfo(); });*/
} }
AboutView aboutView = new AboutView(this, mAPPInfo); @Override
LinearLayout llMain = findViewById(R.id.activityaboutLinearLayout1); protected void onPostCreate(Bundle savedInstanceState) {
llMain.addView(aboutView); super.onPostCreate(savedInstanceState);
setSubTitle(TAG);
}
//ToastUtils.show(TAG); @Override
protected boolean isAddWinBollToolBar() {
return false;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activityaboutToolbar1);
} }
@Override @Override
@@ -82,11 +73,15 @@ final public class AboutActivity extends Activity implements IWinBollActivity {
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_help) { if (item.getItemId() == R.id.item_help) {
WinBollActivityManager.getInstance(this).startWinBollActivity(this, AssetsHtmlActivity.class); WinBollActivityManager.getInstance(this).startWinBollActivity(this, AssetsHtmlActivity.class);
} }
// else if (item.getItemId() == android.R.id.home) {
// WinBollActivityManager.getInstance(this).finish(this);
// }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }

View File

@@ -5,23 +5,23 @@ package cc.winboll.studio.libapputils.activities;
* @Date 2025/01/03 11:02:49 * @Date 2025/01/03 11:02:49
* @Describe 一个可以浏览随 APP 附带的 Html 文档的窗口 * @Describe 一个可以浏览随 APP 附带的 Html 文档的窗口
*/ */
import cc.winboll.studio.libapputils.R;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.bean.APPInfo; import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.view.SimpleWebView; import cc.winboll.studio.libapputils.view.SimpleWebView;
import com.hjq.toast.ToastUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import android.os.PersistableBundle;
public class AssetsHtmlActivity extends Activity implements IWinBollActivity { public class AssetsHtmlActivity extends WinBollActivity {
public static final String TAG = "AssetsHtmlActivity"; public static final String TAG = "AssetsHtmlActivity";
@@ -34,34 +34,24 @@ public class AssetsHtmlActivity extends Activity implements IWinBollActivity {
// Assets 文件夹里的 Html 文件的名称 // Assets 文件夹里的 Html 文件的名称
String mszHtmlFileName; String mszHtmlFileName;
@Override
public Activity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override @Override
public String getTag() { public String getTag() {
return TAG; return TAG;
} }
@Override @Override
public boolean isEnableDisplayHomeAsUp() { protected boolean isEnableDisplayHomeAsUp() {
return true; return true;
} }
@Override @Override
public boolean isAddWinBollToolBar() { protected boolean isAddWinBollToolBar() {
return false; return false;
} }
@Override @Override
public Toolbar initToolBar() { protected Toolbar initToolBar() {
return findViewById(R.id.activityassetshtmlToolbar1); return findViewById(R.id.activityassetshtmlToolbar1);
} }
@@ -91,7 +81,7 @@ public class AssetsHtmlActivity extends Activity implements IWinBollActivity {
if (szTemp != null && !szTemp.trim().equals("")) { if (szTemp != null && !szTemp.trim().equals("")) {
mszHtmlFileName = szTemp.trim(); mszHtmlFileName = szTemp.trim();
} }
//ToastUtils.show(mszHtmlFileName); ToastUtils.show(mszHtmlFileName);
} }
// 与其他应用分享 html 帮助 // 与其他应用分享 html 帮助
@@ -117,6 +107,13 @@ public class AssetsHtmlActivity extends Activity implements IWinBollActivity {
// myWebView.loadUrl(mszHelpIndexFileUri.toString()); // myWebView.loadUrl(mszHelpIndexFileUri.toString());
} }
@Override
public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
setSubTitle(mszHtmlFileName);
//setSubTitle(TAG);
}
// //
void initWebViewFromAssets(String szHtmlFileName) { void initWebViewFromAssets(String szHtmlFileName) {
try { try {

View File

@@ -1,68 +0,0 @@
package cc.winboll.studio.libapputils.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/08 00:19:39
* @Describe LogActivity
*/
import cc.winboll.studio.libapputils.R;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libapputils.app.IWinBollActivity;
import cc.winboll.studio.libapputils.bean.APPInfo;
public class LogActivity extends Activity implements IWinBollActivity {
public static final String TAG = "LogActivity";
LogView mLogView;
@Override
public Activity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override
public String getTag() {
return TAG;
}
@Override
public Toolbar initToolBar() {
return null;
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override
public boolean isAddWinBollToolBar() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
mLogView = findViewById(R.id.logview);
mLogView.start();
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume");
super.onResume();
}
}

View File

@@ -5,59 +5,48 @@ package cc.winboll.studio.libapputils.activities;
* @Date 2025/01/18 10:32:21 * @Date 2025/01/18 10:32:21
* @Describe 二维码扫码解码窗口 * @Describe 二维码扫码解码窗口
*/ */
import cc.winboll.studio.libapputils.R;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.app.IWinBollActivity; import androidx.core.app.ActivityCompat;
import cc.winboll.studio.libapputils.bean.APPInfo; import androidx.core.content.ContextCompat;
import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import com.google.zxing.ResultPoint; import com.google.zxing.ResultPoint;
import com.journeyapps.barcodescanner.BarcodeCallback; import com.journeyapps.barcodescanner.BarcodeCallback;
import com.journeyapps.barcodescanner.BarcodeResult; import com.journeyapps.barcodescanner.BarcodeResult;
import com.journeyapps.barcodescanner.DecoratedBarcodeView; import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import java.util.List; import java.util.List;
public class QRCodeDecodeActivity extends Activity implements IWinBollActivity { public class QRCodeDecodeActivity extends WinBollActivity {
public static final String TAG = "QRCodeDecodeActivity"; public static final String TAG = "QRCodeDecodeActivity";
public static final String EXTRA_RESULT = "EXTRA_RESULT"; public static final String EXTRA_RESULT = "EXTRA_RESULT";
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final int REQUEST_CAMERA_PERMISSION = 1;
TextView resultTextView; TextView resultTextView;
DecoratedBarcodeView barcodeView; DecoratedBarcodeView barcodeView;
@Override
public Activity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override @Override
public String getTag() { public String getTag() {
return TAG; return TAG;
} }
@Override @Override
public boolean isEnableDisplayHomeAsUp() { protected boolean isEnableDisplayHomeAsUp() {
return true; return true;
} }
@Override @Override
public boolean isAddWinBollToolBar() { protected boolean isAddWinBollToolBar() {
return false; return false;
} }
@Override @Override
public Toolbar initToolBar() { protected Toolbar initToolBar() {
return findViewById(R.id.activityqrcodedecodeToolbar1); return findViewById(R.id.activityqrcodedecodeToolbar1);
} }
@@ -68,15 +57,14 @@ public class QRCodeDecodeActivity extends Activity implements IWinBollActivity {
resultTextView = findViewById(R.id.activityqrcodedecodeTextView1); resultTextView = findViewById(R.id.activityqrcodedecodeTextView1);
barcodeView = findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1); barcodeView = findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1);
// 请求相机权限 // 请求相机权限
// if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
// != PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
// ActivityCompat.requestPermissions(this, ActivityCompat.requestPermissions(this,
// new String[]{android.Manifest.permission.CAMERA}, new String[]{android.Manifest.permission.CAMERA},
// REQUEST_CAMERA_PERMISSION); REQUEST_CAMERA_PERMISSION);
// } else { } else {
// startScanning();
// }
startScanning(); startScanning();
}
} }

View File

@@ -0,0 +1,240 @@
package cc.winboll.studio.libapputils.ads;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/12/09 15:37:35
* @Describe WinBoll 应用推广视图
*/
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.RelativeLayout;
import com.hjq.toast.ToastUtils;
public class ADsView extends RelativeLayout {
public static final String TAG = "ADsView";
public volatile boolean mIsHandling;
public volatile boolean mIsAddNewLog;
Context mContext;
WebView mWebView;
//ScrollView mScrollView;
//TextView mTextView;
//CheckBox mSelectableCheckBox;
//LogViewThread mLogViewThread;
//LogViewHandler mLogViewHandler;
//Spinner mLogLevelSpinner;
//ArrayAdapter<CharSequence> mLogLevelSpinnerAdapter;
public ADsView(Context context) {
super(context);
initView(context);
}
public ADsView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ADsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public ADsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
// public void start() {
// mLogViewThread = new LogViewThread(LogView.this);
// mLogViewThread.start();
// // 显示日志
// showAndScrollLogView();
// }
//
// public void scrollLogUp() {
// mScrollView.post(new Runnable() {
// @Override
// public void run() {
// mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
// // 日志显示结束
// mLogViewHandler.setIsHandling(false);
// // 检查是否添加了新日志
// if (mLogViewHandler.isAddNewLog()) {
// // 有新日志添加,先更改新日志标志
// mLogViewHandler.setIsAddNewLog(false);
// // 再次发送显示日志的显示
// Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
// mLogViewHandler.sendMessage(message);
// }
// }
// });
// }
void initView(Context context) {
mContext = context;
// mLogViewHandler = new LogViewHandler();
// 加载视图布局
View viewMain = inflate(mContext, cc.winboll.studio.libapputils.R.layout.view_ads, null);
mWebView = viewMain.findViewById(cc.winboll.studio.libapputils.R.id.viewadsWebView1);
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
ToastUtils.show(url);
return true;
}
});
// // 初始化日志子控件视图
// //
// mScrollView = findViewById(cc.winboll.studio.libapputils.R.id.viewlogScrollViewLog);
// mTextView = findViewById(cc.winboll.studio.libapputils.R.id.viewlogTextViewLog);
// // 获取Log Level spinner实例
// mLogLevelSpinner = findViewById(cc.winboll.studio.libapputils.R.id.viewlogSpinner1);
//
// (findViewById(cc.winboll.studio.libapputils.R.id.viewlogButtonClean)).setOnClickListener(new View.OnClickListener(){
//
// @Override
// public void onClick(View v) {
// LogUtils.cleanLog();
// LogUtils.d(TAG, "Log is cleaned.");
// }
// });
// (findViewById(cc.winboll.studio.libapputils.R.id.viewlogButtonCopy)).setOnClickListener(new View.OnClickListener(){
//
// @Override
// public void onClick(View v) {
//
// ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
// cm.setPrimaryClip(ClipData.newPlainText(mContext.getPackageName(), LogUtils.loadLog()));
// LogUtils.d(TAG, "Log is copied.");
// }
// });
// mSelectableCheckBox = findViewById(cc.winboll.studio.libapputils.R.id.viewlogCheckBoxSelectable);
// mSelectableCheckBox.setOnClickListener(new View.OnClickListener(){
// @Override
// public void onClick(View v) {
// if (mSelectableCheckBox.isChecked()) {
// setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
// } else {
// setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
// }
// }
// });
//
// // 设置日志级别列表
// ArrayList<String> adapterItems = new ArrayList<>();
// for (LogUtils.LOG_LEVEL e : LogUtils.LOG_LEVEL.values()) {
// adapterItems.add(e.name());
// }
// // 假设你有一个字符串数组作为选项列表
// //String[] options = {"Option 1", "Option 2", "Option 3"};
// // 创建一个ArrayAdapter来绑定数据到spinner
// mLogLevelSpinnerAdapter = ArrayAdapter.createFromResource(
// context, cc.winboll.studio.libapputils.R.array.enum_loglevel_array, android.R.layout.simple_spinner_item);
// mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//
// // 设置适配器并将它应用到spinner上
// mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // 设置下拉视图样式
// mLogLevelSpinner.setAdapter(mLogLevelSpinnerAdapter);
// // 为Spinner添加监听器
// mLogLevelSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
// @Override
// public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// //String selectedOption = mLogLevelSpinnerAdapter.getItem(position);
// // 处理选中的选项...
// LogUtils.setLogLevel(LogUtils.LOG_LEVEL.values()[position]);
// }
// @Override
// public void onNothingSelected(AdapterView<?> parent) {
// // 如果没有选择,则执行此操作...
// }
// });
// // 获取默认值的索引
// int defaultValueIndex = LogUtils.getLogLevel().ordinal();
//
// if (defaultValueIndex != -1) {
// // 如果找到了默认值,设置默认选项
// mLogLevelSpinner.setSelection(defaultValueIndex);
// }
//
// // 设置滚动时不聚焦日志
// setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
public void loadUrl(String url) {
mWebView.loadUrl(url);
//webView.loadUrl("https://www.winboll.cc");
//webView.loadUrl("https://ads.winboll.cc");
}
// public void updateLogView() {
// if (mLogViewHandler.isHandling() == true) {
// // 正在处理日志显示,
// // 就先设置一个新日志标志位
// // 以便日志显示完后,再次显示新日志内容
// mLogViewHandler.setIsAddNewLog(true);
// } else {
// //LogUtils.d(TAG, "LogListener showLog(String path)");
// Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
// mLogViewHandler.sendMessage(message);
// mLogViewHandler.setIsAddNewLog(false);
// }
// }
//
// void showAndScrollLogView() {
// mTextView.setText(LogUtils.loadLog());
// scrollLogUp();
// }
//
// class LogViewHandler extends Handler {
//
// final static int MSG_LOGVIEW_UPDATE = 0;
// volatile boolean isHandling;
// volatile boolean isAddNewLog;
//
// public LogViewHandler() {
// setIsHandling(false);
// setIsAddNewLog(false);
// }
//
// public void setIsHandling(boolean isHandling) {
// this.isHandling = isHandling;
// }
//
// public boolean isHandling() {
// return isHandling;
// }
//
// public void setIsAddNewLog(boolean isAddNewLog) {
// this.isAddNewLog = isAddNewLog;
// }
//
// public boolean isAddNewLog() {
// return isAddNewLog;
// }
//
// public void handleMessage(Message msg) {
// switch (msg.what) {
// case MSG_LOGVIEW_UPDATE:{
// if (isHandling() == false) {
// setIsHandling(true);
// showAndScrollLogView();
// }
// break;
// }
// default:
// break;
// }
// super.handleMessage(msg);
// }
// }
}

View File

@@ -1,54 +0,0 @@
package cc.winboll.studio.libapputils.app;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/02/06 08:45:23
* @Describe 关于活动窗口的介绍窗口工厂
*/
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libapputils.activities.AboutActivity;
import cc.winboll.studio.libapputils.app.AboutActivityFactory;
import cc.winboll.studio.libapputils.bean.APPInfo;
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);
WinBollActivityManager.getInstance(context).startWinBollActivity(context, intent, AboutActivity.class);
}
}

View File

@@ -5,7 +5,7 @@ package cc.winboll.studio.libapputils.app;
* @Date 2024/08/12 14:45:35 * @Date 2024/08/12 14:45:35
* @Describe 应用版本工具集 * @Describe 应用版本工具集
*/ */
import cc.winboll.studio.libappbase.LogUtils; import com.hjq.toast.ToastUtils;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -23,7 +23,6 @@ public class AppVersionUtils {
// true 新版本 == 当前版本 // true 新版本 == 当前版本
// //
public static boolean isHasNewVersion2(String szCurrentName, String szNextName) { public static boolean isHasNewVersion2(String szCurrentName, String szNextName) {
LogUtils.d(TAG, String.format("isHasNewVersion2\nszCurrentName : %s\nszNextName : %s", szCurrentName, szNextName));
//szCurrentName = "AES_6.2.0-beta0_3234.apk"; //szCurrentName = "AES_6.2.0-beta0_3234.apk";
//szNextName = "AES_6.1.12.apk"; //szNextName = "AES_6.1.12.apk";
//szCurrentName = "AES_6.2.0-beta0_3234.apk"; //szCurrentName = "AES_6.2.0-beta0_3234.apk";
@@ -80,7 +79,6 @@ public class AppVersionUtils {
} }
public static boolean isHasNewStageReleaseVersion(String szCurrentName, String szNextName) { public static boolean isHasNewStageReleaseVersion(String szCurrentName, String szNextName) {
LogUtils.d(TAG, String.format("isHasNewStageReleaseVersion\nszCurrentName : %s\nszNextName : %s", szCurrentName, szNextName));
//szCurrentName = "AES_6.2.12.apk"; //szCurrentName = "AES_6.2.12.apk";
//szNextName = "AES_6.3.12.apk"; //szNextName = "AES_6.3.12.apk";
if (checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName))) { if (checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName))) {
@@ -98,10 +96,6 @@ public class AppVersionUtils {
// 返回 true 新版本 > 当前版本 // 返回 true 新版本 > 当前版本
// //
public static Boolean checkNewVersion(String szCurrentCode, String szNextCode) { public static Boolean checkNewVersion(String szCurrentCode, String szNextCode) {
if (szCurrentCode == null || szCurrentCode.equals("") || szNextCode == null || szNextCode.equals("")) {
LogUtils.d(TAG, String.format("checkNewVersion unexpected parameters:\nszCurrentCode : %s\nszNextCode : %s", szCurrentCode, szNextCode));
return false;
}
boolean isNew = false; boolean isNew = false;
String[] appVersionCurrent = szCurrentCode.split("\\."); String[] appVersionCurrent = szCurrentCode.split("\\.");
String[] appVersionNext = szNextCode.split("\\."); String[] appVersionNext = szNextCode.split("\\.");
@@ -112,7 +106,7 @@ public class AppVersionUtils {
if (Integer.parseInt(appVersionNext[i]) > Integer.parseInt(appVersionCurrent[i])) { if (Integer.parseInt(appVersionNext[i]) > Integer.parseInt(appVersionCurrent[i])) {
isNew = true; isNew = true;
return isNew; return isNew;
} else if (Integer.parseInt(appVersionNext[i]) == Integer.parseInt(appVersionCurrent[i])) { } else if(Integer.parseInt(appVersionNext[i]) == Integer.parseInt(appVersionCurrent[i])) {
continue ; continue ;
} else { } else {
isNew = false; isNew = false;
@@ -128,17 +122,14 @@ public class AppVersionUtils {
// 如 AppUtils_7.0.4.apk 版本号为 7.0.4 // 如 AppUtils_7.0.4.apk 版本号为 7.0.4
// //
public static String getCodeInPackageName(String apkName) { public static String getCodeInPackageName(String apkName) {
LogUtils.d(TAG, String.format("getCodeInPackageName apkName : %s", apkName));
//String apkName = "AppUtils_7.0.0.apk"; //String apkName = "AppUtils_7.0.0.apk";
Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+"); Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+");
Matcher matcher = pattern.matcher(apkName); Matcher matcher = pattern.matcher(apkName);
if (matcher.find()) { if (matcher.find()) {
String version = matcher.group(); String version = matcher.group();
LogUtils.d(TAG, String.format("version is %s", version));
return version; return version;
//System.out.println("Version number: " + version); // 输出7.0.0 //System.out.println("Version number: " + version); // 输出7.0.0
} }
LogUtils.d(TAG, String.format("No result."));
return ""; return "";
} }
@@ -158,4 +149,5 @@ public class AppVersionUtils {
} }
return ""; return "";
} }
} }

View File

@@ -1,23 +0,0 @@
package cc.winboll.studio.libapputils.app;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/08 00:15:36
* @Describe WinBoll 活动窗口通用接口
*/
import android.app.Activity;
import android.widget.Toolbar;
import cc.winboll.studio.libapputils.bean.APPInfo;
public interface IWinBollActivity {
public static final String TAG = "IWinBollActivity";
// 获取当前具有 IWinBoll 特征的 AppCompatActivity 活动窗口
abstract public Activity getActivity();
abstract public APPInfo getAppInfo();
abstract public String getTag();
abstract public Toolbar initToolBar();
abstract public boolean isEnableDisplayHomeAsUp();
abstract public boolean isAddWinBollToolBar();
}

View File

@@ -6,19 +6,22 @@ package cc.winboll.studio.libapputils.app;
*/ */
import android.app.Activity; import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libappbase.utils.ToastUtils; import com.hjq.toast.ToastUtils;
import java.util.Set;
public class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { public class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
public static final String TAG = "MyActivityLifecycleCallbacks"; public static final String TAG = "MyActivityLifecycleCallbacks";
public String mInfo = ""; public String mInfo = "";
public MyActivityLifecycleCallbacks() { public MyActivityLifecycleCallbacks(WinBollApplication application) {
} }
void createActivityeInfo(Activity activity) { void createActivityeInfo(Activity activity) {

View File

@@ -0,0 +1,479 @@
package cc.winboll.studio.libapputils.app;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 14:32:08
* @Describe WinBoll 活动窗口基础类
*/
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.activities.AboutActivity;
import cc.winboll.studio.libapputils.log.LogActivity;
import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.view.AboutView;
import com.hjq.toast.ToastUtils;
import java.util.List;
import java.util.Set;
abstract public class WinBollActivity extends AppCompatActivity {
public static final String TAG = "WinBollActivity";
public static final int REQUEST_LOG_ACTIVITY = 0;
Toolbar mToolBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
checkResolveActivity();
LogUtils.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
archiveInstance();
}
boolean checkResolveActivity() {
PackageManager packageManager = getPackageManager();
//Intent intent = new Intent("your_action_here");
Intent intent = getIntent();
if (intent != null) {
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfoList.size() > 0) {
// 传入的Intent action在Activity清单的intent-filter的action节点里有定义
if (intent.getAction() != null) {
if (intent.getAction().equals(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW)) {
WinBollApplication.setIsDebug(true);
//ToastUtils.show!("WinBollApplication.setIsDebug(true) by action : " + intent.getAction());
}
}
return true;
} else {
// 传入的Intent action在Activity清单的intent-filter的action节点里没有定义
//ToastUtils.show("false : " + intent.getAction());
return false;
}
/* ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
// action在清单文件中有声明
} else {
}*/
}
// action在清单文件中没有声明
ToastUtils.show("false");
return false;
}
void archiveInstance() {
Intent intent = getIntent();
StringBuilder sb = new StringBuilder("\n### Archive Instance ###\n");
if (intent != null) {
ComponentName componentName = intent.getComponent();
if (componentName != null) {
String packageName = componentName.getPackageName();
//Log.d("AppStarter", "启动本应用的应用包名: " + packageName);
sb.append("启动本应用的应用包名: \n" + packageName);
}
sb.append("\nImplicit Intent Tracker \n接收到的 Intent 动作: \n" + intent.getAction());
Set<String> categories = intent.getCategories();
if (categories != null) {
for (String category : categories) {
sb.append("\n接收到的 Intent 类别 :\n" + category);
}
}
Uri data = intent.getData();
if (data != null) {
sb.append("\n接收到的 Intent 数据 :\n" + data.toString());
}
} else {
sb.append("Intent is null.");
}
sb.append("\n\n");
LogUtils.d(TAG, sb.toString());
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mToolBar = initToolBar();
setSupportActionBar(mToolBar);
if (isEnableDisplayHomeAsUp() && mToolBar != null) {
// 显示后退按钮
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
// 缓存当前 activity
LogUtils.d(TAG, "ActManager.getInstance().add(this);");
//ToastUtils.show("getTag() " + getTag());
WinBollActivityManager.getInstance(this).add(this);
//WinBollActivityManager.getInstance().printAvtivityListInfo();
//ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE());
//boolean isDebuging = WinBollApplication.loadDebugStatusIsDebuging();
//ToastUtils.show(String.valueOf(isDebuging));
//WinBollApplication.setIsDebug(true);
setSubTitle(getTag());
}
@Override
public void recreate() {
super.recreate();
}
@Override
protected void onDestroy() {
WinBollActivityManager.getInstance(this).registeRemove(this);
super.onDestroy();
}
@Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
}
@Override
public <T extends View> T findViewById(int id) {
return super.findViewById(id);
}
@Override
public MenuInflater getMenuInflater() {
return super.getMenuInflater();
}
public WinBollActivity getActivity() {
return this;
}
@Override
public Context getApplicationContext() {
return super.getApplicationContext();
}
public <T extends FragmentManager> T getWinBollActivitySupportFragmentManager() {
return (T)super.getSupportFragmentManager();
}
@Override
public ActionBar getSupportActionBar() {
return super.getSupportActionBar();
}
@Override
public void setSupportActionBar(Toolbar toolbar) {
super.setSupportActionBar(toolbar);
}
@Override
public void setActionBar(android.widget.Toolbar toolbar) {
super.setActionBar(toolbar);
}
public void setSubTitle(CharSequence title) {
LogUtils.d(TAG, "setSubTitle");
if (super.getSupportActionBar() != null) {
super.getSupportActionBar().setSubtitle(title);
LogUtils.d(TAG, String.format("setSubtitle title : %s", title));
}
}
public CharSequence getSubTitle() {
if (super.getSupportActionBar() != null) {
return super.getSupportActionBar().getSubtitle();
}
return "";
}
@Override
public void setTitle(CharSequence title) {
//super.setTitle(title);
if (super.getSupportActionBar() != null) {
super.getSupportActionBar().setTitle(title);
LogUtils.d(TAG, String.format("setSubtitle title : %s", title));
}
}
@Override
public void setTitle(int titleId) {
//super.setTitle(titleId);
if (super.getSupportActionBar() != null) {
super.getSupportActionBar().setTitle(titleId);
//LogUtils.d(TAG, String.format("setSubtitle title : %s", title));
}
}
@Override
public void setTheme(Resources.Theme theme) {
super.setTheme(theme);
}
@Override
public void setTheme(int resid) {
super.setTheme(resid);
}
@Override
public void setTitleColor(int textColor) {
super.setTitleColor(textColor);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
super.setContentView(view, params);
}
@Override
public void setContentView(View view) {
super.setContentView(view);
}
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return super.getSharedPreferences(name, mode);
}
@Override
public boolean releaseInstance() {
return super.releaseInstance();
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
return super.registerReceiver(receiver, filter, flags);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
return super.registerReceiver(receiver, filter, broadcastPermission, scheduler, flags);
}
@Override
public void startActivities(Intent[] intents) {
super.startActivities(intents);
}
@Override
public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
super.startActivityFromFragment(fragment, intent, requestCode);
}
@Override
public void startActivityFromFragment(android.app.Fragment fragment, Intent intent, int requestCode, Bundle options) {
super.startActivityFromFragment(fragment, intent, requestCode, options);
}
@Override
public void startActivityFromChild(Activity child, Intent intent, int requestCode, Bundle options) {
super.startActivityFromChild(child, intent, requestCode, options);
}
@Override
public void startActivities(Intent[] intents, Bundle options) {
super.startActivities(intents, options);
}
@Override
public boolean startActivityIfNeeded(Intent intent, int requestCode) {
return super.startActivityIfNeeded(intent, requestCode);
}
@Override
public boolean startActivityIfNeeded(Intent intent, int requestCode, Bundle options) {
return super.startActivityIfNeeded(intent, requestCode, options);
}
@Override
public void startActivityFromChild(Activity child, Intent intent, int requestCode) {
super.startActivityFromChild(child, intent, requestCode);
}
@Override
public ComponentName startService(Intent service) {
return super.startService(service);
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
}
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
super.startActivityForResult(intent, requestCode, options);
}
@Override
public void startActivityFromFragment(android.app.Fragment fragment, Intent intent, int requestCode) {
super.startActivityFromFragment(fragment, intent, requestCode);
}
@Override
public void startActivityFromFragment(Fragment requestIndex, Intent fragment, int intent, Bundle requestCode) {
super.startActivityFromFragment(requestIndex, fragment, intent, requestCode);
}
@Override
public void startActivity(Intent intent, Bundle options) {
super.startActivity(intent, options);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (isAddWinBollToolBar()) {
getMenuInflater().inflate(R.menu.toolbar_winboll_shared_main, menu);
}
if (WinBollApplication.isDebug()) {
getMenuInflater().inflate(R.menu.toolbar_studio_debug, menu);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected");
if (item.getItemId() == R.id.item_log) {
LogUtils.d(TAG, "item_log not yet.");
//WinBollActivityManager.getInstance().printAvtivityListInfo();
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class);
} else if (item.getItemId() == R.id.item_exit) {
WinBollActivityManager.getInstance(this).finishAll();
} else if (item.getItemId() == R.id.item_info) {
WinBollApplication application = (WinBollApplication) getApplication();
application.getMyActivityLifecycleCallbacks().showActivityeInfo();
} else if (item.getItemId() == R.id.item_exitdebug) {
AboutView.setApp2NormalMode(getApplicationContext());
} else if (item.getItemId() == R.id.item_about) {
startAboutActivity();
} else if (item.getItemId() == android.R.id.home) {
WinBollActivityManager.getInstance(this).finish(this);
}
// else if (item.getItemId() == android.R.id.home) {
// 回到主窗口速度缓慢,方法备用。现在用 WinBollActivityManager resumeActivity 和 finish 方法管理。
// _mMainWinBollActivity 是 WinBollActivity 的静态属性
// onCreate 函数下 _mMainWinBollActivity 为空时就用 _mMainWinBollActivity = this 赋值。
//startWinBollActivity(new Intent(_mMainWinBollActivity, _mMainWinBollActivity.getClass()), _mMainWinBollActivity.getTag(), _mMainWinBollActivity);
//}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
//super.onBackPressed();
//ToastUtils.show("onBackPressed");
WinBollActivityManager.getInstance(this).finish(this);
}
/*public void getInstanse() {
startWinBollActivity(new Intent(), getTag(), null);
}*/
//
// activity: 为 null 时,
// intent.putExtra 函数 "tag" 参数为 tag
// activity: 不为 null 时,
// intent.putExtra 函数 "tag" 参数为 activity.getTag()
//
// protected <T extends WinBollActivity> void startWinBollActivity(Intent intent, String tag, T activity) {
// LogUtils.d(TAG, "startWinBollActivityForResult tag " + tag);
// //ToastUtils.show("startWinBollActivityForResult tag " + tag);
// //打开多任务窗口 flags
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
// if (activity != null) {
// intent.putExtra("tag", activity.getTag());
// } else {
// intent.putExtra("tag", tag);
// }
// //ToastUtils.show("super.startActivityForResult(intent, requestCode); tag " + tag);
// LogUtils.d(TAG, "startActivityForResult(intent, requestCode);" + tag);
// startActivity(intent);
// }
//
// activity: 为 null 时,
// intent.putExtra 函数 "tag" 参数为 tag
// activity: 不为 null 时,
// intent.putExtra 函数 "tag" 参数为 activity.getTag()
//
protected <T extends AboutActivity> void startAboutActivity() {
Intent intent = new Intent(this, AboutActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.putExtra("tag", AboutActivity.TAG);
startActivity(intent);
}
@Override
public void startActivity(Intent intent) {
//绑定唯一标识 tag存在 则根据 taskId 移动到前台
String tag = intent.getStringExtra("tag");
//ToastUtils.show("startActivityForResult tag " + tag);
//WinBollActivityManager.getInstance(this).printAvtivityListInfo();
if (WinBollActivityManager.getInstance(this).isActive(tag)) {
//ToastUtils.show("resumeActivity");
LogUtils.d(TAG, "resumeActivity");
WinBollActivityManager.getInstance(this).resumeActivity(this, tag);
} else {
//ToastUtils.show("super.startActivity(intent);");
super.startActivity(intent);
}
}
@Override
protected void onActivityResult(int requestCode, int targetFragment, Intent data) {
LogUtils.d(TAG, "onActivityResult");
switch (requestCode) {
case REQUEST_LOG_ACTIVITY : {
LogUtils.d(TAG, "REQUEST_LOG_ACTIVITY");
break;
}
default : {
super.onActivityResult(requestCode, targetFragment, data);
}
}
}
public boolean isAddWinBollInfoMenu() {
return true;
}
abstract public String getTag();
abstract protected Toolbar initToolBar();
abstract protected boolean isEnableDisplayHomeAsUp();
abstract protected boolean isAddWinBollToolBar();
}

View File

@@ -9,10 +9,10 @@ package cc.winboll.studio.libapputils.app;
* https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app * https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
*/ */
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.TaskStackBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils; import androidx.core.app.TaskStackBuilder;
import cc.winboll.studio.libapputils.log.LogUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
@@ -20,26 +20,17 @@ import java.util.Map;
public class WinBollActivityManager { public class WinBollActivityManager {
public static final String TAG = "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; Context mContext;
MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks;
static WinBollActivityManager _mWinBollActivityManager; static WinBollActivityManager _mWinBollActivityManager;
static Map<String, IWinBollActivity> _mapIWinBollList; static Map<String, WinBollActivity> _mapActivityList;
IWinBollActivity firstIWinBollActivity; //static ArrayList<WinBollActivity> _mWinBollActivityList;
public WinBollActivityManager(Context context) { public WinBollActivityManager(Context context) {
mContext = context; mContext = context;
LogUtils.d(TAG, "WinBollActivityManager()"); LogUtils.d(TAG, "WinBollActivityManager()");
_mapIWinBollList = new HashMap<String, IWinBollActivity>(); _mapActivityList = new HashMap<String, WinBollActivity>();
//_mWinBollActivityList = new ArrayList<WinBollActivity>();
} }
public static synchronized WinBollActivityManager getInstance(Context context) { public static synchronized WinBollActivityManager getInstance(Context context) {
@@ -51,46 +42,35 @@ public class WinBollActivityManager {
return _mWinBollActivityManager; return _mWinBollActivityManager;
} }
// /**
// 设置 WinBoll 应用 UI 类型 * 把Activity添加到管理中
// */
public synchronized static void setWinBollUI_TYPE(WinBollUI_TYPE mWinBollUI_TYPE) { public <T extends WinBollActivity> void add(T activity) {
_mWinBollUI_TYPE = mWinBollUI_TYPE; /*for (int i = 0; i < _mWinBollActivityList.size(); i++) {
LogUtils.d(TAG, String.format("add for i %d\nget(i).getTag() %s", i, _mWinBollActivityList.get(i).getTag()));
if (_mWinBollActivityList.get(i).getTag().equals(activity.getTag())) {
_mWinBollActivityList.add(i, activity);
_mWinBollActivityList.remove(i);
LogUtils.d(TAG, String.format("Replace activity : %s\nSize %d", activity.getTag(), _mWinBollActivityList.size()));
return;
} }
}*/
// if (isActive(activity.getTag())) {
// 获取 WinBoll 应用 UI 类型 LogUtils.d(TAG, String.format("add(...) %s is active.", activity.getTag()));
//
public synchronized static WinBollUI_TYPE getWinBollUI_TYPE() {
return _mWinBollUI_TYPE;
}
//
// 把Activity添加到管理中
//
public <T extends IWinBollActivity> void add(T iWinBoll) {
if (isActive(iWinBoll.getTag())) {
LogUtils.d(TAG, String.format("add(...) %s is active.", iWinBoll.getTag()));
} else { } else {
// 设置起始活动窗口,以便最后退出时提问 _mapActivityList.put(activity.getTag(), activity);
if (firstIWinBollActivity == null && _mapIWinBollList.size() == 0) { LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", activity.getTag(), _mapActivityList.size()));
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 时, // activity: 为 null 时,
// intent.putExtra 函数 EXTRA_TAG 参数为 tag // intent.putExtra 函数 "tag" 参数为 tag
// activity: 不为 null 时, // activity: 不为 null 时,
// intent.putExtra 函数 "tag" 参数为 activity.getTag() // intent.putExtra 函数 "tag" 参数为 activity.getTag()
// //
public <T extends IWinBollActivity> void startWinBollActivity(Context context, Class<T> clazz) { public <T extends WinBollActivity> void startWinBollActivity(Context context, Class<T> clazz) {
try { try {
// 如果窗口已存在就重启窗口 // 如果窗口已存在就重启窗口
String tag = clazz.newInstance().getTag(); String tag = clazz.newInstance().getTag();
@@ -104,15 +84,14 @@ public class WinBollActivityManager {
//打开多任务窗口 flags //打开多任务窗口 flags
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("tag", tag);
intent.putExtra(EXTRA_TAG, tag);
mContext.startActivity(intent); mContext.startActivity(intent);
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} }
} }
public <T extends IWinBollActivity> void startWinBollActivity(Context context, Intent intent, Class<T> clazz) { public <T extends WinBollActivity> void startWinBollActivity(Context context, Intent intent, Class<T> clazz) {
try { try {
// 如果窗口已存在就重启窗口 // 如果窗口已存在就重启窗口
String tag = clazz.newInstance().getTag(); String tag = clazz.newInstance().getTag();
@@ -126,30 +105,25 @@ public class WinBollActivityManager {
//打开多任务窗口 flags //打开多任务窗口 flags
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("tag", tag);
intent.putExtra(EXTRA_TAG, tag);
mContext.startActivity(intent); mContext.startActivity(intent);
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} }
} }
public boolean isFirstIWinBollActivity(IWinBollActivity iWinBollActivity) { /**
return firstIWinBollActivity != null && firstIWinBollActivity == iWinBollActivity; * 判断 tag绑定的 MyActivity是否存在
} */
//
// 判断 tag绑定的 MyActivity是否存在
//
public boolean isActive(String tag) { public boolean isActive(String tag) {
//printAvtivityListInfo(); printAvtivityListInfo();
IWinBollActivity iWinBoll = getIWinBoll(tag); WinBollActivity activity = getWinBollActivity(tag);
if (iWinBoll != null) { if (activity != null) {
LogUtils.d(TAG, "isActive(...) activity != null tag " + tag); LogUtils.d(TAG, "isActive(...) activity != null tag " + tag);
//ToastUtils.show("activity != null tag " + tag); //ToastUtils.show("activity != null tag " + tag);
//判断是否为 BaseActivity,如果已经销毁,则移除 //判断是否为 BaseActivity,如果已经销毁,则移除
if (iWinBoll.getActivity().isFinishing() || iWinBoll.getActivity().isDestroyed()) { if (activity.isFinishing() || activity.isDestroyed()) {
_mapIWinBollList.remove(iWinBoll.getTag()); _mapActivityList.remove(activity.getTag());
//_mWinBollActivityList.remove(activity); //_mWinBollActivityList.remove(activity);
LogUtils.d(TAG, String.format("isActive(...) remove activity.\ntag : %s", tag)); LogUtils.d(TAG, String.format("isActive(...) remove activity.\ntag : %s", tag));
return false; return false;
@@ -163,75 +137,75 @@ public class WinBollActivityManager {
} }
} }
static IWinBollActivity getIWinBoll(String tag) { static WinBollActivity getWinBollActivity(String tag) {
return _mapIWinBollList.get(tag); return _mapActivityList.get(tag);
} }
// /**
// 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 * 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
// */
public <T extends IWinBollActivity> void resumeActivity(Context context, String tag) { public <T extends WinBollActivity> void resumeActivity(Context context, String tag) {
LogUtils.d(TAG, "resumeActivty"); LogUtils.d(TAG, "resumeActivty");
T iWinBoll = (T)getIWinBoll(tag); T activity = (T)getWinBollActivity(tag);
//LogUtils.d(TAG, "activity " + activity.getTag()); LogUtils.d(TAG, "activity " + activity.getTag());
if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
resumeActivity(context, iWinBoll); resumeActivity(context, activity);
} }
} }
// /**
// 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 * 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台
// */
public <T extends IWinBollActivity> void resumeActivity(Context context, T iWinBoll) { public <T extends WinBollActivity> void resumeActivity(Context context, T activity) {
ActivityManager am = (ActivityManager) iWinBoll.getActivity().getSystemService(Context.ACTIVITY_SERVICE); ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
//返回启动它的根任务home 或者 MainActivity //返回启动它的根任务home 或者 MainActivity
Intent intent = new Intent(context, iWinBoll.getClass()); Intent intent = new Intent(context, activity.getClass());
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(intent); stackBuilder.addNextIntentWithParentStack(intent);
stackBuilder.startActivities(); stackBuilder.startActivities();
//moveTaskToFront(YourTaskId, 0); //moveTaskToFront(YourTaskId, 0);
LogUtils.d(TAG, "am.moveTaskToFront"); LogUtils.d(TAG, "am.moveTaskToFront");
//ToastUtils.show("resumeActivity am.moveTaskToFront"); //ToastUtils.show("resumeActivity am.moveTaskToFront");
am.moveTaskToFront(iWinBoll.getActivity().getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);
} }
// /**
// 结束所有 Activity * 结束所有 Activity
// */
public void finishAll() { public void finishAll() {
try { try {
for (String key : _mapIWinBollList.keySet()) { LogUtils.d(TAG, "finishAll no yet.");
//System.out.println("Key: " + key + ", Value: " + _mapActivityList.get(key)); //ToastUtils.show(String.format("finishAll() size : %d", _mWinBollActivityList.size()));
IWinBollActivity iWinBoll = _mapIWinBollList.get(key); // for (int i = _mWinBollActivityList.size() - 1; i > -1; i--) {
//ToastUtils.show("finishAll() activity"); // WinBollActivity activity = _mWinBollActivityList.get(i);
if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { // ToastUtils.show("finishAll() activity");
//ToastUtils.show("activity != null ..."); // if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
if (getWinBollUI_TYPE() == WinBollUI_TYPE.Service) { // //ToastUtils.show("activity != null ...");
// 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 // if (WinBollApplication.getWinBollUI_TYPE() == WinBollApplication.WinBollUI_TYPE.Service) {
iWinBoll.getActivity().finishAndRemoveTask(); // // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。
//ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); // activity.finishAndRemoveTask();
} else if (getWinBollUI_TYPE() == WinBollUI_TYPE.Aplication) { // //ToastUtils.show("finishAll() activity.finishAndRemoveTask();");
// 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 // } else if (WinBollApplication.getWinBollUI_TYPE() == WinBollApplication.WinBollUI_TYPE.Aplication) {
iWinBoll.getActivity().finish(); // // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。
//ToastUtils.show("finishAll() activity.finish();"); // activity.finish();
} else { // //ToastUtils.show("finishAll() activity.finish();");
LogUtils.d(TAG, "WinBollApplication.WinBollUI_TYPE error."); // } else {
//ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); // ToastUtils.show("WinBollApplication.WinBollUI_TYPE error.");
} // }
} // }
} // }
} catch (Exception e) { } catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} }
} }
// /**
// 结束指定Activity * 结束指定Activity
// */
public <T extends IWinBollActivity> void finish(T iWinBoll) { public <T extends WinBollActivity> void finish(T activity) {
try { try {
if (iWinBoll != null && !iWinBoll.getActivity().isFinishing() && !iWinBoll.getActivity().isDestroyed()) { if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
//根据tag 移除 MyActivity //根据tag 移除 MyActivity
//String tag= activity.getTag(); //String tag= activity.getTag();
//_mWinBollActivityList.remove(tag); //_mWinBollActivityList.remove(tag);
@@ -246,11 +220,27 @@ public class WinBollActivityManager {
// ★0 1 2 3 [4] >> 3 // ★0 1 2 3 [4] >> 3
// ★:[0] >> 直接关闭当前窗口 // ★:[0] >> 直接关闭当前窗口
LogUtils.d(TAG, "finish no yet."); LogUtils.d(TAG, "finish no yet.");
IWinBollActivity preIWinBoll = getPreIWinBoll(iWinBoll); WinBollActivity preActivity = getPreActivity(activity);
iWinBoll.getActivity().finish(); activity.finish();
if (preIWinBoll != null) { if (preActivity != null) {
resumeActivity(mContext, preIWinBoll); resumeActivity(mContext, preActivity);
} }
// for (int i = 0; i < _mWinBollActivityList.size(); i++) {
// if (_mWinBollActivityList.get(i).getTag().equals(activity.getTag())) {
// //ToastUtils.show(String.format("equals i : %d\nTag : %s\nSize : %d", i, activity.getTag(), _mWinBollActivityList.size()));
// if (i == 0) {
// finishAll();
// //ToastUtils.show("finish finishAll");
// return;
// }
// if (i > 0) {
// activity.finish();
// resumeActivity(mContext, _mWinBollActivityList.get(i - 1));
// return;
// }
// }
// }
} }
} catch (Exception e) { } catch (Exception e) {
@@ -258,24 +248,21 @@ public class WinBollActivityManager {
} }
} }
// WinBollActivity getPreActivity(WinBollActivity activity) {
// 获取窗口队列中的前一个窗口
//
IWinBollActivity getPreIWinBoll(IWinBollActivity iWinBoll) {
try { try {
boolean bingo = false; boolean bingo = false;
IWinBollActivity preIWinBoll = null; WinBollActivity preActivity = null;
for (Map.Entry<String, IWinBollActivity> entity : _mapIWinBollList.entrySet()) { for (Map.Entry<String, WinBollActivity> entity : _mapActivityList.entrySet()) {
if (entity.getKey().equals(iWinBoll.getTag())) { if (entity.getKey().equals(activity.getTag())) {
bingo = true; bingo = true;
LogUtils.d(TAG, "bingo"); LogUtils.d(TAG, "bingo");
break; break;
} }
preIWinBoll = entity.getValue(); preActivity = entity.getValue();
} }
if (bingo) { if (bingo) {
return preIWinBoll; return preActivity;
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
@@ -284,28 +271,36 @@ public class WinBollActivityManager {
return null; return null;
} }
// public <T extends WinBollActivity> boolean registeRemove(T activity) {
// 从管理列表中移除管理项 // for (int i = 0; i < _mWinBollActivityList.size(); i++) {
// // if (registeRemove(activity, i)) {
public <T extends IWinBollActivity> boolean registeRemove(T activity) { // return true;
IWinBollActivity iWinBollTest = _mapIWinBollList.get(activity.getTag()); // }
if (iWinBollTest != null) { // }
_mapIWinBollList.remove(activity.getTag()); WinBollActivity activityTest = _mapActivityList.get(activity.getTag());
if (activityTest != null) {
_mapActivityList.remove(activity.getTag());
return true; return true;
} }
return false; return false;
} }
// // public <T extends WinBollActivity> boolean registeRemove(T activity, int position) {
// 打印管理列表项列表里的信息 // if (_mWinBollActivityList.get(position) == activity) {
// // _mWinBollActivityList.remove(position);
public static void printIWinBollListInfo() { // //ToastUtils.show(String.format("registeRemove remove.\nTag %s\nposition %d", activity.getTag(), position));
// return true;
// }
// return false;
// }
public static void printAvtivityListInfo() {
//LogUtils.d(TAG, "printAvtivityListInfo"); //LogUtils.d(TAG, "printAvtivityListInfo");
if (!_mapIWinBollList.isEmpty()) { if (!_mapActivityList.isEmpty()) {
StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(_mapIWinBollList.size())); StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(_mapActivityList.size()));
Iterator<Map.Entry<String, IWinBollActivity>> iterator = _mapIWinBollList.entrySet().iterator(); Iterator<Map.Entry<String, WinBollActivity>> iterator = _mapActivityList.entrySet().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Map.Entry<String, IWinBollActivity> entry = iterator.next(); Map.Entry<String, WinBollActivity> entry = iterator.next();
sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag());
//ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag());
} }
@@ -315,4 +310,6 @@ public class WinBollActivityManager {
LogUtils.d(TAG, "The map is empty."); LogUtils.d(TAG, "The map is empty.");
} }
} }
} }

View File

@@ -0,0 +1,76 @@
package cc.winboll.studio.libapputils.app;
import cc.winboll.studio.libapputils.bean.DebugBean;
import cc.winboll.studio.libapputils.log.LogUtils;
public class WinBollApplication extends cc.winboll.studio.libappbase.GlobalApplication {
public static final String TAG = "WinBollApplication";
public static enum WinBollUI_TYPE {
Aplication, // 退出应用后,保持最近任务栏任务记录主窗口
Service // 退出应用后,清理所有最近任务栏任务记录窗口
};
// 应用类型标志
volatile static WinBollUI_TYPE _mWinBollUI_TYPE = WinBollUI_TYPE.Service;
static volatile WinBollApplication _WinBollApplication = null;
MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks;
// 标记当前应用是否处于调试状态
static volatile boolean isDebug = false;
public static void setIsDebug(boolean isDebug) {
WinBollApplication.isDebug = isDebug;
}
public static boolean isDebug() {
return isDebug;
}
//
// 设置 WinBoll 应用 UI 类型
//
public static void setWinBollUI_TYPE(WinBollUI_TYPE mWinBollUI_TYPE) {
_mWinBollUI_TYPE = mWinBollUI_TYPE;
}
//
// 获取 WinBoll 应用 UI 类型
//
public static WinBollUI_TYPE getWinBollUI_TYPE() {
return _mWinBollUI_TYPE;
}
MyActivityLifecycleCallbacks getMyActivityLifecycleCallbacks() {
return mMyActivityLifecycleCallbacks;
}
@Override
public void onCreate() {
super.onCreate();
_WinBollApplication = this;
// 应用环境初始化, 基本调试环境
//
CrashHandler.init(this);
LogUtils.init(this);
DebugBean debugBean = DebugBean.loadBean(this, DebugBean.class);
if (debugBean == null) {
//ToastUtils.show("debugBean == null");
setIsDebug(false);
} else {
//ToastUtils.show("saveDebugStatus(" + String.valueOf(debugBean.isDebuging()) + ")");
setIsDebug(debugBean.isDebuging());
}
// 应用运行状态环境设置
//
mMyActivityLifecycleCallbacks = new MyActivityLifecycleCallbacks(this);
registerActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks);
// 设置默认 WinBoll 应用 UI 类型
setWinBollUI_TYPE(WinBollUI_TYPE.Service);
//ToastUtils.show("WinBollUI_TYPE " + getWinBollUI_TYPE());
}
}

View File

@@ -1,141 +0,0 @@
package cc.winboll.studio.libapputils.bean;
/**
* @Author ZhanGSKen@QQ.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;
}
}

View File

@@ -10,7 +10,7 @@ package cc.winboll.studio.libapputils.bean;
import android.content.Context; import android.content.Context;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.util.FileUtils; import cc.winboll.studio.libapputils.util.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,6 +1,6 @@
package cc.winboll.studio.libapputils.git; package cc.winboll.studio.libapputils.git;
import android.content.Context; import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.log.LogUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;

View File

@@ -0,0 +1,66 @@
package cc.winboll.studio.libapputils.log;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.ads.ADsView;
import cc.winboll.studio.libapputils.app.WinBollApplication;
import android.view.View;
import android.app.Activity;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 15:07:58
* @Describe WinBoll 应用日志窗口
*/
public class LogActivity extends Activity {
public static final String TAG = "LogActivity";
LogView mLogView;
//ADsView mADsView;
// @Override
// protected boolean isEnableDisplayHomeAsUp() {
// return false;
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
mLogView = findViewById(R.id.logview);
//mADsView = findViewById(R.id.adsview);
//mADsView.loadUrl("https://www.winboll.cc");
//mLogView.setVisibility(WinBollApplication.isDebug()?View.GONE:View.VISIBLE);
//mADsView.setVisibility(WinBollApplication.isDebug()?View.GONE:View.VISIBLE);
if(WinBollApplication.isDebug()) { mLogView.start(); }
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume");
super.onResume();
mLogView.start();
}
// @Override
// protected boolean isAddWinBollToolBar() {
// return false;
// }
//
// @Override
// protected Toolbar initToolBar() {
// LogUtils.d(TAG, "initToolBar");
// return null;
// }
//
// @Override
// public String getTag() {
// LogUtils.d(TAG, "getTag");
// return TAG;
// }
}

View File

@@ -0,0 +1,370 @@
package cc.winboll.studio.libapputils.log;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 13:44:06
* @Describe LogUtils
* @Describe 应用日志类
*/
import android.content.Context;
import cc.winboll.studio.libapputils.app.WinBollApplication;
import cc.winboll.studio.libapputils.util.FileUtils;
import dalvik.system.DexFile;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class LogUtils {
public static final String TAG = "LogUtils";
public static enum LOG_LEVEL { Off, Error, Warn, Info, Debug, Verbose }
static volatile boolean _IsInited = false;
static Context _mContext;
// 日志显示时间格式
static SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("[yyyyMMdd_HHmmSS]", Locale.getDefault());
// 应用日志文件夹
static File _mfLogCacheDir;
static File _mfLogDataDir;
// 应用日志文件
static File _mfLogCatchFile;
static File _mfLogUtilsBeanFile;
static LogUtilsBean _mLogUtilsBean;
public static Map<String, Boolean> mapTAGList = new HashMap<String, Boolean>();
//
// 初始化函数
//
public static void init(Context context) {
_mContext = context;
init(context, LOG_LEVEL.Off);
}
//
// 初始化函数
//
public static void init(Context context, LOG_LEVEL logLevel) {
if (WinBollApplication.isDebug()) {
// 初始化日志缓存文件路径
_mfLogCacheDir = new File(context.getApplicationContext().getExternalCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) {
_mfLogCacheDir.mkdirs();
}
_mfLogCatchFile = new File(_mfLogCacheDir, "log.txt");
// 初始化日志配置文件路径
_mfLogDataDir = context.getApplicationContext().getExternalFilesDir(TAG);
if (!_mfLogDataDir.exists()) {
_mfLogDataDir.mkdirs();
}
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
} else {
// 初始化日志缓存文件路径
_mfLogCacheDir = new File(context.getApplicationContext().getCacheDir(), TAG);
if (!_mfLogCacheDir.exists()) {
_mfLogCacheDir.mkdirs();
}
_mfLogCatchFile = new File(_mfLogCacheDir, "log.txt");
// 初始化日志配置文件路径
_mfLogDataDir = new File(context.getApplicationContext().getFilesDir(), TAG);
if (!_mfLogDataDir.exists()) {
_mfLogDataDir.mkdirs();
}
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
}
// Toast.makeText(context,
// "_mfLogUtilsBeanFile : " + _mfLogUtilsBeanFile
// + "\n_mfLogCatchFile : " + _mfLogCatchFile,
// Toast.LENGTH_SHORT).show();
//
_mLogUtilsBean = LogUtilsBean.loadBeanFromFile(_mfLogUtilsBeanFile.getPath(), LogUtilsBean.class);
if (_mLogUtilsBean == null) {
_mLogUtilsBean = new LogUtilsBean();
_mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean);
}
// 加载当前应用下的所有类的 TAG
addClassTAGList();
loadTAGBeanSettings();
_IsInited = true;
LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString()));
}
public static Map<String, Boolean> getMapTAGList() {
return mapTAGList;
}
static void loadTAGBeanSettings() {
ArrayList<LogUtilsClassTAGBean> list = new ArrayList<LogUtilsClassTAGBean>();
LogUtilsClassTAGBean.loadBeanList(_mContext, list, LogUtilsClassTAGBean.class);
for (int i = 0; i < list.size(); i++) {
LogUtilsClassTAGBean beanSetting = list.get(i);
for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) {
if (entry.getKey().equals(beanSetting.getTag())) {
entry.setValue(beanSetting.getEnable());
}
}
}
}
static void saveTAGBeanSettings() {
ArrayList<LogUtilsClassTAGBean> list = new ArrayList<LogUtilsClassTAGBean>();
for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) {
list.add(new LogUtilsClassTAGBean(entry.getKey(), entry.getValue()));
}
LogUtilsClassTAGBean.saveBeanList(_mContext, list, LogUtilsClassTAGBean.class);
}
static void addClassTAGList() {
//ClassLoader classLoader = getClass().getClassLoader();
try {
//String packageName = context.getPackageName();
String packageNamePrefix = "cc.winboll.studio";
List<String> classNames = new ArrayList<>();
String apkPath = _mContext.getPackageCodePath();
//Log.d("APK_PATH", "The APK path is: " + apkPath);
LogUtils.d(TAG, String.format("apkPath : %s", apkPath));
//String apkPath = "/data/app/" + packageName + "-";
//DexFile dexfile = new DexFile(apkPath + "1/base.apk");
DexFile dexfile = new DexFile(apkPath);
int countTemp = 0;
Enumeration<String> entries = dexfile.entries();
while (entries.hasMoreElements()) {
countTemp++;
String className = entries.nextElement();
if (className.startsWith(packageNamePrefix)) {
classNames.add(className);
}
}
LogUtils.d(TAG, String.format("countTemp : %d\nClassNames size : %d", countTemp, classNames.size()));
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) && field.getType() == String.class && "TAG".equals(field.getName())) {
String tagValue = (String) field.get(null);
//Log.d("TAG_INFO", "Class: " + className + ", TAG value: " + tagValue);
//LogUtils.d(TAG, String.format("Tag Value : %s", tagValue));
//mapTAGList.put(tagValue, true);
mapTAGList.put(tagValue, false);
}
}
} catch (ClassNotFoundException | IllegalAccessException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
public static void setTAGListEnable(String tag, boolean isEnable) {
Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Boolean> entry = iterator.next();
if (tag.equals(entry.getKey())) {
entry.setValue(isEnable);
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
break;
}
}
saveTAGBeanSettings();
LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString()));
}
public static void setALlTAGListEnable(boolean isEnable) {
Iterator<Map.Entry<String, Boolean>> iterator = mapTAGList.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Boolean> entry = iterator.next();
entry.setValue(isEnable);
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
saveTAGBeanSettings();
LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString()));
}
public static void setLogLevel(LOG_LEVEL logLevel) {
LogUtils._mLogUtilsBean.setLogLevel(logLevel);
_mLogUtilsBean.saveBeanToFile(_mfLogUtilsBeanFile.getPath(), _mLogUtilsBean);
}
public static LOG_LEVEL getLogLevel() {
return LogUtils._mLogUtilsBean.getLogLevel();
}
static boolean isLoggable(String tag, LOG_LEVEL logLevel) {
return _IsInited && mapTAGList.get(tag) && isInTheLevel(logLevel);
}
static boolean isInTheLevel(LOG_LEVEL logLevel) {
return (LogUtils._mLogUtilsBean.getLogLevel().ordinal() == logLevel.ordinal()
|| LogUtils._mLogUtilsBean.getLogLevel().ordinal() > logLevel.ordinal());
}
//
// 获取应用日志文件夹
//
public static File getLogCacheDir() {
return _mfLogCacheDir;
}
//
// 调试日志写入函数
//
public static void e(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, szMessage);
}
}
//
// 调试日志写入函数
//
public static void w(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, szMessage);
}
}
//
// 调试日志写入函数
//
public static void i(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Info, szMessage);
}
}
//
// 调试日志写入函数
//
public static void d(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, szMessage);
}
}
//
// 调试日志写入函数
// 包含线程调试堆栈信息
//
public static void d(String szTAG, String szMessage, StackTraceElement[] listStackTrace) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
StringBuilder sbMessage = new StringBuilder(szMessage);
sbMessage.append(" \nAt ");
sbMessage.append(listStackTrace[2].getMethodName());
sbMessage.append(" (");
sbMessage.append(listStackTrace[2].getFileName());
sbMessage.append(":");
sbMessage.append(listStackTrace[2].getLineNumber());
sbMessage.append(")");
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
}
}
//
// 调试日志写入函数
// 包含异常信息和线程调试堆栈信息
//
public static void d(String szTAG, Exception e, StackTraceElement[] listStackTrace) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
StringBuilder sbMessage = new StringBuilder(e.getClass().toGenericString());
sbMessage.append(" : ");
sbMessage.append(e.getMessage());
sbMessage.append(" \nAt ");
sbMessage.append(listStackTrace[2].getMethodName());
sbMessage.append(" (");
sbMessage.append(listStackTrace[2].getFileName());
sbMessage.append(":");
sbMessage.append(listStackTrace[2].getLineNumber());
sbMessage.append(")");
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
}
}
//
// 调试日志写入函数
//
public static void v(String szTAG, String szMessage) {
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, szMessage);
}
}
//
// 日志文件保存函数
//
static void saveLog(String szTAG, LogUtils.LOG_LEVEL logLevel, String szMessage) {
try {
BufferedWriter out = null;
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_mfLogCatchFile, true), "UTF-8"));
out.write("[" + logLevel + "] " + mSimpleDateFormat.format(System.currentTimeMillis()) + " [" + szTAG + "]\n" + szMessage + "\n");
out.close();
} catch (IOException e) {
LogUtils.d(TAG, "IOException : " + e.getMessage());
}
}
//
// 历史日志加载函数
//
public static String loadLog() {
if (_mfLogCatchFile.exists()) {
StringBuffer sb = new StringBuffer();
try {
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(new FileInputStream(_mfLogCatchFile), "UTF-8"));
String line = "";
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
} catch (IOException e) {
LogUtils.d(TAG, "IOException : " + e.getMessage());
}
return sb.toString();
}
return "";
}
//
// 清理日志函数
//
public static void cleanLog() {
if (_mfLogCatchFile.exists()) {
try {
FileUtils.writeStringToFile(_mfLogCatchFile.getPath(), "");
//LogUtils.d(TAG, "cleanLog");
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
}

View File

@@ -0,0 +1,71 @@
package cc.winboll.studio.libapputils.log;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/23 15:39:07
* @Describe LogUtils 数据配置类。
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libapputils.bean.BaseBean;
import java.io.IOException;
public class LogUtilsBean extends BaseBean {
public static final String TAG = "LogUtilsBean";
LogUtils.LOG_LEVEL logLevel;
public LogUtilsBean() {
this.logLevel = LogUtils.LOG_LEVEL.Off;
}
public LogUtilsBean(LogUtils.LOG_LEVEL logLevel) {
this.logLevel = logLevel;
}
public void setLogLevel(LogUtils.LOG_LEVEL logLevel) {
this.logLevel = logLevel;
}
public LogUtils.LOG_LEVEL getLogLevel() {
return logLevel;
}
@Override
public String getName() {
return LogUtilsBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
LogUtilsBean bean = this;
jsonWriter.name("logLevel").value(bean.getLogLevel().ordinal());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("logLevel")) {
setLogLevel(LogUtils.LOG_LEVEL.values()[jsonReader.nextInt()]);
} 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;
}
}

View File

@@ -0,0 +1,88 @@
package cc.winboll.studio.libapputils.log;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/04 14:17:02
* @Describe 日志类class TAG 标签数据类
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libapputils.bean.BaseBean;
import java.io.IOException;
public class LogUtilsClassTAGBean extends BaseBean {
public static final String TAG = "LogUtilsClassTAGBean";
// 标签名
String tag;
// 是否启用
Boolean enable;
public LogUtilsClassTAGBean() {
this.tag = TAG;
this.enable = true;
}
public LogUtilsClassTAGBean(String tag, Boolean enable) {
this.tag = tag;
this.enable = enable;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getTag() {
return tag;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public Boolean getEnable() {
return enable;
}
@Override
public String getName() {
return LogUtilsClassTAGBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
LogUtilsClassTAGBean bean = this;
jsonWriter.name("tag").value(bean.getTag());
jsonWriter.name("enable").value(bean.getEnable());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("tag")) {
setTag(jsonReader.nextString());
} else if (name.equals("enable")) {
setEnable(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;
}
}

View File

@@ -0,0 +1,386 @@
package cc.winboll.studio.libapputils.log;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 14:36:18
* @Describe 日志视图类,继承 RelativeLayout 类。
*/
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.libapputils.R;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class LogView extends RelativeLayout {
public static final String TAG = "LogView";
public volatile boolean mIsHandling;
public volatile boolean mIsAddNewLog;
Context mContext;
ScrollView mScrollView;
TextView mTextView;
CheckBox mSelectableCheckBox;
CheckBox mSelectAllTAGCheckBox;
TAGListAdapter mTAGListAdapter;
LogViewThread mLogViewThread;
LogViewHandler mLogViewHandler;
Spinner mLogLevelSpinner;
ArrayAdapter<CharSequence> mLogLevelSpinnerAdapter;
// 标签列表
RecyclerView recyclerView;
public LogView(Context context) {
super(context);
initView(context);
}
public LogView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public LogView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public LogView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
public void start() {
mLogViewThread = new LogViewThread(LogView.this);
mLogViewThread.start();
// 显示日志
showAndScrollLogView();
}
public void scrollLogUp() {
mScrollView.post(new Runnable() {
@Override
public void run() {
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
// 日志显示结束
mLogViewHandler.setIsHandling(false);
// 检查是否添加了新日志
if (mLogViewHandler.isAddNewLog()) {
// 有新日志添加,先更改新日志标志
mLogViewHandler.setIsAddNewLog(false);
// 再次发送显示日志的显示
Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
mLogViewHandler.sendMessage(message);
}
}
});
}
void initView(Context context) {
mContext = context;
mLogViewHandler = new LogViewHandler();
// 加载视图布局
addView(inflate(mContext, cc.winboll.studio.libapputils.R.layout.view_log, null));
// 初始化日志子控件视图
//
mScrollView = findViewById(cc.winboll.studio.libapputils.R.id.viewlogScrollViewLog);
mTextView = findViewById(cc.winboll.studio.libapputils.R.id.viewlogTextViewLog);
// 获取Log Level spinner实例
mLogLevelSpinner = findViewById(cc.winboll.studio.libapputils.R.id.viewlogSpinner1);
(findViewById(cc.winboll.studio.libapputils.R.id.viewlogButtonClean)).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
LogUtils.cleanLog();
LogUtils.d(TAG, "Log is cleaned.");
}
});
(findViewById(cc.winboll.studio.libapputils.R.id.viewlogButtonCopy)).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(mContext.getPackageName(), LogUtils.loadLog()));
LogUtils.d(TAG, "Log is copied.");
}
});
mSelectableCheckBox = findViewById(cc.winboll.studio.libapputils.R.id.viewlogCheckBoxSelectable);
mSelectableCheckBox.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
if (mSelectableCheckBox.isChecked()) {
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
} else {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
});
// 设置日志级别列表
ArrayList<String> adapterItems = new ArrayList<>();
for (LogUtils.LOG_LEVEL e : LogUtils.LOG_LEVEL.values()) {
adapterItems.add(e.name());
}
// 假设你有一个字符串数组作为选项列表
//String[] options = {"Option 1", "Option 2", "Option 3"};
// 创建一个ArrayAdapter来绑定数据到spinner
mLogLevelSpinnerAdapter = ArrayAdapter.createFromResource(
context, cc.winboll.studio.libapputils.R.array.enum_loglevel_array, android.R.layout.simple_spinner_item);
mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// 设置适配器并将它应用到spinner上
mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // 设置下拉视图样式
mLogLevelSpinner.setAdapter(mLogLevelSpinnerAdapter);
// 为Spinner添加监听器
mLogLevelSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//String selectedOption = mLogLevelSpinnerAdapter.getItem(position);
// 处理选中的选项...
LogUtils.setLogLevel(LogUtils.LOG_LEVEL.values()[position]);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 如果没有选择,则执行此操作...
}
});
// 获取默认值的索引
int defaultValueIndex = LogUtils.getLogLevel().ordinal();
if (defaultValueIndex != -1) {
// 如果找到了默认值,设置默认选项
mLogLevelSpinner.setSelection(defaultValueIndex);
}
// 加载标签列表
Map<String, Boolean> mapTAGList = LogUtils.getMapTAGList();
boolean isAllSelect = true;
for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) {
if (entry.getValue() == false) {
isAllSelect = false;
break;
}
}
CheckBox cbALLTAG = findViewById(cc.winboll.studio.libapputils.R.id.viewlogCheckBox1);
cbALLTAG.setChecked(isAllSelect);
// 加载标签表
recyclerView = findViewById(cc.winboll.studio.libapputils.R.id.viewlogRecyclerView1);
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);
mTAGListAdapter = new TAGListAdapter(mapTAGList);
recyclerView.setAdapter(mTAGListAdapter);
// 可以添加点击监听器来处理勾选框状态变化后的逻辑,比如获取当前勾选情况等
mTAGListAdapter.notifyDataSetChanged();
mSelectAllTAGCheckBox = findViewById(cc.winboll.studio.libapputils.R.id.viewlogCheckBox1);
mSelectAllTAGCheckBox.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
LogUtils.setALlTAGListEnable(mSelectAllTAGCheckBox.isChecked());
//LogUtils.setALlTAGListEnable(false);
//mTAGListAdapter.notifyDataSetChanged();
mTAGListAdapter.reload();
//ToastUtils.show(String.format("onClick\nmSelectAllTAGCheckBox.isChecked() : %s", mSelectAllTAGCheckBox.isChecked()));
}
});
// 设置滚动时不聚焦日志
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
public void updateLogView() {
if (mLogViewHandler.isHandling() == true) {
// 正在处理日志显示,
// 就先设置一个新日志标志位
// 以便日志显示完后,再次显示新日志内容
mLogViewHandler.setIsAddNewLog(true);
} else {
//LogUtils.d(TAG, "LogListener showLog(String path)");
Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
mLogViewHandler.sendMessage(message);
mLogViewHandler.setIsAddNewLog(false);
}
}
void showAndScrollLogView() {
mTextView.setText(LogUtils.loadLog());
scrollLogUp();
}
class LogViewHandler extends Handler {
final static int MSG_LOGVIEW_UPDATE = 0;
volatile boolean isHandling;
volatile boolean isAddNewLog;
public LogViewHandler() {
setIsHandling(false);
setIsAddNewLog(false);
}
public void setIsHandling(boolean isHandling) {
this.isHandling = isHandling;
}
public boolean isHandling() {
return isHandling;
}
public void setIsAddNewLog(boolean isAddNewLog) {
this.isAddNewLog = isAddNewLog;
}
public boolean isAddNewLog() {
return isAddNewLog;
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOGVIEW_UPDATE:{
if (isHandling() == false) {
setIsHandling(true);
showAndScrollLogView();
}
break;
}
default:
break;
}
super.handleMessage(msg);
}
}
public class TAGItemModel {
private String tag;
private boolean isChecked;
public TAGItemModel(String tag, boolean isChecked) {
this.tag = tag;
this.isChecked = isChecked;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
public class TAGListAdapter extends RecyclerView.Adapter<TAGListAdapter.ViewHolder> {
private Map<String, Boolean> mapOrigin;
private List<TAGItemModel> itemList;
public TAGListAdapter(Map<String, Boolean> map) {
mapOrigin = map;
loadMap(mapOrigin);
}
void loadMap(Map<String, Boolean> map) {
itemList = new ArrayList<TAGItemModel>();
for (Map.Entry<String, Boolean> entry : map.entrySet()) {
itemList.add(new TAGItemModel(entry.getKey(), entry.getValue()));
}
// 添加排序功能按照tag进行升序排序
Collections.sort(itemList, new SortMapEntryByKeyString(true));
//Collections.sort(itemList, new SortMapEntryByKeyString(false));
}
public void reload() {
loadMap(mapOrigin);
super.notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_logtag, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final TAGItemModel item = itemList.get(position);
holder.tvText.setText(item.getTag());
holder.cbChecked.setChecked(item.isChecked());
holder.cbChecked.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
LogUtils.setTAGListEnable(item.getTag(), ((CheckBox)v).isChecked());
}
});
}
@Override
public int getItemCount() {
return itemList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvText;
CheckBox cbChecked;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvText = itemView.findViewById(R.id.viewlogtagTextView1);
cbChecked = itemView.findViewById(R.id.viewlogtagCheckBox1);
}
}
}
class SortMapEntryByKeyString implements Comparator<TAGItemModel> {
private boolean mIsDesc = true;
// isDesc 是否降序排列
public SortMapEntryByKeyString(boolean isDesc) {
mIsDesc = isDesc;
}
Collator cmp = Collator.getInstance(java.util.Locale.CHINA);
@Override
public int compare(TAGItemModel o1, TAGItemModel o2) {
if (mIsDesc) {
return o1.getTag().compareTo(o2.getTag());
} else {
return o2.getTag().compareTo(o1.getTag());
}
}
}
}

View File

@@ -0,0 +1,79 @@
package cc.winboll.studio.libapputils.log;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 14:43:50
* @Describe 日志视图线程类
*/
import android.os.FileObserver;
import java.lang.ref.WeakReference;
public class LogViewThread extends Thread {
public static final String TAG = "LogViewThread";
// 线程退出标志
volatile boolean isExist = false;
// 应用日志文件监听实例
LogListener mLogListener;
// 日志视图弱引用
WeakReference<LogView> mwrLogView;
//
// 构造函数
// @logView : 日志显示输出视图类
public LogViewThread(LogView logView) {
mwrLogView = new WeakReference<LogView>(logView);
}
public void setIsExist(boolean isExist) {
this.isExist = isExist;
}
public boolean isExist() {
return isExist;
}
@Override
public void run() {
String szLogDir = LogUtils.getLogCacheDir().getPath();
mLogListener = new LogListener(szLogDir);
mLogListener.startWatching();
while (isExist() == false) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
mLogListener.stopWatching();
}
//
// 日志文件监听类
//
class LogListener extends FileObserver {
public LogListener(String path) {
super(path);
}
@Override
public void onEvent(int event, String path) {
int e = event & FileObserver.ALL_EVENTS;
switch (e) {
case FileObserver.CLOSE_WRITE:{
if (mwrLogView.get() != null) {
mwrLogView.get().updateLogView();
}
break;
}
case FileObserver.DELETE:{
if (mwrLogView.get() != null) {
mwrLogView.get().updateLogView();
}
break;
}
}
}
}
}

View File

@@ -5,11 +5,15 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.libappbase.LogUtils; import android.os.IInterface;
import cc.winboll.studio.libappbase.utils.ToastUtils; import android.os.Parcel;
import android.os.RemoteException;
import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.util.ServiceUtils; import cc.winboll.studio.libapputils.util.ServiceUtils;
import com.hjq.toast.ToastUtils;
import java.io.FileDescriptor;
import android.graphics.drawable.Drawable;
/** /**
* @Author ZhanGSKen@QQ.COM * @Author ZhanGSKen@QQ.COM

View File

@@ -9,7 +9,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.net.Uri; import android.net.Uri;
import cc.winboll.studio.libappbase.LogUtils; import androidx.core.content.FileProvider;
import cc.winboll.studio.libapputils.log.LogUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -22,7 +23,6 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import android.support.v4.content.FileProvider;
public class FileUtils { public class FileUtils {

View File

@@ -6,12 +6,18 @@ package cc.winboll.studio.libapputils.util;
* @Describe 二维码工具 * @Describe 二维码工具
*/ */
import android.graphics.Bitmap; import android.graphics.Bitmap;
import cc.winboll.studio.libappbase.LogUtils; import android.widget.TextView;
import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.log.LogUtils;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.QRCodeWriter;
import com.journeyapps.barcodescanner.BarcodeEncoder; import com.journeyapps.barcodescanner.BarcodeEncoder;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class QRCodeGenerator { public class QRCodeGenerator {

View File

@@ -5,7 +5,6 @@ package cc.winboll.studio.libapputils.view;
* @Date 2024/08/12 14:38:03 * @Date 2024/08/12 14:38:03
* @Describe AboutView * @Describe AboutView
*/ */
import cc.winboll.studio.libapputils.R;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -17,21 +16,23 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libapputils.R;
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.app.AppVersionUtils;
import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.APPInfo; import cc.winboll.studio.libapputils.app.WinBollApplication;
import cc.winboll.studio.libapputils.bean.DebugBean; import cc.winboll.studio.libapputils.bean.DebugBean;
import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.util.PrefUtils; import cc.winboll.studio.libapputils.util.PrefUtils;
import com.hjq.toast.ToastUtils;
import java.io.IOException; import java.io.IOException;
//import okhttp3.Call; import mehdi.sakout.aboutpage.AboutPage;
//import okhttp3.Callback; import mehdi.sakout.aboutpage.Element;
//import okhttp3.Credentials; import okhttp3.Call;
//import okhttp3.OkHttpClient; import okhttp3.Callback;
//import okhttp3.Request; import okhttp3.Credentials;
//import okhttp3.Response; import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class AboutView extends LinearLayout { public class AboutView extends LinearLayout {
@@ -40,10 +41,8 @@ public class AboutView extends LinearLayout {
public static final int MSG_APPUPDATE_CHECKED = 0; public static final int MSG_APPUPDATE_CHECKED = 0;
Context mContext; Context mContext;
APPInfo mAPPInfo;
WinBollServiceStatusView mWinBollServiceStatusView; WinBollServiceStatusView mWinBollServiceStatusView;
//OnRequestDevUserInfoAutofillListener mOnRequestDevUserInfoAutofillListener; OnRequestDevUserInfoAutofillListener mOnRequestDevUserInfoAutofillListener;
String mszAppName = ""; String mszAppName = "";
String mszAppAPKFolderName = ""; String mszAppAPKFolderName = "";
String mszAppAPKName = ""; String mszAppAPKName = "";
@@ -56,97 +55,64 @@ public class AboutView extends LinearLayout {
String mszGitea = ""; String mszGitea = "";
int mnAppIcon = 0; int mnAppIcon = 0;
String mszWinBollServerHost; String mszWinBollServerHost;
//String mszReleaseAPKName; String mszReleaseAPKName;
EditText metDevUserName; EditText metDevUserName;
EditText metDevUserPassword; EditText metDevUserPassword;
public AboutView(Context context, APPInfo appInfo) {
super(context);
mContext = context;
setAPPInfo(appInfo);
initView(context);
}
public AboutView(Context context, AttributeSet attrs) { public AboutView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mContext = context;
initView(context, attrs); initView(context, attrs);
} }
public void setAPPInfo(APPInfo appInfo) { void initView(Context context, AttributeSet attrs) {
mAPPInfo = appInfo; mContext = context;
} mszWinBollServerHost = WinBollApplication.isDebug() ? "http://10.8.0.13": "https://www.winboll.cc";
APPInfo createAppInfo(Context context, AttributeSet attrs) {
APPInfo appInfo = new APPInfo();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AboutView); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AboutView);
appInfo.setAppName(typedArray.getString(R.styleable.AboutView_app_name)); mszAppName = typedArray.getString(R.styleable.AboutView_app_name);
appInfo.setAppAPKFolderName(typedArray.getString(R.styleable.AboutView_app_apkfoldername)); mszAppAPKFolderName = typedArray.getString(R.styleable.AboutView_app_apkfoldername);
appInfo.setAppAPKName(typedArray.getString(R.styleable.AboutView_app_apkname)); mszAppAPKName = typedArray.getString(R.styleable.AboutView_app_apkname);
appInfo.setAppGitName(typedArray.getString(R.styleable.AboutView_app_gitname)); mszAppGitName = typedArray.getString(R.styleable.AboutView_app_gitname);
appInfo.setAppGitOwner(typedArray.getString(R.styleable.AboutView_app_gitowner)); mszAppDescription = typedArray.getString(R.styleable.AboutView_appdescription);
appInfo.setAppGitAPPBranch(typedArray.getString(R.styleable.AboutView_app_gitappbranch)); mnAppIcon = typedArray.getResourceId(R.styleable.AboutView_appicon, R.drawable.ic_winboll);
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(); typedArray.recycle();
return appInfo;
}
void initView(Context context) {}
// void initView(Context context) { try {
// mszAppName = mAPPInfo.getAppName(); mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
// mszAppAPKFolderName = mAPPInfo.getAppAPKFolderName(); } catch (PackageManager.NameNotFoundException e) {
// mszAppAPKName = mAPPInfo.getAppAPKName(); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// mszAppGitName = mAPPInfo.getAppGitName(); }
// mszAppDescription = mAPPInfo.getAppDescription(); mszCurrentAppPackageName = mszAppName + "_" + mszAppVersionName + ".apk";
// mnAppIcon = mAPPInfo.getAppIcon(); mszHomePage = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName;
// mszGitea = "https://gitea.winboll.cc/Studio/" + mszAppGitName + ".git";
// mszWinBollServerHost = GlobalApplication.isDebuging() ? "https://dev.winboll.cc": "https://www.winboll.cc";
// if (WinBollApplication.isDebug()) {
// try { LayoutInflater inflater = LayoutInflater.from(mContext);
// mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName; View addedView = inflater.inflate(R.layout.view_about_dev, this, false);
// } catch (PackageManager.NameNotFoundException e) { LinearLayout llMain = addedView.findViewById(R.id.viewaboutdevLinearLayout1);
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); metDevUserName = addedView.findViewById(R.id.viewaboutdevEditText1);
// } metDevUserPassword = addedView.findViewById(R.id.viewaboutdevEditText2);
// mszCurrentAppPackageName = mszAppAPKName + "_" + mszAppVersionName + ".apk"; metDevUserName.setText(PrefUtils.getString(mContext, "metDevUserName", ""));
// mszHomePage = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; metDevUserPassword.setText(PrefUtils.getString(mContext, "metDevUserPassword", ""));
// if(mAPPInfo.getAppGitAPPBranch().equals("")) { //mDevelopHostConnectionStatusView = new DevelopHostConnectionStatusView(context);
// mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName; mWinBollServiceStatusView = addedView.findViewById(R.id.viewaboutdevWinBollServiceStatusView1);
// } else { mWinBollServiceStatusView.setServerHost(mszWinBollServerHost);
// mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName + "/src/branch/" + mAPPInfo.getAppGitAPPBranch() + "/" + mAPPInfo.getAppGitAPPSubProjectFolder(); mWinBollServiceStatusView.setAuthInfo(metDevUserName.getText().toString(), metDevUserPassword.getText().toString());
//} //llMain.addView(mDevelopHostConnectionStatusView);
// llMain.addView(createAboutPage());
// if (GlobalApplication.isDebuging()) { addView(addedView);
// LayoutInflater inflater = LayoutInflater.from(mContext); } else {
// View addedView = inflater.inflate(R.layout.view_about_dev, this, false); LayoutInflater inflater = LayoutInflater.from(mContext);
// LinearLayout llMain = addedView.findViewById(R.id.viewaboutdevLinearLayout1); View addedView = inflater.inflate(R.layout.view_about_www, this, false);
// metDevUserName = addedView.findViewById(R.id.viewaboutdevEditText1); LinearLayout llMain = addedView.findViewById(R.id.viewaboutwwwLinearLayout1);
// metDevUserPassword = addedView.findViewById(R.id.viewaboutdevEditText2); //mDevelopHostConnectionStatusView = new DevelopHostConnectionStatusView(context);
// metDevUserName.setText(PrefUtils.getString(mContext, "metDevUserName", "")); mWinBollServiceStatusView = addedView.findViewById(R.id.viewaboutwwwWinBollServiceStatusView1);
// metDevUserPassword.setText(PrefUtils.getString(mContext, "metDevUserPassword", "")); mWinBollServiceStatusView.setServerHost(mszWinBollServerHost);
// //mDevelopHostConnectionStatusView = new DevelopHostConnectionStatusView(context); mWinBollServiceStatusView.setAuthInfo("", "");
// mWinBollServiceStatusView = addedView.findViewById(R.id.viewaboutdevWinBollServiceStatusView1); //llMain.addView(mDevelopHostConnectionStatusView);
// mWinBollServiceStatusView.setServerHost(mszWinBollServerHost); llMain.addView(createAboutPage());
// mWinBollServiceStatusView.setAuthInfo(metDevUserName.getText().toString(), metDevUserPassword.getText().toString()); addView(addedView);
// //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)); //setSubtitle(getContext().getString(R.string.text_about));
@@ -154,236 +120,226 @@ public class AboutView extends LinearLayout {
//llMain.addView(createAboutPage()); //llMain.addView(createAboutPage());
// 就读取正式版应用包版本号,设置 Release 应用包文件名 // 就读取正式版应用包版本号,设置 Release 应用包文件名
// String szReleaseAppVersionName = ""; String szReleaseAppVersionName = "";
// try { try {
// //LogUtils.d(TAG, String.format("mContext.getPackageName() %s", mContext.getPackageName())); szReleaseAppVersionName = mContext.getPackageManager().getPackageInfo(subBetaSuffix(mContext.getPackageName()), 0).versionName;
// String szSubBetaSuffix = subBetaSuffix(mContext.getPackageName()); } catch (PackageManager.NameNotFoundException e) {
// //LogUtils.d(TAG, String.format("szSubBetaSuffix : %s", szSubBetaSuffix)); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// szReleaseAppVersionName = mContext.getPackageManager().getPackageInfo(szSubBetaSuffix, 0).versionName; }
// } catch (PackageManager.NameNotFoundException e) { mszReleaseAPKName = mszAppAPKName + "_" + szReleaseAppVersionName + ".apk";
// 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) { public static String subBetaSuffix(String input) {
// if (input.endsWith(".beta")) { if (input.endsWith(".beta")) {
// return input.substring(0, input.length() - ".beta".length()); return input.substring(0, input.length() - ".beta".length());
// } }
// return input; 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() { android.os.Handler mHandler = new android.os.Handler() {
// // 定义应用调试按钮 @Override
// // public void handleMessage(Message msg) {
// Element elementAppMode; super.handleMessage(msg);
// if (GlobalApplication.isDebuging()) { switch (msg.what) {
// elementAppMode = new Element(mContext.getString(R.string.app_normal), R.drawable.ic_winboll); case MSG_APPUPDATE_CHECKED : {
// elementAppMode.setOnClickListener(mAppNormalOnClickListener); /*//检查当前应用包文件名是否是测试版,如果是就忽略检查
// } else { if(mszCurrentAppPackageName.matches(".*_\\d+\\.\\d+\\.\\d+-beta.*\\.apk")) {
// elementAppMode = new Element(mContext.getString(R.string.app_debug), R.drawable.ic_winboll); ToastUtils.show("APP is the beta Version. Version check ignore.");
// elementAppMode.setOnClickListener(mAppDebugOnClickListener); return;
// } }*/
// // 定义 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(){ if (!AppVersionUtils.isHasNewStageReleaseVersion(mszReleaseAPKName, mszNewestAppPackageName)) {
// @Override ToastUtils.delayedShow("Current app is the newest.", 5000);
// public void onClick(View view) { } else {
// setApp2DebugMode(mContext); String szMsg = "Current app is :\n[ " + mszReleaseAPKName
// } + " ]\nThe last app is :\n[ " + mszNewestAppPackageName
// }; + " ]\nIs download the last app?";
// YesNoAlertDialog.show(mContext, "Application Update Prompt", szMsg, mIsDownlaodUpdateListener);
// View.OnClickListener mAppNormalOnClickListener = new View.OnClickListener(){ }
// @Override break;
// public void onClick(View view) { }
// setApp2NormalMode(mContext); }
// } }
// }; };
//
// public static void setApp2DebugMode(Context context) { protected View createAboutPage() {
// Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); // 定义应用调试按钮
// if (intent != null) { //
// intent.setAction(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW); Element elementAppMode;
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (WinBollApplication.isDebug()) {
// GlobalApplication.setIsDebuging(context, true); elementAppMode = new Element(mContext.getString(R.string.app_normal), R.drawable.ic_winboll);
// DebugBean.saveBean(context, new DebugBean(true)); elementAppMode.setOnClickListener(mAppNormalOnClickListener);
// } else {
// WinBollActivityManager.getInstance(context).finishAll(); elementAppMode = new Element(mContext.getString(R.string.app_debug), R.drawable.ic_winboll);
// context.startActivity(intent); elementAppMode.setOnClickListener(mAppDebugOnClickListener);
// } }
// } // 定义 GitWeb 按钮
// //
// public static void setApp2NormalMode(Context context) { Element elementGitWeb = new Element(mContext.getString(R.string.gitea_home), R.drawable.ic_winboll);
// Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); elementGitWeb.setOnClickListener(mGitWebOnClickListener);
// if (intent != null) { // 定义检查更新按钮
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //
// GlobalApplication.setIsDebuging(context, false); Element elementAppUpdate = new Element(mContext.getString(R.string.app_update), R.drawable.ic_winboll);
// DebugBean.saveBean(context, new DebugBean(false)); elementAppUpdate.setOnClickListener(mAppUpdateOnClickListener);
//
// WinBollActivityManager.getInstance(context).finishAll(); String szAppInfo = "";
// context.startActivity(intent); try {
// } szAppInfo = mszAppName + " "
// } + mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName
// + "\n" + mszAppDescription;
// View.OnClickListener mGitWebOnClickListener = new View.OnClickListener(){ } catch (PackageManager.NameNotFoundException e) {
// @Override LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// public void onClick(View view) { }
// Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mszGitea)); View aboutPage = new AboutPage(mContext)
// mContext.startActivity(browserIntent); .setDescription(szAppInfo)
// } //.isRTL(false)
// }; //.setCustomFont(String) // or Typeface
// .setImage(mnAppIcon)
// View.OnClickListener mAppUpdateOnClickListener = new View.OnClickListener(){ //.addItem(versionElement)
// @Override //.addItem(adsElement)
// public void onClick(View view) { //.addGroup("Connect with us")
// ToastUtils.show("Start app update checking."); .addEmail("ZhanGSKen@QQ.COM")
// new Thread(new Runnable() { .addWebsite(mszHomePage)
// @Override .addItem(elementAppMode)
// public void run() { .addItem(elementGitWeb)
// String szUrl = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; .addItem(elementAppUpdate)
// // 构建包含认证信息的请求 //.addFacebook("the.medy")
// String credential = ""; //.addTwitter("medyo80")
// if (GlobalApplication.isDebuging()) { //.addYoutube("UCdPQtdWIsg7_pi4mrRu46vA")
// credential = Credentials.basic(metDevUserName.getText().toString(), metDevUserPassword.getText().toString()); //.addPlayStore("com.ideashower.readitlater.pro")
// PrefUtils.saveString(mContext, "metDevUserName", metDevUserName.getText().toString()); //.addGitHub("medyo")
// PrefUtils.saveString(mContext, "metDevUserPassword", metDevUserPassword.getText().toString()); //.addInstagram("medyo80")
// } .create();
// OkHttpClient client = new OkHttpClient(); return aboutPage;
// Request request = new Request.Builder() }
// .url(szUrl)
// .header("Accept", "text/plain") // 设置正确的Content-Type头 View.OnClickListener mAppDebugOnClickListener = new View.OnClickListener(){
// .header("Authorization", credential) @Override
// .build(); public void onClick(View view) {
// Call call = client.newCall(request); setApp2DebugMode(mContext);
// call.enqueue(new Callback() { }
// @Override };
// public void onFailure(Call call, IOException e) {
// // 处理网络请求失败 View.OnClickListener mAppNormalOnClickListener = new View.OnClickListener(){
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); @Override
// } public void onClick(View view) {
// setApp2NormalMode(mContext);
// @Override }
// public void onResponse(Call call, Response response) throws IOException { };
// if (!response.isSuccessful()) {
// LogUtils.d(TAG, "Unexpected code " + response, Thread.currentThread().getStackTrace()); public static void setApp2DebugMode(Context context) {
// return; Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
// } if (intent != null) {
// intent.setAction(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW);
// try { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// // 读取响应体作为字符串,注意这里可能需要解码 WinBollApplication.setIsDebug(true);
// String text = response.body().string(); DebugBean.saveBean(context, new DebugBean(true));
// org.jsoup.nodes.Document doc = org.jsoup.Jsoup.parse(text);
// LogUtils.v(TAG, doc.text()); WinBollActivityManager.getInstance(context).finishAll();
// context.startActivity(intent);
// // 使用id选择器找到具有特定id的元素 }
// org.jsoup.nodes.Element elementWithId = doc.select("#LastRelease").first(); // 获取第一个匹配的元素 }
//
// // 提取并打印元素的文本内容 public static void setApp2NormalMode(Context context) {
// mszNewestAppPackageName = elementWithId.text(); Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
// //ToastUtils.delayedShow(text + "\n" + mszNewestAppPackageName, 5000); if (intent != null) {
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// mHandler.sendMessage(mHandler.obtainMessage(MSG_APPUPDATE_CHECKED)); WinBollApplication.setIsDebug(false);
// } catch (Exception e) { DebugBean.saveBean(context, new DebugBean(false));
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// } WinBollActivityManager.getInstance(context).finishAll();
// } context.startActivity(intent);
// }); }
// } }
// }).start();
// } View.OnClickListener mGitWebOnClickListener = new View.OnClickListener(){
// }; @Override
// public void onClick(View view) {
// YesNoAlertDialog.OnDialogResultListener mIsDownlaodUpdateListener = new YesNoAlertDialog.OnDialogResultListener() { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mszGitea));
// @Override mContext.startActivity(browserIntent);
// 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); View.OnClickListener mAppUpdateOnClickListener = new View.OnClickListener(){
// } @Override
// public void onClick(View view) {
// @Override ToastUtils.show("Start app update checking.");
// public void onNo() { new Thread(new Runnable() {
// } @Override
// }; public void run() {
// String szUrl = mszWinBollServerHost + "/studio/details.php?app=" + mszAppAPKFolderName;
// public interface OnRequestDevUserInfoAutofillListener { // 构建包含认证信息的请求
// void requestAutofill(EditText etDevUserName, EditText etDevUserPassword); String credential = "";
// } if (WinBollApplication.isDebug()) {
// credential = Credentials.basic(metDevUserName.getText().toString(), metDevUserPassword.getText().toString());
// public void setOnRequestDevUserInfoAutofillListener(OnRequestDevUserInfoAutofillListener l) { PrefUtils.saveString(mContext, "metDevUserName", metDevUserName.getText().toString());
// mOnRequestDevUserInfoAutofillListener = l; 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;
}
} }

View File

@@ -9,6 +9,7 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import com.hjq.toast.ToastUtils;
public class SimpleWebView extends WebView { public class SimpleWebView extends WebView {

View File

@@ -5,7 +5,6 @@ package cc.winboll.studio.libapputils.view;
* @Date 2024/12/19 13:49:14 * @Date 2024/12/19 13:49:14
* @Describe 把字符串转化为二维码的视图 * @Describe 把字符串转化为二维码的视图
*/ */
import cc.winboll.studio.libapputils.R;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -14,7 +13,12 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.util.QRCodeGenerator; import cc.winboll.studio.libapputils.util.QRCodeGenerator;
import com.google.zxing.Result;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.journeyapps.barcodescanner.DecoratedBarcodeView; import com.journeyapps.barcodescanner.DecoratedBarcodeView;
public class StringToQrCodeView extends LinearLayout { public class StringToQrCodeView extends LinearLayout {

View File

@@ -5,7 +5,6 @@ package cc.winboll.studio.libapputils.view;
* @Date 2024/12/07 20:15:47 * @Date 2024/12/07 20:15:47
* @Describe WinBoll 服务主机连接状态视图 * @Describe WinBoll 服务主机连接状态视图
*/ */
import cc.winboll.studio.libapputils.R;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -19,20 +18,22 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import cc.winboll.studio.libappbase.LogUtils; import androidx.core.content.ContextCompat;
import cc.winboll.studio.libappbase.utils.ToastUtils; import cc.winboll.studio.libapputils.R;
import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libapputils.service.IWinBollClientServiceBinder; import cc.winboll.studio.libapputils.service.IWinBollClientServiceBinder;
import cc.winboll.studio.libapputils.service.WinBollClientService; import cc.winboll.studio.libapputils.service.WinBollClientService;
import cc.winboll.studio.libapputils.service.WinBollClientServiceBean; import cc.winboll.studio.libapputils.service.WinBollClientServiceBean;
import com.hjq.toast.ToastUtils;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
//import okhttp3.Authenticator; import okhttp3.Authenticator;
//import okhttp3.Credentials; import okhttp3.Credentials;
//import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
//import okhttp3.Request; import okhttp3.Request;
//import okhttp3.Response; import okhttp3.Response;
//import okhttp3.Route; import okhttp3.Route;
public class WinBollServiceStatusView extends LinearLayout { public class WinBollServiceStatusView extends LinearLayout {
@@ -210,7 +211,7 @@ public class WinBollServiceStatusView extends LinearLayout {
void setImageViewByConnection(ImageView imageView, boolean isConnected) { void setImageViewByConnection(ImageView imageView, boolean isConnected) {
//mIsConnected = isConnected; //mIsConnected = isConnected;
// 获取vector drawable // 获取vector drawable
Drawable drawable = mContext.getDrawable(isConnected ? R.drawable.ic_dev_connected : R.drawable.ic_dev_disconnected); Drawable drawable = ContextCompat.getDrawable(mContext, isConnected ? R.drawable.ic_dev_connected : R.drawable.ic_dev_disconnected);
if (drawable != null) { if (drawable != null) {
imageView.setImageDrawable(drawable); imageView.setImageDrawable(drawable);
} }
@@ -221,49 +222,49 @@ public class WinBollServiceStatusView extends LinearLayout {
//String username = "your_username"; //String username = "your_username";
//String password = "your_password"; //String password = "your_password";
// OkHttpClient client = new OkHttpClient.Builder() OkHttpClient client = new OkHttpClient.Builder()
// .authenticator(new Authenticator() { .authenticator(new Authenticator() {
// @Override @Override
// public Request authenticate(Route route, Response response) throws IOException { public Request authenticate(Route route, Response response) throws IOException {
// String credential = Credentials.basic(username, password); String credential = Credentials.basic(username, password);
// return response.request().newBuilder() return response.request().newBuilder()
// .header("Authorization", credential) .header("Authorization", credential)
// .build(); .build();
// } }
// }) })
// .build(); .build();
//
// Request request = new Request.Builder() Request request = new Request.Builder()
// .url(targetUrl) // 替换为实际要请求的网页地址 .url(targetUrl) // 替换为实际要请求的网页地址
// .build(); .build();
//
// try { try {
// Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
// if (response.isSuccessful()) { if (response.isSuccessful()) {
// //System.out.println(response.body().string()); //System.out.println(response.body().string());
// //ToastUtils.show("Develop Host Connection IP is : " + response.body().string()); //ToastUtils.show("Develop Host Connection IP is : " + response.body().string());
// // 获取当前时间 // 获取当前时间
// LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
//
// // 定义时间格式 // 定义时间格式
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
// // 按照指定格式格式化时间并输出 // 按照指定格式格式化时间并输出
// String formattedDateTime = now.format(formatter); String formattedDateTime = now.format(formatter);
// //System.out.println(formattedDateTime); //System.out.println(formattedDateTime);
// textViewHandler.postMessageText("ClientIP<" + formattedDateTime + ">: " + response.body().string()); textViewHandler.postMessageText("ClientIP<" + formattedDateTime + ">: " + response.body().string());
// textViewHandler.postMessageConnectionStatus(true); textViewHandler.postMessageConnectionStatus(true);
// } else { } else {
// String sz = "请求失败,状态码: " + response.code(); String sz = "请求失败,状态码: " + response.code();
// setImageViewByConnection(mImageView, false); setImageViewByConnection(mImageView, false);
// textViewHandler.postMessageText(sz); textViewHandler.postMessageText(sz);
// textViewHandler.postMessageConnectionStatus(false); textViewHandler.postMessageConnectionStatus(false);
// LogUtils.d(TAG, sz); LogUtils.d(TAG, sz);
// } }
// } catch (IOException e) { } catch (IOException e) {
// textViewHandler.postMessageText(e.getMessage()); textViewHandler.postMessageText(e.getMessage());
// textViewHandler.postMessageConnectionStatus(false); textViewHandler.postMessageConnectionStatus(false);
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// } }
} }
class WinBollServiceViewHandler extends Handler { class WinBollServiceViewHandler extends Handler {

View File

@@ -6,17 +6,20 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activityaboutToolbar1"/> android:id="@+id/activityaboutToolbar1"/>
<LinearLayout <cc.winboll.studio.libapputils.view.AboutView
android:orientation="vertical" app:app_name= "APP"
app:app_apkfoldername="APP"
app:app_apkname="APP"
app:app_gitname="APP"
app:appdescription="WinBoll.CC 网站客户端。"
app:appicon="@drawable/ic_winboll"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:layout_weight="1.0" android:id="@+id/activityaboutAboutView1"/>
android:id="@+id/activityaboutLinearLayout1"/>
</LinearLayout> </LinearLayout>

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activityassetshtmlToolbar1"/> android:id="@+id/activityassetshtmlToolbar1"/>

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<cc.winboll.studio.libappbase.LogView <cc.winboll.studio.libapputils.log.LogView
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activityqrcodedecodeToolbar1"/> android:id="@+id/activityqrcodedecodeToolbar1"/>

View File

@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000">
<RelativeLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:background="@drawable/bg_shadow"
android:id="@+id/viewlogRelativeLayoutToolbar">
<Button
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="Clean"
android:textSize="14dp"
android:layout_centerVertical="true"
android:id="@+id/viewlogButtonClean"
android:layout_marginLeft="5dp"/>
<TextView
android:background="#FF000000"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:text="LV:"
android:layout_toRightOf="@+id/viewlogButtonClean"
android:layout_centerVertical="true"
android:id="@+id/viewlogTextView1"
android:textColor="#FFFFFFFF"/>
<Spinner
android:background="#FFFFFFFF"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_toRightOf="@+id/viewlogTextView1"
android:layout_centerVertical="true"
android:id="@+id/viewlogSpinner1"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_toLeftOf="@+id/viewlogButtonCopy"
android:layout_centerVertical="true"
android:text="Selectable"
android:background="#FFFFFFFF"
android:paddingRight="10dp"
android:textSize="16dp"
android:id="@+id/viewlogCheckBoxSelectable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="36dp"
android:text="Copy"
android:layout_alignParentRight="true"
android:textSize="14dp"
android:layout_centerVertical="true"
android:id="@+id/viewlogButtonCopy"
android:layout_marginRight="5dp"/>
</RelativeLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/bg_shadow"
android:layout_below="@+id/viewlogRelativeLayoutToolbar"
android:id="@+id/viewlogLinearLayout1"
android:gravity="center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ALL"
android:id="@+id/viewlogCheckBox1"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/view_border"
android:id="@+id/viewlogRecyclerView1"
android:layout_weight="1.0"
android:layout_marginRight="5dp"
android:padding="2dp"/>
</LinearLayout>
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_alignParentBottom="true"
android:layout_below="@+id/viewlogLinearLayout1">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000"
android:id="@+id/viewlogScrollViewLog">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Text"
android:textColor="#FF00FF00"
android:textIsSelectable="true"
android:id="@+id/viewlogTextViewLog"/>
</ScrollView>
</RelativeLayout>
</RelativeLayout>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#F5F5F5"
app:cardElevation="4dp"
app:cardCornerRadius="4dp"
android:id="@+id/listviewauthinfoCardView1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="24dp"
android:id="@+id/viewlogtagTextView1"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="24dp"
android:id="@+id/viewlogtagCheckBox1"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@@ -15,15 +15,13 @@
<item android:title="DebugTools"> <item android:title="DebugTools">
<menu> <menu>
<item
android:id="@+id/item_testcrashreport"
android:title="Test Application Crash Report"/>
<item <item
android:id="@+id/item_unittest" android:id="@+id/item_unittest"
android:title="UnitTest"/> android:title="UnitTest"/>
<item <item
android:id="@+id/item_log" android:id="@+id/item_log"
android:title="APPLOG"/> android:title="APPLOG"
app:showAsAction="always"/>
<item <item
android:id="@+id/item_info" android:id="@+id/item_info"
android:title="Info"/> android:title="Info"/>

View File

@@ -4,5 +4,6 @@
<item <item
android:id="@+id/item_help" android:id="@+id/item_help"
android:title="HELP" android:title="HELP"
android:icon="@drawable/winboll_help"/> android:icon="@drawable/winboll_help"
app:showAsAction="always"/>
</menu> </menu>

View File

@@ -4,9 +4,11 @@
<item <item
android:id="@+id/item_exit" android:id="@+id/item_exit"
android:title="EXIT" android:title="EXIT"
android:icon="@drawable/winboll_point"/> android:icon="@drawable/winboll_point"
app:showAsAction="always"/>
<item <item
android:id="@+id/item_about" android:id="@+id/item_about"
android:title="About" android:title="About"
android:icon="@drawable/winboll_logo"/> android:icon="@drawable/winboll_logo"
app:showAsAction="always"/>
</menu> </menu>

View File

@@ -5,9 +5,6 @@
<attr name="app_apkfoldername" format="string" /> <attr name="app_apkfoldername" format="string" />
<attr name="app_apkname" format="string" /> <attr name="app_apkname" format="string" />
<attr name="app_gitname" format="string" /> <attr name="app_gitname" format="string" />
<attr name="app_gitowner" format="string" />
<attr name="app_gitappbranch" format="string" />
<attr name="app_gitappsubprojectfolder" format="string" />
<attr name="appdescription" format="string" /> <attr name="appdescription" format="string" />
<attr name="appicon" format="reference" /> <attr name="appicon" format="reference" />
</declare-styleable> </declare-styleable>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="lib_name">libapputils</string> <string name="lib_name">library</string>
<string name="app_normal">Click here is switch to Normal APP</string> <string name="app_normal">Click here is switch to Normal APP</string>
<string name="app_debug">Click here is switch to APP DEBUG</string> <string name="app_debug">Click here is switch to APP DEBUG</string>
<string name="gitea_home">GITEA HOME</string> <string name="gitea_home">GITEA HOME</string>

View File

@@ -1,14 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="MyAppTheme" parent="APPBaseTheme"> <style name="AppTheme" parent="WinBoll.SupportThemeNoActionBar"/>
<item name="attrColorPrimary">@color/colorPrimary</item>
<item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item>
</style>
<style name="MyGlobalCrashActivityTheme" parent="GlobalCrashActivityTheme"> <style name="WinBoll.Theme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="colorTittle">#FFFFFFFF</item> <!-- Customize your theme here. -->
<item name="colorTittleBackgound">#FF00A4B3</item> </style>
<item name="colorText">#FFFFFFFF</item> <style name="WinBoll.SupportTheme" parent="Theme.AppCompat.Light">
<item name="colorTextBackgound">#FF000000</item> <!-- Customize your theme here. -->
</style>
<style name="WinBoll.ThemeNoActionBar" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
<style name="WinBoll.SupportThemeNoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style> </style>
</resources> </resources>