test build

This commit is contained in:
2025-10-09 23:46:19 +05:00
parent 3abc665b12
commit eb599e88ca
73 changed files with 1378 additions and 187 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.claude
*.iml
.gradle
/local.properties
@@ -13,3 +14,5 @@
.externalNativeBuild
.cxx
local.properties
app/build/outputs/apk/*
app/release/app-release.apk

6
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

10
.idea/deploymentTargetSelector.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

7
.idea/gradle.xml generated
View File

@@ -1,11 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>

2
.idea/misc.xml generated
View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

7
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/ScreenshotAssistant" vcs="Git" />
</component>
</project>

48
app/build.gradle Normal file
View File

@@ -0,0 +1,48 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.customassistant'
compileSdk 34
defaultConfig {
applicationId "com.customassistant"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.preference:preference-ktx:1.2.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

View File

@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.customassistant",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

View File

@@ -2,6 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -10,7 +14,9 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CustomAssistant">
android:theme="@style/Theme.CustomAssistant"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
@@ -18,10 +24,47 @@
android:theme="@style/Theme.CustomAssistant">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AssistantActivity"
android:exported="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:excludeFromRecents="true"
android:noHistory="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1000">
<action android:name="android.intent.action.VOICE_COMMAND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1000">
<action android:name="android.speech.action.VOICE_SEARCH_HANDS_FREE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".CustomAssistantService"
android:permission="android.permission.BIND_VOICE_INTERACTION"
android:exported="true">
<meta-data
android:name="android.voice_interaction"
android:resource="@xml/assistant_service_config" />
<intent-filter>
<action android:name="android.service.voice.VoiceInteractionService" />
</intent-filter>
</service>
<service
android:name=".CustomAssistantSessionService"
android:permission="android.permission.BIND_VOICE_INTERACTION"
android:exported="false" />
</application>
</manifest>

View File

@@ -0,0 +1,9 @@
package com.customassistant
data class ActionItem(
val type: ActionType,
val title: String,
val description: String,
val packageName: String? = null,
val isSelected: Boolean = false
)

View File

@@ -0,0 +1,6 @@
package com.customassistant
enum class ActionType {
TOGGLE_FLASHLIGHT,
LAUNCH_APP
}

View File

@@ -0,0 +1,68 @@
package com.customassistant
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class ActionsAdapter(
private val actions: MutableList<ActionItem>,
private val onActionSelected: (ActionItem) -> Unit
) : RecyclerView.Adapter<ActionsAdapter.ActionViewHolder>() {
private var selectedPosition = -1
class ActionViewHolder(
private val rbAction: RadioButton,
private val tvTitle: TextView,
private val tvDescription: TextView
) : RecyclerView.ViewHolder(rbAction.parent as ViewGroup) {
fun bind(action: ActionItem, isSelected: Boolean, onSelected: () -> Unit) {
rbAction.isChecked = isSelected
tvTitle.text = action.title
tvDescription.text = action.description
itemView.setOnClickListener {
onSelected()
}
rbAction.setOnClickListener {
onSelected()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActionViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_action, parent, false)
return ActionViewHolder(
view.findViewById(R.id.rbAction),
view.findViewById(R.id.tvActionTitle),
view.findViewById(R.id.tvActionDescription)
)
}
override fun onBindViewHolder(holder: ActionViewHolder, position: Int) {
val action = actions[position]
val isSelected = position == selectedPosition
holder.bind(action, isSelected) {
val previousSelected = selectedPosition
selectedPosition = position
if (previousSelected != -1) {
notifyItemChanged(previousSelected)
}
notifyItemChanged(selectedPosition)
onActionSelected(action)
}
}
override fun getItemCount() = actions.size
fun getSelectedAction(): ActionItem? {
return if (selectedPosition != -1) actions[selectedPosition] else null
}
}

View File

@@ -0,0 +1,34 @@
package com.customassistant
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
class AppLauncher(private val context: Context) {
fun launchApp(packageName: String): Boolean {
return try {
val intent = context.packageManager.getLaunchIntentForPackage(packageName)
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
true
} else {
false
}
} catch (e: Exception) {
e.printStackTrace()
false
}
}
fun getAppName(packageName: String): String? {
return try {
val packageManager = context.packageManager
val applicationInfo = packageManager.getApplicationInfo(packageName, 0)
packageManager.getApplicationLabel(applicationInfo).toString()
} catch (e: PackageManager.NameNotFoundException) {
null
}
}
}

View File

@@ -0,0 +1,49 @@
package com.customassistant
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class AssistantActivity : AppCompatActivity() {
private lateinit var preferenceManager: PreferenceManager
private lateinit var flashlightManager: FlashlightManager
private lateinit var appLauncher: AppLauncher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// No UI - execute action immediately and close
initManagers()
executeStoredAction()
}
private fun initManagers() {
preferenceManager = PreferenceManager(this)
flashlightManager = FlashlightManager(this)
appLauncher = AppLauncher(this)
}
private fun executeStoredAction() {
val (actionType, packageName) = preferenceManager.getSelectedAction()
// Execute action silently
when (actionType) {
ActionType.TOGGLE_FLASHLIGHT -> {
flashlightManager.toggleFlashlight()
finish() // Close immediately after flashlight toggle
}
ActionType.LAUNCH_APP -> {
if (packageName != null) {
appLauncher.launchApp(packageName)
}
finish() // Close immediately after launching app
}
null -> {
// No action configured - just close
finish()
}
}
}
}

View File

@@ -0,0 +1,5 @@
package com.customassistant
import android.service.voice.VoiceInteractionService
class CustomAssistantService : VoiceInteractionService()

View File

@@ -0,0 +1,22 @@
package com.customassistant
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.service.voice.VoiceInteractionSession
class CustomAssistantSession(context: Context) : VoiceInteractionSession(context) {
override fun onShow(args: Bundle?, flags: Int) {
super.onShow(args, flags)
// Launch our assistant activity
val intent = Intent(context, AssistantActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
context.startActivity(intent)
// Hide the session since we're launching our own UI
hide()
}
}

View File

@@ -0,0 +1,8 @@
package com.customassistant
import android.os.Bundle
import android.service.voice.VoiceInteractionSessionService
class CustomAssistantSessionService : VoiceInteractionSessionService() {
override fun onNewSession(bundle: Bundle?) = CustomAssistantSession(this)
}

View File

@@ -0,0 +1,74 @@
package com.customassistant
import android.content.Context
import android.content.SharedPreferences
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
class FlashlightManager(private val context: Context) {
private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private val prefs: SharedPreferences = context.getSharedPreferences("flashlight_prefs", Context.MODE_PRIVATE)
private var cameraId: String? = null
companion object {
private const val KEY_FLASHLIGHT_STATE = "flashlight_on"
}
init {
try {
cameraId = cameraManager.cameraIdList[0]
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
fun toggleFlashlight(): Boolean {
return if (isFlashlightOn()) {
turnOffFlashlight()
} else {
turnOnFlashlight()
}
}
private fun turnOnFlashlight(): Boolean {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraId?.let { id ->
cameraManager.setTorchMode(id, true)
saveFlashlightState(true)
true
} ?: false
} else {
false
}
} catch (e: CameraAccessException) {
e.printStackTrace()
false
}
}
private fun turnOffFlashlight(): Boolean {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraId?.let { id ->
cameraManager.setTorchMode(id, false)
saveFlashlightState(false)
true
} ?: false
} else {
false
}
} catch (e: CameraAccessException) {
e.printStackTrace()
false
}
}
private fun saveFlashlightState(isOn: Boolean) {
prefs.edit().putBoolean(KEY_FLASHLIGHT_STATE, isOn).apply()
}
fun isFlashlightOn(): Boolean = prefs.getBoolean(KEY_FLASHLIGHT_STATE, false)
}

View File

@@ -0,0 +1,117 @@
package com.customassistant
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
private lateinit var rvActions: RecyclerView
private lateinit var tvSelectedAction: TextView
private lateinit var btnSaveAction: Button
private lateinit var actionsAdapter: ActionsAdapter
private lateinit var preferenceManager: PreferenceManager
private val actions = mutableListOf<ActionItem>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
preferenceManager = PreferenceManager(this)
initViews()
setupActions()
setupRecyclerView()
setupSaveButton()
}
private fun initViews() {
rvActions = findViewById(R.id.rvActions)
tvSelectedAction = findViewById(R.id.tvSelectedAction)
btnSaveAction = findViewById(R.id.btnSaveAction)
}
private fun setupActions() {
actions.clear()
actions.addAll(
listOf(
ActionItem(
type = ActionType.TOGGLE_FLASHLIGHT,
title = getString(R.string.action_toggle_flashlight),
description = "Turn flashlight on/off"
),
ActionItem(
type = ActionType.LAUNCH_APP,
title = getString(R.string.action_launch_app),
description = "Launch a selected app"
)
)
)
}
private fun setupRecyclerView() {
actionsAdapter = ActionsAdapter(actions) { selectedAction ->
when (selectedAction.type) {
ActionType.LAUNCH_APP -> showAppSelectionDialog()
ActionType.TOGGLE_FLASHLIGHT -> {
tvSelectedAction.text = selectedAction.title
}
}
}
rvActions.layoutManager = LinearLayoutManager(this)
rvActions.adapter = actionsAdapter
}
private fun setupSaveButton() {
btnSaveAction.setOnClickListener {
val selectedAction = actionsAdapter.getSelectedAction()
if (selectedAction != null) {
when (selectedAction.type) {
ActionType.TOGGLE_FLASHLIGHT -> {
preferenceManager.saveSelectedAction(ActionType.TOGGLE_FLASHLIGHT)
Toast.makeText(this, "Flashlight toggle saved!", Toast.LENGTH_SHORT).show()
}
ActionType.LAUNCH_APP -> {
Toast.makeText(this, "Please select an app first", Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(this, "Please select an action", Toast.LENGTH_SHORT).show()
}
}
}
private fun showAppSelectionDialog() {
val packageManager = packageManager
val installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
.filter { packageManager.getLaunchIntentForPackage(it.packageName) != null }
.map {
Pair(it.loadLabel(packageManager).toString(), it.packageName)
}
.sortedBy { it.first }
val appNames = installedApps.map { it.first }.toTypedArray()
AlertDialog.Builder(this)
.setTitle(getString(R.string.select_app))
.setItems(appNames) { _, which ->
val selectedApp = installedApps[which]
tvSelectedAction.text = "Launch: ${selectedApp.first}"
btnSaveAction.setOnClickListener {
preferenceManager.saveSelectedAction(ActionType.LAUNCH_APP, selectedApp.second)
Toast.makeText(this, "App launch saved: ${selectedApp.first}", Toast.LENGTH_SHORT).show()
}
}
.setNegativeButton("Cancel", null)
.show()
}
}

View File

@@ -0,0 +1,28 @@
package com.customassistant
import android.content.Context
import android.content.SharedPreferences
class PreferenceManager(context: Context) {
private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
companion object {
private const val PREFS_NAME = "custom_assistant_prefs"
private const val KEY_SELECTED_ACTION = "selected_action"
private const val KEY_SELECTED_PACKAGE = "selected_package"
}
fun saveSelectedAction(actionType: ActionType, packageName: String? = null) {
prefs.edit()
.putString(KEY_SELECTED_ACTION, actionType.name)
.putString(KEY_SELECTED_PACKAGE, packageName)
.apply()
}
fun getSelectedAction(): Pair<ActionType?, String?> {
val actionName = prefs.getString(KEY_SELECTED_ACTION, null)
val packageName = prefs.getString(KEY_SELECTED_PACKAGE, null)
val actionType = actionName?.let { ActionType.valueOf(it) }
return Pair(actionType, packageName)
}
}

View File

@@ -1,47 +0,0 @@
package sh.sar.customass
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import sh.sar.customass.ui.theme.CustomAssistantTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
CustomAssistantTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
CustomAssistantTheme {
Greeting("Android")
}
}

View File

@@ -1,11 +0,0 @@
package sh.sar.customass.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

View File

@@ -1,58 +0,0 @@
package sh.sar.customass.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun CustomAssistantTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}

View File

@@ -1,34 +0,0 @@
package sh.sar.customass.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="32dp">
<TextView
android:id="@+id/tvActionStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_executed"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="24dp" />
<TextView
android:id="@+id/tvActionDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:gravity="center"
android:layout_marginBottom="32dp" />
<Button
android:id="@+id/btnClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
android:layout_gravity="center" />
</LinearLayout>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_action"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="24dp" />
<TextView
android:id="@+id/tvSelectedAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_action_selected"
android:textSize="18sp"
android:gravity="center"
android:layout_marginBottom="24dp"
android:padding="12dp"
android:background="@android:color/background_light" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvActions"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/btnSaveAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Selected Action"
android:textSize="16sp" />
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<RadioButton
android:id="@+id/rbAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="12dp">
<TextView
android:id="@+id/tvActionTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvActionDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
android:layout_marginTop="4dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,3 +1,11 @@
<resources>
<string name="app_name">Custom Assistant</string>
<string name="action_toggle_flashlight">Toggle Flashlight</string>
<string name="action_launch_app">Launch App</string>
<string name="select_action">Select Action</string>
<string name="no_action_selected">No action selected</string>
<string name="action_executed">Action executed</string>
<string name="select_app">Select App</string>
<string name="flashlight_on">Flashlight ON</string>
<string name="flashlight_off">Flashlight OFF</string>
</resources>

View File

@@ -1,5 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.CustomAssistant" parent="Theme.Material3.DayNight">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
</style>
<style name="Theme.CustomAssistant" parent="android:Theme.Material.Light.NoActionBar" />
<style name="Theme.CustomAssistant.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
android:recognitionService="com.customassistant.CustomAssistantService"
android:sessionService="com.customassistant.CustomAssistantSessionService"
android:supportsAssist="true" />

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
</uses-policies>
</device-admin>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CustomAssistant"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.CustomAssistant">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AssistantActivity"
android:exported="true"
android:theme="@style/Theme.CustomAssistant.NoActionBar">
<intent-filter android:priority="1">
<action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.VOICE_COMMAND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,9 @@
package com.customassistant
data class ActionItem(
val type: ActionType,
val title: String,
val description: String,
val packageName: String? = null,
val isSelected: Boolean = false
)

View File

@@ -0,0 +1,6 @@
package com.customassistant
enum class ActionType {
TOGGLE_FLASHLIGHT,
LAUNCH_APP
}

View File

@@ -0,0 +1,68 @@
package com.customassistant
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.RadioButton
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class ActionsAdapter(
private val actions: MutableList<ActionItem>,
private val onActionSelected: (ActionItem) -> Unit
) : RecyclerView.Adapter<ActionsAdapter.ActionViewHolder>() {
private var selectedPosition = -1
class ActionViewHolder(
private val rbAction: RadioButton,
private val tvTitle: TextView,
private val tvDescription: TextView
) : RecyclerView.ViewHolder(rbAction.parent as ViewGroup) {
fun bind(action: ActionItem, isSelected: Boolean, onSelected: () -> Unit) {
rbAction.isChecked = isSelected
tvTitle.text = action.title
tvDescription.text = action.description
itemView.setOnClickListener {
onSelected()
}
rbAction.setOnClickListener {
onSelected()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActionViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_action, parent, false)
return ActionViewHolder(
view.findViewById(R.id.rbAction),
view.findViewById(R.id.tvActionTitle),
view.findViewById(R.id.tvActionDescription)
)
}
override fun onBindViewHolder(holder: ActionViewHolder, position: Int) {
val action = actions[position]
val isSelected = position == selectedPosition
holder.bind(action, isSelected) {
val previousSelected = selectedPosition
selectedPosition = position
if (previousSelected != -1) {
notifyItemChanged(previousSelected)
}
notifyItemChanged(selectedPosition)
onActionSelected(action)
}
}
override fun getItemCount() = actions.size
fun getSelectedAction(): ActionItem? {
return if (selectedPosition != -1) actions[selectedPosition] else null
}
}

View File

@@ -0,0 +1,34 @@
package com.customassistant
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
class AppLauncher(private val context: Context) {
fun launchApp(packageName: String): Boolean {
return try {
val intent = context.packageManager.getLaunchIntentForPackage(packageName)
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
true
} else {
false
}
} catch (e: Exception) {
e.printStackTrace()
false
}
}
fun getAppName(packageName: String): String? {
return try {
val packageManager = context.packageManager
val applicationInfo = packageManager.getApplicationInfo(packageName, 0)
packageManager.getApplicationLabel(applicationInfo).toString()
} catch (e: PackageManager.NameNotFoundException) {
null
}
}
}

View File

@@ -0,0 +1,92 @@
package com.customassistant
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class AssistantActivity : AppCompatActivity() {
private lateinit var tvActionStatus: TextView
private lateinit var tvActionDetails: TextView
private lateinit var btnClose: Button
private lateinit var preferenceManager: PreferenceManager
private lateinit var flashlightManager: FlashlightManager
private lateinit var appLauncher: AppLauncher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_assistant)
initViews()
initManagers()
executeStoredAction()
setupCloseButton()
}
private fun initViews() {
tvActionStatus = findViewById(R.id.tvActionStatus)
tvActionDetails = findViewById(R.id.tvActionDetails)
btnClose = findViewById(R.id.btnClose)
}
private fun initManagers() {
preferenceManager = PreferenceManager(this)
flashlightManager = FlashlightManager(this)
appLauncher = AppLauncher(this)
}
private fun executeStoredAction() {
val (actionType, packageName) = preferenceManager.getSelectedAction()
if (actionType == null) {
tvActionStatus.text = "No Action Configured"
tvActionDetails.text = "Please configure an action in the main app"
return
}
when (actionType) {
ActionType.TOGGLE_FLASHLIGHT -> {
val success = flashlightManager.toggleFlashlight()
if (success) {
val status = if (flashlightManager.isFlashlightOn()) {
getString(R.string.flashlight_on)
} else {
getString(R.string.flashlight_off)
}
tvActionStatus.text = getString(R.string.action_executed)
tvActionDetails.text = status
} else {
tvActionStatus.text = "Action Failed"
tvActionDetails.text = "Could not toggle flashlight"
}
}
ActionType.LAUNCH_APP -> {
if (packageName != null) {
val appName = appLauncher.getAppName(packageName)
val success = appLauncher.launchApp(packageName)
if (success) {
tvActionStatus.text = getString(R.string.action_executed)
tvActionDetails.text = "Launching ${appName ?: packageName}"
finish()
} else {
tvActionStatus.text = "Action Failed"
tvActionDetails.text = "Could not launch ${appName ?: packageName}"
}
} else {
tvActionStatus.text = "Action Failed"
tvActionDetails.text = "No app configured"
}
}
}
}
private fun setupCloseButton() {
btnClose.setOnClickListener {
finish()
}
}
}

View File

@@ -0,0 +1,65 @@
package com.customassistant
import android.content.Context
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
class FlashlightManager(private val context: Context) {
private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private var cameraId: String? = null
private var isFlashlightOn = false
init {
try {
cameraId = cameraManager.cameraIdList[0]
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
fun toggleFlashlight(): Boolean {
return if (isFlashlightOn) {
turnOffFlashlight()
} else {
turnOnFlashlight()
}
}
private fun turnOnFlashlight(): Boolean {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraId?.let { id ->
cameraManager.setTorchMode(id, true)
isFlashlightOn = true
true
} ?: false
} else {
false
}
} catch (e: CameraAccessException) {
e.printStackTrace()
false
}
}
private fun turnOffFlashlight(): Boolean {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraId?.let { id ->
cameraManager.setTorchMode(id, false)
isFlashlightOn = false
true
} ?: false
} else {
false
}
} catch (e: CameraAccessException) {
e.printStackTrace()
false
}
}
fun isFlashlightOn(): Boolean = isFlashlightOn
}

View File

@@ -0,0 +1,117 @@
package com.customassistant
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
private lateinit var rvActions: RecyclerView
private lateinit var tvSelectedAction: TextView
private lateinit var btnSaveAction: Button
private lateinit var actionsAdapter: ActionsAdapter
private lateinit var preferenceManager: PreferenceManager
private val actions = mutableListOf<ActionItem>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
preferenceManager = PreferenceManager(this)
initViews()
setupActions()
setupRecyclerView()
setupSaveButton()
}
private fun initViews() {
rvActions = findViewById(R.id.rvActions)
tvSelectedAction = findViewById(R.id.tvSelectedAction)
btnSaveAction = findViewById(R.id.btnSaveAction)
}
private fun setupActions() {
actions.clear()
actions.addAll(
listOf(
ActionItem(
type = ActionType.TOGGLE_FLASHLIGHT,
title = getString(R.string.action_toggle_flashlight),
description = "Turn flashlight on/off"
),
ActionItem(
type = ActionType.LAUNCH_APP,
title = getString(R.string.action_launch_app),
description = "Launch a selected app"
)
)
)
}
private fun setupRecyclerView() {
actionsAdapter = ActionsAdapter(actions) { selectedAction ->
when (selectedAction.type) {
ActionType.LAUNCH_APP -> showAppSelectionDialog()
ActionType.TOGGLE_FLASHLIGHT -> {
tvSelectedAction.text = selectedAction.title
}
}
}
rvActions.layoutManager = LinearLayoutManager(this)
rvActions.adapter = actionsAdapter
}
private fun setupSaveButton() {
btnSaveAction.setOnClickListener {
val selectedAction = actionsAdapter.getSelectedAction()
if (selectedAction != null) {
when (selectedAction.type) {
ActionType.TOGGLE_FLASHLIGHT -> {
preferenceManager.saveSelectedAction(ActionType.TOGGLE_FLASHLIGHT)
Toast.makeText(this, "Flashlight toggle saved!", Toast.LENGTH_SHORT).show()
}
ActionType.LAUNCH_APP -> {
Toast.makeText(this, "Please select an app first", Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(this, "Please select an action", Toast.LENGTH_SHORT).show()
}
}
}
private fun showAppSelectionDialog() {
val packageManager = packageManager
val installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
.filter { packageManager.getLaunchIntentForPackage(it.packageName) != null }
.map {
Pair(it.loadLabel(packageManager).toString(), it.packageName)
}
.sortedBy { it.first }
val appNames = installedApps.map { it.first }.toTypedArray()
AlertDialog.Builder(this)
.setTitle(getString(R.string.select_app))
.setItems(appNames) { _, which ->
val selectedApp = installedApps[which]
tvSelectedAction.text = "Launch: ${selectedApp.first}"
btnSaveAction.setOnClickListener {
preferenceManager.saveSelectedAction(ActionType.LAUNCH_APP, selectedApp.second)
Toast.makeText(this, "App launch saved: ${selectedApp.first}", Toast.LENGTH_SHORT).show()
}
}
.setNegativeButton("Cancel", null)
.show()
}
}

View File

@@ -0,0 +1,28 @@
package com.customassistant
import android.content.Context
import android.content.SharedPreferences
class PreferenceManager(context: Context) {
private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
companion object {
private const val PREFS_NAME = "custom_assistant_prefs"
private const val KEY_SELECTED_ACTION = "selected_action"
private const val KEY_SELECTED_PACKAGE = "selected_package"
}
fun saveSelectedAction(actionType: ActionType, packageName: String? = null) {
prefs.edit()
.putString(KEY_SELECTED_ACTION, actionType.name)
.putString(KEY_SELECTED_PACKAGE, packageName)
.apply()
}
fun getSelectedAction(): Pair<ActionType?, String?> {
val actionName = prefs.getString(KEY_SELECTED_ACTION, null)
val packageName = prefs.getString(KEY_SELECTED_PACKAGE, null)
val actionType = actionName?.let { ActionType.valueOf(it) }
return Pair(actionType, packageName)
}
}

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="32dp">
<TextView
android:id="@+id/tvActionStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_executed"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="24dp" />
<TextView
android:id="@+id/tvActionDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:gravity="center"
android:layout_marginBottom="32dp" />
<Button
android:id="@+id/btnClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
android:layout_gravity="center" />
</LinearLayout>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_action"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="24dp" />
<TextView
android:id="@+id/tvSelectedAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_action_selected"
android:textSize="18sp"
android:gravity="center"
android:layout_marginBottom="24dp"
android:padding="12dp"
android:background="@android:color/background_light" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvActions"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/btnSaveAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Selected Action"
android:textSize="16sp" />
</LinearLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<RadioButton
android:id="@+id/rbAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="12dp">
<TextView
android:id="@+id/tvActionTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvActionDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
android:layout_marginTop="4dp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,11 @@
<resources>
<string name="app_name">Custom Assistant</string>
<string name="action_toggle_flashlight">Toggle Flashlight</string>
<string name="action_launch_app">Launch App</string>
<string name="select_action">Select Action</string>
<string name="no_action_selected">No action selected</string>
<string name="action_executed">Action executed</string>
<string name="select_app">Select App</string>
<string name="flashlight_on">Flashlight ON</string>
<string name="flashlight_off">Flashlight OFF</string>
</resources>

View File

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.CustomAssistant" parent="Theme.Material3.DayNight">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
</style>
<style name="Theme.CustomAssistant.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
</full-backup-content>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
<cloud-backup>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
</cloud-backup>
<device-transfer>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
</device-transfer>
</data-extraction-rules>

4
build.gradle Normal file
View File

@@ -0,0 +1,4 @@
plugins {
id 'com.android.application' version '8.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
}

View File

@@ -1,23 +1,5 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
android.enableJetifier=true
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

17
settings.gradle Normal file
View File

@@ -0,0 +1,17 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Custom Assistant"
include ':app'