Skip to content

Commit

Permalink
Revert settings via notification (#206)
Browse files Browse the repository at this point in the history
* Added Notification

* Added Notification Button to revert settings

* Move broadcast receiver to a module
  • Loading branch information
JackEblan authored Nov 2, 2024
1 parent dc427cd commit 8a3eedd
Show file tree
Hide file tree
Showing 57 changed files with 732 additions and 157 deletions.
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ android {

defaultConfig {
applicationId = "com.android.geto"
versionCode = 160
versionName = "1.16.0"
versionCode = 161
versionName = "1.16.1"

// Custom test runner to set up Hilt dependency graph
testInstrumentationRunner = "com.android.geto.core.testing.GetoTestRunner"
Expand Down Expand Up @@ -71,6 +71,8 @@ dependencies {
implementation(projects.feature.home)
implementation(projects.feature.settings)

implementation(projects.broadcastReceiver)

implementation(libs.androidx.activity.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.core.ktx)
Expand Down
3 changes: 2 additions & 1 deletion app/release-badging.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package: name='com.android.geto' versionCode='160' versionName='1.16.0' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14'
package: name='com.android.geto' versionCode='161' versionName='1.16.1' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14'
sdkVersion:'21'
targetSdkVersion:'34'
uses-permission: name='android.permission.POST_NOTIFICATIONS'
uses-permission: name='android.permission.WRITE_SECURE_SETTINGS'
uses-permission: name='com.android.geto.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION'
application-label:'Geto'
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />

<application
android:name=".GetoApplication"
android:allowBackup="true"
Expand Down
97 changes: 36 additions & 61 deletions app/src/main/kotlin/com/android/geto/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package com.android.geto

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
Expand Down Expand Up @@ -55,48 +54,28 @@ class MainActivity : ComponentActivity() {

var mainActivityUiState: MainActivityUiState by mutableStateOf(MainActivityUiState.Loading)

// Update the uiState
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.onEach { mainActivityUiState = it }.collect()
}
}

// Keep the splash screen on-screen until the UI state is loaded. This condition is
// evaluated each time the app needs to be redrawn so it should be fast to avoid blocking
// the UI.
splashScreen.setKeepOnScreenCondition {
when (mainActivityUiState) {
MainActivityUiState.Loading -> true
is MainActivityUiState.Success -> false
}
}

// Turn off the decor fitting system windows, which allows us to handle insets,
// including IME animations, and go edge-to-edge
// This also sets up the initial system bar style based on the platform theme
enableEdgeToEdge()

setContent {
val darkTheme = shouldUseDarkTheme(mainActivityUiState)

val navController = rememberNavController()

// Update the edge to edge configuration to match the theme
// This is the same parameters as the default enableEdgeToEdge call, but we manually
// resolve whether or not to show dark theme using uiState, since it can be different
// than the configuration's dark theme value based on the user preference.
DisposableEffect(darkTheme) {
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(
android.graphics.Color.TRANSPARENT,
android.graphics.Color.TRANSPARENT,
) { darkTheme },
navigationBarStyle = SystemBarStyle.auto(
lightScrim,
darkScrim,
) { darkTheme },
)
enableEdgeToEdge()
onDispose {}
}

Expand All @@ -112,50 +91,46 @@ class MainActivity : ComponentActivity() {
}
}
}
}

@Composable
private fun shouldUseGreenTheme(
mainActivityUiState: MainActivityUiState,
): Boolean = when (mainActivityUiState) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> when (mainActivityUiState.userData.themeBrand) {
ThemeBrand.GREEN -> true
ThemeBrand.PURPLE -> false
@Composable
private fun shouldUseGreenTheme(
state: MainActivityUiState,
): Boolean = when (state) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> when (state.userData.themeBrand) {
ThemeBrand.GREEN -> true
ThemeBrand.PURPLE -> false
}
}
}

@Composable
private fun shouldUsePurpleTheme(
mainActivityUiState: MainActivityUiState,
): Boolean = when (mainActivityUiState) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> when (mainActivityUiState.userData.themeBrand) {
ThemeBrand.GREEN -> false
ThemeBrand.PURPLE -> true
@Composable
private fun shouldUsePurpleTheme(
state: MainActivityUiState,
): Boolean = when (state) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> when (state.userData.themeBrand) {
ThemeBrand.GREEN -> false
ThemeBrand.PURPLE -> true
}
}
}

