├── app
├── .gitignore
├── autodingding.jks
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-xxhdpi
│ │ │ ├── bg_2.jpg
│ │ │ ├── bg_3.jpg
│ │ │ ├── ding.png
│ │ │ ├── logo.jpg
│ │ │ ├── about.png
│ │ │ ├── clock.png
│ │ │ ├── delete.png
│ │ │ ├── empty.png
│ │ │ ├── output.png
│ │ │ ├── right.png
│ │ │ ├── shaizi.png
│ │ │ ├── day_blue.png
│ │ │ ├── day_gray.png
│ │ │ ├── history.png
│ │ │ ├── settings.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── logo_round.png
│ │ │ ├── update_code.png
│ │ │ ├── settings_blue.png
│ │ │ ├── settings_gray.png
│ │ │ └── ic_launcher_round.png
│ │ ├── raw
│ │ │ └── tip
│ │ ├── drawable
│ │ │ ├── bg_textview.xml
│ │ │ ├── bg_textview_error.xml
│ │ │ ├── select_switch_circle.xml
│ │ │ ├── bottom_text_color.xml
│ │ │ ├── list_divider.xml
│ │ │ ├── select_switch_background.xml
│ │ │ ├── swich_background_on.xml
│ │ │ ├── popup_list_divider.xml
│ │ │ ├── switch_circle_off.xml
│ │ │ ├── swich_background_off.xml
│ │ │ ├── svg_back.xml
│ │ │ ├── switch_circle_on.xml
│ │ │ ├── ic_stop.xml
│ │ │ └── ic_launcher_background.xml
│ │ ├── anim
│ │ │ ├── popup_hide.xml
│ │ │ └── popup_show.xml
│ │ ├── layout
│ │ │ ├── easy_popup.xml
│ │ │ ├── item_tab.xml
│ │ │ ├── item_easy_popup.xml
│ │ │ ├── include_title.xml
│ │ │ ├── item_list.xml
│ │ │ ├── fragment_remote_sign.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_history.xml
│ │ │ ├── fragment_push.xml
│ │ │ ├── permission_fragment.xml
│ │ │ ├── fragment_mail_conf.xml
│ │ │ └── fragment_day.xml
│ │ ├── menu
│ │ │ └── bottom_nav_menu.xml
│ │ ├── xml-v24
│ │ │ └── gesture_accessibility_config.xml
│ │ ├── xml
│ │ │ └── base_accessibility_config.xml
│ │ └── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── java
│ │ ├── com
│ │ │ └── pengxh
│ │ │ │ └── autodingding
│ │ │ │ ├── ApiException.kt
│ │ │ │ ├── bean
│ │ │ │ ├── PushChannel.kt
│ │ │ │ ├── ThirdPartyConf.kt
│ │ │ │ ├── Workday.kt
│ │ │ │ ├── PushOption.kt
│ │ │ │ ├── PushResp.kt
│ │ │ │ ├── WorkdayResp.kt
│ │ │ │ ├── PushAudience.kt
│ │ │ │ ├── PushNotification.kt
│ │ │ │ ├── Version.kt
│ │ │ │ ├── AndroidNotif.kt
│ │ │ │ ├── BodyMsg.kt
│ │ │ │ ├── PushMessage.kt
│ │ │ │ ├── MailInfo.kt
│ │ │ │ └── HistoryRecordBean.java
│ │ │ │ ├── service
│ │ │ │ ├── PushService.kt
│ │ │ │ ├── GestureService.kt
│ │ │ │ ├── BaseAccessibilityService.kt
│ │ │ │ └── NotificationMonitorService.kt
│ │ │ │ ├── base
│ │ │ │ ├── ApiResponse.kt
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ └── BaseVmFragment.kt
│ │ │ │ ├── actions
│ │ │ │ ├── Action.kt
│ │ │ │ ├── SwipeUnlockAction.kt
│ │ │ │ └── DingSignAction.kt
│ │ │ │ ├── net
│ │ │ │ ├── api
│ │ │ │ │ ├── UpdateApi.kt
│ │ │ │ │ ├── PushApi.kt
│ │ │ │ │ └── WorkDayApi.kt
│ │ │ │ ├── AuthInterceptor.kt
│ │ │ │ └── RetrofitManager.kt
│ │ │ │ ├── ui
│ │ │ │ ├── fragment
│ │ │ │ │ ├── PermissionVM.kt
│ │ │ │ │ ├── RemoteSignFragment.kt
│ │ │ │ │ ├── MailConfVM.kt
│ │ │ │ │ ├── PushVM.kt
│ │ │ │ │ ├── PermissionFragment.kt
│ │ │ │ │ ├── MailConfFragment.kt
│ │ │ │ │ └── PushFragment.kt
│ │ │ │ └── WelcomeActivity.kt
│ │ │ │ ├── utils
│ │ │ │ ├── EmailAuthenticator.kt
│ │ │ │ ├── Param.java
│ │ │ │ ├── Constant.java
│ │ │ │ ├── KtUtils.kt
│ │ │ │ ├── TimeOrDateUtil.kt
│ │ │ │ ├── AccessibilityUtil.kt
│ │ │ │ ├── StatusBarColorUtil.java
│ │ │ │ ├── ViewExt.kt
│ │ │ │ ├── RomUtils.kt
│ │ │ │ ├── SendMailUtil.kt
│ │ │ │ ├── ParamUtil.kt
│ │ │ │ ├── MailSender.kt
│ │ │ │ └── ExcelUtils.kt
│ │ │ │ ├── adapter
│ │ │ │ ├── FragAdapter.kt
│ │ │ │ └── HistoryRecordAdapter.kt
│ │ │ │ ├── BatteryLevelReceiver.kt
│ │ │ │ ├── greendao
│ │ │ │ ├── DaoSession.java
│ │ │ │ ├── DaoMaster.java
│ │ │ │ └── HistoryRecordBeanDao.java
│ │ │ │ ├── widgets
│ │ │ │ ├── EasyPopupWindow.kt
│ │ │ │ └── PopupAdapter.java
│ │ │ │ ├── BaseApplication.kt
│ │ │ │ ├── AndroidxBaseFragment.java
│ │ │ │ └── AndroidxBaseActivity.java
│ │ └── xcom
│ │ │ └── warof
│ │ │ └── chosen
│ │ │ └── greendao
│ │ │ ├── DaoSession.java
│ │ │ ├── DaoMaster.java
│ │ │ └── HistoryRecordBeanDao.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── img.png
├── sxwdsoft.jks
├── demoImage
├── 0.jpg
├── 1.jpg
├── 2.jpg
├── 3.jpg
├── 4.jpg
├── 5.jpg
├── 6.png
└── 7.jpg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── encodings.xml
├── compiler.xml
├── kotlinc.xml
├── migrations.xml
├── deploymentTargetSelector.xml
├── jarRepositories.xml
├── codeStyles
│ └── Project.xml
└── misc.xml
├── settings.gradle
├── gradle.properties
├── README.md
├── .gitignore
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/img.png
--------------------------------------------------------------------------------
/sxwdsoft.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/sxwdsoft.jks
--------------------------------------------------------------------------------
/demoImage/0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/0.jpg
--------------------------------------------------------------------------------
/demoImage/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/1.jpg
--------------------------------------------------------------------------------
/demoImage/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/2.jpg
--------------------------------------------------------------------------------
/demoImage/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/3.jpg
--------------------------------------------------------------------------------
/demoImage/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/4.jpg
--------------------------------------------------------------------------------
/demoImage/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/5.jpg
--------------------------------------------------------------------------------
/demoImage/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/6.png
--------------------------------------------------------------------------------
/demoImage/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/demoImage/7.jpg
--------------------------------------------------------------------------------
/app/autodingding.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/autodingding.jks
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/bg_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/bg_2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/bg_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/bg_3.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/ding.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/logo.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/about.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/clock.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/delete.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/empty.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/output.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/right.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/shaizi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/shaizi.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/day_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/day_blue.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/day_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/day_gray.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/history.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/history.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/settings.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/update_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/update_code.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/settings_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/settings_blue.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/settings_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/settings_gray.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/littleclaw/AutoDing/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ApiException.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding
2 |
3 | class ApiException(val errorMessage: String, val errorCode: Int) :
4 | Throwable()
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushChannel.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushChannel {
4 | var distribution_customize = "secondary_push"
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/ThirdPartyConf.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class ThirdPartyConf {
4 | var huawei: PushChannel = PushChannel()
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/Workday.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | data class Workday(val type:Int, val name: String, val date:String, val rest: Int)
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushOption.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushOption {
4 | var third_party_channel:ThirdPartyConf? = ThirdPartyConf()
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushResp.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushResp {
4 | var errorCode = 0
5 | var messageCn:String? = null
6 |
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/WorkdayResp.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class WorkdayResp{
4 | val code :Int = 0
5 | var workday: Workday? = null
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushAudience.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushAudience {
4 | var registration_id: MutableList = mutableListOf()
5 | }
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/service/PushService.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.service
2 |
3 | import cn.jpush.android.service.JCommonService
4 |
5 | class PushService : JCommonService()
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushNotification.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushNotification {
4 | var alert:String?= null
5 | var android:AndroidNotif? = null
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/Version.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | data class Version(val apkUrl:String, val versionCode: Int, val versionName: String, val description: String, val apkSize: String)
--------------------------------------------------------------------------------
/app/src/main/res/raw/tip:
--------------------------------------------------------------------------------
1 | 妈我建议你可以考虑这几个方向。
2 | 1、见下国强小姑,和国强小姑商量一下你怎么和院长发个短信打个电话之类的方法跟进一下事情进展,
3 | 让院长能给到我爸明确的彩礼数字和给的时间的答复。
4 | 2、见下小辰她妈妈,和她妈妈一起吐槽一下爸这边态度问题,舒缓一下两家紧张的关系,再私下在领证前给到她妈妈3万,请她临场只问我爸要5万8,
5 | 我爸要是高兴了可能还是会坚持按院长说的给足8万8的话引玲姨自然会把你多给的3万再私下退回给你
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_textview.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_textview_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/base/ApiResponse.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.base
2 |
3 | data class ApiResponse(var errorCode: Int, var errorMsg: String, var data: T) {
4 | fun isSucces(): Boolean {
5 | return errorCode == 0
6 | }
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_hide.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/AndroidNotif.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class AndroidNotif {
4 | var title:String? = null
5 | var category:String? = "CATEGORY_REMINDER"
6 | var priority:Int = 1
7 | val display_foreground:String = "1"
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_switch_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 27 09:13:07 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/BodyMsg.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | import org.json.JSONObject
4 |
5 | class BodyMsg {
6 | var msg_content:String = ""
7 | var title = "cmd"
8 | var content_type:String? = null
9 | var extras:JSONObject? = null
10 | }
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/actions/Action.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.actions
2 |
3 | import android.app.Activity
4 |
5 |
6 | abstract class Action {
7 | abstract val name: String
8 | abstract suspend fun run(act: Activity)
9 |
10 | override fun toString() = name
11 |
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/PushMessage.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | class PushMessage {
4 | var platform = "android"
5 | var audience: PushAudience? = null
6 | var notification: PushNotification? = null
7 | var message: BodyMsg? = null
8 | var options: PushOption? = null
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bottom_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/list_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_switch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/swich_background_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/net/api/UpdateApi.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.net.api
2 |
3 | import com.pengxh.autodingding.base.ApiResponse
4 | import com.pengxh.autodingding.bean.Version
5 | import retrofit2.http.GET
6 |
7 | interface UpdateApi {
8 | @GET("api/version.json")
9 | suspend fun getVersion(): ApiResponse
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/PermissionVM.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import androidx.databinding.ObservableBoolean
4 | import com.pengxh.autodingding.base.BaseViewModel
5 |
6 | class PermissionVM : BaseViewModel() {
7 | val accessibilityEnable = ObservableBoolean()
8 | val bgStartEnable = ObservableBoolean()
9 |
10 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/popup_list_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/net/api/PushApi.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.net.api
2 |
3 | import com.pengxh.autodingding.bean.PushMessage
4 | import com.pengxh.autodingding.bean.PushResp
5 | import retrofit2.http.Body
6 | import retrofit2.http.POST
7 |
8 | interface PushApi {
9 | @POST("v3/push")
10 | suspend fun pushMsg(@Body pushMessage: PushMessage): PushResp
11 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/switch_circle_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/swich_background_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/svg_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/switch_circle_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/EmailAuthenticator.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import javax.mail.Authenticator
4 | import javax.mail.PasswordAuthentication
5 |
6 | class EmailAuthenticator(private val userName: String, private val password: String) :
7 | Authenticator() {
8 | override fun getPasswordAuthentication(): PasswordAuthentication {
9 | return PasswordAuthentication(userName, password)
10 | }
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/Param.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * des 参数解析注解
10 | */
11 | @Target(ElementType.FIELD)
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface Param {
14 | String value() default "";
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/net/api/WorkDayApi.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.net.api
2 |
3 | import com.pengxh.autodingding.bean.WorkdayResp
4 | import retrofit2.http.GET
5 | import retrofit2.http.Headers
6 |
7 | interface WorkDayApi {
8 | @Headers("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36")
9 | @GET("/api/holiday/workday/next/")
10 | suspend fun getNextWorkday(): WorkdayResp
11 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_show.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
3 | repositories {
4 | google()
5 | mavenCentral()
6 | maven { url 'https://jitpack.io' }
7 | maven { url "https://maven.aliyun.com/repository/public" }
8 | maven { url 'https://maven.aliyun.com/repository/google' }
9 | maven { url 'https://developer.huawei.com/repo/'
10 | allowInsecureProtocol = true}
11 | }
12 | }
13 | include ':app'
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/adapter/FragAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.adapter
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentActivity
5 | import androidx.viewpager2.adapter.FragmentStateAdapter
6 |
7 | class FragAdapter(fragmentActivity: FragmentActivity,
8 | private val pageList:List) : FragmentStateAdapter(fragmentActivity) {
9 | override fun getItemCount(): Int {
10 | return pageList.size
11 | }
12 |
13 | override fun createFragment(position: Int): Fragment = pageList[position]
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/RemoteSignFragment.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import com.pengxh.autodingding.AndroidxBaseFragment
4 | import com.pengxh.autodingding.databinding.FragmentRemoteSignBinding
5 |
6 | class RemoteSignFragment: AndroidxBaseFragment() {
7 | override fun setupTopBarLayout() {
8 |
9 | }
10 |
11 | override fun initData() {
12 | // check if is master or slave first, then lis
13 | }
14 |
15 | override fun initEvent() {
16 | TODO("Not yet implemented")
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/easy_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml-v24/gesture_accessibility_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/service/GestureService.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.service
2 |
3 | import android.accessibilityservice.AccessibilityService
4 | import android.view.accessibility.AccessibilityEvent
5 | import cn.vove7.andro_accessibility_api.AccessibilityApi
6 |
7 | class GestureService: AccessibilityService() {
8 |
9 | override fun onCreate() {
10 | super.onCreate()
11 | //must call
12 | AccessibilityApi.gestureService = this
13 | }
14 | override fun onDestroy() {
15 | super.onDestroy()
16 | //must call
17 | AccessibilityApi.gestureService = null
18 | }
19 |
20 | override fun onAccessibilityEvent(event: AccessibilityEvent?) {
21 | }
22 |
23 | override fun onInterrupt() {
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/Constant.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils;
2 |
3 | import android.Manifest;
4 |
5 | import com.pengxh.autodingding.R;
6 |
7 |
8 | public class Constant {
9 | public static final int PERMISSIONS_CODE = 999;
10 | public static final String[] USER_PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
11 | Manifest.permission.READ_EXTERNAL_STORAGE};
12 |
13 | //钉钉包名:com.alibaba.android.rimet
14 | //打卡页面类名:com.alibaba.lightapp.runtime.activity.CommonWebViewActivity
15 | public static final String DINGDING = "com.alibaba.android.rimet";
16 |
17 | public static final int[] images = {R.mipmap.delete, R.mipmap.output};
18 |
19 | public static final long ONE_WEEK = 5 * 24 * 60 * 60 * 1000L;
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/base_accessibility_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/MailConfVM.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 |
4 | import com.pengxh.autodingding.base.BaseViewModel
5 | import com.pengxh.autodingding.utils.MailSender
6 | import com.pengxh.autodingding.utils.SendMailUtil
7 | import kotlinx.coroutines.Dispatchers
8 | import kotlinx.coroutines.withContext
9 |
10 | class MailConfVM : BaseViewModel() {
11 |
12 | fun sendMail(fromEmail: String, fromAuth: String, toEmail: String) = launch {
13 | withContext(Dispatchers.IO) {
14 | MailSender().sendTextMail(
15 | SendMailUtil.createMail(
16 | toEmail,
17 | "测试邮件",
18 | fromEmail,
19 | fromAuth
20 | )
21 | )
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #FFFFFF
7 | #CCCCCC
8 | #0D0D0D
9 | #171717
10 | #333333
11 | #313131
12 | #0094FF
13 | #4DDC64
14 | #0094FF
15 | #ffa500
16 | #00ffff
17 | #32cd32
18 |
19 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_easy_popup.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/service/BaseAccessibilityService.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.service
2 |
3 | import android.util.Log
4 | import cn.vove7.andro_accessibility_api.AccessibilityApi
5 | import cn.vove7.auto.core.AppScope
6 |
7 | class BaseAccessibilityService: AccessibilityApi() {
8 |
9 | override val enableListenPageUpdate: Boolean
10 | get() = true
11 | companion object {
12 | private const val TAG = "BaseAccessibilityService"
13 | }
14 |
15 | override fun onCreate() {
16 | //must set
17 | baseService = this
18 | super.onCreate()
19 | }
20 |
21 | override fun onDestroy() {
22 | //must set
23 | baseService = null
24 | super.onDestroy()
25 | }
26 |
27 | //页面更新回调
28 | override fun onPageUpdate(currentScope: AppScope) {
29 | Log.d(TAG, "onPageUpdate: $currentScope")
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
22 |
23 |
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.useAndroidX=true
10 | # Automatically convert third-party libraries to use AndroidX
11 | android.enableJetifier=true
12 | # Kotlin code style for this project: "official" or "obsolete":
13 | kotlin.code.style=official
14 | org.gradle.jvmargs=-Xmx1536m
15 | android.injected.testOnly=false
16 | android.nonTransitiveRClass=false
17 | android.nonFinalResIds=false
18 | # When configured, Gradle will run in incubating parallel mode.
19 | # This option should only be used with decoupled projects. More details, visit
20 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
21 | # org.gradle.parallel=true
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 上班帮手
3 |
4 | Tips:此版本是测试版本,可能会有些问题我自测试没有发现的,有问题请发邮件给lttclaw@qq.com。建议用一台闲置的手机
5 | 放在公司来打卡,另一台手机来推送打卡指令。基本用法只需要一台闲置手机,定好时间后会自动打开钉钉,完成极速打卡;进阶用法
6 | 需要一台打卡手机,一台自用手机,把打卡手机的注册ID复制到推送界面推送打卡指令可以远程打开钉钉,完成极速打卡。设置须知:\n
7 | 1、请先确认好通知栏监听已开启,如不开启将无法监听打卡成功的通知。\n
8 | 2、调起钉钉实现自动打卡,需要把打卡手机锁屏密码之类的取消掉\n
9 | 3、部分手机需要授权允许后台打开窗口\n
10 | 3、先在设置里面测试下能否正常打开钉钉,第一次有些手机会让授权\n
11 | 4、将钉钉软件上下班都设置为“极速打卡”。\n
12 | 5、设置好自己的收信邮箱,跳转到“钉钉”打卡成功后会发送一封打卡成功的邮件到你自己设置好的邮箱。\n
13 |
14 |
15 | 空白页
16 |
17 | 请注意,如果您使用应用内自带的发件邮箱配置,即开发者本人的个人qq邮箱来发送打卡通知,您的这些邮件都会被本人在qq邮箱的
18 | 发件箱中看到,而且如果使用我的邮箱发件人数太多,我会考虑更换邮箱授权码,界时用此授权码的发邮件功能将无法正常工作。
19 | 因此,为了您的隐私考虑,请您最好去自己的qq邮箱设置里打开smtp服务获取自己的邮箱授权码在此配置
20 |
21 | 远程启钉基础辅助服务
22 | 远程启钉手势服务
23 | 前台服务
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/actions/SwipeUnlockAction.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.actions
2 |
3 | import android.app.Activity
4 | import cn.vove7.auto.core.api.swipe
5 | import kotlinx.coroutines.delay
6 |
7 | class SwipeUnlockAction(val orientation: ORIENTATION=ORIENTATION.VERTICAL): Action() {
8 | enum class ORIENTATION{
9 | HORIZONTAL,VERTICAL,CUSTOM
10 | }
11 | constructor(startX:Int, startY:Int, endX:Int, endY:Int) : this(ORIENTATION.CUSTOM) {
12 | this.startX = startX
13 | this.startY = startY
14 | this.endX = endX
15 | this.endY = endY
16 | }
17 | var startX= 0
18 | var startY = 0
19 | var endX = 0
20 | var endY = 0
21 | override val name: String
22 | get() = "解锁"
23 |
24 | override suspend fun run(act: Activity) {
25 | delay(1000)
26 | //从下往上的滑动
27 | when (orientation) {
28 | ORIENTATION.VERTICAL -> swipe(500, 1200, 500, 400, 800)
29 | ORIENTATION.HORIZONTAL -> swipe(100, 900, 600, 900, 800)
30 | else -> swipe(startX, startY, endX, endY, 800)
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/net/AuthInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.net
2 |
3 | import com.blankj.utilcode.util.EncodeUtils
4 | import com.blankj.utilcode.util.LogUtils
5 | import okhttp3.Interceptor
6 | import okhttp3.Response
7 | import java.io.IOException
8 |
9 | object AuthInterceptor : Interceptor {
10 | private const val appKey = "f01b8a02b66ea2d632e52e2e"
11 | private const val masterSecret = "5e9ebea1163a6f3e2197f35d"
12 | private const val authString = "$appKey:$masterSecret"
13 |
14 | private var token = "Basic ${EncodeUtils.base64Encode2String(authString.toByteArray())}"
15 | set(value) {
16 | field = value
17 | }
18 |
19 | override fun intercept(chain: Interceptor.Chain): Response {
20 | val origin = chain.request()
21 | val builder = origin.newBuilder().addHeader("Authorization", token)
22 | val response : Response
23 | try {
24 | response = chain.proceed(builder.build())
25 |
26 | }catch (e:Exception){
27 | e.printStackTrace()
28 | throw IOException(e)
29 | }
30 | return response
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/KtUtils.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import android.widget.Toast
6 | import com.pengxh.autodingding.BaseApplication
7 | import kotlinx.coroutines.*
8 | import kotlin.coroutines.CoroutineContext
9 | import kotlin.coroutines.EmptyCoroutineContext
10 |
11 |
12 |
13 | @DelicateCoroutinesApi
14 | fun launchWithExpHandler(
15 | context: CoroutineContext = EmptyCoroutineContext,
16 | start: CoroutineStart = CoroutineStart.DEFAULT,
17 | block: suspend CoroutineScope.() -> Unit
18 | ) = GlobalScope.launch(context + ExceptionHandler, start, block)
19 |
20 |
21 | val ExceptionHandler by lazy {
22 | CoroutineExceptionHandler { _, throwable ->
23 | toast(throwable.message ?: "$throwable")
24 | throwable.printStackTrace()
25 | }
26 | }
27 |
28 | val mainHandler by lazy {
29 | Handler(Looper.getMainLooper())
30 | }
31 |
32 | fun runOnUi(block: () -> Unit) {
33 | if (Looper.getMainLooper() == Looper.myLooper()) {
34 | block()
35 | } else {
36 | mainHandler.post(block)
37 | }
38 | }
39 |
40 |
41 | fun toast(m: String) =
42 | runOnUi {
43 | Toast.makeText(BaseApplication.application, m, Toast.LENGTH_SHORT).show()
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/MailInfo.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean
2 |
3 | import java.io.File
4 | import java.util.Properties
5 |
6 | /**
7 | * @author: lttclaw
8 | * @email: lttclaw@qq.com
9 | * @description: 邮件相关
10 | * @date: 2020/1/16 15:40
11 | */
12 | class MailInfo {
13 | // 发送邮件的服务器的IP和端口
14 | var mailServerHost: String? = null
15 | var mailServerPort: String? = null
16 |
17 | // 邮件发送者的地址
18 | var fromAddress: String? = null
19 |
20 | // 邮件接收者的地址
21 | var toAddress: String? = null
22 |
23 | // 登陆邮件发送服务器的用户名和密码
24 | var userName: String? = null
25 | var password: String? = null
26 |
27 | // 是否需要身份验证
28 | var isValidate = false
29 |
30 | // 邮件主题
31 | var subject: String? = null
32 |
33 | // 邮件的文本内容
34 | var content: String? = null
35 |
36 | // 邮件的附件
37 | var attachFile: File? = null
38 |
39 | // 邮件附件的文件名
40 | var attachFileName: String? = null
41 | val properties: Properties
42 | /**
43 | * 获得邮件会话属性
44 | */
45 | get() {
46 | val p = Properties()
47 | p["mail.smtp.host"] = mailServerHost
48 | p["mail.smtp.port"] = mailServerPort
49 | p["mail.smtp.ssl.enable"] = "true"
50 | p["mail.smtp.auth"] = "true"
51 | return p
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/BatteryLevelReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.BatteryManager
7 | import cn.jpush.android.api.JPushInterface
8 | import com.blankj.utilcode.util.ProcessUtils
9 | import com.blankj.utilcode.util.ScreenUtils
10 | import com.pengxh.autodingding.utils.SendMailUtil
11 | import com.pengxh.autodingding.utils.Utils
12 |
13 | class BatteryLevelReceiver : BroadcastReceiver() {
14 | override fun onReceive(context: Context, intent: Intent) {
15 | val action = intent.action
16 | if (Intent.ACTION_BATTERY_LOW == action){
17 | val emailAddress = Utils.readEmailAddress()
18 | val manager = context.getSystemService(AndroidxBaseActivity.BATTERY_SERVICE) as BatteryManager
19 | val curBatteryCurrent = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW)
20 | val curBattery = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)///当前电量百分比
21 | val regId = JPushInterface.getRegistrationID(context)
22 | val screenLock = ScreenUtils.isScreenLock()
23 | val message = "警告!低电量!注册ID: $regId 是否锁屏:$screenLock " +
24 | "当前电流:$curBatteryCurrent mA 当前电量百分比:$curBattery %"
25 | SendMailUtil.send(emailAddress, message)
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/TimeOrDateUtil.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import com.blankj.utilcode.util.ToastUtils
4 | import java.text.SimpleDateFormat
5 | import java.util.*
6 |
7 | object TimeOrDateUtil {
8 | private var dateFormat: SimpleDateFormat? = null
9 |
10 | /**
11 | * 时间戳转日期
12 | */
13 | fun rTimestampToDate(millSeconds: Long): String {
14 | dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
15 | return dateFormat!!.format(Date(millSeconds))
16 | }
17 |
18 | /**
19 | * 时间戳转时间
20 | */
21 | fun timestampToTime(millSeconds: Long): String {
22 | dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA)
23 | return dateFormat!!.format(Date(millSeconds))
24 | }
25 |
26 | /**
27 | * 时间戳转详细日期时间
28 | */
29 | fun timestampToDate(millSeconds: Long): String {
30 | dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
31 | return dateFormat!!.format(Date(millSeconds))
32 | }
33 |
34 | /**
35 | * 计算时间差
36 | *
37 | * @param fixedTime 结束时间
38 | */
39 | fun deltaTime(fixedTime: Long): Long {
40 | val currentTime = System.currentTimeMillis() / 1000
41 | if (fixedTime > currentTime) {
42 | return fixedTime - currentTime
43 | } else {
44 | ToastUtils.showLong("时间设置异常")
45 | }
46 | return 0L
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/bean/HistoryRecordBean.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.bean;
2 |
3 | import org.greenrobot.greendao.annotation.Entity;
4 | import org.greenrobot.greendao.annotation.Generated;
5 | import org.greenrobot.greendao.annotation.Id;
6 |
7 | @Entity
8 | public class HistoryRecordBean {
9 | @Id(autoincrement = true)
10 | private Long id;//主键ID
11 |
12 | private String uuid;
13 | private String date;
14 | private String message;
15 |
16 | @Generated(hash = 1681950394)
17 | public HistoryRecordBean(Long id, String uuid, String date, String message) {
18 | this.id = id;
19 | this.uuid = uuid;
20 | this.date = date;
21 | this.message = message;
22 | }
23 |
24 | @Generated(hash = 1791356846)
25 | public HistoryRecordBean() {
26 | }
27 |
28 | public Long getId() {
29 | return this.id;
30 | }
31 |
32 | public void setId(Long id) {
33 | this.id = id;
34 | }
35 |
36 | public String getUuid() {
37 | return this.uuid;
38 | }
39 |
40 | public void setUuid(String uuid) {
41 | this.uuid = uuid;
42 | }
43 |
44 | public String getDate() {
45 | return this.date;
46 | }
47 |
48 | public void setDate(String date) {
49 | this.date = date;
50 | }
51 |
52 | public String getMessage() {
53 | return this.message;
54 | }
55 |
56 | public void setMessage(String message) {
57 | this.message = message;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
27 |
28 |
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoDing
2 | + 目前release中的包名于24年圣诞节下午又又被加入黑名单了,为了不被再一次被加入黑名单,之后将不再提供APK包的更新,但我会详尽列出各位自行打包需要的步骤,请各位自行下载源码修改一个包名并做如下定制打包。
3 | 1. 起一个包名,结构类似com.furry.rimet这种,修改app级build.gradle中applicationId,daoPackage的前缀为自己的(查找替换即可)
4 | 2. 修改app/src/main/AndroidManifest.xml中包名,查找替换即可
5 | 3. 重新进行gradle sync,完成后执行Build————Rebuild Project
6 | 4. 然后去极光推送开发者后台建一个应用,用刚才自己重构的applicationId申请一个推送应用,把appKey,masterSecret保存
7 | 5. 在app级build.gradle配置中的manifestPlaceholders中的JPUSH_APPKEY值换成上一步的appKey
8 | 6. 在代码搜索类AuthInterceptor,替换里面的常量appKey和masterSecret
9 | 7. (可选)打包前也可修改app/src/main/res/values/strings.xml里面的app_name值,即应用名,防止应用名也被屏蔽
10 | 8. 重新打包,然后分别装在两个手机上,配置推送regID,测试是否可发送响应指令
11 | -------------
12 | 钉钉打卡,包括定时打卡和远程推送打卡,定时打卡功能是根据AutoDingDing项目修改而来,不是此项目重点,此项目主要功能在于实现远程
13 | 打开钉钉,从而完成极速打卡,其主要是用极光推送SDK实现网络指令下发。
14 | 建议用一台闲置的手机放在公司来打卡,另一台手机来推送打卡指令。
15 | 需要一台打卡手机,一台自用手机,都安装上此APP后,把打卡手机的注册ID复制到推送界面推送打卡指令可以远程打开钉钉,完成极速打卡。使用须知:
16 | 1. 请先确认好要打卡的手机通知栏监听已开启,如不开启将无法监听打卡成功的通知。
17 | 2. 要打卡的手机保持连网,wifi或者数据都可,否则怎么收网络指令啊。
18 | 3. 要打卡的手机最好保持打开界面放置灭屏,因为如果应用被切到后台,过上一晚不活跃有可能会被安卓系统杀掉从而不能接收打卡指令。
19 | 4. 调起钉钉实现自动打卡,需要把打卡手机锁屏密码之类的取消掉,屏幕不用常亮,但锁屏手势、指纹、密码这些验证不能有,否则在熄屏状态下应用接收到消息也无法唤醒屏幕。
20 | 5. 部分手机需要授权允许后台打开窗口,先在设置里面测试下能否正常打开钉钉,第一次有些手机会让授权。
21 | 6. 将钉钉软件上下班都设置为“极速打卡”。
22 | 7. 设置好自己的发信和收信邮箱,跳转到“钉钉”打卡成功后会发送一封打卡成功的邮件到你自己设置好的邮箱。
23 | 8. 不要忘了,此应用只能打开钉钉,如果你钉钉没登录、被其他设备踢下线、打开时机不在考勤时间区间里,极速打卡是不会生效的。
24 |
25 | + 请在邮件配置中尽量使用自己的qq邮箱,申请邮箱授权码的方法请上网查询,目前邮箱只支持qq邮箱,因为邮箱服务器和端口在代码里写死了,想用别的邮箱的可以找到这部分代码修改这部分设置
26 | -------------
27 | 可选建议
28 | 1. 在应用权限设置里设置成允许锁屏显示,能大幅降低打卡唤醒应用时被各种不能取消的锁屏带来的干扰
29 | 2. 在开发者模式中设置充电时不锁定屏幕,然后一直插电保持亮屏,则肯定能保证稳定运行和接收消息,可以把屏幕调到最暗来减少屏幕损耗
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/AccessibilityUtil.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.content.Context
4 | import android.provider.Settings
5 | import android.text.TextUtils.SimpleStringSplitter
6 | import android.util.Log
7 | import android.view.accessibility.AccessibilityManager
8 |
9 |
10 | object AccessibilityUtil {
11 | fun isServiceOn(context: Context, serviceName: String): Boolean{
12 | val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
13 | if (am.isEnabled){
14 | val fullAccName = "${context.packageName}/${serviceName}"
15 | return isAccessibilitySettingsOn(context, fullAccName)
16 | }
17 | return false
18 | }
19 |
20 | private fun isAccessibilitySettingsOn(context: Context, service: String): Boolean {
21 | Log.d("param service name", service)
22 | val mStringColonSplitter = SimpleStringSplitter(':')
23 | val settingValue: String = Settings.Secure.getString(
24 | context.applicationContext.contentResolver,
25 | Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
26 | )
27 | mStringColonSplitter.setString(settingValue)
28 | while (mStringColonSplitter.hasNext()) {
29 | val accessibilityService = mStringColonSplitter.next()
30 | Log.d("accessibility services", accessibilityService)
31 | if (accessibilityService.equals(service, ignoreCase = true)) {
32 | return true
33 | }
34 | }
35 | return false
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/xcom/warof/chosen/greendao/DaoSession.java:
--------------------------------------------------------------------------------
1 | package xcom.warof.chosen.greendao;
2 |
3 | import java.util.Map;
4 |
5 | import org.greenrobot.greendao.AbstractDao;
6 | import org.greenrobot.greendao.AbstractDaoSession;
7 | import org.greenrobot.greendao.database.Database;
8 | import org.greenrobot.greendao.identityscope.IdentityScopeType;
9 | import org.greenrobot.greendao.internal.DaoConfig;
10 |
11 | import com.pengxh.autodingding.bean.HistoryRecordBean;
12 |
13 | import xcom.warof.chosen.greendao.HistoryRecordBeanDao;
14 |
15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
16 |
17 | /**
18 | * {@inheritDoc}
19 | *
20 | * @see org.greenrobot.greendao.AbstractDaoSession
21 | */
22 | public class DaoSession extends AbstractDaoSession {
23 |
24 | private final DaoConfig historyRecordBeanDaoConfig;
25 |
26 | private final HistoryRecordBeanDao historyRecordBeanDao;
27 |
28 | public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig>
29 | daoConfigMap) {
30 | super(db);
31 |
32 | historyRecordBeanDaoConfig = daoConfigMap.get(HistoryRecordBeanDao.class).clone();
33 | historyRecordBeanDaoConfig.initIdentityScope(type);
34 |
35 | historyRecordBeanDao = new HistoryRecordBeanDao(historyRecordBeanDaoConfig, this);
36 |
37 | registerDao(HistoryRecordBean.class, historyRecordBeanDao);
38 | }
39 |
40 | public void clear() {
41 | historyRecordBeanDaoConfig.clearIdentityScope();
42 | }
43 |
44 | public HistoryRecordBeanDao getHistoryRecordBeanDao() {
45 | return historyRecordBeanDao;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_remote_sign.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
22 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/greendao/DaoSession.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.greendao;
2 |
3 | import java.util.Map;
4 |
5 | import org.greenrobot.greendao.AbstractDao;
6 | import org.greenrobot.greendao.AbstractDaoSession;
7 | import org.greenrobot.greendao.database.Database;
8 | import org.greenrobot.greendao.identityscope.IdentityScopeType;
9 | import org.greenrobot.greendao.internal.DaoConfig;
10 |
11 | import com.pengxh.autodingding.bean.HistoryRecordBean;
12 |
13 | import com.pengxh.autodingding.greendao.HistoryRecordBeanDao;
14 |
15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
16 |
17 | /**
18 | * {@inheritDoc}
19 | *
20 | * @see org.greenrobot.greendao.AbstractDaoSession
21 | */
22 | public class DaoSession extends AbstractDaoSession {
23 |
24 | private final DaoConfig historyRecordBeanDaoConfig;
25 |
26 | private final HistoryRecordBeanDao historyRecordBeanDao;
27 |
28 | public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig>
29 | daoConfigMap) {
30 | super(db);
31 |
32 | historyRecordBeanDaoConfig = daoConfigMap.get(HistoryRecordBeanDao.class).clone();
33 | historyRecordBeanDaoConfig.initIdentityScope(type);
34 |
35 | historyRecordBeanDao = new HistoryRecordBeanDao(historyRecordBeanDaoConfig, this);
36 |
37 | registerDao(HistoryRecordBean.class, historyRecordBeanDao);
38 | }
39 |
40 | public void clear() {
41 | historyRecordBeanDaoConfig.clearIdentityScope();
42 | }
43 |
44 | public HistoryRecordBeanDao getHistoryRecordBeanDao() {
45 | return historyRecordBeanDao;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/WelcomeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AppCompatActivity
6 | import com.blankj.utilcode.util.ToastUtils
7 | import com.pengxh.autodingding.utils.Constant
8 | import com.pengxh.autodingding.utils.mainHandler
9 | import pub.devrel.easypermissions.EasyPermissions
10 | import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
11 |
12 | class WelcomeActivity : AppCompatActivity(), PermissionCallbacks {
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | startMainActivity()
16 | }
17 |
18 | private fun startMainActivity() {
19 | startActivity(Intent(this, MainActivity::class.java))
20 | finish()
21 | }
22 |
23 | override fun onPermissionsGranted(requestCode: Int, perms: List) {
24 | startMainActivity()
25 | }
26 |
27 | override fun onPermissionsDenied(requestCode: Int, perms: List) {
28 | if (perms.size == Constant.USER_PERMISSIONS.size) { //授权全部失败,则提示用户
29 | ToastUtils.showShort("授权失败")
30 | mainHandler.postDelayed({ this@WelcomeActivity.finish() }, 1500)
31 | }
32 | }
33 |
34 | override fun onRequestPermissionsResult(
35 | requestCode: Int,
36 | permissions: Array,
37 | grantResults: IntArray
38 | ) {
39 | super.onRequestPermissionsResult(requestCode, permissions, grantResults)
40 | //将请求结果传递EasyPermission库处理
41 | EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
42 | }
43 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/StatusBarColorUtil.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils;
2 |
3 | import android.app.Activity;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.view.WindowManager;
7 | import android.widget.LinearLayout;
8 |
9 | public class StatusBarColorUtil {
10 | public static void setColor(Activity activity, int color) {
11 | //限制android系统的版本
12 | // 设置状态栏透明
13 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
14 | // 生成一个状态栏大小的矩形
15 | View statusView = createStatusView(activity, color);
16 | // 添加 statusView 到布局中
17 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
18 | decorView.addView(statusView);
19 | // 设置根布局的参数
20 | ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
21 | rootView.setFitsSystemWindows(true);
22 | rootView.setClipToPadding(true);
23 | }
24 |
25 | /**
26 | * 生成一个和状态栏大小相同的矩形条
27 | *
28 | * @param activity 需要设置的activity
29 | * @param color 状态栏颜色值
30 | * @return 状态栏矩形条
31 | */
32 | private static View createStatusView(Activity activity, int color) {
33 | // 获得状态栏高度
34 | int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
35 | int statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
36 | // 绘制一个和状态栏一样高的矩形
37 | View statusView = new View(activity);
38 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
39 | statusView.setLayoutParams(params);
40 | statusView.setBackgroundColor(color);
41 | return statusView;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/widgets/EasyPopupWindow.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.widgets
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import android.widget.AdapterView.OnItemClickListener
7 | import android.widget.ListView
8 | import android.widget.PopupWindow
9 | import com.pengxh.autodingding.R
10 |
11 | /**
12 | * @description: TODO 顶部下拉菜单
13 | * @author: Pengxh
14 | * @email: 290677893@qq.com
15 | * @date: 2019/12/28 20:35
16 | */
17 | class EasyPopupWindow(private val mContext: Context, private val itemList: List) :
18 | PopupWindow(
19 | mContext
20 | ) {
21 | private var mClickListener: PopupWindowClickListener? = null
22 |
23 | init {
24 | width = 400
25 | height = ViewGroup.LayoutParams.WRAP_CONTENT
26 | isOutsideTouchable = true
27 | isFocusable = true
28 | animationStyle = R.style.PopupAnimation
29 | val contentView = LayoutInflater.from(mContext).inflate(R.layout.easy_popup, null, false)
30 | setContentView(contentView)
31 | val popupListView = contentView.findViewById(R.id.popupListView)
32 | setupListView(popupListView)
33 | }
34 |
35 | //给PopupWindow列表绑定数据
36 | private fun setupListView(popupListView: ListView) {
37 | val adapter = PopupAdapter(mContext, itemList)
38 | popupListView.adapter = adapter
39 | popupListView.onItemClickListener = OnItemClickListener { adapterView, view, i, l ->
40 | if (mClickListener != null) {
41 | mClickListener!!.popupWindowClick(i)
42 | }
43 | dismiss()
44 | }
45 | }
46 |
47 | interface PopupWindowClickListener {
48 | fun popupWindowClick(position: Int)
49 | }
50 |
51 | fun setPopupWindowClickListener(windowClickListener: PopupWindowClickListener?) {
52 | mClickListener = windowClickListener
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 |
23 |
24 |
29 |
30 |
38 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/BaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import cn.jpush.android.api.JPushInterface
6 | import cn.vove7.andro_accessibility_api.AccessibilityApi
7 | import com.blankj.utilcode.util.CacheDiskUtils
8 | import com.pengxh.autodingding.greendao.DaoMaster
9 | import com.pengxh.autodingding.greendao.DaoMaster.DevOpenHelper
10 | import com.pengxh.autodingding.greendao.DaoSession
11 | import com.pengxh.autodingding.service.BaseAccessibilityService
12 | import com.pengxh.autodingding.service.GestureService
13 | import com.pengxh.autodingding.utils.Utils
14 |
15 | class BaseApplication : Application() {
16 | override fun onCreate() {
17 | super.onCreate()
18 | application = this
19 | Utils.init(this)
20 | initDataBase()
21 | JPushInterface.setDebugMode(true)
22 | JPushInterface.init(this)
23 | val strings = HashSet()
24 | strings.add("main")
25 | JPushInterface.setTags(this, 0, strings)
26 | val pushRegId = JPushInterface.getRegistrationID(this)
27 | CacheDiskUtils.getInstance().put("pushRegId", pushRegId)
28 |
29 | //辅助服务
30 | AccessibilityApi.apply {
31 | BASE_SERVICE_CLS = BaseAccessibilityService::class.java
32 | GESTURE_SERVICE_CLS = GestureService::class.java
33 | }
34 | }
35 |
36 | override fun attachBaseContext(base: Context?) {
37 | super.attachBaseContext(base)
38 | application = this;
39 | }
40 |
41 | private fun initDataBase() {
42 | val helper = DevOpenHelper(this, "DingRecord.db")
43 | val db = helper.writableDatabase
44 | val daoMaster = DaoMaster(db)
45 | daoSession = daoMaster.newSession()
46 | }
47 |
48 | companion object {
49 | @JvmStatic
50 | var daoSession: DaoSession? = null
51 | private set
52 |
53 | @Volatile
54 | var application: BaseApplication? = null
55 | }
56 | }
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/PushVM.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import cn.jpush.android.api.JPushInterface
5 | import com.blankj.utilcode.util.CacheDiskUtils
6 | import com.pengxh.autodingding.base.BaseViewModel
7 | import com.pengxh.autodingding.bean.BodyMsg
8 | import com.pengxh.autodingding.bean.PushAudience
9 | import com.pengxh.autodingding.bean.PushMessage
10 | import com.pengxh.autodingding.bean.PushResp
11 | import com.pengxh.autodingding.net.RetrofitManager
12 | import com.pengxh.autodingding.net.api.PushApi
13 | import com.pengxh.autodingding.service.PushCoreService
14 | import kotlinx.coroutines.Dispatchers
15 | import kotlinx.coroutines.withContext
16 |
17 | class PushVM: BaseViewModel() {
18 | val pushResult = MutableLiveData()
19 |
20 | fun pushCheck(regId:String) {
21 | pushCmd(regId, PushCoreService.MSG_MAIL_CHECK)
22 | }
23 |
24 | fun pushSign(regId:String) {
25 | pushCmd(regId, PushCoreService.MSG_SIGN)
26 | }
27 |
28 | fun pushStatusFetch(regId: String){
29 | pushCmd(regId, PushCoreService.MSG_STATUS_REPORT)
30 | }
31 |
32 | fun pushScreenShot(regId: String){
33 | pushCmd(regId, PushCoreService.MSG_SCREEN_SHOT)
34 | }
35 |
36 | fun pushManualSign(regId: String){
37 | pushCmd(regId, PushCoreService.MSG_MANUAL_SIGN)
38 | }
39 |
40 | private fun pushCmd(regId: String, cmd: String) = launch {
41 | pushResult.value = withContext(Dispatchers.IO){
42 | val api = RetrofitManager.retrofitClient.create(PushApi::class.java)
43 | val pushMessage = PushMessage()
44 | pushMessage.audience = PushAudience().apply {
45 | registration_id = mutableListOf(regId)
46 | }
47 | pushMessage.message = BodyMsg().apply {
48 | msg_content = cmd
49 | title = CacheDiskUtils.getInstance().getString("pushRegId")
50 | }
51 | api.pushMsg(pushMessage)
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/AndroidxBaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.fragment.app.Fragment;
11 | import androidx.viewbinding.ViewBinding;
12 |
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.lang.reflect.Method;
15 | import java.lang.reflect.ParameterizedType;
16 | import java.lang.reflect.Type;
17 |
18 | public abstract class AndroidxBaseFragment extends Fragment {
19 |
20 | protected VB viewBinding;
21 |
22 | @Nullable
23 | @Override
24 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
25 | Type type = getClass().getGenericSuperclass();
26 | if (type == null) {
27 | throw new NullPointerException();
28 | }
29 | Class> cls = (Class>) ((ParameterizedType) type).getActualTypeArguments()[0];
30 | try {
31 | Method method = cls.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
32 | viewBinding = (VB) method.invoke(null, getLayoutInflater(), container, false);
33 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
34 | e.printStackTrace();
35 | }
36 | if (viewBinding == null) {
37 | throw new NullPointerException();
38 | }
39 | setupTopBarLayout();
40 | initData();
41 | initEvent();
42 | return viewBinding.getRoot();
43 | }
44 |
45 | protected abstract void setupTopBarLayout();
46 |
47 | /**
48 | * 初始化默认数据
49 | */
50 | protected abstract void initData();
51 |
52 | /**
53 | * 初始化业务逻辑
54 | */
55 | protected abstract void initEvent();
56 |
57 | @Override
58 | public void onDestroyView() {
59 | viewBinding = null;
60 | super.onDestroyView();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/ViewExt.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.content.ClipData
4 | import android.content.ClipboardManager
5 | import android.content.Context
6 | import android.content.res.TypedArray
7 | import android.view.View
8 | import android.view.inputmethod.EditorInfo
9 | import android.widget.EditText
10 | import com.scwang.smartrefresh.layout.SmartRefreshLayout
11 |
12 |
13 | /**
14 | * 防止重复点击
15 | * @param interval 重复间隔
16 | * @param onClick 事件响应
17 | */
18 | var lastTime = 0L
19 | fun View.clickNoRepeat(interval: Long = 400, onClick: (View) -> Unit) {
20 | setOnClickListener {
21 | val currentTime = System.currentTimeMillis()
22 | if (lastTime != 0L && (currentTime - lastTime < interval)) {
23 | return@setOnClickListener
24 | }
25 | lastTime = currentTime
26 | onClick(it)
27 | }
28 | }
29 |
30 | /**
31 | * 复制剪切板
32 | */
33 | fun copy(context: Context, msg: String) {
34 | val clip = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
35 | clip.setPrimaryClip(ClipData.newPlainText("text", msg))
36 | toast("已复制")
37 | }
38 |
39 |
40 | /**
41 | * 隐藏刷新加载ui
42 | */
43 | fun SmartRefreshLayout.smartDismiss() {
44 | finishRefresh(0)
45 | finishLoadMore(0)
46 | }
47 |
48 |
49 | /**
50 | * 获取当前主图颜色属性
51 | */
52 | fun Context.getThemeColor(attr: Int): Int {
53 | val array: TypedArray = theme.obtainStyledAttributes(
54 | intArrayOf(
55 | attr
56 | )
57 | )
58 | val color = array.getColor(0, -0x50506)
59 | array.recycle()
60 | return color
61 | }
62 |
63 |
64 | /**
65 | * editText搜索按钮
66 | * @param onClick 搜索点击事件
67 | */
68 | fun EditText.keyBoardSearch(onClick: () -> Unit) {
69 | //添加搜索按钮
70 | setOnEditorActionListener { _, actionId, _ ->
71 | if (actionId == EditorInfo.IME_ACTION_SEARCH) {
72 | onClick()
73 | } else {
74 | toast("请输入关键字")
75 | return@setOnEditorActionListener false
76 | }
77 | return@setOnEditorActionListener true
78 | }
79 | }
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/PermissionFragment.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.provider.Settings
6 | import com.blankj.utilcode.util.IntentUtils
7 | import com.pengxh.autodingding.R
8 | import com.pengxh.autodingding.base.BaseVmFragment
9 | import com.pengxh.autodingding.databinding.PermissionFragmentBinding
10 | import com.pengxh.autodingding.service.BaseAccessibilityService
11 | import com.pengxh.autodingding.utils.AccessibilityUtil
12 | import com.pengxh.autodingding.utils.RomUtils
13 | import com.pengxh.autodingding.utils.clickNoRepeat
14 |
15 | class PermissionFragment : BaseVmFragment() {
16 | private lateinit var viewModel: PermissionVM
17 | override fun getLayoutId() = R.layout.permission_fragment
18 |
19 | override fun init(savedInstanceState: Bundle?) {
20 | initView()
21 | }
22 |
23 | override fun initViewModel() {
24 | viewModel = getFragmentViewModel(PermissionVM::class.java)
25 | }
26 |
27 | override fun initView() {
28 | binding.vm = viewModel
29 | }
30 |
31 | override fun onClick() {
32 | binding.ivBack.setOnClickListener {
33 | parentFragmentManager.beginTransaction()
34 | .hide(this)
35 | .commit()
36 | }
37 | binding.rlAccessibility.clickNoRepeat {
38 | val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
39 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
40 | activity?.startActivity(intent)
41 | }
42 |
43 | binding.rlBgStart.clickNoRepeat {
44 | activity?.startActivity(IntentUtils.getLaunchAppDetailsSettingsIntent(context?.packageName))
45 | }
46 | }
47 |
48 | override fun onStart() {
49 | super.onStart()
50 | viewModel.bgStartEnable.set(RomUtils.isBackgroundStartAllowed(requireContext()))
51 | viewModel.accessibilityEnable.set(AccessibilityUtil.isServiceOn(requireContext(),
52 | BaseAccessibilityService::class.java.canonicalName?:""))
53 | }
54 |
55 |
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/widgets/PopupAdapter.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.widgets;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.pengxh.autodingding.R;
12 | import com.pengxh.autodingding.utils.Constant;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * @description: TODO
18 | * @author: Pengxh
19 | * @email: 290677893@qq.com
20 | * @date: 2019/12/28 20:46
21 | */
22 | public class PopupAdapter extends BaseAdapter {
23 |
24 | private final List itemList;
25 | private final LayoutInflater inflater;
26 |
27 | public PopupAdapter(Context mContext, List stringList) {
28 | this.itemList = stringList;
29 | inflater = LayoutInflater.from(mContext);
30 | }
31 |
32 | @Override
33 | public int getCount() {
34 | return itemList == null ? 0 : itemList.size();
35 | }
36 |
37 | @Override
38 | public Object getItem(int position) {
39 | return itemList.get(position);
40 | }
41 |
42 | @Override
43 | public long getItemId(int position) {
44 | return position;
45 | }
46 |
47 | @Override
48 | public View getView(int position, View convertView, ViewGroup parent) {
49 | PopupWindowHolder holder;
50 | if (convertView == null) {
51 | convertView = inflater.inflate(R.layout.item_easy_popup, null);
52 | holder = new PopupWindowHolder();
53 | holder.itemIcon = convertView.findViewById(R.id.itemIcon);
54 | holder.itemName = convertView.findViewById(R.id.itemName);
55 | convertView.setTag(holder);
56 | } else {
57 | holder = (PopupWindowHolder) convertView.getTag();
58 | }
59 | holder.bindData(itemList.get(position), position);
60 | return convertView;
61 | }
62 |
63 | private static class PopupWindowHolder {
64 | private ImageView itemIcon;
65 | private TextView itemName;
66 |
67 | void bindData(String s, int index) {
68 | itemIcon.setImageResource(Constant.images[index]);
69 | itemName.setText(s);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/adapter/HistoryRecordAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.adapter
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.BaseAdapter
8 | import android.widget.ImageView
9 | import android.widget.TextView
10 | import com.pengxh.autodingding.R
11 | import com.pengxh.autodingding.bean.HistoryRecordBean
12 |
13 | class HistoryRecordAdapter(mContext: Context?, private val beanList: List?) :
14 | BaseAdapter() {
15 | private val mInflater: LayoutInflater
16 |
17 | init {
18 | mInflater = LayoutInflater.from(mContext)
19 | }
20 |
21 | override fun getCount(): Int {
22 | return beanList?.size ?: 0
23 | }
24 |
25 | override fun getItem(position: Int): Any {
26 | return beanList!![position]
27 | }
28 |
29 | override fun getItemId(position: Int): Long {
30 | return position.toLong()
31 | }
32 |
33 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
34 | var convertView = convertView
35 | val holder: HistoryViewHolder
36 | if (convertView == null) {
37 | convertView = mInflater.inflate(R.layout.item_list, parent)
38 | holder = HistoryViewHolder()
39 | holder.noticeDate = convertView.findViewById(R.id.noticeDate)
40 | holder.noticeMessage = convertView.findViewById(R.id.noticeMessage)
41 | holder.tagView = convertView.findViewById(R.id.tagView)
42 | convertView.tag = holder
43 | } else {
44 | holder = convertView.tag as HistoryViewHolder
45 | }
46 | holder.bindData(beanList!![position])
47 | return convertView!!
48 | }
49 |
50 | private class HistoryViewHolder {
51 | var noticeDate: TextView? = null
52 | var noticeMessage: TextView? = null
53 | var tagView: ImageView? = null
54 | fun bindData(historyBean: HistoryRecordBean) {
55 | val message = historyBean.message
56 | if (!message.contains("成功")) {
57 | tagView!!.setBackgroundResource(R.drawable.bg_textview_error)
58 | }
59 | noticeMessage!!.text = message
60 | noticeDate!!.text = historyBean.date
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/AndroidxBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 |
6 | import androidx.annotation.Nullable;
7 | import androidx.appcompat.app.AppCompatActivity;
8 | import androidx.core.content.ContextCompat;
9 | import androidx.viewbinding.ViewBinding;
10 |
11 | import com.gyf.immersionbar.ImmersionBar;
12 | import com.pengxh.autodingding.utils.StatusBarColorUtil;
13 |
14 | import java.lang.reflect.InvocationTargetException;
15 | import java.lang.reflect.Method;
16 | import java.lang.reflect.ParameterizedType;
17 | import java.lang.reflect.Type;
18 |
19 | public abstract class AndroidxBaseActivity extends AppCompatActivity {
20 |
21 | protected VB viewBinding;
22 |
23 | @Override
24 | protected void onCreate(@Nullable Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | Type type = getClass().getGenericSuperclass();
27 | if (type == null) {
28 | throw new NullPointerException();
29 | }
30 | Class> cls = (Class>) ((ParameterizedType) type).getActualTypeArguments()[0];
31 | try {
32 | Method method = cls.getDeclaredMethod("inflate", LayoutInflater.class);
33 | viewBinding = (VB) method.invoke(null, getLayoutInflater());
34 | if (viewBinding == null) {
35 | throw new NullPointerException();
36 | }
37 | setContentView(viewBinding.getRoot());
38 | StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.colorAppThemeLight));
39 | ImmersionBar.with(this).statusBarDarkFont(false).init();//沉浸式状态栏
40 | setupTopBarLayout();
41 | initData();
42 | initEvent();
43 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
44 | e.printStackTrace();
45 | }
46 | }
47 |
48 | /**
49 | * 初始化默认数据
50 | */
51 | protected abstract void initData();
52 |
53 | /**
54 | * 特定页面定制沉浸式状态栏
55 | */
56 | protected abstract void setupTopBarLayout();
57 |
58 | /**
59 | * 初始化业务逻辑
60 | */
61 | protected abstract void initEvent();
62 |
63 | @Override
64 | protected void onDestroy() {
65 | viewBinding = null;
66 | super.onDestroy();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
24 |
25 |
32 |
33 |
34 |
39 |
40 |
41 |
47 |
48 |
49 |
56 |
57 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_history.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
24 |
25 |
29 |
30 |
31 |
35 |
36 |
39 |
40 |
43 |
44 |
51 |
52 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/service/NotificationMonitorService.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.service
2 |
3 | import android.app.Notification
4 | import android.content.ComponentName
5 | import android.os.Build
6 | import android.service.notification.NotificationListenerService
7 | import android.service.notification.StatusBarNotification
8 | import com.drake.channel.sendEvent
9 | import com.pengxh.autodingding.BaseApplication
10 | import com.pengxh.autodingding.bean.HistoryRecordBean
11 | import com.pengxh.autodingding.greendao.HistoryRecordBeanDao
12 | import com.pengxh.autodingding.ui.fragment.SettingsFragment
13 | import com.pengxh.autodingding.utils.TimeOrDateUtil
14 | import java.util.*
15 |
16 | class NotificationMonitorService : NotificationListenerService() {
17 | private var recordBeanDao: HistoryRecordBeanDao? = null
18 |
19 | /**
20 | * 有可用的并且和通知管理器连接成功时回调
21 | */
22 | override fun onListenerConnected() {
23 | recordBeanDao = BaseApplication.daoSession?.historyRecordBeanDao
24 | }
25 |
26 | /**
27 | * 当有新通知到来时会回调
28 | */
29 | override fun onNotificationPosted(sbn: StatusBarNotification) {
30 | val extras = sbn.notification.extras
31 | // 获取接收消息APP的包名
32 | val packageName = sbn.packageName
33 | // 获取接收消息的内容
34 | val notificationText = extras.getString(Notification.EXTRA_TEXT)
35 | if (packageName == "com.alibaba.android.rimet") {
36 | if (notificationText == null || notificationText == "") {
37 | return
38 | }
39 | if (notificationText.contains("考勤打卡")) {
40 | //保存打卡记录
41 | val bean = HistoryRecordBean()
42 | bean.uuid = UUID.randomUUID().toString()
43 | bean.date = TimeOrDateUtil.timestampToDate(System.currentTimeMillis())
44 | bean.message = notificationText
45 | recordBeanDao!!.save(bean)
46 | //通知发送邮件和更新界面
47 | sendEvent(notificationText)
48 | }
49 | }else if(packageName == "com.pengxh.autodingding"){
50 | if (notificationText == null || notificationText == "") {
51 | return
52 | }
53 | if(notificationText.contains("")){
54 |
55 | }
56 | }
57 | }
58 |
59 | /**
60 | * 当有通知移除时会回调
61 | */
62 | override fun onNotificationRemoved(sbn: StatusBarNotification) {}
63 | override fun onListenerDisconnected() {
64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
65 | // 通知侦听器断开连接 - 请求重新绑定
66 | requestRebind(ComponentName(this, NotificationListenerService::class.java))
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/net/RetrofitManager.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.net
2 |
3 | import okhttp3.OkHttpClient
4 | import okhttp3.logging.HttpLoggingInterceptor
5 | import retrofit2.Retrofit
6 | import retrofit2.converter.gson.GsonConverterFactory
7 | import java.util.concurrent.TimeUnit
8 |
9 | object RetrofitManager {
10 | private const val BASE_URL ="https://api.jpush.cn"
11 | private const val API_DAY_URL = "http://timor.tech"
12 | private const val UPDATE_BASE_URL = "http://smallfurrypaw.top"
13 |
14 | lateinit var okHttpClient: OkHttpClient
15 |
16 | val retrofitClient: Retrofit
17 | get() {
18 | return Retrofit.Builder()
19 | .baseUrl(BASE_URL)
20 | .addConverterFactory(GsonConverterFactory.create())
21 | .client(genericOkClient())
22 | .build()
23 | }
24 | val workdayClient: Retrofit
25 | get() {
26 | return Retrofit.Builder()
27 | .baseUrl(API_DAY_URL)
28 | .addConverterFactory(GsonConverterFactory.create())
29 | .client(generateWorkdayClient())
30 | .build()
31 | }
32 | val updateClient: Retrofit
33 | get(){
34 | return Retrofit.Builder()
35 | .baseUrl(UPDATE_BASE_URL)
36 | .addConverterFactory(GsonConverterFactory.create())
37 | .client(generateWorkdayClient())
38 | .build()
39 | }
40 | private fun genericOkClient(): OkHttpClient {
41 | val httpLoggingInterceptor = HttpLoggingInterceptor()
42 | httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
43 |
44 | return OkHttpClient.Builder()
45 | .connectTimeout(5_000L, TimeUnit.MILLISECONDS)
46 | .readTimeout(10_000, TimeUnit.MILLISECONDS)
47 | .writeTimeout(30_000, TimeUnit.MILLISECONDS)
48 | .retryOnConnectionFailure(true)
49 | .addInterceptor(httpLoggingInterceptor)
50 | .addInterceptor(AuthInterceptor)
51 | .build().also {
52 | okHttpClient = it
53 | }
54 | }
55 |
56 | private fun generateWorkdayClient(): OkHttpClient {
57 | val httpLoggingInterceptor = HttpLoggingInterceptor()
58 | httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
59 |
60 | return OkHttpClient.Builder()
61 | .connectTimeout(5_000L, TimeUnit.MILLISECONDS)
62 | .readTimeout(10_000, TimeUnit.MILLISECONDS)
63 | .writeTimeout(30_000, TimeUnit.MILLISECONDS)
64 | .retryOnConnectionFailure(false)
65 | .addInterceptor(httpLoggingInterceptor)
66 | .build()
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/RomUtils.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.AppOpsManager
5 | import android.content.Context
6 | import android.net.Uri
7 | import android.os.Build
8 | import android.provider.Settings
9 | import java.lang.reflect.Method
10 |
11 | object RomUtils {
12 | private val TAG = RomUtils::class.java.simpleName
13 |
14 | private fun isXiaoMi(): Boolean {
15 | return checkManufacturer("xiaomi")
16 | }
17 |
18 | private fun isOppo(): Boolean {
19 | return checkManufacturer("oppo")
20 | }
21 |
22 | private fun isVivo(): Boolean {
23 | return checkManufacturer("vivo")
24 | }
25 |
26 | private fun checkManufacturer(manufacturer: String): Boolean {
27 | return manufacturer.equals(Build.MANUFACTURER, true)
28 | }
29 |
30 | fun isBackgroundStartAllowed(context: Context): Boolean {
31 | if (isXiaoMi()) {
32 | return isXiaomiBgStartPermissionAllowed(context)
33 | }
34 |
35 | if (isVivo()) {
36 | return isVivoBgStartPermissionAllowed(context)
37 | }
38 |
39 | if (isOppo() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
40 | return Settings.canDrawOverlays(context)
41 | }
42 | return true
43 | }
44 |
45 |
46 | private fun isXiaomiBgStartPermissionAllowed(context: Context): Boolean {
47 | val ops = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
48 | try {
49 | val op = 10021
50 | val method: Method = ops.javaClass.getMethod("checkOpNoThrow", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java)
51 | val result = method.invoke(ops, op, android.os.Process.myUid(), context.packageName) as Int
52 | return result == AppOpsManager.MODE_ALLOWED
53 | } catch (e: Exception) {
54 | e.printStackTrace()
55 | }
56 | return false
57 | }
58 |
59 | private fun isVivoBgStartPermissionAllowed(context: Context): Boolean {
60 | return getVivoBgStartPermissionStatus(context) == 0
61 | }
62 |
63 | /**
64 | * 判断Vivo后台弹出界面状态, 1无权限,0有权限
65 | * @param context context
66 | */
67 | @SuppressLint("Range")
68 | private fun getVivoBgStartPermissionStatus(context: Context): Int {
69 | val uri: Uri = Uri.parse("content://com.vivo.permissionmanager.provider.permission/start_bg_activity")
70 | val selection = "pkgname = ?"
71 | val selectionArgs = arrayOf(context.packageName)
72 | var state = 1
73 | try {
74 | context.contentResolver.query(uri, null, selection, selectionArgs, null)?.use {
75 | if (it.moveToFirst()) {
76 | state = it.getInt(it.getColumnIndex("currentstate"))
77 | }
78 | }
79 | } catch (e: Exception) {
80 | e.printStackTrace()
81 | }
82 | return state
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/SendMailUtil.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import com.blankj.utilcode.util.CacheDiskUtils
4 | import com.blankj.utilcode.util.ToastUtils
5 | import com.pengxh.autodingding.bean.MailInfo
6 | import java.io.File
7 |
8 | object SendMailUtil {
9 | fun send(
10 | toAddress: String?, emailMessage: String
11 | ) {
12 | Thread {
13 | MailSender().sendTextMail(
14 | createMail(
15 | toAddress,
16 | emailMessage,
17 | CacheDiskUtils.getInstance().getString("senderEmail", "lttclaw@qq.com"),
18 | CacheDiskUtils.getInstance().getString("senderAuth", "hwpzapzrkmgpgaba")
19 | )
20 | )
21 | }
22 | .start()
23 | }
24 |
25 | @JvmStatic
26 | fun sendAttachFileEmail(toAddress: String, filePath: String?) {
27 | val file = File(filePath)
28 | if (!file.exists()) {
29 | ToastUtils.showLong("打卡记录不存在,请检查")
30 | return
31 | }
32 | Thread {
33 | val isSendSuccess = MailSender().sendAccessoryMail(
34 | createAttachMail(
35 | toAddress,
36 | file
37 | )
38 | )
39 | }.start()
40 | }
41 |
42 | fun createMail(
43 | toAddress: String?,
44 | emailMessage: String,
45 | senderEmail: String = "lttclaw@qq.com",
46 | senderAuth: String = "hwpzapzrkmgpgaba"
47 | ): MailInfo {
48 | val mailInfo = MailInfo()
49 | mailInfo.mailServerHost = "smtp.qq.com" //发送方邮箱服务器
50 | mailInfo.mailServerPort = "465" //发送方邮箱端口号
51 | mailInfo.isValidate = true
52 | mailInfo.userName = senderEmail // 发送者邮箱地址
53 | mailInfo.password = senderAuth //邮箱授权码,不是密码
54 | mailInfo.toAddress = toAddress // 接收者邮箱
55 | mailInfo.fromAddress = senderEmail // 发送者邮箱
56 | mailInfo.subject = "自动打卡通知" // 邮件主题
57 | if (emailMessage == "") {
58 | mailInfo.content =
59 | "未监听到打卡成功的通知,请手动登录检查" + TimeOrDateUtil.timestampToDate(System.currentTimeMillis()) // 邮件文本
60 | } else {
61 | mailInfo.content = emailMessage // 邮件文本
62 | }
63 | return mailInfo
64 | }
65 |
66 | fun createAttachMail(
67 | toAddress: String,
68 | file: File,
69 | senderEmail: String = "lttclaw@qq.com",
70 | senderAuth: String = "hwpzapzrkmgpgaba"
71 | ): MailInfo {
72 | val mailInfo = MailInfo()
73 | mailInfo.mailServerHost = "smtp.qq.com" //发送方邮箱服务器
74 | mailInfo.mailServerPort = "465" //发送方邮箱端口号
75 | mailInfo.isValidate = true
76 | mailInfo.userName = senderEmail // 发送者邮箱地址
77 | mailInfo.password = senderAuth //邮箱授权码,不是密码
78 | mailInfo.toAddress = toAddress // 接收者邮箱
79 | mailInfo.fromAddress = senderEmail // 发送者邮箱
80 | mailInfo.subject = "打卡记录" // 邮件主题
81 | mailInfo.attachFile = file
82 | return mailInfo
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/actions/DingSignAction.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.actions
2 |
3 | import android.app.Activity
4 | import android.graphics.Point
5 | import cn.vove7.andro_accessibility_api.requireBaseAccessibility
6 | import cn.vove7.auto.core.api.back
7 | import cn.vove7.auto.core.api.click
8 | import cn.vove7.auto.core.viewfinder.SF
9 | import cn.vove7.auto.core.viewfinder.containsText
10 | import cn.vove7.auto.core.viewfinder.id
11 | import com.blankj.utilcode.util.TimeUtils
12 | import com.pengxh.autodingding.utils.Constant
13 | import com.pengxh.autodingding.utils.toast
14 | import kotlinx.coroutines.delay
15 |
16 | class DingSignAction : Action() {
17 | private var result = false
18 | var message = StringBuilder()
19 | override val name: String
20 | get() = "打开钉钉,手动打卡"
21 |
22 | override suspend fun run(act: Activity) {
23 | requireBaseAccessibility(true)
24 |
25 | toast("1秒后启动钉钉")
26 | delay(1000)
27 | val targetApp = Constant.DINGDING
28 | genLog("启动钉钉")
29 | act.startActivity(act.packageManager.getLaunchIntentForPackage(targetApp))
30 |
31 | delay(9000)
32 | genLog("查找钉钉首页元素")
33 | val messageTab = SF.containsText("消息").findFirst(false)
34 |
35 | toast(if (messageTab != null) "找到消息按钮" else "未找到消息按钮")
36 | if (messageTab != null) {
37 | messageTab.tryClick()
38 | delay(2000)
39 | }
40 | val signTab = SF.containsText("打卡").findFirst(false)
41 | toast("找到${signTab != null}打卡")
42 | genLog("查找打卡入口")
43 | if (signTab != null) {
44 | val signClick = signTab.tryClick()
45 | genLog("点击打卡入口" + if (signClick) "成功" else "失败")
46 | toast("8秒后尝试寻找打卡按钮")
47 | delay(8000)
48 | }
49 | val webPage = SF.id("com.alibaba.android.rimet:id/h5_pc_container").findFirst()
50 | genLog("查找打卡webView" + if (webPage != null) "成功" else "失败")
51 | var clickSucceed = false
52 | if (webPage != null) {
53 | val centerP = webPage.getCenterPoint()
54 | for (i in 1..5) {
55 | val delta = 70
56 | tryClick(Point(centerP.x, centerP.y + i * delta))
57 | clickSucceed = SF.containsText("成功")
58 | .findFirst(false) != null
59 | if (clickSucceed) {
60 | break
61 | }
62 | }
63 | }
64 | genLog("点击打卡" + if (clickSucceed) "成功" else "失败" + ",准备查看页面结果")
65 | val succeed = SF.containsText("成功")
66 | .findFirst(false) != null
67 | toast("手动打卡 " + if (succeed) "成功" else "失败")
68 | genLog("页面结果判断打卡" + if (succeed) "成功" else "失败" + ",准备回退")
69 | delay(2000)
70 | back()
71 | genLog("回退第一次")
72 | delay(2000)
73 | back()
74 | result = succeed
75 | genLog("回退第二次,执行结束,最终执行判定:" + if (result) "成功" else "失败")
76 | }
77 |
78 | private fun genLog(actionDesc: String) {
79 | message.append(actionDesc + "-----" + TimeUtils.getNowString() + "\n")
80 | }
81 |
82 | private suspend fun tryClick(p: Point) {
83 | click(p.x, p.y)
84 | val delayTime = 5L
85 | genLog("点击坐标点${p.x},${p.y},并等待${delayTime}秒")
86 | delay(delayTime * 1000)
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/ParamUtil.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.app.Activity
4 | import android.os.Bundle
5 | import android.os.Parcelable
6 | import android.text.TextUtils
7 | import androidx.fragment.app.Fragment
8 |
9 | /**
10 | * 页面跳转传参 注解+反射获取页面入参
11 | */
12 | object ParamUtil {
13 | /**
14 | * Fragment
15 | */
16 | fun initParam(fragment: Fragment) {
17 | val javaClass = fragment.javaClass
18 | fragment.arguments?.apply {
19 | setParam(fragment, this)
20 | }
21 | }
22 |
23 | /**
24 | * Activity
25 | */
26 | fun initParam(activity: Activity) {
27 | activity.intent.extras?.apply {
28 | setParam(activity, this)
29 | }
30 | }
31 |
32 | private fun setParam(obj: Any, intent: Bundle) {
33 | val javaClass = obj.javaClass
34 | val fields = javaClass.declaredFields
35 | for (item in fields) {
36 | if (item.isAnnotationPresent(Param::class.java)) {
37 | item.getAnnotation(Param::class.java)?.let {
38 | val key: String = if (TextUtils.isEmpty(it.value)) item.name else it.value
39 | if (intent.containsKey(key)) {
40 | val type = item.type
41 | when (type) {
42 | Boolean::class.javaPrimitiveType -> {
43 | intent.getBoolean(key, false)
44 | }
45 | Int::class.javaPrimitiveType -> {
46 | intent.getInt(key, 0)
47 | }
48 | Long::class.javaPrimitiveType -> {
49 | intent.getLong(key, 0L)
50 | }
51 | String::class.java -> {
52 | intent.getString(key)
53 | }
54 | Double::class.javaPrimitiveType -> {
55 | intent.getDouble(key, 0.0)
56 | }
57 | Byte::class.javaPrimitiveType -> {
58 | intent.getByte(key, "".toByte())
59 | }
60 | Char::class.javaPrimitiveType -> {
61 | intent.getChar(key, '\u0000')
62 | }
63 | Float::class.javaPrimitiveType -> {
64 | intent.getFloat(key, 0f)
65 | }
66 | else -> {
67 | if((type as Class).interfaces.asList().contains(Parcelable::class.java)){
68 | intent.getParcelable(key)
69 | }else{
70 | intent.getSerializable(key)
71 | }
72 | }
73 | }?.apply {
74 | item.isAccessible = true
75 | try {
76 | item[obj] = this
77 | } catch (e: IllegalAccessException) {
78 | e.printStackTrace()
79 | }
80 | item.isAccessible = false
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/xcom/warof/chosen/greendao/DaoMaster.java:
--------------------------------------------------------------------------------
1 | package xcom.warof.chosen.greendao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteDatabase.CursorFactory;
6 | import android.util.Log;
7 |
8 | import org.greenrobot.greendao.AbstractDaoMaster;
9 | import org.greenrobot.greendao.database.StandardDatabase;
10 | import org.greenrobot.greendao.database.Database;
11 | import org.greenrobot.greendao.database.DatabaseOpenHelper;
12 | import org.greenrobot.greendao.identityscope.IdentityScopeType;
13 |
14 |
15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
16 | /**
17 | * Master of DAO (schema version 1): knows all DAOs.
18 | */
19 | public class DaoMaster extends AbstractDaoMaster {
20 | public static final int SCHEMA_VERSION = 1;
21 |
22 | /** Creates underlying database table using DAOs. */
23 | public static void createAllTables(Database db, boolean ifNotExists) {
24 | HistoryRecordBeanDao.createTable(db, ifNotExists);
25 | }
26 |
27 | /** Drops underlying database table using DAOs. */
28 | public static void dropAllTables(Database db, boolean ifExists) {
29 | HistoryRecordBeanDao.dropTable(db, ifExists);
30 | }
31 |
32 | /**
33 | * WARNING: Drops all table on Upgrade! Use only during development.
34 | * Convenience method using a {@link DevOpenHelper}.
35 | */
36 | public static DaoSession newDevSession(Context context, String name) {
37 | Database db = new DevOpenHelper(context, name).getWritableDb();
38 | DaoMaster daoMaster = new DaoMaster(db);
39 | return daoMaster.newSession();
40 | }
41 |
42 | public DaoMaster(SQLiteDatabase db) {
43 | this(new StandardDatabase(db));
44 | }
45 |
46 | public DaoMaster(Database db) {
47 | super(db, SCHEMA_VERSION);
48 | registerDaoClass(HistoryRecordBeanDao.class);
49 | }
50 |
51 | public DaoSession newSession() {
52 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
53 | }
54 |
55 | public DaoSession newSession(IdentityScopeType type) {
56 | return new DaoSession(db, type, daoConfigMap);
57 | }
58 |
59 | /**
60 | * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
61 | */
62 | public static abstract class OpenHelper extends DatabaseOpenHelper {
63 | public OpenHelper(Context context, String name) {
64 | super(context, name, SCHEMA_VERSION);
65 | }
66 |
67 | public OpenHelper(Context context, String name, CursorFactory factory) {
68 | super(context, name, factory, SCHEMA_VERSION);
69 | }
70 |
71 | @Override
72 | public void onCreate(Database db) {
73 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
74 | createAllTables(db, false);
75 | }
76 | }
77 |
78 | /** WARNING: Drops all table on Upgrade! Use only during development. */
79 | public static class DevOpenHelper extends OpenHelper {
80 | public DevOpenHelper(Context context, String name) {
81 | super(context, name);
82 | }
83 |
84 | public DevOpenHelper(Context context, String name, CursorFactory factory) {
85 | super(context, name, factory);
86 | }
87 |
88 | @Override
89 | public void onUpgrade(Database db, int oldVersion, int newVersion) {
90 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
91 | dropAllTables(db, true);
92 | onCreate(db);
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.base
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.blankj.utilcode.util.LogUtils
7 | import com.pengxh.autodingding.ApiException
8 | import com.pengxh.autodingding.BuildConfig
9 | import kotlinx.coroutines.*
10 | import org.json.JSONException
11 | import retrofit2.HttpException
12 | import java.net.ConnectException
13 | import java.net.SocketTimeoutException
14 | import java.net.UnknownHostException
15 |
16 |
17 | typealias VmError = (e: ApiException) -> Unit
18 |
19 | open class BaseViewModel: ViewModel() {
20 | val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
21 | throwable.printStackTrace()
22 | LogUtils.e(coroutineContext, throwable)
23 | }
24 |
25 | /**
26 | * 错误信息liveData
27 | */
28 | val errorLiveData = MutableLiveData()
29 |
30 | /**
31 | * 无更多数据
32 | */
33 | val footLiveDate = MutableLiveData()
34 |
35 | /**
36 | * 无数据
37 | */
38 | val emptyLiveDate = MutableLiveData()
39 |
40 | /**
41 | * 处理错误
42 | */
43 |
44 | protected fun launch(
45 | block: () -> T
46 | , error:VmError? = null) {
47 | viewModelScope.launch {
48 | runCatching {
49 | block()
50 | }.onFailure {
51 | it.printStackTrace()
52 | getApiException(it).apply {
53 | withContext(Dispatchers.Main){
54 | error?.invoke(this@apply)
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
61 | protected fun launch(block: suspend () -> T) {
62 | viewModelScope.launch {
63 | runCatching {
64 | block()
65 | }.onFailure {
66 | if (BuildConfig.DEBUG) {
67 | it.printStackTrace()
68 | }
69 | getApiException(it).apply {
70 | withContext(Dispatchers.Main){
71 | //统一响应错误信息
72 | errorLiveData.value = this@apply
73 | }
74 | }
75 | }
76 | }
77 | }
78 |
79 | /**
80 | * 捕获异常信息
81 | */
82 | private fun getApiException(e: Throwable): ApiException {
83 | return when (e) {
84 | is UnknownHostException -> {
85 | ApiException("网络异常", -100)
86 | }
87 | is JSONException -> {//|| e is JsonParseException
88 | ApiException("数据异常", -100)
89 | }
90 | is SocketTimeoutException -> {
91 | ApiException("连接超时", -100)
92 | }
93 | is ConnectException -> {
94 | ApiException("连接错误", -100)
95 | }
96 | is HttpException -> {
97 | ApiException("http code ${e.code()}", -100)
98 | }
99 | is ApiException -> {
100 | e
101 | }
102 | /**
103 | * 如果协程还在运行,个别机型退出当前界面时,viewModel会通过抛出CancellationException,
104 | * 强行结束协程,与java中InterruptException类似,所以不必理会,只需将toast隐藏即可
105 | */
106 | is CancellationException -> {
107 | ApiException("", -10)
108 | }
109 | else -> {
110 | ApiException("未知错误", -100)
111 | }
112 | }
113 | }
114 |
115 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/greendao/DaoMaster.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.greendao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteDatabase.CursorFactory;
6 | import android.util.Log;
7 |
8 | import org.greenrobot.greendao.AbstractDaoMaster;
9 | import org.greenrobot.greendao.database.StandardDatabase;
10 | import org.greenrobot.greendao.database.Database;
11 | import org.greenrobot.greendao.database.DatabaseOpenHelper;
12 | import org.greenrobot.greendao.identityscope.IdentityScopeType;
13 |
14 |
15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
16 | /**
17 | * Master of DAO (schema version 1): knows all DAOs.
18 | */
19 | public class DaoMaster extends AbstractDaoMaster {
20 | public static final int SCHEMA_VERSION = 1;
21 |
22 | /** Creates underlying database table using DAOs. */
23 | public static void createAllTables(Database db, boolean ifNotExists) {
24 | HistoryRecordBeanDao.createTable(db, ifNotExists);
25 | }
26 |
27 | /** Drops underlying database table using DAOs. */
28 | public static void dropAllTables(Database db, boolean ifExists) {
29 | HistoryRecordBeanDao.dropTable(db, ifExists);
30 | }
31 |
32 | /**
33 | * WARNING: Drops all table on Upgrade! Use only during development.
34 | * Convenience method using a {@link DevOpenHelper}.
35 | */
36 | public static DaoSession newDevSession(Context context, String name) {
37 | Database db = new DevOpenHelper(context, name).getWritableDb();
38 | DaoMaster daoMaster = new DaoMaster(db);
39 | return daoMaster.newSession();
40 | }
41 |
42 | public DaoMaster(SQLiteDatabase db) {
43 | this(new StandardDatabase(db));
44 | }
45 |
46 | public DaoMaster(Database db) {
47 | super(db, SCHEMA_VERSION);
48 | registerDaoClass(HistoryRecordBeanDao.class);
49 | }
50 |
51 | public DaoSession newSession() {
52 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
53 | }
54 |
55 | public DaoSession newSession(IdentityScopeType type) {
56 | return new DaoSession(db, type, daoConfigMap);
57 | }
58 |
59 | /**
60 | * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
61 | */
62 | public static abstract class OpenHelper extends DatabaseOpenHelper {
63 | public OpenHelper(Context context, String name) {
64 | super(context, name, SCHEMA_VERSION);
65 | }
66 |
67 | public OpenHelper(Context context, String name, CursorFactory factory) {
68 | super(context, name, factory, SCHEMA_VERSION);
69 | }
70 |
71 | @Override
72 | public void onCreate(Database db) {
73 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
74 | createAllTables(db, false);
75 | }
76 | }
77 |
78 | /** WARNING: Drops all table on Upgrade! Use only during development. */
79 | public static class DevOpenHelper extends OpenHelper {
80 | public DevOpenHelper(Context context, String name) {
81 | super(context, name);
82 | }
83 |
84 | public DevOpenHelper(Context context, String name, CursorFactory factory) {
85 | super(context, name, factory);
86 | }
87 |
88 | @Override
89 | public void onUpgrade(Database db, int oldVersion, int newVersion) {
90 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
91 | dropAllTables(db, true);
92 | onCreate(db);
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/MailConfFragment.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.ViewModel
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.blankj.utilcode.util.CacheDiskUtils
12 | import com.blankj.utilcode.util.ToastUtils
13 | import com.pengxh.autodingding.databinding.FragmentMailConfBinding
14 | import com.pengxh.autodingding.utils.Utils
15 |
16 | class MailConfFragment :Fragment() {
17 | private var fragmentProvider: ViewModelProvider? = null
18 | private lateinit var binding: FragmentMailConfBinding
19 | private var configTested = false
20 | private lateinit var vm: MailConfVM
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater,
24 | container: ViewGroup?,
25 | savedInstanceState: Bundle?
26 | ): View {
27 | binding = FragmentMailConfBinding.inflate(inflater, container, false);
28 | return binding.root
29 | }
30 |
31 | override fun onAttach(context: Context) {
32 | super.onAttach(context)
33 | vm = getFragmentViewModel(MailConfVM::class.java)
34 | }
35 |
36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
37 | super.onViewCreated(view, savedInstanceState)
38 | val savedFromAddress = CacheDiskUtils.getInstance().getString("senderEmail", "lttclaw@qq.com")
39 | val savedFromAuth = CacheDiskUtils.getInstance().getString("senderAuth", "hwpzapzrkmgpgaba")
40 | val savedToAddress = Utils.readEmailAddress()
41 | binding.etSenderEmailAddress.setText(savedFromAddress)
42 | binding.etSenderEmailAuth.setText(savedFromAuth)
43 | binding.etReceiverEmailAddress.setText(savedToAddress)
44 |
45 | binding.btnCheck.setOnClickListener {
46 | val fromAddress = binding.etSenderEmailAddress.text.toString()
47 | val fromAuth = binding.etSenderEmailAuth.text.toString()
48 | val toAddress = binding.etReceiverEmailAddress.text.toString()
49 | if(fromAddress.isEmpty() || fromAuth.isEmpty() || toAddress.isEmpty()){
50 | ToastUtils.showShort("配置选项缺失!")
51 | }else{
52 | vm.sendMail(fromAddress, fromAuth, toAddress)
53 | configTested = true
54 | ToastUtils.showShort("已尝试发送邮件")
55 | }
56 | }
57 | binding.btnSave.setOnClickListener {
58 | val fromAddress = binding.etSenderEmailAddress.text.toString()
59 | val fromAuth = binding.etSenderEmailAuth.text.toString()
60 | val toAddress = binding.etReceiverEmailAddress.text.toString()
61 | if(configTested){
62 | CacheDiskUtils.getInstance().put("senderEmail" , fromAddress)
63 | CacheDiskUtils.getInstance().put("senderAuth", fromAuth)
64 | Utils.saveEmailAddress(toAddress)
65 | ToastUtils.showShort("保存配置成功")
66 | }else{
67 | ToastUtils.showShort("请先进行配置测试")
68 | }
69 | }
70 | binding.ivBack.setOnClickListener {
71 | parentFragmentManager.beginTransaction()
72 | .hide(this)
73 | .commit()
74 | }
75 | }
76 |
77 | private fun getFragmentViewModel(modelClass: Class): T {
78 | if (fragmentProvider == null) {
79 | fragmentProvider = ViewModelProvider(this)
80 | }
81 | return fragmentProvider!![modelClass]
82 | }
83 | }
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/MailSender.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.util.Log
4 | import com.blankj.utilcode.util.ToastUtils
5 | import com.pengxh.autodingding.bean.MailInfo
6 | import java.util.*
7 | import javax.activation.DataHandler
8 | import javax.activation.DataSource
9 | import javax.activation.FileDataSource
10 | import javax.mail.*
11 | import javax.mail.internet.*
12 |
13 | class MailSender {
14 | /**
15 | * 以文本格式发送邮件
16 | * @param mailInfo 待发送的邮件的信息
17 | */
18 | @Throws(MessagingException::class)
19 | fun sendTextMail(mailInfo: MailInfo) {
20 | // 判断是否需要身份认证
21 | var authenticator: EmailAuthenticator? = null
22 | val pro = mailInfo.properties
23 | if (mailInfo.isValidate) {
24 | // 如果需要身份认证,则创建一个密码验证器
25 | authenticator = EmailAuthenticator(mailInfo.userName ?: "", mailInfo.password ?: "")
26 | }
27 | // 根据邮件会话属性和密码验证器构造一个发送邮件的session
28 | val sendMailSession = Session.getInstance(pro, authenticator)
29 |
30 | // 根据session创建一个邮件消息
31 | val mailMessage: Message = MimeMessage(sendMailSession)
32 | // 创建邮件发送者地址
33 | val from: Address = InternetAddress(mailInfo.fromAddress)
34 | // 设置邮件消息的发送者
35 | mailMessage.setFrom(from)
36 | // 创建邮件的接收者地址,并设置到邮件消息中
37 | val to: Address = InternetAddress(mailInfo.toAddress)
38 | mailMessage.setRecipient(Message.RecipientType.TO, to)
39 | // 设置邮件消息的主题
40 | val mailSubject = mailInfo.subject
41 | mailMessage.subject = mailSubject
42 | // 设置邮件消息发送的时间
43 | mailMessage.sentDate = Date()
44 | // 设置邮件消息的主要内容
45 | val mailContent = mailInfo.content
46 | mailMessage.setText(mailContent)
47 | // 发送邮件
48 | Transport.send(mailMessage)
49 | }
50 |
51 | // 发送带附件的邮件
52 | fun sendAccessoryMail(mailInfo: MailInfo): Boolean {
53 | Log.d("MailSender", "sendAccessoryMail: 发送带附件的邮件")
54 | // 判断是否需要身份验证
55 | var authenticator: EmailAuthenticator? = null
56 | val p = mailInfo.properties
57 | // 如果需要身份验证,则创建一个密码验证器
58 | if (mailInfo.isValidate) {
59 | authenticator = EmailAuthenticator(mailInfo.userName ?: "", mailInfo.password ?: "")
60 | }
61 | // 根据邮件会话属性和密码验证器构造一个发送邮件的session
62 | val sendMailSession = Session.getInstance(p, authenticator)
63 | try {
64 | // 根据session创建一个邮件消息
65 | val mailMessage: Message = MimeMessage(sendMailSession)
66 | // 创建邮件发送者的地址
67 | val fromAddress: Address = InternetAddress(mailInfo.fromAddress)
68 | // 设置邮件消息的发送者
69 | mailMessage.setFrom(fromAddress)
70 | // 创建邮件接收者的地址
71 | val toAddress: Address = InternetAddress(mailInfo.toAddress)
72 | // 设置邮件消息的接收者
73 | mailMessage.setRecipient(Message.RecipientType.TO, toAddress)
74 | // 设置邮件消息的主题
75 | mailMessage.subject = mailInfo.subject
76 | // 设置邮件消息的发送时间
77 | mailMessage.sentDate = Date()
78 | // MimeMultipart类是一个容器类,包含MimeBodyPart类型的对象
79 | val mainPart: Multipart = MimeMultipart()
80 | val file = mailInfo.attachFile!!
81 | if (!file.exists()) {
82 | ToastUtils.showShort("需要导出的表格不存在,请重试")
83 | return false
84 | } else {
85 | // 创建一个MimeBodyPart来包含附件
86 | val bodyPart: BodyPart = MimeBodyPart()
87 | val source: DataSource = FileDataSource(file)
88 | bodyPart.dataHandler = DataHandler(source)
89 | bodyPart.fileName = MimeUtility.encodeWord(file.name)
90 | mainPart.addBodyPart(bodyPart)
91 | }
92 | // 将MimeMultipart对象设置为邮件内容
93 | mailMessage.setContent(mainPart)
94 | // 发送邮件
95 | Transport.send(mailMessage)
96 | return true
97 | } catch (e: Exception) {
98 | e.printStackTrace()
99 | }
100 | return false
101 | }
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/base/BaseVmFragment.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.base
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.annotation.Keep
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.databinding.DataBindingUtil
11 | import androidx.databinding.ViewDataBinding
12 | import androidx.fragment.app.Fragment
13 | import androidx.lifecycle.ViewModel
14 | import androidx.lifecycle.ViewModelProvider
15 | import com.pengxh.autodingding.utils.ParamUtil
16 |
17 |
18 | @Keep
19 | abstract class BaseVmFragment : Fragment() {
20 |
21 | /**
22 | * 开放给外部使用
23 | */
24 | lateinit var mContext: Context
25 | lateinit var mActivity: AppCompatActivity
26 | private var fragmentProvider: ViewModelProvider? = null
27 | private var activityProvider: ViewModelProvider? = null
28 | protected lateinit var binding: BD
29 | private var mBinding: ViewDataBinding? = null
30 |
31 | override fun onCreate(savedInstanceState: Bundle?) {
32 | super.onCreate(savedInstanceState)
33 | //由于同一个fragment对象可能被activity attach多次(比如viewPager+PagerStateAdapter中)
34 | //所以fragmentViewModel不能放在onCreateView初始化,否则会产生多个fragmentViewModel
35 | initFragmentViewModel()
36 | }
37 |
38 | override fun onAttach(context: Context) {
39 | super.onAttach(context)
40 | mContext = context
41 | mActivity = context as AppCompatActivity
42 | // 必须要在Activity与Fragment绑定后,因为如果Fragment可能获取的是Activity中ViewModel
43 | // 必须在onCreateView之前初始化viewModel,因为onCreateView中需要通过ViewModel与DataBinding绑定
44 | initViewModel()
45 | ParamUtil.initParam(this)
46 | }
47 |
48 | override fun onCreateView(
49 | inflater: LayoutInflater,
50 | container: ViewGroup?,
51 | savedInstanceState: Bundle?
52 | ): View? {
53 | getLayoutId()?.let {
54 | //获取ViewDataBinding
55 | binding = DataBindingUtil.inflate(inflater, it, container, false)
56 | //将ViewDataBinding生命周期与Fragment绑定
57 | binding.lifecycleOwner = viewLifecycleOwner
58 | return binding.root
59 | }
60 | return super.onCreateView(inflater, container, savedInstanceState)
61 | }
62 |
63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
64 | super.onViewCreated(view, savedInstanceState)
65 | init(savedInstanceState)
66 | //observe一定要在初始化最后,因为observe会收到黏性事件,随后对ui做处理
67 | observe()
68 | onClick()
69 | }
70 |
71 | /**
72 | * 初始化viewModel
73 | * 之所以没有设计为抽象,是因为部分简单activity可能不需要viewModel
74 | * observe同理
75 | */
76 | open fun initViewModel() {
77 |
78 | }
79 |
80 | open fun initFragmentViewModel() {
81 |
82 | }
83 |
84 | /**
85 | * 注册观察者
86 | */
87 | open fun observe() {
88 |
89 | }
90 |
91 | /**
92 | * 通过activity获取viewModel,跟随activity生命周期
93 | */
94 | protected fun getActivityViewModel(modelClass: Class): T {
95 | if (activityProvider == null) {
96 | activityProvider = ViewModelProvider(mActivity)
97 | }
98 | return activityProvider!![modelClass]
99 | }
100 |
101 | /**
102 | * 通过fragment获取viewModel,跟随fragment生命周期
103 | */
104 | protected open fun getFragmentViewModel(modelClass: Class): T {
105 | if (fragmentProvider == null) {
106 | fragmentProvider = ViewModelProvider(this)
107 | }
108 | return fragmentProvider!![modelClass]
109 | }
110 |
111 | /**
112 | * 点击事件
113 | */
114 | open fun onClick() {
115 |
116 | }
117 |
118 | /**
119 | * 初始化View以及事件
120 | */
121 | open fun initView() {
122 |
123 | }
124 |
125 | /**
126 | * 加载数据
127 | */
128 | open fun loadData() {
129 | }
130 |
131 | /**
132 | * 获取layout布局
133 | */
134 | abstract fun getLayoutId(): Int?
135 |
136 | /**
137 | * 初始化入口
138 | */
139 | abstract fun init(savedInstanceState: Bundle?)
140 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/ui/fragment/PushFragment.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.ui.fragment
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.fragment.app.Fragment
10 | import androidx.lifecycle.ViewModel
11 | import androidx.lifecycle.ViewModelProvider
12 | import com.blankj.utilcode.util.CacheDiskUtils
13 | import com.blankj.utilcode.util.ToastUtils
14 | import com.pengxh.autodingding.databinding.FragmentPushBinding
15 | import com.pengxh.autodingding.utils.clickNoRepeat
16 |
17 | open class PushFragment : Fragment() {
18 | private var fragmentProvider: ViewModelProvider? = null
19 | private var binding: FragmentPushBinding? = null
20 | private lateinit var pushVM: PushVM
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater, container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View? {
26 | binding = FragmentPushBinding.inflate(inflater, container, false)
27 | return binding!!.root
28 | }
29 |
30 | override fun onAttach(context: Context) {
31 | super.onAttach(context)
32 | pushVM = getFragmentViewModel(PushVM::class.java)
33 | }
34 |
35 | @SuppressLint("SetTextI18n")
36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
37 | super.onViewCreated(view, savedInstanceState)
38 | pushVM.pushResult.observe(viewLifecycleOwner){
39 | if (it.errorCode == 0){
40 | ToastUtils.showShort("指令下发成功")
41 | saveRegId()
42 | }else{
43 | ToastUtils.showShort(it.messageCn)
44 | }
45 | }
46 | val savedRegId = CacheDiskUtils.getInstance().getString("regId")
47 | if (savedRegId != null){
48 | binding!!.etTargetRegId.setText(savedRegId)
49 | }
50 | binding!!.ivBack.setOnClickListener {
51 | parentFragmentManager.beginTransaction()
52 | .hide(this)
53 | .commit()
54 | }
55 | binding!!.btnCheck.setOnClickListener {
56 | if (binding!!.etTargetRegId.text.toString() == "") {
57 | ToastUtils.showShort("注册id必须填写")
58 | }else {
59 | pushVM.pushCheck(binding!!.etTargetRegId.text.toString())
60 | }
61 | }
62 | binding!!.btnPush.setOnClickListener {
63 | if (binding!!.etTargetRegId.text.toString() == "") {
64 | ToastUtils.showShort("注册id必须填写")
65 | }else {
66 | pushVM.pushSign(binding!!.etTargetRegId.text.toString())
67 | }
68 | }
69 | binding!!.btnStatus.setOnClickListener {
70 | if (binding!!.etTargetRegId.text.toString() == "") {
71 | ToastUtils.showShort("注册id必须填写")
72 | } else {
73 | pushVM.pushStatusFetch(binding!!.etTargetRegId.text.toString())
74 | }
75 | }
76 | binding!!.btnScreenShot.setOnClickListener {
77 | if (binding!!.etTargetRegId.text.toString() == "") {
78 | ToastUtils.showShort("注册id必须填写")
79 | } else {
80 | pushVM.pushScreenShot(binding!!.etTargetRegId.text.toString())
81 | }
82 | }
83 | binding!!.btnManualSign.clickNoRepeat(1000) {
84 | if (binding!!.etTargetRegId.text.toString() == "") {
85 | ToastUtils.showShort("注册id必须填写")
86 | } else {
87 | pushVM.pushManualSign(binding!!.etTargetRegId.text.toString())
88 | }
89 | }
90 |
91 | }
92 |
93 | private fun getFragmentViewModel(modelClass: Class): T {
94 | if (fragmentProvider == null) {
95 | fragmentProvider = ViewModelProvider(this)
96 | }
97 | return fragmentProvider!![modelClass]
98 | }
99 |
100 | private fun saveRegId(){
101 | val curRegId = binding!!.etTargetRegId.text.toString()
102 | CacheDiskUtils.getInstance().put("regId", curRegId)
103 | }
104 |
105 | companion object {
106 | @JvmStatic
107 | fun newInstance(): PushFragment {
108 | return PushFragment()
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
67 |
68 |
69 |
70 |
71 |
72 |
77 |
78 |
79 |
80 |
82 |
83 |
89 |
90 |
91 |
92 |
95 |
96 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_push.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
31 |
32 |
43 |
44 |
45 |
54 |
55 |
64 |
73 |
82 |
91 |
92 |
103 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/permission_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
19 |
20 |
31 |
32 |
41 |
42 |
53 |
54 |
60 |
61 |
68 |
69 |
79 |
80 |
84 |
90 |
91 |
98 |
99 |
109 |
110 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/utils/ExcelUtils.kt:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.utils
2 |
3 | import android.util.Log
4 | import com.blankj.utilcode.util.ToastUtils
5 | import com.pengxh.autodingding.bean.HistoryRecordBean
6 | import com.pengxh.autodingding.utils.SendMailUtil.sendAttachFileEmail
7 | import jxl.Workbook
8 | import jxl.WorkbookSettings
9 | import jxl.format.Alignment
10 | import jxl.format.Border
11 | import jxl.format.BorderLineStyle
12 | import jxl.format.Colour
13 | import jxl.write.*
14 | import java.io.File
15 | import java.io.FileInputStream
16 | import java.io.IOException
17 | import java.io.InputStream
18 |
19 | object ExcelUtils {
20 | private const val TAG = "ExcelUtils"
21 | private var arial14format: WritableCellFormat? = null
22 | private var arial10format: WritableCellFormat? = null
23 | private var arial12format: WritableCellFormat? = null
24 | private const val UTF8_ENCODING = "UTF-8"
25 |
26 | /**
27 | * 初始化Excel
28 | *
29 | * @param fileName
30 | * @param colName
31 | */
32 | fun initExcel(fileName: String?, colName: Array) {
33 | format()
34 | var workbook: WritableWorkbook? = null
35 | try {
36 | val file = File(fileName)
37 | if (!file.exists()) {
38 | file.createNewFile()
39 | }
40 | workbook = Workbook.createWorkbook(file)
41 | val sheet = workbook.createSheet("打卡记录表", 0)
42 | //创建标题栏
43 | sheet.addCell(Label(0, 0, fileName, arial14format))
44 | for (col in colName.indices) {
45 | sheet.addCell(Label(col, 0, colName[col], arial10format))
46 | }
47 | sheet.setRowView(0, 340) //设置行高
48 | workbook.write()
49 | } catch (e: Exception) {
50 | e.printStackTrace()
51 | } finally {
52 | if (workbook != null) {
53 | try {
54 | workbook.close()
55 | } catch (e: Exception) {
56 | e.printStackTrace()
57 | }
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * 单元格的格式设置 字体大小 颜色 对齐方式、背景颜色等...
64 | */
65 | private fun format() {
66 | try {
67 | val arial14font = WritableFont(WritableFont.ARIAL, 14, WritableFont.BOLD)
68 | arial14font.colour = Colour.LIGHT_BLUE
69 | arial14format = WritableCellFormat(arial14font)
70 | arial14format!!.alignment = Alignment.CENTRE
71 | arial14format!!.setBorder(Border.ALL, BorderLineStyle.THIN)
72 | arial14format!!.setBackground(Colour.VERY_LIGHT_YELLOW)
73 | arial10format =
74 | WritableCellFormat(WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD))
75 | arial10format!!.alignment = Alignment.CENTRE
76 | arial10format!!.setBorder(Border.ALL, BorderLineStyle.THIN)
77 | arial10format!!.setBackground(Colour.GRAY_25)
78 | arial12format = WritableCellFormat(WritableFont(WritableFont.ARIAL, 10))
79 | arial10format!!.alignment = Alignment.CENTRE //对齐格式
80 | arial12format!!.setBorder(Border.ALL, BorderLineStyle.THIN) //设置边框
81 | } catch (e: WriteException) {
82 | e.printStackTrace()
83 | }
84 | }
85 |
86 | fun writeObjListToExcel(objList: List?, fileName: String?) {
87 | if (objList != null && objList.size > 0) {
88 | var writebook: WritableWorkbook? = null
89 | var `in`: InputStream? = null
90 | try {
91 | val setEncode = WorkbookSettings()
92 | setEncode.encoding = UTF8_ENCODING
93 | `in` = FileInputStream(File(fileName))
94 | val workbook = Workbook.getWorkbook(`in`)
95 | writebook = Workbook.createWorkbook(File(fileName), workbook)
96 | val sheet = writebook.getSheet(0)
97 | for (j in objList.indices) {
98 | val historyBean = objList[j]
99 | val uuid = historyBean.uuid
100 | val date = historyBean.date
101 | val message = historyBean.message
102 | //第一行留作表头
103 | sheet.addCell(Label(0, j + 1, uuid, arial12format))
104 | sheet.addCell(Label(1, j + 1, date, arial12format))
105 | sheet.addCell(Label(2, j + 1, message, arial12format))
106 | sheet.setRowView(j + 1, 350) //设置行高
107 | }
108 | writebook.write()
109 | Log.d(TAG, "writeObjListToExcel: 导出表格到本地成功")
110 | //然后发送邮件到指定邮箱
111 | val emailAddress = Utils.readEmailAddress()
112 | if (emailAddress == "") {
113 | ToastUtils.showLong("邮箱未填写,无法导出")
114 | return
115 | }
116 | sendAttachFileEmail(emailAddress, fileName)
117 | } catch (e: Exception) {
118 | e.printStackTrace()
119 | } finally {
120 | if (writebook != null) {
121 | try {
122 | writebook.close()
123 | } catch (e: Exception) {
124 | e.printStackTrace()
125 | }
126 | }
127 | if (`in` != null) {
128 | try {
129 | `in`.close()
130 | } catch (e: IOException) {
131 | e.printStackTrace()
132 | }
133 | }
134 | }
135 | }
136 | }
137 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_mail_conf.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
31 |
32 |
43 |
44 |
52 |
62 |
70 |
81 |
89 |
99 |
100 |
109 |
118 |
123 |
--------------------------------------------------------------------------------
/app/src/main/java/xcom/warof/chosen/greendao/HistoryRecordBeanDao.java:
--------------------------------------------------------------------------------
1 | package xcom.warof.chosen.greendao;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteStatement;
5 |
6 | import org.greenrobot.greendao.AbstractDao;
7 | import org.greenrobot.greendao.Property;
8 | import org.greenrobot.greendao.internal.DaoConfig;
9 | import org.greenrobot.greendao.database.Database;
10 | import org.greenrobot.greendao.database.DatabaseStatement;
11 |
12 | import com.pengxh.autodingding.bean.HistoryRecordBean;
13 |
14 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
15 | /**
16 | * DAO for table "HISTORY_RECORD_BEAN".
17 | */
18 | public class HistoryRecordBeanDao extends AbstractDao {
19 |
20 | public static final String TABLENAME = "HISTORY_RECORD_BEAN";
21 |
22 | /**
23 | * Properties of entity HistoryRecordBean.
24 | * Can be used for QueryBuilder and for referencing column names.
25 | */
26 | public static class Properties {
27 | public final static Property Id = new Property(0, Long.class, "id", true, "_id");
28 | public final static Property Uuid = new Property(1, String.class, "uuid", false, "UUID");
29 | public final static Property Date = new Property(2, String.class, "date", false, "DATE");
30 | public final static Property Message = new Property(3, String.class, "message", false, "MESSAGE");
31 | }
32 |
33 |
34 | public HistoryRecordBeanDao(DaoConfig config) {
35 | super(config);
36 | }
37 |
38 | public HistoryRecordBeanDao(DaoConfig config, DaoSession daoSession) {
39 | super(config, daoSession);
40 | }
41 |
42 | /** Creates the underlying database table. */
43 | public static void createTable(Database db, boolean ifNotExists) {
44 | String constraint = ifNotExists? "IF NOT EXISTS ": "";
45 | db.execSQL("CREATE TABLE " + constraint + "\"HISTORY_RECORD_BEAN\" (" + //
46 | "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
47 | "\"UUID\" TEXT," + // 1: uuid
48 | "\"DATE\" TEXT," + // 2: date
49 | "\"MESSAGE\" TEXT);"); // 3: message
50 | }
51 |
52 | /** Drops the underlying database table. */
53 | public static void dropTable(Database db, boolean ifExists) {
54 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"HISTORY_RECORD_BEAN\"";
55 | db.execSQL(sql);
56 | }
57 |
58 | @Override
59 | protected final void bindValues(DatabaseStatement stmt, HistoryRecordBean entity) {
60 | stmt.clearBindings();
61 |
62 | Long id = entity.getId();
63 | if (id != null) {
64 | stmt.bindLong(1, id);
65 | }
66 |
67 | String uuid = entity.getUuid();
68 | if (uuid != null) {
69 | stmt.bindString(2, uuid);
70 | }
71 |
72 | String date = entity.getDate();
73 | if (date != null) {
74 | stmt.bindString(3, date);
75 | }
76 |
77 | String message = entity.getMessage();
78 | if (message != null) {
79 | stmt.bindString(4, message);
80 | }
81 | }
82 |
83 | @Override
84 | protected final void bindValues(SQLiteStatement stmt, HistoryRecordBean entity) {
85 | stmt.clearBindings();
86 |
87 | Long id = entity.getId();
88 | if (id != null) {
89 | stmt.bindLong(1, id);
90 | }
91 |
92 | String uuid = entity.getUuid();
93 | if (uuid != null) {
94 | stmt.bindString(2, uuid);
95 | }
96 |
97 | String date = entity.getDate();
98 | if (date != null) {
99 | stmt.bindString(3, date);
100 | }
101 |
102 | String message = entity.getMessage();
103 | if (message != null) {
104 | stmt.bindString(4, message);
105 | }
106 | }
107 |
108 | @Override
109 | public Long readKey(Cursor cursor, int offset) {
110 | return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
111 | }
112 |
113 | @Override
114 | public HistoryRecordBean readEntity(Cursor cursor, int offset) {
115 | HistoryRecordBean entity = new HistoryRecordBean( //
116 | cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
117 | cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // uuid
118 | cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // date
119 | cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3) // message
120 | );
121 | return entity;
122 | }
123 |
124 | @Override
125 | public void readEntity(Cursor cursor, HistoryRecordBean entity, int offset) {
126 | entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
127 | entity.setUuid(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
128 | entity.setDate(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2));
129 | entity.setMessage(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3));
130 | }
131 |
132 | @Override
133 | protected final Long updateKeyAfterInsert(HistoryRecordBean entity, long rowId) {
134 | entity.setId(rowId);
135 | return rowId;
136 | }
137 |
138 | @Override
139 | public Long getKey(HistoryRecordBean entity) {
140 | if(entity != null) {
141 | return entity.getId();
142 | } else {
143 | return null;
144 | }
145 | }
146 |
147 | @Override
148 | public boolean hasKey(HistoryRecordBean entity) {
149 | return entity.getId() != null;
150 | }
151 |
152 | @Override
153 | protected final boolean isEntityUpdateable() {
154 | return true;
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pengxh/autodingding/greendao/HistoryRecordBeanDao.java:
--------------------------------------------------------------------------------
1 | package com.pengxh.autodingding.greendao;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteStatement;
5 |
6 | import org.greenrobot.greendao.AbstractDao;
7 | import org.greenrobot.greendao.Property;
8 | import org.greenrobot.greendao.internal.DaoConfig;
9 | import org.greenrobot.greendao.database.Database;
10 | import org.greenrobot.greendao.database.DatabaseStatement;
11 |
12 | import com.pengxh.autodingding.bean.HistoryRecordBean;
13 |
14 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
15 | /**
16 | * DAO for table "HISTORY_RECORD_BEAN".
17 | */
18 | public class HistoryRecordBeanDao extends AbstractDao {
19 |
20 | public static final String TABLENAME = "HISTORY_RECORD_BEAN";
21 |
22 | /**
23 | * Properties of entity HistoryRecordBean.
24 | * Can be used for QueryBuilder and for referencing column names.
25 | */
26 | public static class Properties {
27 | public final static Property Id = new Property(0, Long.class, "id", true, "_id");
28 | public final static Property Uuid = new Property(1, String.class, "uuid", false, "UUID");
29 | public final static Property Date = new Property(2, String.class, "date", false, "DATE");
30 | public final static Property Message = new Property(3, String.class, "message", false, "MESSAGE");
31 | }
32 |
33 |
34 | public HistoryRecordBeanDao(DaoConfig config) {
35 | super(config);
36 | }
37 |
38 | public HistoryRecordBeanDao(DaoConfig config, DaoSession daoSession) {
39 | super(config, daoSession);
40 | }
41 |
42 | /** Creates the underlying database table. */
43 | public static void createTable(Database db, boolean ifNotExists) {
44 | String constraint = ifNotExists? "IF NOT EXISTS ": "";
45 | db.execSQL("CREATE TABLE " + constraint + "\"HISTORY_RECORD_BEAN\" (" + //
46 | "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
47 | "\"UUID\" TEXT," + // 1: uuid
48 | "\"DATE\" TEXT," + // 2: date
49 | "\"MESSAGE\" TEXT);"); // 3: message
50 | }
51 |
52 | /** Drops the underlying database table. */
53 | public static void dropTable(Database db, boolean ifExists) {
54 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"HISTORY_RECORD_BEAN\"";
55 | db.execSQL(sql);
56 | }
57 |
58 | @Override
59 | protected final void bindValues(DatabaseStatement stmt, HistoryRecordBean entity) {
60 | stmt.clearBindings();
61 |
62 | Long id = entity.getId();
63 | if (id != null) {
64 | stmt.bindLong(1, id);
65 | }
66 |
67 | String uuid = entity.getUuid();
68 | if (uuid != null) {
69 | stmt.bindString(2, uuid);
70 | }
71 |
72 | String date = entity.getDate();
73 | if (date != null) {
74 | stmt.bindString(3, date);
75 | }
76 |
77 | String message = entity.getMessage();
78 | if (message != null) {
79 | stmt.bindString(4, message);
80 | }
81 | }
82 |
83 | @Override
84 | protected final void bindValues(SQLiteStatement stmt, HistoryRecordBean entity) {
85 | stmt.clearBindings();
86 |
87 | Long id = entity.getId();
88 | if (id != null) {
89 | stmt.bindLong(1, id);
90 | }
91 |
92 | String uuid = entity.getUuid();
93 | if (uuid != null) {
94 | stmt.bindString(2, uuid);
95 | }
96 |
97 | String date = entity.getDate();
98 | if (date != null) {
99 | stmt.bindString(3, date);
100 | }
101 |
102 | String message = entity.getMessage();
103 | if (message != null) {
104 | stmt.bindString(4, message);
105 | }
106 | }
107 |
108 | @Override
109 | public Long readKey(Cursor cursor, int offset) {
110 | return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
111 | }
112 |
113 | @Override
114 | public HistoryRecordBean readEntity(Cursor cursor, int offset) {
115 | HistoryRecordBean entity = new HistoryRecordBean( //
116 | cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
117 | cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // uuid
118 | cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // date
119 | cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3) // message
120 | );
121 | return entity;
122 | }
123 |
124 | @Override
125 | public void readEntity(Cursor cursor, HistoryRecordBean entity, int offset) {
126 | entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
127 | entity.setUuid(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
128 | entity.setDate(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2));
129 | entity.setMessage(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3));
130 | }
131 |
132 | @Override
133 | protected final Long updateKeyAfterInsert(HistoryRecordBean entity, long rowId) {
134 | entity.setId(rowId);
135 | return rowId;
136 | }
137 |
138 | @Override
139 | public Long getKey(HistoryRecordBean entity) {
140 | if(entity != null) {
141 | return entity.getId();
142 | } else {
143 | return null;
144 | }
145 | }
146 |
147 | @Override
148 | public boolean hasKey(HistoryRecordBean entity) {
149 | return entity.getId() != null;
150 | }
151 |
152 | @Override
153 | protected final boolean isEntityUpdateable() {
154 | return true;
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.greenrobot.greendao'
4 | id 'kotlin-android'
5 | id 'kotlin-kapt'
6 | }
7 |
8 | android {
9 | compileSdk 33
10 | defaultConfig {
11 | applicationId "xcom.warof.chosen"
12 | minSdkVersion 23
13 | targetSdkVersion 33
14 | versionCode 18
15 | versionName "1.1.8"
16 | ndk {
17 | //选择要添加的对应 cpu 类型的 .so 库。
18 | abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
19 | // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
20 | }
21 |
22 | manifestPlaceholders = [
23 | JPUSH_PKGNAME : applicationId,
24 | JPUSH_APPKEY : "f01b8a02b66ea2d632e52e2e", //JPush 上注册的包名对应的 Appkey.
25 | JPUSH_CHANNEL : "jpush", //暂时填写默认值即可.
26 | VERSION_NAME : versionName,
27 | CHANNEL : 'self',
28 | DEBUG : true,
29 | MEIZU_APPKEY : "MZ-魅族的APPKEY",
30 | MEIZU_APPID : "MZ-魅族的APPID",
31 | XIAOMI_APPID : "MI-小米的APPID",
32 | XIAOMI_APPKEY : "MI-小米的APPKEY",
33 | OPPO_APPKEY : "OP-oppo的APPKEY",
34 | OPPO_APPID : "OP-oppo的APPID",
35 | OPPO_APPSECRET : "OP-oppo的APPSECRET",
36 | VIVO_APPKEY : "vivo的APPKEY",
37 | VIVO_APPID : "vivo的APPID"
38 | ]
39 | }
40 |
41 | signingConfigs {
42 | sign {
43 | storeFile file("../sxwdsoft.jks")
44 | storePassword "sxwdsoft4989"
45 | keyAlias "sxwdsoft"
46 | keyPassword "sxwdsoft4989"
47 | }
48 | }
49 |
50 | buildTypes {
51 | release {
52 | minifyEnabled false
53 | // 启用资源压缩,需配合 minifyEnabled=true 使用
54 | shrinkResources false
55 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
56 | signingConfig signingConfigs.sign
57 | }
58 | debug {
59 | debuggable true
60 | manifestPlaceholders["DEBUG"] = debuggable
61 | minifyEnabled false
62 | shrinkResources false
63 | signingConfig signingConfigs.sign
64 | //禁用PNG压缩。
65 | crunchPngs false
66 | }
67 | }
68 | packagingOptions {
69 | resources {
70 | excludes += ['META-INF/NOTICE.md', 'META-INF/LICENSE.md']
71 | }
72 | }
73 | compileOptions {
74 | targetCompatibility JavaVersion.VERSION_17
75 | sourceCompatibility JavaVersion.VERSION_17
76 | }
77 | kotlinOptions {
78 | jvmTarget = '17'
79 | }
80 |
81 | greendao {
82 | schemaVersion 1//数据库版本号
83 | targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录
84 | daoPackage 'xcom.warof.chosen.greendao'//设置DaoMaster、DaoSession、Dao包名
85 | }
86 |
87 | buildFeatures {
88 | viewBinding true
89 | dataBinding true
90 | buildConfig true
91 | }
92 | namespace 'com.pengxh.autodingding'
93 | lint {
94 | checkReleaseBuilds false
95 | }
96 | }
97 |
98 | tasks.configureEach { task ->
99 | if (task.name.matches("\\w*compile\\w*Kotlin")) {
100 | task.dependsOn('greendao')
101 | }
102 | if (task.name.matches("\\w*kaptGenerateStubs\\w*Kotlin")) {
103 | task.dependsOn('greendao')
104 | }
105 |
106 | if (task.name.matches("\\w*kapt\\w*Kotlin")) {
107 | task.dependsOn('greendao')
108 | }
109 | }
110 |
111 | dependencies {
112 | implementation fileTree(include: ['*.jar'], dir: 'libs')
113 | implementation 'androidx.appcompat:appcompat:1.4.0'
114 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
115 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
116 | implementation 'com.google.android.material:material:1.4.0'
117 | implementation 'androidx.core:core-ktx:1.8.0'
118 | implementation 'com.android.databinding:viewbinding:7.2.2'
119 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
120 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
121 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
122 | implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
123 | implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
124 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
125 |
126 | //Google官方授权库
127 | implementation 'pub.devrel:easypermissions:3.0.0'
128 | implementation 'androidx.recyclerview:recyclerview:1.2.1'
129 | implementation 'androidx.cardview:cardview:1.0.0'
130 | implementation 'com.google.code.gson:gson:2.8.6'
131 | implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1'
132 | implementation 'com.sun.mail:android-mail:1.6.6'
133 | implementation 'com.sun.mail:android-activation:1.6.6'
134 | //事件总线
135 | implementation 'com.github.liangjingkanji:Channel:1.1.5'
136 | //retrofit okhttp
137 | implementation "com.squareup.retrofit2:retrofit:2.9.0"
138 | implementation "com.squareup.retrofit2:converter-gson:2.9.0"
139 | implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"
140 | //上拉加载下拉刷新
141 | implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0'
142 | implementation group: 'net.sourceforge.jexcelapi', name: 'jxl', version: '2.6.12'
143 | //沉浸式状态栏。基础依赖包,必须要依赖
144 | implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
145 | implementation 'com.afollestad.material-dialogs:core:3.2.1'
146 | //fragment快速实现
147 | implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
148 | //数据库框架
149 | implementation 'org.greenrobot:greendao:3.3.0'
150 | implementation "com.blankj:utilcodex:1.30.5"
151 | implementation 'cn.jiguang.sdk:jpush:5.2.2'
152 | implementation 'cn.jiguang.sdk:joperate:2.0.2'
153 | //无障碍
154 | implementation 'com.github.Krosxx:Android-Auto-Api:4.1.2'
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_day.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
28 |
29 |
35 |
36 |
39 |
40 |
45 |
46 |
53 |
54 |
60 |
61 |
62 |
70 |
71 |
78 |
79 |
85 |
86 |
87 |
88 |
91 |
92 |
99 |
100 |
106 |
107 |
110 |
111 |
116 |
117 |
124 |
125 |
131 |
132 |
133 |
141 |
142 |
149 |
150 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------