Skip to content

Commit

Permalink
Merge pull request #143 from Team-HMH/feat/lock_api
Browse files Browse the repository at this point in the history
[feat/lock_api]: ์ž ๊ธˆํ™”๋ฉด ๋ฏธ์…˜ ์‹คํŒจ API ์ž‘์—…
  • Loading branch information
kez-lab authored Jan 19, 2024
2 parents 08f4eff + cba5e79 commit 3755f93
Show file tree
Hide file tree
Showing 37 changed files with 505 additions and 146 deletions.
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
tools:ignore="QueryAllPackagesPermission" />

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

<application
android:name=".HMHApplication"
android:allowBackup="true"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/hmh_app_logo"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.hmh.hamyeonham.navigation
import android.content.Context
import android.content.Intent
import com.hmh.hamyeonham.common.navigation.NavigationProvider
import com.hmh.hamyeonham.feature.lock.LockActivity
import com.hmh.hamyeonham.feature.login.LoginActivity
import com.hmh.hamyeonham.feature.main.MainActivity
import com.hmh.hamyeonham.feature.onboarding.OnBoardingActivity
Expand All @@ -23,4 +24,8 @@ class DefaultNavigationProvider @Inject constructor(
override fun toMain(): Intent {
return Intent(context, MainActivity::class.java)
}

override fun toLock(packageName: String): Intent {
return LockActivity.getIntent(context, packageName)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.hmh.hamyeonham.common.activity

import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.PowerManager
import android.provider.Settings
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
Expand All @@ -15,3 +21,84 @@ fun AppCompatActivity.addFragment(containerViewId: Int, fragment: Fragment) {
add(containerViewId, fragment)
}
}

fun AppCompatActivity.requestAccessibilitySettings() {
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
startActivity(intent)
}

fun AppCompatActivity.requestOverlayPermission() {
val packageUri = Uri.parse("package:$packageName")
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, packageUri)
startActivity(intent)
}

fun AppCompatActivity.requestUsageAccessPermission() {
try {
val packageUri = Uri.parse("package:$packageName")
val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS, packageUri)
startActivity(intent)
} catch (e: Exception) {
startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
}

fun AppCompatActivity.checkAccessibilityServiceEnabled(classCanonicalName: String): Boolean {
val service = "$packageName/$classCanonicalName"
val enabledServicesSetting = Settings.Secure.getString(
contentResolver,
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
)
return enabledServicesSetting?.contains(service) == true
}

fun AppCompatActivity.hasUsageStatsPermission(): Boolean {
val usageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val time = System.currentTimeMillis()
val stats = usageStatsManager.queryUsageStats(
UsageStatsManager.INTERVAL_DAILY,
time - 1000 * 60,
time,
)
return stats != null && stats.isNotEmpty()
}

fun AppCompatActivity.hasOverlayPermission(): Boolean {
return Settings.canDrawOverlays(this)
}

fun AppCompatActivity.checkAllPermissionIsGranted(classCanonicalName: String) {
when {
!checkAccessibilityServiceEnabled(classCanonicalName) -> {
requestAccessibilitySettings()
}

!hasUsageStatsPermission() -> {
requestUsageAccessPermission()
}

!hasOverlayPermission() -> {
requestOverlayPermission()
}
}
}

fun AppCompatActivity.allPermissionIsGranted(classCanonicalName: String): Boolean {
return checkAccessibilityServiceEnabled(classCanonicalName) && hasUsageStatsPermission() && hasOverlayPermission()
}

fun AppCompatActivity.isBatteryOptimizationEnabled(): Boolean {
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
val packageName = packageName
return !powerManager.isIgnoringBatteryOptimizations(packageName)
}

fun AppCompatActivity.requestDisableBatteryOptimization() {
if (isBatteryOptimizationEnabled()) {
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
data = Uri.parse("package:$packageName")
}
startActivity(intent)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package com.hmh.hamyeonham.common.context

import android.app.Dialog
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Point
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.util.Log
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
Expand Down Expand Up @@ -108,7 +110,7 @@ fun Context.colorSecondStrAndBindText(
tv: TextView,
color: Int
) {
val mergedStr = firstStr + " " + secondStr
val mergedStr = "$firstStr $secondStr"
val builder = SpannableStringBuilder(
mergedStr
)
Expand All @@ -125,3 +127,13 @@ fun Context.colorSecondStrAndBindText(
)
tv.text = builder
}

fun Context.isSystemPackage( packageName: String): Boolean {
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
return packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
} catch (e: PackageManager.NameNotFoundException) {
Log.e("isSystemPackage", e.toString())
}
return false
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.hmh.hamyeonham.common.fragment

import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.view.View
import android.widget.Toast
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar

Expand Down Expand Up @@ -35,3 +39,69 @@ val Fragment.viewLifeCycle

val Fragment.viewLifeCycleScope
get() = viewLifecycleOwner.lifecycleScope

fun Fragment.requestAccessibilitySettings() {
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
startActivity(intent)
}

fun Fragment.requestOverlayPermission() {
val packageUri = Uri.parse("package:${requireContext().packageName}")
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, packageUri)
startActivity(intent)
}

