diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba277b1 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# DemoModeTile + +> Moved to [this repository](https://github.com/AlirezaIvaz/DemoMode). + +You get a screenshot, you get a screenshot, everygets a screenshot! + +It's a very simple tool presented as a Quick Tile to simplify the process of setting up and activating Demo Mode. It's already pre-configured out of the box with perfect 7:00 clock, full WiFi, full signal and full battery icons for stunning clutter-free screenshots. + +For it to work you need to grant it two permissions through adb shell from your computer: + +``` +adb -d shell pm grant ir.alirezaivaz.demo_mode android.permission.DUMP +adb -d shell pm grant ir.alirezaivaz.demo_mode android.permission.WRITE_SECURE_SETTINGS +``` + +The `DUMP` permission is required for the Demo Mode to actually work, and the `WRITE_SECURE_SETTINGS` is necessary for the Quick Tile to read the setting and present the correct icon depending on its state. + +Since these permissions can be a little scary, for transparency sake I've open sourced it https://github.com/franciscofranco/Demo-Mode-tile. diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 88f9d8b..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,96 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -android { - compileSdkVersion 30 - buildToolsVersion "30.0.2" - - defaultConfig { - applicationId "com.franco.demomode" - minSdkVersion 24 - targetSdkVersion 30 - versionName "1.6" - versionCode 1910030257 - archivesBaseName = "DemoModeTile-${android.defaultConfig.versionName}" - } - - signingConfigs { - release { - readKeystoreProperties('release') - } - - debug { - readKeystoreProperties('debug') - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - lintOptions { - abortOnError false - checkAllWarnings false - disable 'InvalidPackage' - } - - packagingOptions { - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/NOTICE.txt' - } - - buildTypes { - release { - debuggable false - minifyEnabled true - shrinkResources true - signingConfig signingConfigs.release - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - - debug { - minifyEnabled false - shrinkResources false - } - } - - buildFeatures { - viewBinding = true - } - kotlinOptions { - jvmTarget = '1.8' - } -} - -def readKeystoreProperties(def configName) { - def propsFile = rootProject.file('../../keystore.properties') - - if (propsFile.exists()) { - def props = new Properties() - props.load(new FileInputStream(propsFile)) - android.signingConfigs[configName].storeFile = file(props['storeFile']) - android.signingConfigs[configName].storePassword = props['storePassword'] - android.signingConfigs[configName].keyAlias = props['keyAlias'] - android.signingConfigs[configName].keyPassword = props['keyPassword'] - } -} - -dependencies { - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.1' - implementation 'androidx.preference:preference-ktx:1.1.1' - implementation "androidx.fragment:fragment-ktx:1.2.5" - implementation "androidx.core:core-ktx:1.3.1" - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9' - - def lifecycle_version = "2.3.0-alpha07" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" -} - -repositories { - mavenCentral() -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..e5bc0c6 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,143 @@ +plugins { + alias(libs.plugins.application) + alias(libs.plugins.kotlin) + kotlin("kapt") +} + +val githubUrl = "https://github.com/AlirezaIvaz/DemoMode" + +android { + namespace = "ir.alirezaivaz.demo_mode" + compileSdk = 33 + + defaultConfig { + applicationId = "ir.alirezaivaz.demo_mode" + minSdk = 24 + targetSdk = 33 + versionName = "1.0.0" + versionCode = 100 + resourceConfigurations += arrayOf( + "en", "fa" + ) + buildConfigField( + "String", + "GITHUB_REPO_URL", + "\"$githubUrl\"" + ) + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + lint { + abortOnError = false + checkAllWarnings = false + disable += "InvalidPackage" + } + + packaging { + resources { + excludes += listOf( + "META-INF/LICENSE.txt", + "META-INF/NOTICE.txt" + ) + } + } + + buildTypes { + release { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + flavorDimensions += "distributor" + productFlavors { + create("github") { + dimension = "distributor" + versionNameSuffix = "-GH" + buildConfigField( + "String", + "DOWNLOAD_LINK", + "\"$githubUrl\"" + ) + buildConfigField( + "String", + "RATE_INTENT", + "\"$githubUrl/issues\"" + ) + buildConfigField( + "String", + "APPS_INTENT", + "\"https://github.com/AlirezaIvaz\"" + ) + } + create("cafebazaar") { + dimension = "distributor" + versionNameSuffix = "-CB" + buildConfigField( + "String", + "DOWNLOAD_LINK", + "\"https://cafebazaar.ir/app/${defaultConfig.applicationId}\"" + ) + buildConfigField( + "String", + "RATE_INTENT", + "\"bazaar://details?id=${defaultConfig.applicationId}\"" + ) + buildConfigField( + "String", + "APPS_INTENT", + "\"bazaar://collection?slug=by_author&aid=alirezaivaz\"" + ) + } + create("myket") { + dimension = "distributor" + versionNameSuffix = "-MK" + buildConfigField( + "String", + "DOWNLOAD_LINK", + "\"https://myket.ir/app/${defaultConfig.applicationId}\"" + ) + buildConfigField( + "String", + "RATE_INTENT", + "\"myket://comment?id=${defaultConfig.applicationId}\"" + ) + buildConfigField( + "String", + "APPS_INTENT", + "\"myket://developer/${defaultConfig.applicationId}\"" + ) + } + } + + buildFeatures { + buildConfig = true + viewBinding = true + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.core.splashscreen) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.browser) + implementation(libs.androidx.fragment.ktx) + implementation(libs.androidx.lifecycle.livedata.ktx) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.preference.ktx) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.material) + implementation(libs.tablericons) + kapt(libs.androidx.lifecycle.compiler) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index a965f92..61d27cc 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -2,7 +2,7 @@ # By default, the flags in this file are appended to flags specified # in /usr/local/opt/android-sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. +# directive in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/app/src/github/res/menu/main.xml b/app/src/github/res/menu/main.xml new file mode 100644 index 0000000..fc50ccd --- /dev/null +++ b/app/src/github/res/menu/main.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 59f7652..74e4cf1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ + xmlns:tools="http://schemas.android.com/tools"> + android:theme="@style/Theme.DemoModeTile" + tools:targetApi="tiramisu"> - + - + + diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..70e5e71 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/franco/demomode/activities/MainActivity.kt b/app/src/main/java/com/franco/demomode/activities/MainActivity.kt deleted file mode 100644 index 4bc9f68..0000000 --- a/app/src/main/java/com/franco/demomode/activities/MainActivity.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.franco.demomode.activities - -import android.content.DialogInterface -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.lifecycleScope -import com.franco.demomode.R -import com.franco.demomode.Utils -import com.franco.demomode.databinding.ActivityMainBinding -import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.launch - -class MainActivity : AppCompatActivity() { - private lateinit var binding: ActivityMainBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) - - setContentView(binding.root) - setSupportActionBar(binding.toolbar) - supportActionBar!!.setDisplayShowTitleEnabled(false) - - val action = intent?.action ?: "" - if (action == Utils.MISSING_PERMISSION) { - Snackbar.make(binding.root, R.string.permissions_need_to_be_granted, - Snackbar.LENGTH_INDEFINITE).apply { - setAction(R.string.ok) { dismiss() } - show() - } - } - - lifecycleScope.launch { - val isDemoModeAllowed = Utils().isDemoModeAllowed(this@MainActivity) - - if (!isDemoModeAllowed) { - AlertDialog.Builder(this@MainActivity) - .setTitle(R.string.demo_mode_allowed_title) - .setMessage(R.string.demo_mode_allowed_message) - .setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int -> dialog.dismiss() } - .show() - } - } - } - - override fun onResume() { - super.onResume() - Utils().setLightNavBar(binding.root) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt b/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt deleted file mode 100644 index 86fd6f4..0000000 --- a/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.franco.demomode.fragments - -import android.os.Bundle -import android.view.View -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.viewModels -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import com.franco.demomode.R -import kotlin.time.ExperimentalTime - -@ExperimentalTime -class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceClickListener { - private lateinit var dumpPermissionPref: Preference - private lateinit var writeSecureSettingsPref: Preference - - private val viewModel by viewModels() - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {} - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - addPreferencesFromResource(R.xml.settings) - - dumpPermissionPref = findPreference(KEY_DUMP)!! - writeSecureSettingsPref = findPreference(KET_WRITE_SECURE_SETTINGS)!! - - dumpPermissionPref.onPreferenceClickListener = this - writeSecureSettingsPref.onPreferenceClickListener = this - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.isDumpPermissionUpdates(requireContext()).observe(viewLifecycleOwner, ::renderDump) - viewModel.isWriteSecureSettingsPermissionUpdates(requireContext()) - .observe(viewLifecycleOwner, ::renderWriteSecureSettings) - } - - private fun renderDump(isGranted: Boolean) { - dumpPermissionPref.summary = when (isGranted) { - true -> getString(R.string.granted) - false -> getString(R.string.not_granted) - } - } - - private fun renderWriteSecureSettings(isGranted: Boolean) { - writeSecureSettingsPref.summary = when (isGranted) { - true -> getString(R.string.granted) - false -> getString(R.string.not_granted) - } - } - - override fun onPreferenceClick(preference: Preference): Boolean { - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.permission_request_title) - .setMessage(when (preference.key) { - KEY_DUMP -> R.string.dump_permission_msg - KET_WRITE_SECURE_SETTINGS -> R.string.write_secure_settings_permission_msg - else -> throw IllegalArgumentException("well, this shouldn't ever happen") - }) - .show() - return false - } - - companion object { - private const val KEY_DUMP = "dump_permission" - private const val KET_WRITE_SECURE_SETTINGS = "write_secure_settings" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/franco/demomode/Utils.kt b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/Utils.kt similarity index 80% rename from app/src/main/java/com/franco/demomode/Utils.kt rename to app/src/main/kotlin/ir/alirezaivaz/demo_mode/Utils.kt index 53523f9..3bfbaa5 100644 --- a/app/src/main/java/com/franco/demomode/Utils.kt +++ b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/Utils.kt @@ -1,15 +1,11 @@ -package com.franco.demomode +package ir.alirezaivaz.demo_mode import android.Manifest -import android.app.Activity import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.os.Build import android.provider.Settings import android.provider.Settings.SettingNotFoundException -import android.view.View -import androidx.core.content.ContextCompat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -109,28 +105,13 @@ class Utils { == PackageManager.PERMISSION_GRANTED) } - suspend fun isWriteSecureSettingsPermissionGranted(context: Context): Boolean = withContext(Dispatchers.IO) { - (context.packageManager.checkPermission( - Manifest.permission.WRITE_SECURE_SETTINGS, context.packageName) - == PackageManager.PERMISSION_GRANTED) - } - - fun setLightNavBar(view: View) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - var flags = view.systemUiVisibility - flags = flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - view.systemUiVisibility = flags - (view.context as Activity).window.navigationBarColor = ContextCompat.getColor(view.context, R.color.primary) - } - } - - fun clearLightNavBar(view: View) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - var flags = view.systemUiVisibility - flags = flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() - view.systemUiVisibility = flags + suspend fun isWriteSecureSettingsPermissionGranted(context: Context): Boolean = + withContext(Dispatchers.IO) { + (context.packageManager.checkPermission( + Manifest.permission.WRITE_SECURE_SETTINGS, context.packageName + ) + == PackageManager.PERMISSION_GRANTED) } - } companion object { private const val DEMO_MODE_ALLOWED = "sysui_demo_allowed" diff --git a/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivityMain.kt b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivityMain.kt new file mode 100644 index 0000000..c49577b --- /dev/null +++ b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivityMain.kt @@ -0,0 +1,277 @@ +package ir.alirezaivaz.demo_mode.activities + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.provider.Settings +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.Toast +import androidx.activity.viewModels +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.appcompat.app.AppCompatActivity +import androidx.browser.customtabs.CustomTabColorSchemeParams +import androidx.browser.customtabs.CustomTabsIntent +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton +import com.google.android.material.snackbar.BaseTransientBottomBar.Duration +import com.google.android.material.snackbar.Snackbar +import ir.alirezaivaz.demo_mode.BuildConfig +import ir.alirezaivaz.demo_mode.R +import ir.alirezaivaz.demo_mode.Utils +import ir.alirezaivaz.demo_mode.databinding.ActivityMainBinding +import ir.alirezaivaz.demo_mode.viewmodel.MainViewModel +import kotlinx.coroutines.launch +import java.io.IOException +import kotlin.time.ExperimentalTime + +@ExperimentalTime +class ActivityMain : AppCompatActivity() { + private val activityMain = this@ActivityMain + private lateinit var binding: ActivityMainBinding + private val viewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + + setContentView(binding.root) + setSupportActionBar(binding.toolbar) + + binding.fab.initGitHubFab() + + viewModel.isDumpPermissionUpdates(activityMain) + .observe(activityMain, ::renderDump) + viewModel.isWriteSecureSettingsPermissionUpdates(activityMain) + .observe(activityMain, ::renderWriteSecureSettings) + + binding.dumpGrant.setOnClickListener { + showGrantPermissionDialog( + ir.alirezaivaz.tablericons.R.drawable.ic_components, + R.string.permission_dump, + Manifest.permission.DUMP + ) + } + binding.writeGrant.setOnClickListener { + showGrantPermissionDialog( + ir.alirezaivaz.tablericons.R.drawable.ic_settings, + R.string.permission_write_secure_settings, + Manifest.permission.WRITE_SECURE_SETTINGS + ) + } + +// grantPermissions() + + val action = intent?.action ?: "" + if (action == Utils.MISSING_PERMISSION) { + Snackbar.make( + binding.root, + R.string.warning_permissions_need_to_be_granted, + Snackbar.LENGTH_INDEFINITE + ).apply { + setAction(R.string.action_ok) { dismiss() } + show() + } + } + + lifecycleScope.launch { + val isDemoModeAllowed = Utils().isDemoModeAllowed(activityMain) + + if (!isDemoModeAllowed) { + MaterialAlertDialogBuilder(activityMain).apply { + setIcon(ir.alirezaivaz.tablericons.R.drawable.ic_progress_alert) + setTitle(R.string.warning_demo_mode_allowed_title) + setMessage(R.string.warning_demo_mode_allowed_message) + setPositiveButton(R.string.action_open_developer) { _, _ -> + startActivity( + Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS) + ) + } + setNegativeButton(R.string.action_cancel, null) + show() + } + } + } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_share -> { + val shareIntent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name)) + putExtra( + Intent.EXTRA_TEXT, + "${getString(R.string.app_name)}\n${BuildConfig.DOWNLOAD_LINK}" + ) + } + startActivity( + Intent.createChooser( + shareIntent, + getString(R.string.action_share_chooser) + ) + ) + } + + R.id.action_rate -> { + try { + val intentAction = if (BuildConfig.FLAVOR == "cafebazaar") + Intent.ACTION_EDIT + else + Intent.ACTION_VIEW + val intent = Intent(intentAction, Uri.parse(BuildConfig.RATE_INTENT)) + startActivity(intent) + } catch (e: Exception) { + binding.root.snackBar(R.string.error_action_failure) + } + } + + R.id.action_apps -> { + try { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.APPS_INTENT)) + startActivity(intent) + } catch (e: Exception) { + binding.root.snackBar(R.string.error_action_failure) + } + } + } + return true + } + + private fun renderDump(isGranted: Boolean) { + if (isGranted) { + with(binding) { + with(dumpStatus) { + setImageResource(ir.alirezaivaz.tablericons.R.drawable.ic_circle_check) + imageTintList = ContextCompat.getColorStateList(activityMain, R.color.green) + } + dumpGrant.isVisible = false + dumpDescription.isVisible = false + dumpDivider.isVisible = false + } + } else { + with(binding) { + with(dumpStatus) { + setImageResource(ir.alirezaivaz.tablericons.R.drawable.ic_progress_alert) + imageTintList = ContextCompat.getColorStateList(activityMain, R.color.orange) + } + dumpDivider.isVisible = true + dumpDescription.isVisible = true + dumpGrant.isVisible = true + } + } + } + + private fun renderWriteSecureSettings(isGranted: Boolean) { + if (isGranted) { + with(binding) { + with(writeStatus) { + setImageResource(ir.alirezaivaz.tablericons.R.drawable.ic_circle_check) + imageTintList = ContextCompat.getColorStateList(activityMain, R.color.green) + } + writeGrant.isVisible = false + writeDescription.isVisible = false + writeDivider.isVisible = false + } + } else { + with(binding) { + with(writeStatus) { + setImageResource(ir.alirezaivaz.tablericons.R.drawable.ic_progress_alert) + imageTintList = ContextCompat.getColorStateList(activityMain, R.color.orange) + } + writeDivider.isVisible = true + writeDescription.isVisible = true + writeGrant.isVisible = true + } + } + } + + private fun showGrantPermissionDialog( + @DrawableRes icon: Int, + @StringRes name: Int, + permission: String + ) { + MaterialAlertDialogBuilder(activityMain).apply { + setIcon(icon) + setTitle(name) + setMessage( + String.format( + getString(R.string.permission_request_description), + getString(name), + packageName, + permission + ) + ) + setPositiveButton(R.string.action_ok, null) + setNeutralButton(R.string.action_grant_root) { _, _ -> + grantPermissionWithRoot(permission) + } + show() + } + } + + private fun grantPermissionWithRoot(permission: String) { + try { + val su = Runtime.getRuntime().exec("su") + val command = "pm grant $packageName $permission\n" + su.outputStream.write(command.toByteArray(charset("UTF-8"))) + su.outputStream.flush() + su.outputStream.write("exit\n".toByteArray(charset("UTF-8"))) + su.outputStream.flush() + } catch (e: IOException) { + binding.root.snackBar(R.string.error_root_access) + } + } + + private fun View.snackBar(message: Int, @Duration length: Int = Snackbar.LENGTH_SHORT) { + Snackbar.make(this, message, length) + .setAnimationMode(Snackbar.ANIMATION_MODE_SLIDE) + .show() + } + + private fun ExtendedFloatingActionButton.initGitHubFab() { + smoothShrink() + this.setOnClickListener { + extend() + smoothShrink() + val params = CustomTabColorSchemeParams.Builder() + .setToolbarColor(ContextCompat.getColor(activityMain, R.color.github)) + .build() + CustomTabsIntent.Builder() + .setDefaultColorSchemeParams(params) + .setShowTitle(true) + .build() + .launchUrl( + activityMain, + Uri.parse(BuildConfig.GITHUB_REPO_URL) + ) + } + setOnLongClickListener { + extend() + smoothShrink() + true + } + } + + private fun ExtendedFloatingActionButton.smoothShrink() { + Handler(Looper.getMainLooper()).postDelayed({ + this.shrink() + }, 2000) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivitySplash.kt b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivitySplash.kt new file mode 100644 index 0000000..5f972da --- /dev/null +++ b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/activities/ActivitySplash.kt @@ -0,0 +1,27 @@ +package ir.alirezaivaz.demo_mode.activities + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.core.splashscreen.SplashScreen +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import kotlin.time.ExperimentalTime + +@ExperimentalTime +class ActivitySplash : AppCompatActivity() { + private lateinit var splashScreen: SplashScreen + override fun onCreate(savedInstanceState: Bundle?) { + splashScreen = installSplashScreen() + super.onCreate(savedInstanceState) + splashScreen.setOnExitAnimationListener { + startActivity( + Intent( + this@ActivitySplash, + ActivityMain::class.java + ) + ) + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) + finish() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/tiles/DemoModeTile.kt similarity index 51% rename from app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt rename to app/src/main/kotlin/ir/alirezaivaz/demo_mode/tiles/DemoModeTile.kt index 6fdb8c0..616bcaf 100644 --- a/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt +++ b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/tiles/DemoModeTile.kt @@ -1,15 +1,17 @@ -package com.franco.demomode.tiles +package ir.alirezaivaz.demo_mode.tiles import android.content.Intent import android.graphics.drawable.Icon import android.service.quicksettings.Tile import android.service.quicksettings.TileService -import com.franco.demomode.R -import com.franco.demomode.Utils -import com.franco.demomode.activities.MainActivity +import ir.alirezaivaz.demo_mode.Utils +import ir.alirezaivaz.demo_mode.activities.ActivityMain +import ir.alirezaivaz.tablericons.R import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import kotlin.time.ExperimentalTime +@ExperimentalTime class DemoModeTile : TileService() { override fun onStartListening() { super.onStartListening() @@ -18,18 +20,25 @@ class DemoModeTile : TileService() { val isDemoModeAllowed = Utils().isDemoModeAllowed(applicationContext) val isDemoMode = Utils().isDemoModeOn(applicationContext) - qsTile?.state = when { - !isDemoModeAllowed -> Tile.STATE_UNAVAILABLE - isDemoMode -> Tile.STATE_ACTIVE - else -> Tile.STATE_INACTIVE - } + with(qsTile) { + state = when { + !isDemoModeAllowed -> Tile.STATE_UNAVAILABLE + isDemoMode -> Tile.STATE_ACTIVE + else -> Tile.STATE_INACTIVE + } + icon = when { + isDemoMode -> Icon.createWithResource( + applicationContext, + R.drawable.ic_tilt_shift + ) - qsTile?.icon = when { - isDemoMode -> Icon.createWithResource(applicationContext, R.drawable.ic_on) - else -> Icon.createWithResource(applicationContext, R.drawable.ic_off) + else -> Icon.createWithResource( + applicationContext, + R.drawable.ic_tilt_shift_off + ) + } + updateTile() } - - qsTile?.updateTile() } } @@ -38,11 +47,12 @@ class DemoModeTile : TileService() { GlobalScope.launch { val hasDumpPermission = Utils().isDumpPermissionGranted(applicationContext) - val hasWriteSecurePermission = Utils().isWriteSecureSettingsPermissionGranted(applicationContext) + val hasWriteSecurePermission = + Utils().isWriteSecureSettingsPermissionGranted(applicationContext) when { !hasDumpPermission || !hasWriteSecurePermission -> { - Intent(applicationContext, MainActivity::class.java).apply { + Intent(applicationContext, ActivityMain::class.java).apply { action = Utils.MISSING_PERMISSION flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK startActivity(this) @@ -50,17 +60,22 @@ class DemoModeTile : TileService() { } else -> { - qsTile?.apply { + with(qsTile) { if (state == Tile.STATE_ACTIVE) { state = Tile.STATE_INACTIVE - icon = Icon.createWithResource(applicationContext, R.drawable.ic_off) + icon = Icon.createWithResource( + applicationContext, + R.drawable.ic_tilt_shift_off + ) Utils().disableDemoMode(applicationContext) } else { state = Tile.STATE_ACTIVE - icon = Icon.createWithResource(applicationContext, R.drawable.ic_on) + icon = Icon.createWithResource( + applicationContext, + R.drawable.ic_tilt_shift + ) Utils().enableDemoMode(applicationContext) } - updateTile() } } diff --git a/app/src/main/java/com/franco/demomode/fragments/SettingsViewModel.kt b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/viewmodel/MainViewModel.kt similarity index 64% rename from app/src/main/java/com/franco/demomode/fragments/SettingsViewModel.kt rename to app/src/main/kotlin/ir/alirezaivaz/demo_mode/viewmodel/MainViewModel.kt index 0da85de..89a05e8 100644 --- a/app/src/main/java/com/franco/demomode/fragments/SettingsViewModel.kt +++ b/app/src/main/kotlin/ir/alirezaivaz/demo_mode/viewmodel/MainViewModel.kt @@ -1,32 +1,30 @@ -package com.franco.demomode.fragments +package ir.alirezaivaz.demo_mode.viewmodel import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData -import com.franco.demomode.Utils +import ir.alirezaivaz.demo_mode.Utils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flow import kotlin.random.Random +import kotlin.time.Duration.Companion.seconds import kotlin.time.ExperimentalTime -import kotlin.time.seconds @ExperimentalTime -class SettingsViewModel : ViewModel() { +class MainViewModel : ViewModel() { fun isDumpPermissionUpdates(context: Context) = flow { while (true) { emit(Utils().isDumpPermissionGranted(context)) - delay(Random.nextLong(1.seconds.toLongMilliseconds(), - 2.seconds.toLongMilliseconds())) + delay(Random.nextLong(1.seconds.inWholeMilliseconds, 2.seconds.inWholeMilliseconds)) } }.asLiveData(Dispatchers.IO) fun isWriteSecureSettingsPermissionUpdates(context: Context) = flow { while (true) { emit(Utils().isWriteSecureSettingsPermissionGranted(context)) - delay(Random.nextLong(1.seconds.toLongMilliseconds(), - 2.seconds.toLongMilliseconds())) + delay(Random.nextLong(1.seconds.inWholeMilliseconds, 2.seconds.inWholeMilliseconds)) } }.asLiveData(Dispatchers.IO) } \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/ic_off.png b/app/src/main/res/drawable-xhdpi/ic_off.png deleted file mode 100644 index 034e705..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_off.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_on.png b/app/src/main/res/drawable-xhdpi/ic_on.png deleted file mode 100644 index a9f376d..0000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_on.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_off.png b/app/src/main/res/drawable-xxhdpi/ic_off.png deleted file mode 100644 index 56eab54..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_off.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_on.png b/app/src/main/res/drawable-xxhdpi/ic_on.png deleted file mode 100644 index 62aef14..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_on.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_off.png b/app/src/main/res/drawable-xxxhdpi/ic_off.png deleted file mode 100644 index 7e8a298..0000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_off.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_on.png b/app/src/main/res/drawable-xxxhdpi/ic_on.png deleted file mode 100644 index e8870e4..0000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_on.png and /dev/null differ diff --git a/app/src/main/res/drawable/bug.xml b/app/src/main/res/drawable/bug.xml deleted file mode 100644 index e6bcb4e..0000000 --- a/app/src/main/res/drawable/bug.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/code_braces.xml b/app/src/main/res/drawable/code_braces.xml deleted file mode 100644 index 50f01a8..0000000 --- a/app/src/main/res/drawable/code_braces.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_black_24dp.xml b/app/src/main/res/drawable/ic_settings_black_24dp.xml deleted file mode 100644 index 24a5623..0000000 --- a/app/src/main/res/drawable/ic_settings_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/twitter.xml b/app/src/main/res/drawable/twitter.xml deleted file mode 100644 index ae08ca6..0000000 --- a/app/src/main/res/drawable/twitter.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/font/poppins.xml b/app/src/main/res/font/poppins.xml new file mode 100644 index 0000000..85d997f --- /dev/null +++ b/app/src/main/res/font/poppins.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/poppins_bold.ttf b/app/src/main/res/font/poppins_bold.ttf new file mode 100644 index 0000000..00559ee Binary files /dev/null and b/app/src/main/res/font/poppins_bold.ttf differ diff --git a/app/src/main/res/font/poppins_regular.ttf b/app/src/main/res/font/poppins_regular.ttf new file mode 100644 index 0000000..9f0c71b Binary files /dev/null and b/app/src/main/res/font/poppins_regular.ttf differ diff --git a/app/src/main/res/font/vazirmatn.xml b/app/src/main/res/font/vazirmatn.xml new file mode 100644 index 0000000..05dc3e3 --- /dev/null +++ b/app/src/main/res/font/vazirmatn.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/vazirmatn_bold.ttf b/app/src/main/res/font/vazirmatn_bold.ttf new file mode 100644 index 0000000..e10be05 Binary files /dev/null and b/app/src/main/res/font/vazirmatn_bold.ttf differ diff --git a/app/src/main/res/font/vazirmatn_regular.ttf b/app/src/main/res/font/vazirmatn_regular.ttf new file mode 100644 index 0000000..89a1211 Binary files /dev/null and b/app/src/main/res/font/vazirmatn_regular.ttf differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 056a9b7..e923fed 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,27 +1,218 @@ - + android:fitsSystemWindows="true"> - + android:layout_height="wrap_content" + android:fitsSystemWindows="true"> - - + android:layout_height="?attr/collapsingToolbarLayoutLargeSize" + android:fitsSystemWindows="true" + app:collapsedTitleTextAppearance="@style/TextAppearance.DemoModeTile.TitleLarge" + app:expandedTitleTextAppearance="@style/TextAppearance.DemoModeTile.HeadlineMedium" + app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> + + - + + + - \ No newline at end of file + android:layout_height="match_parent" + android:overScrollMode="always" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml new file mode 100644 index 0000000..efae070 --- /dev/null +++ b/app/src/main/res/menu/main.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..a83cd23 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..a83cd23 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..933d630 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..6f71f2c Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9502653 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..8235174 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..3b5d1df Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..ae8ef61 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..3481a19 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..ba930f4 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..fe155f2 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..66c0d04 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index f734513..85ed72d 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..e793926 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..cab1634 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..ceb9154 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e12cfbc Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 6404cbc..7fa9b59 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..d51d521 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..893a935 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..4002d8e Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..dc8b203 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index a3eb3f0..d43a4be 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..a567309 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..15f3163 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..70f45a3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..66aafa1 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000..58f7efd --- /dev/null +++ b/app/src/main/res/values-fa/strings.xml @@ -0,0 +1,43 @@ + + + کاشی حالت نمایشی + حالت نمایشی + گیت‌هاب + ایشوها در گیت‌هاب + نمایهٔ گیت‌هاب + هم‌رسانی + هم‌رسانی با… + امتیاز به برنامه + برنامه‌های بیشتر + بازکردن گزینه‌های برنامه‌نویسان + اعطای دسترسی + اعطا با روت + باشه + انصراف + دسترسی‌ها + + "برای این‌که این برنامه به‌درستی کار کند به دسترسی‌های زیر نیاز داریم. از آن‌جا که این دسترسی‌ها بخشی‌از" + "دسترسی‌های محافظت‌شده هستند، برای اعطای آن‌ها به برنامه باید از فرمان adb shell در رایانه شخصی " + "یا از ترمینال با دسترسی روت استفاده کنید." + + دسترسی به گزارش دامپ سامانه + برای شناسایی و تنظیم درست وضعیت کاشی تنظیمات سریع به این دسترسی نیاز داریم. + نوشتن تنظیمات امن سامانه + برای تغییر تنظیمات حالت نمایشی به این دسترسی نیاز داریم. + درخواست دسترسی کاشی حالت نمایشی + + "برای این‌که این برنامه کار کند نیاز دارد که دسترسی %1$s اعطا شود. متاسفانه اعطای این دسترسی " + "تنها از طریق دستور adb shell در رایانه شما امکان‌پذیر است:\n\n" + "adb -d shell pm grant %2$s %3$s\n\n" + "هم‌چنین اگر دسترسی روت دارید، می‌توانید با کلیک روی دکمه «اعطا با روت» این دسترسی را به‌صورت " + "خودکار به برنامه اعطا کنید." + + برای این‌که کاشی کار کند باید هر دو دسترسی داده شود! + حالت نمایشی مجاز نیست! + + "خواهشمندیم مطمئن شوید که حالت نمایشی در گزینه‌های برنامه‌نویسان را فعال کرده‌اید؛ " + "زیرا تا زمانی که آن‌را فعال نکرده باشید کاشی برنامه به‌درستی کار نخواهد کرد." + + مشکلی در تکمیل این کنش رخ داد! + دسترسی روت رد شد! + diff --git a/app/src/main/res/values-fa/styles.xml b/app/src/main/res/values-fa/styles.xml new file mode 100644 index 0000000..c8b9295 --- /dev/null +++ b/app/src/main/res/values-fa/styles.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml new file mode 100644 index 0000000..2375aa2 --- /dev/null +++ b/app/src/main/res/values-land/dimens.xml @@ -0,0 +1,3 @@ + + 48dp + \ No newline at end of file diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml new file mode 100644 index 0000000..4436067 --- /dev/null +++ b/app/src/main/res/values-w1240dp/dimens.xml @@ -0,0 +1,3 @@ + + 200dp + \ No newline at end of file diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml new file mode 100644 index 0000000..2375aa2 --- /dev/null +++ b/app/src/main/res/values-w600dp/dimens.xml @@ -0,0 +1,3 @@ + + 48dp + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..bbe9bc0 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e663c5e..5a86975 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,5 +1,6 @@ - #5DE8D0 - #7B1FA2 + #FF9800 + #4CAF50 + #24292F diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..3390183 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ + + 8dp + 16dp + 16dp + 16dp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b636baa..6b3f589 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,18 +1,42 @@ Demo Mode tile - Demo mode - Demo mode tile permission request - For this app to work it needs DUMP permission to be granted. Unfortunately that is only possible through adb shell from your computer:\n\nadb -d shell pm grant com.franco.demomode android.permission.DUMP\n\nFor transparency this app\'s source code is available. - For this app to work it needs WRITE_SECURE_SETTINGS permission to be granted. Unfortunately that is only possible through adb shell from your computer:\n\nadb -d shell pm grant com.franco.demomode android.permission.WRITE_SECURE_SETTINGS\n\nFor transparency this app\'s source code is available. - OK - DUMP - WRITE_SECURE_SETTINGS - Not granted - Permissions - Granted - Follow me - Source code - Both permissions need to be granted for the tile to work - Tip! - Make sure you allow demo mode to run by enabling it on Android settings, otherwise this tile might not work + Demo mode + GitHub + GitHub issues + GitHub profile + Share + Share via… + Rate + More apps + Open developer options + Grant permission + Grant with root + OK + Cancel + Permissions + + "We need the following permissions for this app to work properly. Since these " + "permissions are among the protected permissions, to grant them to the app you " + "need to use the adb shell command on the PC or from the terminal with root access." + + Access to system dump report + We need this permission to identify and set the status of the tile correctly. + Write secure settings + We need this permission to change demo mode settings. + @string/app_name + + "For this app to work, it needs %1$s permission to be granted. " + "Unfortunately that is only possible through adb shell from your PC:\n\n" + "adb -d shell pm grant %2$s %3$s\n\n" + "Also if you've root access, you can grant it automatically by " + "clicking on the 'Grant with root' button at below" + + Both permissions need to be granted for the tile to work + Demo mode not allowed! + + "Please make sure you're turned on demo mode in developer options; " + "Because the tile won't works properly until you turned it on!" + + Failed to complete this action! + Root access denied! diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7a6748f..5344fd4 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,10 +1,35 @@ - + - + + + + + + + + + diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..ca71411 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..d806339 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml new file mode 100644 index 0000000..7a6ee38 --- /dev/null +++ b/app/src/main/res/xml/locales_config.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml deleted file mode 100644 index 1ec91a5..0000000 --- a/app/src/main/res/xml/settings.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index e7166b7..0000000 --- a/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -buildscript { - ext.kotlin_version = '1.4.10' - repositories { - jcenter() - google() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.2.0-alpha12' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - jcenter() - google() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..df60f77 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,4 @@ +plugins { + alias(libs.plugins.application) apply false + alias(libs.plugins.kotlin) apply false +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 4fc032a..3e89fcd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,23 @@ -org.gradle.jvmargs=-Xmx1536m -android.useAndroidX=true \ No newline at end of file + # 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. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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": +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 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..a2b2fd5 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,34 @@ +[versions] +android = "8.0.2" +fragment-ktx = "1.5.7" +kotlin = "1.8.0" +androidx-core = "1.10.1" +androidx-core-splashscreen = "1.0.1" +androidx-appcompat = "1.6.1" +androidx-browser = "1.5.0" +androidx-fragment = "1.6.0" +androidx-lifecycle = "2.6.1" +androidx-preference = "1.2.0" +kotlinx-coroutines-core = "1.4.3" +material = "1.9.0" +tablericons = "0.9.0" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core" } +androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } +androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } +androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment" } +androidx-lifecycle-compiler = { group = "androidx.lifecycle", name = "lifecycle-compiler", version.ref = "androidx-lifecycle" } +androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } +androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "androidx-preference" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +tablericons = { group = "ir.alirezaivaz", name = "tablericons", version.ref = "tablericons" } + +[plugins] +application = { id = "com.android.application", version.ref = "android" } +kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } + +[bundles] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 83d6bd2..25f7b87 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index e7b4def..0000000 --- a/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..8d5a641 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven("https://jitpack.io") + } +} +include(":app")