@Composable
private fun shouldUseDynamicTheme(
mainActivityUiState: MainActivityUiState,
): Boolean = when (mainActivityUiState) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> mainActivityUiState.userData.useDynamicColor
}
@Composable
private fun shouldUseDynamicTheme(
state: MainActivityUiState,
): Boolean = when (state) {
MainActivityUiState.Loading -> false
is MainActivityUiState.Success -> state.userData.useDynamicColor
}

@Composable
private fun shouldUseDarkTheme(
uiState: MainActivityUiState,
): Boolean = when (uiState) {
MainActivityUiState.Loading -> isSystemInDarkTheme()
is MainActivityUiState.Success -> when (uiState.userData.darkThemeConfig) {
DarkThemeConfig.FOLLOW_SYSTEM -> isSystemInDarkTheme()
DarkThemeConfig.LIGHT -> false
DarkThemeConfig.DARK -> true
@Composable
private fun shouldUseDarkTheme(
state: MainActivityUiState,
): Boolean = when (state) {
MainActivityUiState.Loading -> isSystemInDarkTheme()
is MainActivityUiState.Success -> when (state.userData.darkThemeConfig) {
DarkThemeConfig.FOLLOW_SYSTEM -> isSystemInDarkTheme()
DarkThemeConfig.LIGHT -> false
DarkThemeConfig.DARK -> true
}
}
}

private val lightScrim = android.graphics.Color.argb(0xe6, 0xFF, 0xFF, 0xFF)

private val darkScrim = android.graphics.Color.argb(0x80, 0x1b, 0x1b, 0x1b)
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import com.android.geto.navigation.TopLevelDestination.APPS
import com.android.geto.navigation.TopLevelDestination.SETTINGS

@Composable
fun GetoNavHost(navController: NavHostController) {
fun GetoNavHost(
navController: NavHostController,
) {
val snackbarHostState = remember {
SnackbarHostState()
}
Expand Down
1 change: 1 addition & 0 deletions broadcast-receiver/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@
* limitations under the License.
*
*/
package com.android.geto.core.data.test.repository

import com.android.geto.core.data.repository.ClipboardRepository
import javax.inject.Inject
plugins {
alias(libs.plugins.com.android.geto.library)
alias(libs.plugins.com.android.geto.hilt)
}

class FakeClipboardRepository @Inject constructor() : ClipboardRepository {
override fun setPrimaryClip(label: String, text: String): Boolean {
return false
}
android {
namespace = "com.android.geto.broadcastreceiver"
}

dependencies {
implementation(libs.androidx.core.ktx)
implementation(projects.core.common)
implementation(projects.core.domain)
implementation(projects.core.model)

implementation(projects.framework.notificationManager)
}
Empty file.
21 changes: 21 additions & 0 deletions broadcast-receiver/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
31 changes: 31 additions & 0 deletions broadcast-receiver/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~
~ Copyright 2023 Einstein Blanco
~
~ Licensed under the GNU General Public License v3.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.gnu.org/licenses/gpl-3.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<receiver
android:name=".RevertSettingsBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="ACTION_REVERT_SETTINGS" />
</intent-filter>
</receiver>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
*
* Copyright 2023 Einstein Blanco
*
* Licensed under the GNU General Public License v3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/gpl-3.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.android.geto.broadcastreceiver

import com.android.geto.core.domain.RevertAppSettingsUseCase
import com.android.geto.core.model.AppSettingsResult
import com.android.geto.framework.notificationmanager.NotificationManagerWrapper

internal class BroadcastReceiverController(
private val revertAppSettingsUseCase: RevertAppSettingsUseCase,
private val notificationManagerWrapper: NotificationManagerWrapper,
) {
suspend fun revertSettings(packageName: String?, notificationId: Int?) {
if (packageName == null || notificationId == null) return

if (revertAppSettingsUseCase(packageName = packageName) == AppSettingsResult.Success) {
notificationManagerWrapper.cancel(notificationId)
}
}
}
Loading

0 comments on commit 8a3eedd

Please sign in to comment.