From 75b2245061ca0a1bb0000a0fa33d1a8039d3100b Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Wed, 12 Feb 2025 23:28:42 +0800 Subject: [PATCH 01/38] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=9D=E5=A7=8B=20Co?= =?UTF-8?q?ntacts=20=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/README.md | 38 ++++ contacts/app_update_description.txt | 1 + contacts/build.gradle | 70 ++++++ contacts/build.properties | 8 + contacts/proguard-rules.pro | 17 ++ contacts/src/beta/AndroidManifest.xml | 13 ++ contacts/src/beta/res/values/strings.xml | 6 + contacts/src/main/AndroidManifest.xml | 48 ++++ .../java/cc/winboll/studio/contacts/App.java | 28 +++ .../winboll/studio/contacts/MainActivity.java | 205 ++++++++++++++++++ .../src/main/res/drawable/ic_launcher.xml | 11 + .../res/drawable/ic_launcher_background.xml | 170 +++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 10 + .../src/main/res/drawable/shape_gradient.xml | 10 + .../src/main/res/layout/activity_main.xml | 30 +++ contacts/src/main/res/layout/view_toast.xml | 32 +++ contacts/src/main/res/menu/toolbar_main.xml | 5 + contacts/src/main/res/values/colors.xml | 7 + contacts/src/main/res/values/strings.xml | 6 + contacts/src/main/res/values/styles.xml | 12 + contacts/src/main/res/xml/studio_provider.xml | 25 +++ contacts/src/stage/AndroidManifest.xml | 12 + contacts/src/stage/res/values/strings.xml | 6 + settings.gradle-demo | 4 + winboll-shared/build.properties | 10 +- 25 files changed, 779 insertions(+), 5 deletions(-) create mode 100644 contacts/README.md create mode 100644 contacts/app_update_description.txt create mode 100644 contacts/build.gradle create mode 100644 contacts/build.properties create mode 100644 contacts/proguard-rules.pro create mode 100644 contacts/src/beta/AndroidManifest.xml create mode 100644 contacts/src/beta/res/values/strings.xml create mode 100644 contacts/src/main/AndroidManifest.xml create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/App.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java create mode 100644 contacts/src/main/res/drawable/ic_launcher.xml create mode 100644 contacts/src/main/res/drawable/ic_launcher_background.xml create mode 100644 contacts/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 contacts/src/main/res/drawable/shape_gradient.xml create mode 100644 contacts/src/main/res/layout/activity_main.xml create mode 100644 contacts/src/main/res/layout/view_toast.xml create mode 100644 contacts/src/main/res/menu/toolbar_main.xml create mode 100644 contacts/src/main/res/values/colors.xml create mode 100644 contacts/src/main/res/values/strings.xml create mode 100644 contacts/src/main/res/values/styles.xml create mode 100644 contacts/src/main/res/xml/studio_provider.xml create mode 100644 contacts/src/stage/AndroidManifest.xml create mode 100644 contacts/src/stage/res/values/strings.xml diff --git a/contacts/README.md b/contacts/README.md new file mode 100644 index 0000000..a52f622 --- /dev/null +++ b/contacts/README.md @@ -0,0 +1,38 @@ +# Contacts + +#### 介绍 +通讯录与拨号 + +#### 软件架构 +适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 +也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 + + +#### Gradle 编译说明 +调试版编译命令 :gradle assembleBetaDebug +阶段版编译命令 :gradle assembleStageRelease + +#### 使用说明 + +在安卓系统中需要设置两个权限允许。 +1.自启动权限允许。 +2.省电策略-无限制权限允许。 + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 : ZhanGSKen(ZhanGSKen@AliYun.Com) +4. 新建 Pull Request + + +#### 特技 + +1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md +2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) +3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 +4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 +5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) +6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) + +#### 参考文档 \ No newline at end of file diff --git a/contacts/app_update_description.txt b/contacts/app_update_description.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/contacts/app_update_description.txt @@ -0,0 +1 @@ + diff --git a/contacts/build.gradle b/contacts/build.gradle new file mode 100644 index 0000000..c7a26c8 --- /dev/null +++ b/contacts/build.gradle @@ -0,0 +1,70 @@ +apply plugin: 'com.android.application' +apply from: '../.winboll/winboll_app_build.gradle' +apply from: '../.winboll/winboll_lint_build.gradle' + +def genVersionName(def versionName){ + // 检查编译标志位配置 + assert (winbollBuildProps['stageCount'] != null) + assert (winbollBuildProps['baseVersion'] != null) + // 保存基础版本号 + winbollBuildProps.setProperty("baseVersion", "${versionName}"); + //保存编译标志配置 + FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) + winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); + fos.close(); + + // 返回编译版本号 + return "${versionName}." + winbollBuildProps['stageCount'] +} + +android { + compileSdkVersion 32 + buildToolsVersion "33.0.3" + + defaultConfig { + applicationId "cc.winboll.studio.contacts" + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + // versionName 更新后需要手动设置 + // 项目模块目录的 build.gradle 文件的 stageCount=0 + // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" + versionName "1.0" + if(true) { + versionName = genVersionName("${versionName}") + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +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.3.1' + api 'androidx.fragment:fragment:1.1.0' + api 'com.google.android.material:material:1.1.0' + + api 'cc.winboll.studio:libapputils:9.3.2' + api 'cc.winboll.studio:libappbase:1.4.1' + + api fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/contacts/build.properties b/contacts/build.properties new file mode 100644 index 0000000..fb546db --- /dev/null +++ b/contacts/build.properties @@ -0,0 +1,8 @@ +#Created by .winboll/winboll_app_build.gradle +#Wed Feb 12 15:27:12 GMT 2025 +stageCount=0 +libraryProject=winboll-shared +baseVersion=1.0 +publishVersion=1.0.0 +buildCount=2 +baseBetaVersion=1.0.1 diff --git a/contacts/proguard-rules.pro b/contacts/proguard-rules.pro new file mode 100644 index 0000000..233bad2 --- /dev/null +++ b/contacts/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/contacts/src/beta/AndroidManifest.xml b/contacts/src/beta/AndroidManifest.xml new file mode 100644 index 0000000..c598f4f --- /dev/null +++ b/contacts/src/beta/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/contacts/src/beta/res/values/strings.xml b/contacts/src/beta/res/values/strings.xml new file mode 100644 index 0000000..dc3720a --- /dev/null +++ b/contacts/src/beta/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Contacts+ + + diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml new file mode 100644 index 0000000..915c449 --- /dev/null +++ b/contacts/src/main/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/App.java b/contacts/src/main/java/cc/winboll/studio/contacts/App.java new file mode 100644 index 0000000..6b00e0f --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/App.java @@ -0,0 +1,28 @@ +package cc.winboll.studio.contacts; + +/** + * @Author ZhanGSKen@QQ.COM + * @Date 2024/12/08 15:10:51 + * @Describe 全局应用类 + */ +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libapputils.app.WinBollActivityManager; + +public class App extends GlobalApplication { + + public static final String TAG = "App"; + + @Override + public void onCreate() { + // 必须在调用基类前设置应用调试标志, + // 这样可以预先设置日志与数据的存储根目录。 + //setIsDebug(BuildConfig.DEBUG); + super.onCreate(); + // 设置 WinBoll 应用 UI 类型 + WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication); + + LogUtils.d(TAG, "onCreate"); + } + +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java new file mode 100644 index 0000000..60e9f78 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -0,0 +1,205 @@ +package cc.winboll.studio.contacts; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import cc.winboll.studio.contacts.BuildConfig; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libapputils.app.IWinBollActivity; +import cc.winboll.studio.libapputils.app.WinBollActivityManager; +import cc.winboll.studio.libapputils.bean.APPInfo; +import cc.winboll.studio.libapputils.util.UriUtils; +import cc.winboll.studio.libapputils.view.StringToQrCodeView; +import cc.winboll.studio.libapputils.view.YesNoAlertDialog; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.UUID; +import cc.winboll.studio.libapputils.app.AboutActivityFactory; + +final public class MainActivity extends AppCompatActivity implements IWinBollActivity { + + public static final String TAG = "MainActivity"; + + public static final int REQUEST_HOME_ACTIVITY = 0; + public static final int REQUEST_ABOUT_ACTIVITY = 1; + + Toolbar mToolbar; + + @Override + public AppCompatActivity getActivity() { + return this; + } + + @Override + public APPInfo getAppInfo() { + String szBranchName = "contacts"; + + APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); + appInfo.setAppName("Contacts"); + appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); + appInfo.setAppDescription("Contacts Description"); + appInfo.setAppGitName("APP"); + appInfo.setAppGitOwner("Studio"); + appInfo.setAppGitAPPBranch(szBranchName); + appInfo.setAppGitAPPSubProjectFolder(szBranchName); + appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); + appInfo.setAppAPKName("Contacts"); + appInfo.setAppAPKFolderName("Contacts"); + return appInfo; + //return null; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + // 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回 + //if (prosessIntents(getIntent())) return; + // 以下正常创建主窗口 + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // 初始化工具栏 + mToolbar = findViewById(R.id.activitymainToolbar1); + setSupportActionBar(mToolbar); + if (isEnableDisplayHomeAsUp()) { + // 显示后退按钮 + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + getSupportActionBar().setSubtitle(getTag()); + + //ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE()); + LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + //setSubTitle(""); + } + + // + // 处理传入的 Intent 数据 + // +// boolean prosessIntents(Intent intent) { +// if (intent == null +// || intent.getAction() == null +// || intent.getAction().equals("")) +// return false; +// +// if (intent.getAction().equals(StringToQrCodeView.ACTION_UNITTEST_QRCODE)) { +// try { +// WinBollActivity clazzActivity = UnitTestActivity.class.newInstance(); +// String tag = clazzActivity.getTag(); +// LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag); +// Intent subIntent = new Intent(this, UnitTestActivity.class); +// subIntent.setAction(intent.getAction()); +// File file = new File(getCacheDir(), UUID.randomUUID().toString()); +// //取出文件uri +// Uri uri = intent.getData(); +// if (uri == null) { +// uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); +// } +// //获取文件真实地址 +// String szSrcPath = UriUtils.getFileFromUri(getApplication(), uri); +// if (TextUtils.isEmpty(szSrcPath)) { +// return false; +// } +// +// Files.copy(Paths.get(szSrcPath), Paths.get(file.getPath())); +// //startWinBollActivity(subIntent, tag); +// WinBollActivityManager.getInstance(this).startWinBollActivity(this, subIntent, UnitTestActivity.class); +// } catch (IllegalAccessException | InstantiationException | IOException e) { +// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); +// // 函数处理异常返回失败 +// return false; +// } +// } else { +// LogUtils.d(TAG, "prosessIntents|" + intent.getAction() + "|yet"); +// return false; +// } +// return true; +// } + + @Override + public String getTag() { + return TAG; + } + + @Override + public Toolbar initToolBar() { + return findViewById(R.id.activitymainToolbar1); + } + + @Override + public boolean isAddWinBollToolBar() { + return true; + } + + @Override + public boolean isEnableDisplayHomeAsUp() { + return false; + } + + @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); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.toolbar_main, menu); + return super.onCreateOptionsMenu(menu); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { +// if (item.getItemId() == R.id.item_unittest) { +// WinBollActivityManager.getInstance(this).startWinBollActivity(this, UnitTestActivity.class); +// } else +// if (item.getItemId() == R.id.item_exit) { +// exit(); +// return true; +// } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (resultCode) { + case REQUEST_HOME_ACTIVITY : { + LogUtils.d(TAG, "REQUEST_HOME_ACTIVITY"); + break; + } + case REQUEST_ABOUT_ACTIVITY : { + LogUtils.d(TAG, "REQUEST_ABOUT_ACTIVITY"); + break; + } + default : { + super.onActivityResult(requestCode, resultCode, data); + } + } + } +} diff --git a/contacts/src/main/res/drawable/ic_launcher.xml b/contacts/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000..d4d1eaf --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/contacts/src/main/res/drawable/ic_launcher_background.xml b/contacts/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..9486190 --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contacts/src/main/res/drawable/ic_launcher_foreground.xml b/contacts/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..872b04e --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + diff --git a/contacts/src/main/res/drawable/shape_gradient.xml b/contacts/src/main/res/drawable/shape_gradient.xml new file mode 100644 index 0000000..c164fe9 --- /dev/null +++ b/contacts/src/main/res/drawable/shape_gradient.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/contacts/src/main/res/layout/activity_main.xml b/contacts/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..ba8cd96 --- /dev/null +++ b/contacts/src/main/res/layout/activity_main.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/contacts/src/main/res/layout/view_toast.xml b/contacts/src/main/res/layout/view_toast.xml new file mode 100644 index 0000000..d6a9915 --- /dev/null +++ b/contacts/src/main/res/layout/view_toast.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/contacts/src/main/res/menu/toolbar_main.xml b/contacts/src/main/res/menu/toolbar_main.xml new file mode 100644 index 0000000..4a5cc30 --- /dev/null +++ b/contacts/src/main/res/menu/toolbar_main.xml @@ -0,0 +1,5 @@ + + + + diff --git a/contacts/src/main/res/values/colors.xml b/contacts/src/main/res/values/colors.xml new file mode 100644 index 0000000..bb20e29 --- /dev/null +++ b/contacts/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + + #FF196ABC + #FF002B57 + #FF80BFFF + diff --git a/contacts/src/main/res/values/strings.xml b/contacts/src/main/res/values/strings.xml new file mode 100644 index 0000000..cc96fb0 --- /dev/null +++ b/contacts/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Contacts + + diff --git a/contacts/src/main/res/values/styles.xml b/contacts/src/main/res/values/styles.xml new file mode 100644 index 0000000..4b743f7 --- /dev/null +++ b/contacts/src/main/res/values/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/contacts/src/main/res/xml/studio_provider.xml b/contacts/src/main/res/xml/studio_provider.xml new file mode 100644 index 0000000..f045677 --- /dev/null +++ b/contacts/src/main/res/xml/studio_provider.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/contacts/src/stage/AndroidManifest.xml b/contacts/src/stage/AndroidManifest.xml new file mode 100644 index 0000000..ee78d9f --- /dev/null +++ b/contacts/src/stage/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/contacts/src/stage/res/values/strings.xml b/contacts/src/stage/res/values/strings.xml new file mode 100644 index 0000000..ace0c41 --- /dev/null +++ b/contacts/src/stage/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/settings.gradle-demo b/settings.gradle-demo index 860f719..e2ad341 100644 --- a/settings.gradle-demo +++ b/settings.gradle-demo @@ -37,3 +37,7 @@ //include ':aes' //include ':libaes' //rootProject.name = "aes" + +// Contacts 项目编译设置 +//include ':contacts' +//rootProject.name = "contacts" diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index d4e3b95..fb546db 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Fri Nov 29 11:55:20 GMT 2024 +#Wed Feb 12 15:27:12 GMT 2025 stageCount=0 libraryProject=winboll-shared -baseVersion=1.8 -publishVersion=1.8.16 -buildCount=0 -baseBetaVersion=1.8.17 +baseVersion=1.0 +publishVersion=1.0.0 +buildCount=2 +baseBetaVersion=1.0.1 From b0e81fc960a95ab2a65f1b2bbcbcb9f6c1b86ba6 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 13 Feb 2025 07:29:48 +0800 Subject: [PATCH 02/38] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=BB=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.gradle | 2 +- contacts/build.properties | 4 +- contacts/src/main/AndroidManifest.xml | 13 +- .../winboll/studio/contacts/MainActivity.java | 43 ++++-- .../contacts/beans/MainServiceBean.java | 68 +++++++++ .../contacts/receivers/MainReceiver.java | 28 ++++ .../studio/contacts/services/MainService.java | 142 ++++++++++++++++++ .../src/main/res/layout/activity_main.xml | 18 ++- winboll-shared/build.properties | 4 +- 9 files changed, 297 insertions(+), 25 deletions(-) create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/beans/MainServiceBean.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java diff --git a/contacts/build.gradle b/contacts/build.gradle index c7a26c8..83e881e 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -64,7 +64,7 @@ dependencies { api 'com.google.android.material:material:1.1.0' api 'cc.winboll.studio:libapputils:9.3.2' - api 'cc.winboll.studio:libappbase:1.4.1' + api 'cc.winboll.studio:libappbase:1.5.0' api fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/contacts/build.properties b/contacts/build.properties index fb546db..5962172 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Feb 12 15:27:12 GMT 2025 +#Wed Feb 12 23:28:05 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=2 +buildCount=6 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 915c449..509b1b2 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -42,7 +42,18 @@ + + + + + + + + + + + - + \ No newline at end of file diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 60e9f78..07ef89c 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -1,28 +1,23 @@ package cc.winboll.studio.contacts; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.widget.CheckBox; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.contacts.BuildConfig; import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libapputils.app.AboutActivityFactory; import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.bean.APPInfo; -import cc.winboll.studio.libapputils.util.UriUtils; -import cc.winboll.studio.libapputils.view.StringToQrCodeView; import cc.winboll.studio.libapputils.view.YesNoAlertDialog; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.UUID; -import cc.winboll.studio.libapputils.app.AboutActivityFactory; final public class MainActivity extends AppCompatActivity implements IWinBollActivity { @@ -32,12 +27,14 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct public static final int REQUEST_ABOUT_ACTIVITY = 1; Toolbar mToolbar; - + CheckBox cbMainService; + MainServiceBean mMainServiceBean; + @Override public AppCompatActivity getActivity() { return this; } - + @Override public APPInfo getAppInfo() { String szBranchName = "contacts"; @@ -73,9 +70,27 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct getSupportActionBar().setDisplayHomeAsUpEnabled(true); } getSupportActionBar().setSubtitle(getTag()); - + //ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE()); LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); + + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mMainServiceBean == null) { + mMainServiceBean = new MainServiceBean(); + } + cbMainService = findViewById(R.id.activitymainCheckBox1); + cbMainService.setChecked(mMainServiceBean.isEnable()); + cbMainService.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view) { + + if (cbMainService.isChecked()) { + MainService.startISOSService(MainActivity.this); + } else { + MainService.stopISOSService(MainActivity.this); + } + } + }); } @Override @@ -146,7 +161,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct public boolean isEnableDisplayHomeAsUp() { return false; } - + @Override public void onBackPressed() { exit(); diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/beans/MainServiceBean.java b/contacts/src/main/java/cc/winboll/studio/contacts/beans/MainServiceBean.java new file mode 100644 index 0000000..de752f3 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/beans/MainServiceBean.java @@ -0,0 +1,68 @@ +package cc.winboll.studio.contacts.beans; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/13 07:06:13 + */ +import android.util.JsonReader; +import android.util.JsonWriter; +import cc.winboll.studio.libappbase.BaseBean; +import java.io.IOException; + +public class MainServiceBean extends BaseBean { + + public static final String TAG = "MainServiceBean"; + + boolean isEnable; + + public MainServiceBean() { + this.isEnable = false; + } + + public void setIsEnable(boolean isEnable) { + this.isEnable = isEnable; + } + + public boolean isEnable() { + return isEnable; + } + + @Override + public String getName() { + return MainServiceBean.class.getName(); + } + + @Override + public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { + super.writeThisToJsonWriter(jsonWriter); + MainServiceBean bean = this; + jsonWriter.name("isEnable").value(bean.isEnable()); + + } + + @Override + public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { + if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { + if (name.equals("isEnable")) { + setIsEnable(jsonReader.nextBoolean()); + } else { + return false; + } + } + return true; + } + + @Override + public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { + jsonReader.beginObject(); + while (jsonReader.hasNext()) { + String name = jsonReader.nextName(); + if (!initObjectsFromJsonReader(jsonReader, name)) { + jsonReader.skipValue(); + } + } + // 结束 JSON 对象 + jsonReader.endObject(); + return this; + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java new file mode 100644 index 0000000..6315f2f --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java @@ -0,0 +1,28 @@ +package cc.winboll.studio.contacts.receivers; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.hjq.toast.ToastUtils; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/13 06:58:04 + * @Describe 主要广播接收器 + */ +public class MainReceiver extends BroadcastReceiver { + + public static final String TAG = "MainReceiver"; + public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; + + @Override + public void onReceive(Context context, Intent intent) { + String szAction = intent.getAction(); + if (szAction.equals(ACTION_BOOT_COMPLETED)) { + ToastUtils.show("ACTION_BOOT_COMPLETED"); + } else { + ToastUtils.show("szAction"); + } + } + +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java new file mode 100644 index 0000000..25ad21a --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -0,0 +1,142 @@ +package cc.winboll.studio.contacts.services; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.libappbase.ISOSAPP; +import cc.winboll.studio.libappbase.ISOSService; +import cc.winboll.studio.libappbase.LogUtils; +import com.hjq.toast.ToastUtils; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/13 06:56:41 + * @Describe 拨号主服务 + */ +public class MainService extends Service implements ISOSService { + + public static final String TAG = "MainService"; + + public static final String ACTION_ENABLE = MainService.class.getName() + ".ACTION_ENABLE"; + public static final String ACTION_DISABLE = MainService.class.getName() + ".ACTION_DISABLE"; + + MainServiceBean mMainServiceBean; + static MainThread _MainThread; + public static synchronized MainThread getMainThreadInstance() { + if (_MainThread == null) { + _MainThread = new MainThread(); + } + return _MainThread; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + LogUtils.d(TAG, "onCreate"); + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + runMainThread(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + LogUtils.d(TAG, "onStartCommand"); + if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) { + LogUtils.d(TAG, "onStartCommand enable service"); + mMainServiceBean.setIsEnable(true); + MainServiceBean.saveBean(this, mMainServiceBean); + } + + runMainThread(); + + //return super.onStartCommand(intent, flags, startId); + return mMainServiceBean.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); + } + + void runMainThread() { + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mMainServiceBean.isEnable() + && _MainThread == null) { + getMainThreadInstance().start(); + } + } + + @Override + public Intent getISOSServiceIntentWhichAskForHelp() { + Intent intentService = new Intent(); + intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, this.getPackageName()); + intentService.putExtra(ISOSAPP.EXTRA_SERVICE, this.getClass().getName()); + return intentService; + } + + @Override + public boolean isEnable() { + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + return mMainServiceBean.isEnable(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + LogUtils.d(TAG, "onDestroy"); + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mMainServiceBean.isEnable()) { + LogUtils.d(TAG, "mSimpleOperateSignalCenterServiceBean.isEnable()"); + ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); + iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); + } + if (_MainThread != null) { + _MainThread.isExist = true; + _MainThread = null; + } + } + + public static void stopISOSService(Context context) { + LogUtils.d(TAG, "stopISOSService"); + MainServiceBean bean = new MainServiceBean(); + bean.setIsEnable(false); + MainServiceBean.saveBean(context, bean); + context.stopService(new Intent(context, MainService.class)); + } + + public static void startISOSService(Context context) { + LogUtils.d(TAG, "startISOSService"); + MainServiceBean bean = new MainServiceBean(); + bean.setIsEnable(true); + MainServiceBean.saveBean(context, bean); + context.startService(new Intent(context, MainService.class)); + } + + static class MainThread extends Thread { + volatile boolean isExist = false; + + public void setIsExist(boolean isExist) { + this.isExist = isExist; + } + + public boolean isExist() { + return isExist; + } + + @Override + public void run() { + super.run(); + while (!isExist) { + LogUtils.d(TAG, "run"); + ToastUtils.show("run"); + try { + sleep(1000); + } catch (InterruptedException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + } + + } +} diff --git a/contacts/src/main/res/layout/activity_main.xml b/contacts/src/main/res/layout/activity_main.xml index ba8cd96..980222d 100644 --- a/contacts/src/main/res/layout/activity_main.xml +++ b/contacts/src/main/res/layout/activity_main.xml @@ -2,7 +2,7 @@ @@ -19,10 +19,18 @@ android:layout_weight="1.0" android:background="#FFEEEEEE"> - + + + + + diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index fb546db..5962172 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Feb 12 15:27:12 GMT 2025 +#Wed Feb 12 23:28:05 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=2 +buildCount=6 baseBetaVersion=1.0.1 From 1baa0c5a61897ac257f4a8276a2255ec18fe304e Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Fri, 14 Feb 2025 03:12:43 +0800 Subject: [PATCH 03/38] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=B1=BB=E5=BA=93?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=90=8C=E5=BA=94=E7=94=A8=E5=8C=85=E4=B9=8B?= =?UTF-8?q?=E9=97=B4=E5=B9=BF=E6=92=AD=E6=B6=88=E6=81=AF=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E9=80=9A=E8=BF=87=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.gradle | 2 +- contacts/build.properties | 4 +-- .../java/cc/winboll/studio/contacts/App.java | 2 +- .../winboll/studio/contacts/MainActivity.java | 23 ++++++++++------ .../studio/contacts/services/MainService.java | 26 ++++++++++++++++--- .../src/main/res/layout/activity_main.xml | 6 +++++ winboll-shared/build.properties | 4 +-- 7 files changed, 50 insertions(+), 17 deletions(-) diff --git a/contacts/build.gradle b/contacts/build.gradle index 83e881e..86bb581 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -64,7 +64,7 @@ dependencies { api 'com.google.android.material:material:1.1.0' api 'cc.winboll.studio:libapputils:9.3.2' - api 'cc.winboll.studio:libappbase:1.5.0' + api 'cc.winboll.studio:libappbase:1.5.1' api fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/contacts/build.properties b/contacts/build.properties index 5962172..ed0e69d 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Feb 12 23:28:05 GMT 2025 +#Thu Feb 13 19:09:39 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=6 +buildCount=13 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/App.java b/contacts/src/main/java/cc/winboll/studio/contacts/App.java index 6b00e0f..6f482d5 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/App.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/App.java @@ -17,7 +17,7 @@ public class App extends GlobalApplication { public void onCreate() { // 必须在调用基类前设置应用调试标志, // 这样可以预先设置日志与数据的存储根目录。 - //setIsDebug(BuildConfig.DEBUG); + setIsDebuging(this, BuildConfig.DEBUG); super.onCreate(); // 设置 WinBoll 应用 UI 类型 WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication); diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 07ef89c..952e7ba 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -11,8 +11,10 @@ import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.contacts.BuildConfig; import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.beans.MainServiceBean; -import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.LogView; +import cc.winboll.studio.libappbase.SOS; import cc.winboll.studio.libapputils.app.AboutActivityFactory; import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivityManager; @@ -25,7 +27,8 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct public static final int REQUEST_HOME_ACTIVITY = 0; public static final int REQUEST_ABOUT_ACTIVITY = 1; - + + LogView mLogView; Toolbar mToolbar; CheckBox cbMainService; MainServiceBean mMainServiceBean; @@ -61,7 +64,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // 以下正常创建主窗口 super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + + mLogView = findViewById(R.id.activitymainLogView1); + if (GlobalApplication.isDebuging()) { mLogView.start(); } + // 初始化工具栏 mToolbar = findViewById(R.id.activitymainToolbar1); setSupportActionBar(mToolbar); @@ -83,12 +90,12 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct cbMainService.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { - - if (cbMainService.isChecked()) { - MainService.startISOSService(MainActivity.this); - } else { - MainService.stopISOSService(MainActivity.this); - } + SOS.sendToWinBoll(MainActivity.this); +// if (cbMainService.isChecked()) { +// MainService.startISOSService(MainActivity.this); +// } else { +// MainService.stopISOSService(MainActivity.this); +// } } }); } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java index 25ad21a..4e9d60a 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -8,7 +8,10 @@ import cc.winboll.studio.contacts.beans.MainServiceBean; import cc.winboll.studio.libappbase.ISOSAPP; import cc.winboll.studio.libappbase.ISOSService; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver; +import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService; import com.hjq.toast.ToastUtils; +import android.content.ComponentName; /** * @Author ZhanGSKen@AliYun.Com @@ -87,9 +90,10 @@ public class MainService extends Service implements ISOSService { LogUtils.d(TAG, "onDestroy"); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); if (mMainServiceBean.isEnable()) { - LogUtils.d(TAG, "mSimpleOperateSignalCenterServiceBean.isEnable()"); - ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); - iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); + LogUtils.d(TAG, "mMainServiceBean.isEnable()"); +// ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); +// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); + sos(); } if (_MainThread != null) { _MainThread.isExist = true; @@ -112,6 +116,22 @@ public class MainService extends Service implements ISOSService { MainServiceBean.saveBean(context, bean); context.startService(new Intent(context, MainService.class)); } + + public void sos() { + // 创建Intent对象,指定广播的action + Intent intentService = new Intent(SOSCSBroadcastReceiver.ACTION_SOS); + String packageName = this.getPackageName(); + String serviceClassName = SOSCSBroadcastReceiver.class.getName(); + intentService.setComponent(new ComponentName(packageName, serviceClassName)); + + // 目标服务的包名和类名 + intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, getPackageName()); + intentService.putExtra(ISOSAPP.EXTRA_SERVICE, MainService.class.getName()); + // 发送广播 + sendBroadcast(intentService); + LogUtils.d(TAG, "sos"); + ToastUtils.show("sos"); + } static class MainThread extends Thread { volatile boolean isExist = false; diff --git a/contacts/src/main/res/layout/activity_main.xml b/contacts/src/main/res/layout/activity_main.xml index 980222d..78d3baa 100644 --- a/contacts/src/main/res/layout/activity_main.xml +++ b/contacts/src/main/res/layout/activity_main.xml @@ -32,6 +32,12 @@ + + diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index 5962172..ed0e69d 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Feb 12 23:28:05 GMT 2025 +#Thu Feb 13 19:09:39 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=6 +buildCount=13 baseBetaVersion=1.0.1 From ffac543f6fb40ff99da98ed530186a7fae9debdf Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 20 Feb 2025 11:28:57 +0800 Subject: [PATCH 04/38] =?UTF-8?q?=E7=B2=BE=E7=AE=80=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.gradle | 2 +- contacts/build.properties | 4 +- contacts/src/main/AndroidManifest.xml | 26 +- .../winboll/studio/contacts/MainActivity.java | 82 +++-- .../contacts/handlers/MainServiceHandler.java | 38 +++ .../contacts/receivers/MainReceiver.java | 36 ++- .../contacts/services/AssistantService.java | 139 +++++++++ .../studio/contacts/services/MainService.java | 291 +++++++++++------- .../contacts/threads/MainServiceThread.java | 77 +++++ .../contacts/widgets/APPStatusWidget.java | 76 +++++ .../widgets/APPStatusWidgetClickListener.java | 32 ++ .../main/res/drawable/ic_launcher_disable.xml | 11 + .../ic_launcher_foreground_disable.xml | 10 + .../src/main/res/layout/widget_layout.xml | 15 + .../main/res/xml/appwidget_provider_info.xml | 8 + winboll-shared/build.properties | 4 +- 16 files changed, 699 insertions(+), 152 deletions(-) create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java create mode 100644 contacts/src/main/res/drawable/ic_launcher_disable.xml create mode 100644 contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml create mode 100644 contacts/src/main/res/layout/widget_layout.xml create mode 100644 contacts/src/main/res/xml/appwidget_provider_info.xml diff --git a/contacts/build.gradle b/contacts/build.gradle index 86bb581..89322a4 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -64,7 +64,7 @@ dependencies { api 'com.google.android.material:material:1.1.0' api 'cc.winboll.studio:libapputils:9.3.2' - api 'cc.winboll.studio:libappbase:1.5.1' + api 'cc.winboll.studio:libappbase:1.5.5' api fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/contacts/build.properties b/contacts/build.properties index ed0e69d..d1c9e68 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 13 19:09:39 GMT 2025 +#Thu Feb 20 03:27:00 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=13 +buildCount=91 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 509b1b2..5ccab58 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -42,7 +42,10 @@ - + + + @@ -54,6 +57,25 @@ + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 952e7ba..9177664 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -1,5 +1,7 @@ package cc.winboll.studio.contacts; + + import android.content.Intent; import android.os.Bundle; import android.view.Menu; @@ -9,13 +11,15 @@ import android.widget.CheckBox; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.contacts.BuildConfig; +import cc.winboll.studio.contacts.MainActivity; import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogView; import cc.winboll.studio.libappbase.SOS; -import cc.winboll.studio.libapputils.app.AboutActivityFactory; +import cc.winboll.studio.libappbase.bean.APPSOSBean; import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.bean.APPInfo; @@ -27,7 +31,9 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct public static final int REQUEST_HOME_ACTIVITY = 0; public static final int REQUEST_ABOUT_ACTIVITY = 1; - + + public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS"; + LogView mLogView; Toolbar mToolbar; CheckBox cbMainService; @@ -40,21 +46,21 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct @Override public APPInfo getAppInfo() { - String szBranchName = "contacts"; - - APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); - appInfo.setAppName("Contacts"); - appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); - appInfo.setAppDescription("Contacts Description"); - appInfo.setAppGitName("APP"); - appInfo.setAppGitOwner("Studio"); - appInfo.setAppGitAPPBranch(szBranchName); - appInfo.setAppGitAPPSubProjectFolder(szBranchName); - appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); - appInfo.setAppAPKName("Contacts"); - appInfo.setAppAPKFolderName("Contacts"); - return appInfo; - //return null; +// String szBranchName = "contacts"; +// +// APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); +// appInfo.setAppName("Contacts"); +// appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); +// appInfo.setAppDescription("Contacts Description"); +// appInfo.setAppGitName("APP"); +// appInfo.setAppGitOwner("Studio"); +// appInfo.setAppGitAPPBranch(szBranchName); +// appInfo.setAppGitAPPSubProjectFolder(szBranchName); +// appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); +// appInfo.setAppAPKName("Contacts"); +// appInfo.setAppAPKFolderName("Contacts"); +// return appInfo; + return null; } @Override @@ -64,11 +70,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // 以下正常创建主窗口 super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - + mLogView = findViewById(R.id.activitymainLogView1); if (GlobalApplication.isDebuging()) { mLogView.start(); } - + // 初始化工具栏 mToolbar = findViewById(R.id.activitymainToolbar1); setSupportActionBar(mToolbar); @@ -90,22 +96,48 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct cbMainService.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { - SOS.sendToWinBoll(MainActivity.this); -// if (cbMainService.isChecked()) { -// MainService.startISOSService(MainActivity.this); -// } else { -// MainService.stopISOSService(MainActivity.this); -// } + if (cbMainService.isChecked()) { + MainService.startMainService(MainActivity.this); + } else { + MainService.stopMainService(MainActivity.this); + } } }); } +// public static void sosToWinBoll(Context context) { +// Intent intent = new Intent(ACTION_SOS); +// intent.putExtra("sos", "SOS"); +// intent.putExtra("sosPackage", context.getPackageName()); +// intent.putExtra("sosCalssType", "Service"); +// intent.putExtra("sosClassName", MainService.class.getName()); +// String szToPackage = ""; +// if (GlobalApplication.isDebuging()) { +// szToPackage = "cc.winboll.studio.appbase.beta"; +// } else { +// szToPackage = "cc.winboll.studio.appbase"; +// } +// intent.setPackage(szToPackage); +// context.sendBroadcast(intent); +// +// LogUtils.d(TAG, String.format("SOS Send To WinBoll. (szToPackage : %s)", szToPackage)); +// //ToastUtils.show("SOS Send To WinBoll"); +// } + @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); //setSubTitle(""); } + @Override + protected void onDestroy() { + super.onDestroy(); + LogUtils.d(TAG, "onDestroy() SOS"); + } + + + // // 处理传入的 Intent 数据 // diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java b/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java new file mode 100644 index 0000000..d19cd99 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java @@ -0,0 +1,38 @@ +package cc.winboll.studio.contacts.handlers; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/14 03:51:40 + */ +import android.os.Handler; +import android.os.Message; +import cc.winboll.studio.contacts.services.MainService; +import java.lang.ref.WeakReference; + +public class MainServiceHandler extends Handler { + public static final String TAG = "MainServiceHandler"; + + public static final int MSG_REMINDTHREAD = 0; + + WeakReference serviceWeakReference; + public MainServiceHandler(MainService service) { + serviceWeakReference = new WeakReference(service); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REMINDTHREAD: // 处理下载完成消息,更新UI + { + // 显示提醒消息 + // + //LogUtils.d(TAG, "显示提醒消息"); + MainService mainService = serviceWeakReference.get(); + if (mainService != null) { + mainService.appenMessage((String)msg.obj); + } + break; + } + } + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java index 6315f2f..7d93891 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java @@ -1,20 +1,32 @@ package cc.winboll.studio.contacts.receivers; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import com.hjq.toast.ToastUtils; - /** * @Author ZhanGSKen@AliYun.Com * @Date 2025/02/13 06:58:04 * @Describe 主要广播接收器 */ +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import cc.winboll.studio.contacts.services.MainService; +import com.hjq.toast.ToastUtils; +import java.lang.ref.WeakReference; + public class MainReceiver extends BroadcastReceiver { - + public static final String TAG = "MainReceiver"; public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; - + WeakReference mwrService; + // 存储电量指示值, + // 用于校验电量消息时的电量变化 + static volatile int _mnTheQuantityOfElectricityOld = -1; + static volatile boolean _mIsCharging = false; + + public MainReceiver(MainService service) { + mwrService = new WeakReference(service); + } + @Override public void onReceive(Context context, Intent intent) { String szAction = intent.getAction(); @@ -24,5 +36,13 @@ public class MainReceiver extends BroadcastReceiver { ToastUtils.show("szAction"); } } - + + // 注册 Receiver + // + public void registerAction(Context context) { + IntentFilter filter=new IntentFilter(); + filter.addAction(ACTION_BOOT_COMPLETED); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + context.registerReceiver(this, filter); + } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java new file mode 100644 index 0000000..a031f4b --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java @@ -0,0 +1,139 @@ +package cc.winboll.studio.contacts.services; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/14 03:38:31 + * @Describe 守护进程服务 + */ +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; + +public class AssistantService extends Service { + + public static final String TAG = "AssistantService"; + + MainServiceBean mMainServiceBean; + MyServiceConnection mMyServiceConnection; + MainService mMainService; + boolean isBound = false; + volatile boolean isThreadAlive = false; + + public synchronized void setIsThreadAlive(boolean isThreadAlive) { + LogUtils.d(TAG, "setIsThreadAlive(...)"); + LogUtils.d(TAG, String.format("isThreadAlive %s", isThreadAlive)); + this.isThreadAlive = isThreadAlive; + } + + public boolean isThreadAlive() { + return isThreadAlive; + } + + @Override + public IBinder onBind(Intent intent) { + return new MyBinder(); + } + + @Override + public void onCreate() { + LogUtils.d(TAG, "onCreate"); + super.onCreate(); + + //mMyBinder = new MyBinder(); + if (mMyServiceConnection == null) { + mMyServiceConnection = new MyServiceConnection(); + } + // 设置运行参数 + setIsThreadAlive(false); + assistantService(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + LogUtils.d(TAG, "call onStartCommand(...)"); + assistantService(); + return START_STICKY; + } + + @Override + public void onDestroy() { + //LogUtils.d(TAG, "onDestroy"); + setIsThreadAlive(false); + // 解除绑定 + if (isBound) { + unbindService(mMyServiceConnection); + isBound = false; + } + super.onDestroy(); + } + + // 运行服务内容 + // + void assistantService() { + LogUtils.d(TAG, "assistantService()"); + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + LogUtils.d(TAG, String.format("mMainServiceBean.isEnable() %s", mMainServiceBean.isEnable())); + if (mMainServiceBean.isEnable()) { + LogUtils.d(TAG, String.format("mIsThreadAlive %s", isThreadAlive())); + if (isThreadAlive() == false) { + // 设置运行状态 + setIsThreadAlive(true); + // 唤醒和绑定主进程 + wakeupAndBindMain(); + } + } + } + + // 唤醒和绑定主进程 + // + void wakeupAndBindMain() { + LogUtils.d(TAG, "wakeupAndBindMain()"); + // 绑定服务的Intent + Intent intent = new Intent(this, MainService.class); + startService(new Intent(this, MainService.class)); + bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); + +// startService(new Intent(this, MainService.class)); +// bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT); + } + + // 主进程与守护进程连接时需要用到此类 + // + class MyServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + LogUtils.d(TAG, "onServiceConnected(...)"); + MainService.MyBinder binder = (MainService.MyBinder) service; + mMainService = binder.getService(); + isBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + LogUtils.d(TAG, "onServiceDisconnected(...)"); + mMainServiceBean = MainServiceBean.loadBean(AssistantService.this, MainServiceBean.class); + if (mMainServiceBean.isEnable()) { + wakeupAndBindMain(); + } + isBound = false; + mMainService = null; + } + } + + // 用于返回服务实例的Binder + public class MyBinder extends Binder { + AssistantService getService() { + LogUtils.d(TAG, "AssistantService MyBinder getService()"); + return AssistantService.this; + } + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java index 4e9d60a..efaf13e 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -1,162 +1,229 @@ package cc.winboll.studio.contacts.services; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import cc.winboll.studio.contacts.beans.MainServiceBean; -import cc.winboll.studio.libappbase.ISOSAPP; -import cc.winboll.studio.libappbase.ISOSService; -import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver; -import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService; -import com.hjq.toast.ToastUtils; -import android.content.ComponentName; - /** * @Author ZhanGSKen@AliYun.Com * @Date 2025/02/13 06:56:41 * @Describe 拨号主服务 + * 参考: + * 进程保活-双进程守护的正确姿势 + * https://blog.csdn.net/sinat_35159441/article/details/75267380 + * Android Service之onStartCommand方法研究 + * https://blog.csdn.net/cyp331203/article/details/38920491 */ -public class MainService extends Service implements ISOSService { - +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.handlers.MainServiceHandler; +import cc.winboll.studio.contacts.receivers.MainReceiver; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.contacts.threads.MainServiceThread; +import cc.winboll.studio.contacts.widgets.APPStatusWidget; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; + +public class MainService extends Service { + public static final String TAG = "MainService"; - - public static final String ACTION_ENABLE = MainService.class.getName() + ".ACTION_ENABLE"; - public static final String ACTION_DISABLE = MainService.class.getName() + ".ACTION_DISABLE"; + + public static final int MSG_UPDATE_STATUS = 0; + + static MainService _mControlCenterService; + + volatile boolean isServiceRunning; MainServiceBean mMainServiceBean; - static MainThread _MainThread; - public static synchronized MainThread getMainThreadInstance() { - if (_MainThread == null) { - _MainThread = new MainThread(); - } - return _MainThread; - } + MainServiceThread mMainServiceThread; + MainServiceHandler mMainServiceHandler; + MyServiceConnection mMyServiceConnection; + AssistantService mAssistantService; + boolean isBound = false; + MainReceiver mMainReceiver; @Override public IBinder onBind(Intent intent) { - return null; + return new MyBinder(); + } + + public MainServiceThread getRemindThread() { + return mMainServiceThread; } @Override public void onCreate() { super.onCreate(); - LogUtils.d(TAG, "onCreate"); + LogUtils.d(TAG, "onCreate()"); + _mControlCenterService = MainService.this; + isServiceRunning = false; mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - runMainThread(); + + if (mMyServiceConnection == null) { + mMyServiceConnection = new MyServiceConnection(); + } + mMainServiceHandler = new MainServiceHandler(this); + + // 运行服务内容 + mainService(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { - LogUtils.d(TAG, "onStartCommand"); - if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) { - LogUtils.d(TAG, "onStartCommand enable service"); - mMainServiceBean.setIsEnable(true); - MainServiceBean.saveBean(this, mMainServiceBean); - } - - runMainThread(); - - //return super.onStartCommand(intent, flags, startId); - return mMainServiceBean.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); + LogUtils.d(TAG, "onStartCommand(...)"); + // 运行服务内容 + mainService(); + return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); } - void runMainThread() { + // 运行服务内容 + // + void mainService() { + LogUtils.d(TAG, "mainService()"); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean.isEnable() - && _MainThread == null) { - getMainThreadInstance().start(); + if (mMainServiceBean.isEnable() && isServiceRunning == false) { + LogUtils.d(TAG, "mainService() start running"); + isServiceRunning = true; + // 唤醒守护进程 + wakeupAndBindAssistant(); + // 召唤 WinBoll APP 绑定本服务 + SOS.bindToAPPService(this, new APPSOSBean(getPackageName(), MainService.class.getName())); + + if (mMainReceiver == null) { + // 注册广播接收器 + mMainReceiver = new MainReceiver(this); + mMainReceiver.registerAction(this); + } + + + MainServiceThread.getInstance(this, mMainServiceHandler).start(); + + LogUtils.i(TAG, "Main Service Is Start."); } } - @Override - public Intent getISOSServiceIntentWhichAskForHelp() { - Intent intentService = new Intent(); - intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, this.getPackageName()); - intentService.putExtra(ISOSAPP.EXTRA_SERVICE, this.getClass().getName()); - return intentService; - } + // 唤醒和绑定守护进程 + // + void wakeupAndBindAssistant() { + LogUtils.d(TAG, "wakeupAndBindAssistant()"); +// if (ServiceUtils.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) { +// startService(new Intent(MainService.this, AssistantService.class)); +// //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService"); +// bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); +// } + Intent intent = new Intent(this, AssistantService.class); + startService(intent); + // 绑定服务的Intent + //Intent intent = new Intent(this, AssistantService.class); + bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); - @Override - public boolean isEnable() { - mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - return mMainServiceBean.isEnable(); +// Intent intent = new Intent(this, AssistantService.class); +// startService(intent); +// LogUtils.d(TAG, "startService(intent)"); +// bindService(new Intent(this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); } @Override public void onDestroy() { - super.onDestroy(); - LogUtils.d(TAG, "onDestroy"); + //LogUtils.d(TAG, "onDestroy"); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean.isEnable()) { - LogUtils.d(TAG, "mMainServiceBean.isEnable()"); -// ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); -// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); - sos(); - } - if (_MainThread != null) { - _MainThread.isExist = true; - _MainThread = null; + //LogUtils.d(TAG, "onDestroy done"); + if (mMainServiceBean.isEnable() == false) { + // 设置运行状态 + isServiceRunning = false;// 解除绑定 + if (isBound) { + unbindService(mMyServiceConnection); + isBound = false; + } + // 停止守护进程 + Intent intent = new Intent(this, AssistantService.class); + stopService(intent); + // 停止Receiver + if (mMainReceiver != null) { + unregisterReceiver(mMainReceiver); + mMainReceiver = null; + } + // 停止前台通知栏 + stopForeground(true); + + // 停止主要进程 + MainServiceThread.getInstance(this, mMainServiceHandler).setIsExit(true); + } + + super.onDestroy(); + } + + // 主进程与守护进程连接时需要用到此类 + // + private class MyServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + LogUtils.d(TAG, "onServiceConnected(...)"); + AssistantService.MyBinder binder = (AssistantService.MyBinder) service; + mAssistantService = binder.getService(); + isBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + LogUtils.d(TAG, "onServiceDisconnected(...)"); + if (mMainServiceBean.isEnable()) { + // 唤醒守护进程 + wakeupAndBindAssistant(); + SOS.sosWinBollService(getApplicationContext(), new APPSOSBean(getPackageName(), MainService.class.getName())); + } + isBound = false; + mAssistantService = null; + } + + } + + + // 用于返回服务实例的Binder + public class MyBinder extends Binder { + MainService getService() { + LogUtils.d(TAG, "MainService MyBinder getService()"); + return MainService.this; } } - public static void stopISOSService(Context context) { - LogUtils.d(TAG, "stopISOSService"); +// // +// // 启动服务 +// // +// public static void startControlCenterService(Context context) { +// Intent intent = new Intent(context, MainService.class); +// context.startForegroundService(intent); +// } +// +// // +// // 停止服务 +// // +// public static void stopControlCenterService(Context context) { +// Intent intent = new Intent(context, MainService.class); +// context.stopService(intent); +// } + + public void appenMessage(String message) { + LogUtils.d(TAG, String.format("Message : %s", message)); + } + + public static void stopMainService(Context context) { + LogUtils.d(TAG, "stopMainService"); MainServiceBean bean = new MainServiceBean(); bean.setIsEnable(false); MainServiceBean.saveBean(context, bean); context.stopService(new Intent(context, MainService.class)); } - public static void startISOSService(Context context) { - LogUtils.d(TAG, "startISOSService"); + public static void startMainService(Context context) { + LogUtils.d(TAG, "startMainService"); MainServiceBean bean = new MainServiceBean(); bean.setIsEnable(true); MainServiceBean.saveBean(context, bean); context.startService(new Intent(context, MainService.class)); } - - public void sos() { - // 创建Intent对象,指定广播的action - Intent intentService = new Intent(SOSCSBroadcastReceiver.ACTION_SOS); - String packageName = this.getPackageName(); - String serviceClassName = SOSCSBroadcastReceiver.class.getName(); - intentService.setComponent(new ComponentName(packageName, serviceClassName)); - - // 目标服务的包名和类名 - intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, getPackageName()); - intentService.putExtra(ISOSAPP.EXTRA_SERVICE, MainService.class.getName()); - // 发送广播 - sendBroadcast(intentService); - LogUtils.d(TAG, "sos"); - ToastUtils.show("sos"); - } - - static class MainThread extends Thread { - volatile boolean isExist = false; - - public void setIsExist(boolean isExist) { - this.isExist = isExist; - } - - public boolean isExist() { - return isExist; - } - - @Override - public void run() { - super.run(); - while (!isExist) { - LogUtils.d(TAG, "run"); - ToastUtils.show("run"); - try { - sleep(1000); - } catch (InterruptedException e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); - } - } - } - - } } + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java b/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java new file mode 100644 index 0000000..0dfd918 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java @@ -0,0 +1,77 @@ +package cc.winboll.studio.contacts.threads; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/14 03:46:44 + */ +import android.content.Context; +import cc.winboll.studio.contacts.handlers.MainServiceHandler; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; +import com.hjq.toast.ToastUtils; +import java.lang.ref.WeakReference; + +public class MainServiceThread extends Thread { + + public static final String TAG = "MainServiceThread"; + + volatile static MainServiceThread _MainServiceThread; + // 控制线程是否退出的标志 + volatile boolean isExit = false; + volatile boolean isStarted = false; + Context mContext; + // 服务Handler, 用于线程发送消息使用 + WeakReference mwrMainServiceHandler; + + MainServiceThread(Context context, MainServiceHandler handler) { + mContext = context; + mwrMainServiceHandler = new WeakReference(handler); + } + + public void setIsExit(boolean isExit) { + this.isExit = isExit; + } + + public boolean isExit() { + return isExit; + } + + public void setIsStarted(boolean isStarted) { + this.isStarted = isStarted; + } + + public boolean isStarted() { + return isStarted; + } + + public static MainServiceThread getInstance(Context context, MainServiceHandler handler) { + if (_MainServiceThread != null) { + _MainServiceThread.setIsExit(true); + } + _MainServiceThread = new MainServiceThread(context, handler); + return _MainServiceThread; + } + + @Override + public void run() { + if (isStarted == false) { + isStarted = true; + LogUtils.d(TAG, "run()"); + + while (!isExit()) { + //ToastUtils.show("run"); + //LogUtils.d(TAG, "run()"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + _MainServiceThread = null; + LogUtils.d(TAG, "run() exit"); + } + } + +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java new file mode 100644 index 0000000..8a9b7c0 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java @@ -0,0 +1,76 @@ +package cc.winboll.studio.contacts.widgets; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/17 14:49:31 + * @Describe APPStatusWidget + */ +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.widget.RemoteViews; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.threads.MainServiceThread; +import cc.winboll.studio.libappbase.LogUtils; +import com.hjq.toast.ToastUtils; + +public class APPStatusWidget extends AppWidgetProvider { + + public static final String TAG = "APPSOSReportWidget"; + + public static final String ACTION_STATUS_ACTIVE = "cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_ACTIVE"; + public static final String ACTION_STATUS_NOACTIVE = "cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_NOACTIVE"; + + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + if (intent.getAction().equals(ACTION_STATUS_ACTIVE)) { + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPStatusWidget.class)); + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } else if (intent.getAction().equals(ACTION_STATUS_NOACTIVE)) { + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPStatusWidget.class)); + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } + + } + + private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { + LogUtils.d(TAG, "updateAppWidget(...)"); + + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); + //设置按钮点击事件 + Intent intentAppButton = new Intent(context, APPStatusWidgetClickListener.class); + intentAppButton.setAction(APPStatusWidgetClickListener.ACTION_APPICON_CLICK); + PendingIntent pendingIntentAppButton = PendingIntent.getBroadcast(context, 0, intentAppButton, PendingIntent.FLAG_UPDATE_CURRENT); + views.setOnClickPendingIntent(R.id.widgetlayoutImageView1, pendingIntentAppButton); + +// boolean isActive = !MainServiceThread.isExist(); +// if (isActive) { +// views.setImageViewResource(R.id.widgetlayoutImageView1, R.drawable.ic_launcher); +// } else { +// views.setImageViewResource(R.id.widgetlayoutImageView1, R.drawable.ic_launcher_disable); +// +// } + appWidgetManager.updateAppWidget(appWidgetId, views); + } + + public static void onAPPStatusWidgetClick(Context context) { + ToastUtils.show("onAPPStatusWidgetClick"); + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java new file mode 100644 index 0000000..016ccb2 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java @@ -0,0 +1,32 @@ +package cc.winboll.studio.contacts.widgets; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/17 14:59:55 + * @Describe WidgetButtonClickListener + */ +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; +import cc.winboll.studio.libappbase.LogUtils; + +public class APPStatusWidgetClickListener extends BroadcastReceiver { + + public static final String TAG = "APPStatusWidgetClickListener"; + + public static final String ACTION_APPICON_CLICK = "cc.winboll.studio.contacts.widgets.APPStatusWidgetClickListener.ACTION_APPICON_CLICK"; + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null) { + LogUtils.d(TAG, String.format("action %s", action)); + return; + } + if (action.equals(ACTION_APPICON_CLICK)) { + LogUtils.d(TAG, "ACTION_APPICON_CLICK"); + Toast.makeText(context, "ACTION_APPICON_CLICK", Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/contacts/src/main/res/drawable/ic_launcher_disable.xml b/contacts/src/main/res/drawable/ic_launcher_disable.xml new file mode 100644 index 0000000..9a31905 --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_disable.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml b/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml new file mode 100644 index 0000000..763b72c --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml @@ -0,0 +1,10 @@ + + + + diff --git a/contacts/src/main/res/layout/widget_layout.xml b/contacts/src/main/res/layout/widget_layout.xml new file mode 100644 index 0000000..0dc6b46 --- /dev/null +++ b/contacts/src/main/res/layout/widget_layout.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/contacts/src/main/res/xml/appwidget_provider_info.xml b/contacts/src/main/res/xml/appwidget_provider_info.xml new file mode 100644 index 0000000..7dda9ab --- /dev/null +++ b/contacts/src/main/res/xml/appwidget_provider_info.xml @@ -0,0 +1,8 @@ + + + diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index ed0e69d..d1c9e68 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 13 19:09:39 GMT 2025 +#Thu Feb 20 03:27:00 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=13 +buildCount=91 baseBetaVersion=1.0.1 From e5dfd5b975f692fd8267091ddf373befd587f6d5 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 20 Feb 2025 14:59:09 +0800 Subject: [PATCH 05/38] =?UTF-8?q?=E6=8B=A8=E5=8F=B7=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E8=AE=BE=E8=AE=A1=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.gradle | 5 +- contacts/build.properties | 4 +- contacts/src/main/AndroidManifest.xml | 37 ++-- .../winboll/studio/contacts/MainActivity.java | 172 +++++++++++++----- .../contacts/adapters/ImagePagerAdapter.java | 14 ++ .../contacts/adapters/MyPagerAdapter.java | 42 +++++ .../contacts/fragments/CallFragment.java | 51 ++++++ .../contacts/fragments/ContactsFragment.java | 50 +++++ .../contacts/fragments/LogFragment.java | 50 +++++ .../src/main/res/layout/activity_main.xml | 31 +--- .../src/main/res/layout/fragment_call.xml | 29 +++ .../src/main/res/layout/fragment_contacts.xml | 15 ++ contacts/src/main/res/layout/fragment_log.xml | 12 ++ winboll-shared/build.properties | 4 +- 14 files changed, 428 insertions(+), 88 deletions(-) create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/adapters/ImagePagerAdapter.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallFragment.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java create mode 100644 contacts/src/main/res/layout/fragment_call.xml create mode 100644 contacts/src/main/res/layout/fragment_contacts.xml create mode 100644 contacts/src/main/res/layout/fragment_log.xml diff --git a/contacts/build.gradle b/contacts/build.gradle index 89322a4..32df31f 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -59,9 +59,10 @@ dependencies { api 'org.jsoup:jsoup:1.13.1' api 'com.squareup.okhttp3:okhttp:4.4.1' - api 'androidx.appcompat:appcompat:1.3.1' + api 'androidx.appcompat:appcompat:1.1.0' + api 'androidx.viewpager:viewpager:1.0.0' api 'androidx.fragment:fragment:1.1.0' - api 'com.google.android.material:material:1.1.0' + api 'com.google.android.material:material:1.4.0' api 'cc.winboll.studio:libapputils:9.3.2' api 'cc.winboll.studio:libappbase:1.5.5' diff --git a/contacts/build.properties b/contacts/build.properties index d1c9e68..e0bef68 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 20 03:27:00 GMT 2025 +#Thu Feb 20 06:57:14 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=91 +buildCount=98 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 5ccab58..4ab1fb6 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -6,6 +6,9 @@ + + + - @@ -57,25 +61,36 @@ - + - - - + + + + + + + + + android:resource="@xml/appwidget_provider_info"/> + - - - - + + + + + + + - + \ No newline at end of file diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 9177664..02a7adb 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -6,26 +6,28 @@ import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import android.widget.CheckBox; +import com.google.android.material.tabs.TabLayout; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import cc.winboll.studio.contacts.BuildConfig; -import cc.winboll.studio.contacts.MainActivity; +import androidx.viewpager.widget.ViewPager; import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.adapters.MyPagerAdapter; import cc.winboll.studio.contacts.beans.MainServiceBean; -import cc.winboll.studio.contacts.services.MainService; -import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogView; -import cc.winboll.studio.libappbase.SOS; -import cc.winboll.studio.libappbase.bean.APPSOSBean; import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.bean.APPInfo; import cc.winboll.studio.libapputils.view.YesNoAlertDialog; +import android.widget.ImageView; +import android.view.View; +import java.util.ArrayList; +import android.view.LayoutInflater; +import android.widget.LinearLayout; +import java.util.List; -final public class MainActivity extends AppCompatActivity implements IWinBollActivity { +final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener { public static final String TAG = "MainActivity"; @@ -38,6 +40,14 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct Toolbar mToolbar; CheckBox cbMainService; MainServiceBean mMainServiceBean; + ViewPager viewPager; + private List views; //用来存放放进ViewPager里面的布局 + //实例化存储imageView(导航原点)的集合 + ImageView[] imageViews; + //MyPagerAdapter adapter;//适配器 + MyPagerAdapter pagerAdapter; + LinearLayout linearLayout;//下标所在在LinearLayout布局里 + int currentPoint = 0;//当前被选中中页面的下标 @Override public AppCompatActivity getActivity() { @@ -70,11 +80,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // 以下正常创建主窗口 super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - - mLogView = findViewById(R.id.activitymainLogView1); - - if (GlobalApplication.isDebuging()) { mLogView.start(); } - + // 初始化工具栏 mToolbar = findViewById(R.id.activitymainToolbar1); setSupportActionBar(mToolbar); @@ -84,45 +90,117 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct } getSupportActionBar().setSubtitle(getTag()); - //ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE()); - LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); + initData(); + initView();//调用初始化视图方法 + //initPoint();//调用初始化导航原点的方法 + viewPager.addOnPageChangeListener(this);//滑动事件 + + ViewPager viewPager = findViewById(R.id.activitymainViewPager1); + MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager()); + viewPager.setAdapter(pagerAdapter); + TabLayout tabLayout = findViewById(R.id.activitymainTabLayout1); + tabLayout.setupWithViewPager(viewPager); - mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean == null) { - mMainServiceBean = new MainServiceBean(); - } - cbMainService = findViewById(R.id.activitymainCheckBox1); - cbMainService.setChecked(mMainServiceBean.isEnable()); - cbMainService.setOnClickListener(new View.OnClickListener(){ - @Override - public void onClick(View view) { - if (cbMainService.isChecked()) { - MainService.startMainService(MainActivity.this); - } else { - MainService.stopMainService(MainActivity.this); - } - } - }); +// mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); +// if (mMainServiceBean == null) { +// mMainServiceBean = new MainServiceBean(); +// } +// cbMainService = findViewById(R.id.activitymainCheckBox1); +// cbMainService.setChecked(mMainServiceBean.isEnable()); +// cbMainService.setOnClickListener(new View.OnClickListener(){ +// @Override +// public void onClick(View view) { +// if (cbMainService.isChecked()) { +// MainService.startMainService(MainActivity.this); +// } else { +// MainService.stopMainService(MainActivity.this); +// } +// } +// }); + } + + + //初始化view,即显示的图片 + void initView() { + viewPager = findViewById(R.id.activitymainViewPager1); + pagerAdapter = new MyPagerAdapter(getSupportFragmentManager()); + viewPager.setAdapter(pagerAdapter); + //adapter = new MyPagerAdapter(views); + //viewPager = findViewById(R.id.activitymainViewPager1); + //viewPager.setAdapter(adapter); + //linearLayout = findViewById(R.id.activitymainLinearLayout1); + //initPoint();//初始化页面下方的点 + viewPager.setOnPageChangeListener(this); + } -// public static void sosToWinBoll(Context context) { -// Intent intent = new Intent(ACTION_SOS); -// intent.putExtra("sos", "SOS"); -// intent.putExtra("sosPackage", context.getPackageName()); -// intent.putExtra("sosCalssType", "Service"); -// intent.putExtra("sosClassName", MainService.class.getName()); -// String szToPackage = ""; -// if (GlobalApplication.isDebuging()) { -// szToPackage = "cc.winboll.studio.appbase.beta"; -// } else { -// szToPackage = "cc.winboll.studio.appbase"; + //初始化所要显示的布局 + void initData() { + ViewPager viewPager = findViewById(R.id.activitymainViewPager1); + LayoutInflater inflater = LayoutInflater.from(getActivity()); + View view1 = inflater.inflate(R.layout.fragment_call, viewPager, false); + View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false); + View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false); + + views = new ArrayList<>(); + views.add(view1); + views.add(view2); + views.add(view3); + } + +// void initPoint() { +// imageViews = new ImageView[5];//实例化5个图片 +// for (int i = 0; i < linearLayout.getChildCount(); i++) { +// imageViews[i] = (ImageView) linearLayout.getChildAt(i); +// imageViews[i].setImageResource(R.drawable.ic_launcher); +// imageViews[i].setOnClickListener(this);//点击导航点,即可跳转 +// imageViews[i].setTag(i);//重复利用实例化的对象 // } -// intent.setPackage(szToPackage); -// context.sendBroadcast(intent); -// -// LogUtils.d(TAG, String.format("SOS Send To WinBoll. (szToPackage : %s)", szToPackage)); -// //ToastUtils.show("SOS Send To WinBoll"); +// currentPoint = 0;//默认第一个坐标 +// imageViews[currentPoint].setImageResource(R.drawable.ic_launcher); // } + + //OnPageChangeListener接口要实现的三个方法 + /* onPageScrollStateChanged(int state) + 此方法是在状态改变的时候调用,其中state这个参数有三种状态: + SCROLL_STATE_DRAGGING(1)表示用户手指“按在屏幕上并且开始拖动”的状态 + (手指按下但是还没有拖动的时候还不是这个状态,只有按下并且手指开始拖动后log才打出。) + SCROLL_STATE_IDLE(0)滑动动画做完的状态。 + SCROLL_STATE_SETTLING(2)在“手指离开屏幕”的状态。*/ + @Override + public void onPageScrollStateChanged(int state) { + + } + /* onPageScrolled(int position, float positionOffset, int positionOffsetPixels) + 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为: + + position :当前页面,即你点击滑动的页面(从A滑B,则是A页面的position。 + positionOffset:当前页面偏移的百分比 + positionOffsetPixels:当前页面偏移的像素位置*/ + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + /* onPageSelected(int position) + 此方法是页面滑动完后得到调用,position是你当前选中的页面的Position(位置编号) + (从A滑动到B,就是B的position)*/ + public void onPageSelected(int position) { + +// ImageView preView = imageViews[currentPoint]; +// preView.setImageResource(R.drawable.ic_launcher); +// ImageView currView = imageViews[position]; +// currView.setImageResource(R.drawable.ic_launcher); +// currentPoint = position; + } + + //小圆点点击事件 + @Override + public void onClick(View v) { + // TODO Auto-generated method stub + //通过getTag(),可以判断是哪个控件 +// int i = (Integer) v.getTag(); +// viewPager.setCurrentItem(i);//直接跳转到某一个页面的情况 + } @Override protected void onPostCreate(Bundle savedInstanceState) { diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/adapters/ImagePagerAdapter.java b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/ImagePagerAdapter.java new file mode 100644 index 0000000..974c4ce --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/ImagePagerAdapter.java @@ -0,0 +1,14 @@ +package cc.winboll.studio.contacts.adapters; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 14:20:38 + * @Describe ImagePagerAdapter + */ +public class ImagePagerAdapter { + + public static final String TAG = "ImagePagerAdapter"; + + + +} \ No newline at end of file diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter.java b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter.java new file mode 100644 index 0000000..3212231 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter.java @@ -0,0 +1,42 @@ +package cc.winboll.studio.contacts.adapters; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 13:33:04 + * @Describe MyPagerAdapter + */ +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import cc.winboll.studio.contacts.fragments.CallFragment; +import cc.winboll.studio.contacts.fragments.ContactsFragment; +import cc.winboll.studio.contacts.fragments.LogFragment; + +public class MyPagerAdapter extends FragmentPagerAdapter { + public static final String TAG = "MyPagerAdapter"; + + private static final int PAGE_COUNT = 3; + + public MyPagerAdapter(@NonNull FragmentManager fm) { + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + } + + @NonNull + @Override + public Fragment getItem(int position) { + if(position == 1) { + return ContactsFragment.newInstance(position); + } else if(position == 2) { + return LogFragment.newInstance(position); + } else { + return CallFragment.newInstance(position); + } + } + + @Override + public int getCount() { + return PAGE_COUNT; + } +} + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallFragment.java new file mode 100644 index 0000000..6acb172 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/CallFragment.java @@ -0,0 +1,51 @@ +package cc.winboll.studio.contacts.fragments; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 12:57:00 + * @Describe 拨号 + */ +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.libappbase.LogView; +import androidx.annotation.Nullable; +import androidx.annotation.NonNull; +import android.widget.TextView; + +public class CallFragment extends Fragment { + + public static final String TAG = "CallFragment"; + + private static final String ARG_PAGE = "ARG_PAGE"; + private int mPage; + + public static CallFragment newInstance(int page) { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, page); + CallFragment fragment = new CallFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments()!= null) { + mPage = getArguments().getInt(ARG_PAGE); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_call, container, false); + TextView textView = view.findViewById(R.id.page_text); + textView.setText("这是第 " + mPage + " 页"); + return view; + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java new file mode 100644 index 0000000..2f7dad6 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java @@ -0,0 +1,50 @@ +package cc.winboll.studio.contacts.fragments; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 12:57:50 + * @Describe 联系人 + */ +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.contacts.R; + +public class ContactsFragment extends Fragment { + + public static final String TAG = "ContactsFragment"; + + private static final String ARG_PAGE = "ARG_PAGE"; + private int mPage; + + public static ContactsFragment newInstance(int page) { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, page); + ContactsFragment fragment = new ContactsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments()!= null) { + mPage = getArguments().getInt(ARG_PAGE); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_contacts, container, false); + TextView textView = view.findViewById(R.id.page_text); + textView.setText("这是第 " + mPage + " 页"); + return view; + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java new file mode 100644 index 0000000..e2df22a --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/LogFragment.java @@ -0,0 +1,50 @@ +package cc.winboll.studio.contacts.fragments; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 12:58:15 + * @Describe 应用日志 + */ +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.libappbase.LogView; + +public class LogFragment extends Fragment { + + public static final String TAG = "LogFragment"; + + private static final String ARG_PAGE = "ARG_PAGE"; + private int mPage; + + public static LogFragment newInstance(int page) { + Bundle args = new Bundle(); + args.putInt(ARG_PAGE, page); + LogFragment fragment = new LogFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mPage = getArguments().getInt(ARG_PAGE); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_log, container, false); + LogView logView = view.findViewById(R.id.logview); + logView.start(); + return view; + } +} diff --git a/contacts/src/main/res/layout/activity_main.xml b/contacts/src/main/res/layout/activity_main.xml index 78d3baa..5376c86 100644 --- a/contacts/src/main/res/layout/activity_main.xml +++ b/contacts/src/main/res/layout/activity_main.xml @@ -2,6 +2,7 @@ @@ -11,34 +12,16 @@ android:layout_height="wrap_content" android:id="@+id/activitymainToolbar1"/> - + android:id="@+id/activitymainViewPager1"/> - - - - - - - - - + diff --git a/contacts/src/main/res/layout/fragment_call.xml b/contacts/src/main/res/layout/fragment_call.xml new file mode 100644 index 0000000..1b8673c --- /dev/null +++ b/contacts/src/main/res/layout/fragment_call.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/contacts/src/main/res/layout/fragment_contacts.xml b/contacts/src/main/res/layout/fragment_contacts.xml new file mode 100644 index 0000000..aeec420 --- /dev/null +++ b/contacts/src/main/res/layout/fragment_contacts.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/contacts/src/main/res/layout/fragment_log.xml b/contacts/src/main/res/layout/fragment_log.xml new file mode 100644 index 0000000..7636182 --- /dev/null +++ b/contacts/src/main/res/layout/fragment_log.xml @@ -0,0 +1,12 @@ + + + + diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index d1c9e68..e0bef68 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 20 03:27:00 GMT 2025 +#Thu Feb 20 06:57:14 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=91 +buildCount=98 baseBetaVersion=1.0.1 From 64a97122947d2aede8dabb9a2405886f26f53b2a Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Thu, 20 Feb 2025 17:29:33 +0800 Subject: [PATCH 06/38] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=B5=E8=AF=9D?= =?UTF-8?q?=E6=8B=A8=E6=89=93=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contacts/build.properties | 4 +- contacts/src/main/AndroidManifest.xml | 2 + .../winboll/studio/contacts/MainActivity.java | 22 ++-- .../contacts/activities/CallActivity.java | 118 ++++++++++++++++++ .../src/main/res/layout/activity_call.xml | 28 +++++ contacts/src/main/res/menu/toolbar_main.xml | 4 + winboll-shared/build.properties | 4 +- 7 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 contacts/src/main/java/cc/winboll/studio/contacts/activities/CallActivity.java create mode 100644 contacts/src/main/res/layout/activity_call.xml diff --git a/contacts/build.properties b/contacts/build.properties index e0bef68..50bc646 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 20 06:57:14 GMT 2025 +#Thu Feb 20 09:27:14 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=98 +buildCount=99 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 4ab1fb6..fbba644 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -91,6 +91,8 @@ + + \ No newline at end of file diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 02a7adb..5ccbc69 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -1,7 +1,5 @@ package cc.winboll.studio.contacts; - - import android.content.Intent; import android.os.Bundle; import android.view.Menu; @@ -26,6 +24,7 @@ import java.util.ArrayList; import android.view.LayoutInflater; import android.widget.LinearLayout; import java.util.List; +import cc.winboll.studio.contacts.activities.CallActivity; final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener { @@ -80,7 +79,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // 以下正常创建主窗口 super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - + // 初始化工具栏 mToolbar = findViewById(R.id.activitymainToolbar1); setSupportActionBar(mToolbar); @@ -94,7 +93,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct initView();//调用初始化视图方法 //initPoint();//调用初始化导航原点的方法 viewPager.addOnPageChangeListener(this);//滑动事件 - + ViewPager viewPager = findViewById(R.id.activitymainViewPager1); MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(pagerAdapter); @@ -118,7 +117,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // } // }); } - + //初始化view,即显示的图片 void initView() { @@ -131,7 +130,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct //linearLayout = findViewById(R.id.activitymainLinearLayout1); //initPoint();//初始化页面下方的点 viewPager.setOnPageChangeListener(this); - + } //初始化所要显示的布局 @@ -147,7 +146,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct views.add(view2); views.add(view3); } - + // void initPoint() { // imageViews = new ImageView[5];//实例化5个图片 // for (int i = 0; i < linearLayout.getChildCount(); i++) { @@ -159,7 +158,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // currentPoint = 0;//默认第一个坐标 // imageViews[currentPoint].setImageResource(R.drawable.ic_launcher); // } - + //OnPageChangeListener接口要实现的三个方法 /* onPageScrollStateChanged(int state) 此方法是在状态改变的时候调用,其中state这个参数有三种状态: @@ -308,8 +307,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct @Override public boolean onOptionsItemSelected(MenuItem item) { -// if (item.getItemId() == R.id.item_unittest) { -// WinBollActivityManager.getInstance(this).startWinBollActivity(this, UnitTestActivity.class); + if (item.getItemId() == R.id.item_call) { + Intent intent = new Intent(this, CallActivity.class); + startActivity(intent); + //WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class); + } // } else // if (item.getItemId() == R.id.item_exit) { // exit(); diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/activities/CallActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/activities/CallActivity.java new file mode 100644 index 0000000..e8f8e3e --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/activities/CallActivity.java @@ -0,0 +1,118 @@ +package cc.winboll.studio.contacts.activities; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/20 17:15:46 + * @Describe 拨号窗口 + */ +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import cc.winboll.studio.contacts.MainActivity; +import cc.winboll.studio.contacts.R; + +public class CallActivity extends AppCompatActivity { + public static final String TAG = "CallActivity"; + + private static final int REQUEST_CALL_PHONE = 1; + private EditText phoneNumberEditText; + private TextView callStatusTextView; + private TelephonyManager telephonyManager; + private MyPhoneStateListener phoneStateListener; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //setContentView(R.layout.activity_main); + setContentView(R.layout.activity_call); + + phoneNumberEditText = findViewById(R.id.phone_number); + Button dialButton = findViewById(R.id.dial_button); + callStatusTextView = findViewById(R.id.call_status); + + dialButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String phoneNumber = phoneNumberEditText.getText().toString().trim(); + if (!phoneNumber.isEmpty()) { + if (ContextCompat.checkSelfPermission(CallActivity.this, Manifest.permission.CALL_PHONE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(CallActivity.this, + new String[]{Manifest.permission.CALL_PHONE}, + REQUEST_CALL_PHONE); + } else { + dialPhoneNumber(phoneNumber); + } + } else { + Toast.makeText(CallActivity.this, "请输入电话号码", Toast.LENGTH_SHORT).show(); + } + } + }); + + // 初始化TelephonyManager和PhoneStateListener + telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); + phoneStateListener = new MyPhoneStateListener(); + telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_CALL_PHONE) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + String phoneNumber = phoneNumberEditText.getText().toString().trim(); + dialPhoneNumber(phoneNumber); + } else { + Toast.makeText(this, "未授予拨打电话权限", Toast.LENGTH_SHORT).show(); + } + } + } + + private void dialPhoneNumber(String phoneNumber) { + Intent intent = new Intent(Intent.ACTION_CALL); + intent.setData(android.net.Uri.parse("tel:" + phoneNumber)); + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { + return; + } + startActivity(intent); + } + + private class MyPhoneStateListener extends PhoneStateListener { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + switch (state) { + case TelephonyManager.CALL_STATE_IDLE: + callStatusTextView.setText("电话已挂断"); + break; + case TelephonyManager.CALL_STATE_OFFHOOK: + callStatusTextView.setText("正在通话中"); + break; + case TelephonyManager.CALL_STATE_RINGING: + callStatusTextView.setText("来电: " + incomingNumber); + break; + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + // 取消监听 + if (telephonyManager != null) { + telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); + } + } +} + diff --git a/contacts/src/main/res/layout/activity_call.xml b/contacts/src/main/res/layout/activity_call.xml new file mode 100644 index 0000000..460b416 --- /dev/null +++ b/contacts/src/main/res/layout/activity_call.xml @@ -0,0 +1,28 @@ + + + + + +