fun Fragment.requestUsageAccessPermission() {
try {
val packageUri = Uri.parse("package:${requireContext().packageName}")
val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS, packageUri)
startActivity(intent)
} catch (e: Exception) {
startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
}

fun Fragment.checkAccessibilityServiceEnabled(classCanonicalName: String): Boolean {
val service = "${requireContext().packageName}/${classCanonicalName}"
val enabledServicesSetting = Settings.Secure.getString(
requireContext().contentResolver,
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
)
return enabledServicesSetting?.contains(service) == true
}

fun Fragment.hasUsageStatsPermission(): Boolean {
val usageStatsManager =
requireContext().getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val time = System.currentTimeMillis()
val stats = usageStatsManager.queryUsageStats(
UsageStatsManager.INTERVAL_DAILY,
time - 1000 * 60,
time,
)
return stats != null && stats.isNotEmpty()
}

fun Fragment.hasOverlayPermission(): Boolean {
return Settings.canDrawOverlays(requireContext())
}

fun Fragment.checkAllPermissionIsGranted(classCanonicalName: String) {
when {
!checkAccessibilityServiceEnabled(classCanonicalName) -> {
requestAccessibilitySettings()
}

!hasUsageStatsPermission() -> {
requestUsageAccessPermission()
}

!hasOverlayPermission() -> {
requestOverlayPermission()
}
}
}

fun Fragment.allPermissionIsGranted(classCanonicalName: String): Boolean {
return this.checkAccessibilityServiceEnabled(classCanonicalName) && hasUsageStatsPermission() && hasOverlayPermission()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ package com.hmh.hamyeonham.common.navigation
import android.content.Intent

interface NavigationProvider {
companion object{
const val UN_LOCK_PACKAGE_NAME = "UN_LOCK_PACKAGE_NAME"
}
fun toOnBoarding(): Intent
fun toLogin(): Intent
fun toMain(): Intent
fun toLock(packageName:String): Intent
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ fun convertTimeToString(time: Long): String {
// ๋ถ„์„ ms๋กœ ๋ฐ”๊พธ๋Š” ํ•จ์ˆ˜
fun Int.timeToMs(): Long {
return this * 60 * 1000L
}
}

fun Long.msToHour(): Long {
return TimeUnit.MILLISECONDS.toHours(this)
}

fun Int.msToHour(): Long {
return TimeUnit.MILLISECONDS.toHours(this.toLong())
}
2 changes: 2 additions & 0 deletions core/designsystem/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="all_hour">์‹œ๊ฐ„</string>
<string name="all_format_hour">%s์‹œ๊ฐ„</string>

<string name="all_minute">๋ถ„</string>

<string name="all_okay">ํ™•์ธ</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hmh.hamyeonham.core.network.di

import com.hmh.hamyeonham.common.qualifier.Secured
import com.hmh.hamyeonham.core.network.usagegoal.UsageGoalService
import com.hmh.hamyeonham.core.network.usagegoal.DailyChallengeService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -15,5 +15,5 @@ import javax.inject.Singleton
object UsageGoalModule {
@Provides
@Singleton
fun provideUsageGoalApi(@Secured retrofit: Retrofit): UsageGoalService = retrofit.create()
fun provideUsageGoalApi(@Secured retrofit: Retrofit): DailyChallengeService = retrofit.create()
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.hmh.hamyeonham.core.network.usagegoal

import com.hmh.hamyeonham.core.network.model.BaseResponse
import com.hmh.hamyeonham.core.network.usagegoal.model.UsageGoalResponse
import retrofit2.http.GET

interface UsageGoalService {
@GET("api/v1/dailychallenge")
suspend fun getUsageGoal(): BaseResponse<UsageGoalResponse>
}
package com.hmh.hamyeonham.core.network.usagegoal

import com.hmh.hamyeonham.core.network.model.BaseResponse
import com.hmh.hamyeonham.core.network.usagegoal.model.UsageGoalResponse
import retrofit2.http.GET
import retrofit2.http.PATCH

interface DailyChallengeService {
@GET("api/v1/dailychallenge")
suspend fun getUsageGoal(): BaseResponse<UsageGoalResponse>

@PATCH("/api/v1/dailychallenge/failure")
suspend fun updateDailyChallengeFailed(): BaseResponse<Unit>
}
1 change: 1 addition & 0 deletions core/service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
18 changes: 18 additions & 0 deletions core/service/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
hmh("feature")
}

android {
namespace = "com.hmh.hamyeonham.core.service"
}

dependencies {
implementation(projects.core.common)
implementation(projects.core.designsystem)
implementation(projects.core.domain)

implementation(projects.domain.usagestats)

implementation(libs.lifecycle.process)
}
4 changes: 4 additions & 0 deletions core/service/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Loading

0 comments on commit 3755f93

Please sign in to comment.