diff --git a/.gitignore b/.gitignore
index 39fb081..5393359 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,8 @@
*.iml
.gradle
/local.properties
-/.idea/workspace.xml
-/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
+/.idea
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43e..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index e7bedf3..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 7ac24c7..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 635999d..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 1fff92a..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index c4613a2..88f9d8b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,16 @@
apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
android {
- compileSdkVersion 26
- buildToolsVersion "26.0.1"
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.franco.demomode"
minSdkVersion 24
- targetSdkVersion 26
- versionName "1.2"
- versionCode getVersionCodeTimestamp()
+ targetSdkVersion 30
+ versionName "1.6"
+ versionCode 1910030257
archivesBaseName = "DemoModeTile-${android.defaultConfig.versionName}"
}
@@ -46,15 +47,20 @@ android {
shrinkResources true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- manifestPlaceholders = [vmSafeModeEnabled: "false"]
}
debug {
minifyEnabled false
shrinkResources false
- manifestPlaceholders = [vmSafeModeEnabled: "true"]
}
}
+
+ buildFeatures {
+ viewBinding = true
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
}
def readKeystoreProperties(def configName) {
@@ -70,13 +76,21 @@ def readKeystoreProperties(def configName) {
}
}
-static def getVersionCodeTimestamp() {
- return new Date().format('yyMMddHHmm').toInteger()
+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"
}
-dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:design:26.1.0'
- compile 'com.jakewharton:butterknife:8.8.1'
- annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
+repositories {
+ mavenCentral()
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cdbe115..59f7652 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,31 +1,26 @@
-
+
+ tools:ignore="ProtectedPermissions" />
+ tools:ignore="ProtectedPermissions" />
+ android:theme="@style/DemoModeTheme">
-
+
-
+
-
+
@@ -35,7 +30,7 @@
android:label="@string/demo_mode"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
-
+
diff --git a/app/src/main/java/com/franco/demomode/Utils.java b/app/src/main/java/com/franco/demomode/Utils.java
deleted file mode 100644
index 536ab2d..0000000
--- a/app/src/main/java/com/franco/demomode/Utils.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.franco.demomode;
-
-import android.Manifest;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-
-import com.franco.demomode.application.App;
-
-public class Utils {
- private static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed";
- private static final String DEMO_MODE_ON = "sysui_tuner_demo_on";
- public static final String MISSING_PERMISSION = "missing_permission";
-
- public static void enableDemoMode() {
- if (!isDemoModeAllowed()) {
- Settings.Global.putInt(App.CONTEXT.getContentResolver(), DEMO_MODE_ALLOWED, 1);
- }
-
- Settings.Global.putInt(App.CONTEXT.getContentResolver(), DEMO_MODE_ON, 1);
-
- // clock with the latest release string
- Intent clock = new Intent("com.android.systemui.demo");
- clock.putExtra("command", "clock");
- clock.putExtra("hhmm", "0800");
- App.CONTEXT.sendBroadcast(clock);
-
- // battery icon needs to be perfect
- Intent battery = new Intent("com.android.systemui.demo");
- battery.putExtra("command", "battery");
- battery.putExtra("level", "100");
- battery.putExtra("plugged", "false");
- App.CONTEXT.sendBroadcast(battery);
-
- // signal icon
- Intent data = new Intent("com.android.systemui.demo");
- data.putExtra("command", "network");
- data.putExtra("mobile", "show");
- data.putExtra("datatype", "hide");
- data.putExtra("level", "4");
- App.CONTEXT.sendBroadcast(data);
-
- // mock sim carrier connection
- Intent signal = new Intent("com.android.systemui.demo");
- signal.putExtra("command", "network");
- signal.putExtra("fully", "true");
- App.CONTEXT.sendBroadcast(signal);
-
- // WiFi icon
- Intent wifi = new Intent("com.android.systemui.demo");
- wifi.putExtra("command", "network");
- wifi.putExtra("wifi", "show");
- wifi.putExtra("level", "4");
- App.CONTEXT.sendBroadcast(wifi);
-
- // rip icons
- Intent miscNetwork = new Intent("com.android.systemui.demo");
- miscNetwork.putExtra("command", "network");
- miscNetwork.putExtra("airplane", "hide");
- miscNetwork.putExtra("nosim", "hide");
- miscNetwork.putExtra("sims", 1);
- App.CONTEXT.sendBroadcast(miscNetwork);
-
-
- // if there's one thing I hate is cluttered statusbar with notifs
- Intent notifs = new Intent("com.android.systemui.demo");
- notifs.putExtra("command", "notifications");
- notifs.putExtra("visible", "false");
- App.CONTEXT.sendBroadcast(notifs);
-
- // goodbye more icons!
- Intent miscIcons = new Intent("com.android.systemui.demo");
- miscIcons.putExtra("command", "status");
- miscIcons.putExtra("bluetooth", "hide");
- miscIcons.putExtra("volume", "hide");
- miscIcons.putExtra("mute", "hide");
- App.CONTEXT.sendBroadcast(miscIcons);
- }
-
- public static void disableDemoMode() {
- Settings.Global.putInt(App.CONTEXT.getContentResolver(), Utils.DEMO_MODE_ON, 0);
-
- Intent enableDemoMode = new Intent("com.android.systemui.demo");
- enableDemoMode.putExtra("command", "exit");
- App.CONTEXT.sendBroadcast(enableDemoMode);
- }
-
- public static boolean isDemoModeAllowed() {
- try {
- return Settings.Global.getInt(App.CONTEXT.getContentResolver(), DEMO_MODE_ALLOWED) == 1;
- } catch (Settings.SettingNotFoundException e) {
- e.printStackTrace();
- return false;
- }
- }
-
- public static boolean isDemoModeOn() {
- return Settings.Global.getInt(App.CONTEXT.getContentResolver(),
- DEMO_MODE_ON, 0) != 0;
- }
-
- public static boolean isDumpPermissionGranted() {
- return App.CONTEXT.getPackageManager().checkPermission(Manifest.permission.DUMP, App.CONTEXT.getPackageName())
- == PackageManager.PERMISSION_GRANTED;
- }
-
- public static boolean isWriteSecureSettingsPermissionGranted() {
- return App.CONTEXT.getPackageManager()
- .checkPermission(Manifest.permission.WRITE_SECURE_SETTINGS, App.CONTEXT.getPackageName())
- == PackageManager.PERMISSION_GRANTED;
- }
-}
diff --git a/app/src/main/java/com/franco/demomode/Utils.kt b/app/src/main/java/com/franco/demomode/Utils.kt
new file mode 100644
index 0000000..53523f9
--- /dev/null
+++ b/app/src/main/java/com/franco/demomode/Utils.kt
@@ -0,0 +1,140 @@
+package com.franco.demomode
+
+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
+
+class Utils {
+ suspend fun enableDemoMode(context: Context) {
+ withContext(Dispatchers.IO) {
+ if (!isDemoModeAllowed(context)) {
+ Settings.Global.putInt(context.contentResolver, DEMO_MODE_ALLOWED, 1)
+ }
+
+ Settings.Global.putInt(context.contentResolver, DEMO_MODE_ON, 1)
+ }
+
+ // clock with the latest release string
+ val clock = Intent("com.android.systemui.demo")
+ clock.putExtra("command", "clock")
+ clock.putExtra("hhmm", "1100")
+ context.sendBroadcast(clock)
+
+ // battery icon needs to be perfect
+ val battery = Intent("com.android.systemui.demo")
+ battery.putExtra("command", "battery")
+ battery.putExtra("level", "100")
+ battery.putExtra("plugged", "false")
+ context.sendBroadcast(battery)
+
+ // signal icon
+ val data = Intent("com.android.systemui.demo")
+ data.putExtra("command", "network")
+ data.putExtra("mobile", "show")
+ data.putExtra("datatype", "hide")
+ data.putExtra("level", "4")
+ context.sendBroadcast(data)
+
+ // mock sim carrier connection
+ val signal = Intent("com.android.systemui.demo")
+ signal.putExtra("command", "network")
+ signal.putExtra("fully", "true")
+ context.sendBroadcast(signal)
+
+ // WiFi icon
+ val wifi = Intent("com.android.systemui.demo")
+ wifi.putExtra("command", "network")
+ wifi.putExtra("wifi", "show")
+ wifi.putExtra("level", "4")
+ context.sendBroadcast(wifi)
+
+ // rip icons
+ val miscNetwork = Intent("com.android.systemui.demo")
+ miscNetwork.putExtra("command", "network")
+ miscNetwork.putExtra("airplane", "hide")
+ miscNetwork.putExtra("nosim", "hide")
+ miscNetwork.putExtra("sims", 1)
+ context.sendBroadcast(miscNetwork)
+
+
+ // if there's one thing I hate is cluttered statusbar with notifs
+ val notifs = Intent("com.android.systemui.demo")
+ notifs.putExtra("command", "notifications")
+ notifs.putExtra("visible", "false")
+ context.sendBroadcast(notifs)
+
+ // goodbye more icons!
+ val miscIcons = Intent("com.android.systemui.demo")
+ miscIcons.putExtra("command", "status")
+ miscIcons.putExtra("bluetooth", "hide")
+ miscIcons.putExtra("volume", "hide")
+ miscIcons.putExtra("mute", "hide")
+ context.sendBroadcast(miscIcons)
+ }
+
+ suspend fun disableDemoMode(context: Context) {
+ withContext(Dispatchers.IO) {
+ Settings.Global.putInt(context.contentResolver, DEMO_MODE_ON, 0)
+ }
+
+ val enableDemoMode = Intent("com.android.systemui.demo")
+ enableDemoMode.putExtra("command", "exit")
+ context.sendBroadcast(enableDemoMode)
+ }
+
+ suspend fun isDemoModeAllowed(context: Context): Boolean = withContext(Dispatchers.IO) {
+ try {
+ Settings.Global.getInt(context.contentResolver, DEMO_MODE_ALLOWED) == 1
+ } catch (e: SettingNotFoundException) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ suspend fun isDemoModeOn(context: Context): Boolean = withContext(Dispatchers.IO) {
+ Settings.Global.getInt(context.contentResolver, DEMO_MODE_ON, 0) != 0
+ }
+
+ suspend fun isDumpPermissionGranted(context: Context): Boolean = withContext(Dispatchers.IO) {
+ (context.packageManager.checkPermission(Manifest.permission.DUMP, context.packageName)
+ == 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
+ }
+ }
+
+ companion object {
+ private const val DEMO_MODE_ALLOWED = "sysui_demo_allowed"
+ private const val DEMO_MODE_ON = "sysui_tuner_demo_on"
+ const val MISSING_PERMISSION = "missing_permission"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/franco/demomode/activities/MainActivity.java b/app/src/main/java/com/franco/demomode/activities/MainActivity.java
deleted file mode 100644
index 58a8365..0000000
--- a/app/src/main/java/com/franco/demomode/activities/MainActivity.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.franco.demomode.activities;
-
-import android.app.AlertDialog;
-import android.os.Bundle;
-import android.os.Process;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.support.annotation.Nullable;
-import android.support.design.widget.Snackbar;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.widget.Toolbar;
-
-import com.franco.demomode.R;
-import com.franco.demomode.Utils;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-
-
-public class MainActivity extends AppCompatActivity {
- @BindView(R.id.toolbar)
- protected Toolbar toolbar;
- @BindView(R.id.root_layout)
- protected View rootLayout;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ButterKnife.bind(this);
-
- setActionBar(toolbar);
-
- if (getIntent() != null) {
- if (getIntent().getAction() != null) {
- if (getIntent().getAction().equals(Utils.MISSING_PERMISSION)) {
- final Snackbar snackbar = Snackbar.make(rootLayout,
- R.string.permissions_need_to_be_granted, Snackbar.LENGTH_INDEFINITE);
- snackbar.setAction(R.string.ok, view -> snackbar.dismiss());
- snackbar.show();
- }
- }
- }
-
- if (!Utils.isDemoModeAllowed()) {
- new AlertDialog.Builder(this)
- .setTitle(R.string.demo_mode_allowed_title)
- .setMessage(R.string.demo_mode_allowed_message)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
- .show();
- }
- }
-
- public static class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener {
- private static final String KEY_DUMP = "dump_permission";
- private static final String KET_WRITE_SECURE_SETTINGS = "write_secure_settings";
-
- private Preference dump;
- private Preference writeSecureSettings;
-
- private Thread permissionsPollThread;
-
- private boolean isDumpPermissionGranted;
- private boolean isWriteSecureSettingsPermissionGranted;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.settings);
-
- dump = findPreference(KEY_DUMP);
- writeSecureSettings = findPreference(KET_WRITE_SECURE_SETTINGS);
-
- dump.setOnPreferenceClickListener(this);
- writeSecureSettings.setOnPreferenceClickListener(this);
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- new AlertDialog.Builder(getActivity())
- .setTitle(R.string.permission_request_title)
- .setMessage(preference.getKey().equals(KEY_DUMP) ?
- R.string.dump_permission_msg :
- R.string.write_secure_settings_permission_msg)
- .show();
-
- return false;
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- isDumpPermissionGranted = Utils.isDumpPermissionGranted();
- isWriteSecureSettingsPermissionGranted = Utils.isWriteSecureSettingsPermissionGranted();
-
- dump.setSummary(isDumpPermissionGranted ? R.string.granted : R.string.not_granted);
- writeSecureSettings.setSummary(isWriteSecureSettingsPermissionGranted
- ? R.string.granted : R.string.not_granted);
-
- // there isn't a listener for when these permissions states change, so we have to poll it
- // Runs in a BG thread so it's ok
- permissionsPollThread = new Thread(new Runnable() {
- long lastNow = System.currentTimeMillis();
-
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- try {
- while (permissionsPollThread != null && permissionsPollThread.isAlive()) {
- if ((lastNow + 1000) < System.currentTimeMillis()) {
- lastNow = System.currentTimeMillis();
-
- if (isDumpPermissionGranted != Utils.isDumpPermissionGranted()) {
- isDumpPermissionGranted = Utils.isDumpPermissionGranted();
-
- getActivity().runOnUiThread(() ->
- dump.setSummary(isDumpPermissionGranted ?
- R.string.granted : R.string.not_granted));
- }
-
- if (isWriteSecureSettingsPermissionGranted != Utils.isWriteSecureSettingsPermissionGranted()) {
- isWriteSecureSettingsPermissionGranted = Utils.isWriteSecureSettingsPermissionGranted();
-
- getActivity().runOnUiThread(() ->
- writeSecureSettings.setSummary(isWriteSecureSettingsPermissionGranted
- ? R.string.granted : R.string.not_granted));
- }
- }
- }
- } catch (Exception ignored) {
- // it's ok to catch the exception here and not treat it properly.
- // not doing anything important and the thread object might be null even after the null check
- // so fail gracefully and in peace
- }
- }
- });
-
- permissionsPollThread.start();
- }
-
- @Override
- public void onStop() {
- super.onStop();
-
- if (permissionsPollThread != null && !permissionsPollThread.isInterrupted()) {
- permissionsPollThread.interrupt();
- permissionsPollThread = null;
- }
- }
- }
-}
diff --git a/app/src/main/java/com/franco/demomode/activities/MainActivity.kt b/app/src/main/java/com/franco/demomode/activities/MainActivity.kt
new file mode 100644
index 0000000..4bc9f68
--- /dev/null
+++ b/app/src/main/java/com/franco/demomode/activities/MainActivity.kt
@@ -0,0 +1,51 @@
+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/application/App.java b/app/src/main/java/com/franco/demomode/application/App.java
deleted file mode 100644
index 2fbe6cc..0000000
--- a/app/src/main/java/com/franco/demomode/application/App.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.franco.demomode.application;
-
-import android.app.Application;
-import android.content.Context;
-
-public class App extends Application {
- public static Context CONTEXT;
-
- @Override
- public void onCreate() {
- super.onCreate();
- CONTEXT = this;
- }
-}
diff --git a/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt b/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt
new file mode 100644
index 0000000..86fd6f4
--- /dev/null
+++ b/app/src/main/java/com/franco/demomode/fragments/SettingsFragment.kt
@@ -0,0 +1,71 @@
+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/fragments/SettingsViewModel.kt b/app/src/main/java/com/franco/demomode/fragments/SettingsViewModel.kt
new file mode 100644
index 0000000..0da85de
--- /dev/null
+++ b/app/src/main/java/com/franco/demomode/fragments/SettingsViewModel.kt
@@ -0,0 +1,32 @@
+package com.franco.demomode.fragments
+
+import android.content.Context
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.asLiveData
+import com.franco.demomode.Utils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.flow
+import kotlin.random.Random
+import kotlin.time.ExperimentalTime
+import kotlin.time.seconds
+
+@ExperimentalTime
+class SettingsViewModel : ViewModel() {
+
+ fun isDumpPermissionUpdates(context: Context) = flow {
+ while (true) {
+ emit(Utils().isDumpPermissionGranted(context))
+ delay(Random.nextLong(1.seconds.toLongMilliseconds(),
+ 2.seconds.toLongMilliseconds()))
+ }
+ }.asLiveData(Dispatchers.IO)
+
+ fun isWriteSecureSettingsPermissionUpdates(context: Context) = flow {
+ while (true) {
+ emit(Utils().isWriteSecureSettingsPermissionGranted(context))
+ delay(Random.nextLong(1.seconds.toLongMilliseconds(),
+ 2.seconds.toLongMilliseconds()))
+ }
+ }.asLiveData(Dispatchers.IO)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.java b/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.java
deleted file mode 100644
index b4b5a6a..0000000
--- a/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.franco.demomode.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;
-
-public class DemoModeTile extends TileService {
- @Override
- public void onCreate() {
- super.onCreate();
- }
-
- @Override
- public void onStartListening() {
- super.onStartListening();
-
- getQsTile().setState(Utils.isDemoModeOn() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
- getQsTile().setIcon(Utils.isDemoModeOn() ?
- Icon.createWithResource(getApplicationContext(), R.drawable.ic_on) :
- Icon.createWithResource(getApplicationContext(), R.drawable.ic_off));
- getQsTile().updateTile();
- }
-
- @Override
- public void onClick() {
- super.onClick();
-
- if (!Utils.isDumpPermissionGranted() || !Utils.isWriteSecureSettingsPermissionGranted()) {
- Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class);
- mainActivity.setAction(Utils.MISSING_PERMISSION);
- mainActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(mainActivity);
- } else {
- if (getQsTile().getState() == Tile.STATE_ACTIVE) {
- getQsTile().setState(Tile.STATE_INACTIVE);
- getQsTile().setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.ic_off));
- getQsTile().updateTile();
-
- Utils.disableDemoMode();
- } else {
- getQsTile().setState(Tile.STATE_ACTIVE);
- getQsTile().setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.ic_on));
- getQsTile().updateTile();
-
- Utils.enableDemoMode();
- }
- }
- }
-}
diff --git a/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt b/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt
new file mode 100644
index 0000000..6fdb8c0
--- /dev/null
+++ b/app/src/main/java/com/franco/demomode/tiles/DemoModeTile.kt
@@ -0,0 +1,70 @@
+package com.franco.demomode.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 kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+
+class DemoModeTile : TileService() {
+ override fun onStartListening() {
+ super.onStartListening()
+
+ GlobalScope.launch {
+ 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
+ }
+
+ qsTile?.icon = when {
+ isDemoMode -> Icon.createWithResource(applicationContext, R.drawable.ic_on)
+ else -> Icon.createWithResource(applicationContext, R.drawable.ic_off)
+ }
+
+ qsTile?.updateTile()
+ }
+ }
+
+ override fun onClick() {
+ super.onClick()
+
+ GlobalScope.launch {
+ val hasDumpPermission = Utils().isDumpPermissionGranted(applicationContext)
+ val hasWriteSecurePermission = Utils().isWriteSecureSettingsPermissionGranted(applicationContext)
+
+ when {
+ !hasDumpPermission || !hasWriteSecurePermission -> {
+ Intent(applicationContext, MainActivity::class.java).apply {
+ action = Utils.MISSING_PERMISSION
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ startActivity(this)
+ }
+ }
+
+ else -> {
+ qsTile?.apply {
+ if (state == Tile.STATE_ACTIVE) {
+ state = Tile.STATE_INACTIVE
+ icon = Icon.createWithResource(applicationContext, R.drawable.ic_off)
+ Utils().disableDemoMode(applicationContext)
+ } else {
+ state = Tile.STATE_ACTIVE
+ icon = Icon.createWithResource(applicationContext, R.drawable.ic_on)
+ Utils().enableDemoMode(applicationContext)
+ }
+
+ updateTile()
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-xhdpi/ic_demo_off.png b/app/src/main/res/drawable-xhdpi/ic_demo_off.png
deleted file mode 100644
index 1e54e21..0000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_demo_off.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_demo_on.png b/app/src/main/res/drawable-xhdpi/ic_demo_on.png
deleted file mode 100644
index b04ce48..0000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_demo_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_demo_off.png b/app/src/main/res/drawable-xxhdpi/ic_demo_off.png
deleted file mode 100644
index ccbca1a..0000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_demo_off.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_demo_on.png b/app/src/main/res/drawable-xxhdpi/ic_demo_on.png
deleted file mode 100644
index b55c563..0000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_demo_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_demo_off.png b/app/src/main/res/drawable-xxxhdpi/ic_demo_off.png
deleted file mode 100644
index 3c8545e..0000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_demo_off.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_demo_on.png b/app/src/main/res/drawable-xxxhdpi/ic_demo_on.png
deleted file mode 100644
index 0c2a5d2..0000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_demo_on.png and /dev/null differ
diff --git a/app/src/main/res/drawable/bug.xml b/app/src/main/res/drawable/bug.xml
new file mode 100644
index 0000000..e6bcb4e
--- /dev/null
+++ b/app/src/main/res/drawable/bug.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ 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
new file mode 100644
index 0000000..50f01a8
--- /dev/null
+++ b/app/src/main/res/drawable/code_braces.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ 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
new file mode 100644
index 0000000..24a5623
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/twitter.xml b/app/src/main/res/drawable/twitter.xml
new file mode 100644
index 0000000..ae08ca6
--- /dev/null
+++ b/app/src/main/res/drawable/twitter.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 5caafb8..056a9b7 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,20 +1,27 @@
-
-
+ android:layout_height="?attr/actionBarSize"
+ android:gravity="center">
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-fr/string.xml b/app/src/main/res/values-fr/string.xml
deleted file mode 100644
index 9d050cf..0000000
--- a/app/src/main/res/values-fr/string.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
- Demo Mode tile
- Demo mode
- Autorisations
- Pour que cette application fonctionne, elle a besoin de l\'autorisation \"DUMP\". Malheureusement, cela n\'est possible qu\'à partir d\'un \"shell adb\" depuis votre ordinateur :\n\nadb -d shell pm grant com.franco.demomode android.permission.DUMP\n\nPour plus de transparence, le code source de cette application est disponible.
- Pour que cette application fonctionne, elle a besoin de l\'autorisation \"WRITE_SECURE_SETTINGS\". Malheureusement, cela n\'est possible qu\'à partir d\'un \"shell adb\" depuis votre ordinateur :\n\nadb -d shell pm grant com.franco.demomode android.permission.WRITE_SECURE_SETTINGS\n\nPour plus de transparence, le code source de cette application est disponible.
- Non
- OK
- Autorisation \"DUMP\"
- Autorisation \"WRITE_SECURE_SETTINGS\"
- Non accordée
- Autorisations
- Accordée
- Suivez-moi
- Code source
- Les deux autorisations doivent être accordées pour que la tuile puisse fonctionner
-
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
deleted file mode 100644
index 1b32e1b..0000000
--- a/app/src/main/res/values-it/strings.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
- Demo Mode tile
- Demo mode
- Demo mode tile richesta dei permessi
- Perchè l\'applicazione funzioni è necessario dare il consenso al permesso DUMP. Sfortunatamente questo è possibile solo tramite adb shell dal tuo computer:\n\nadb -d shell pm grant com.franco.demomode android.permission.DUMP\n\nPer trasparenza, il codice sorgente di questa applicazione è disponibile.
- Perchè l\'applicazione funzioni è necessario dare il consenso al permesso WRITE_SECURE_SETTINGS. Sfortunatamente questo è possibile solo tramite adb shell dal tuo computer:\n\nadb -d shell pm grant com.franco.demomode android.permission.WRITE_SECURE_SETTINGS\n\nPer trasparenza, il codice sorgente di questa applicazione è disponibile.
- No
- OK
- android.permission.DUMP
- android.permission.WRITE_SECURE_SETTINGS
- Negato
- Permessi
- Consentito
- Seguimi
- Codice sorgente
- Entrambi i permessi sono necessari perchè il tile funzioni correttamente
-
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
deleted file mode 100644
index aeb9789..0000000
--- a/app/src/main/res/values-tr/strings.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
- Demo Mode Tile
- Demo Modu
- Demo modu blok izni isteği
- Bu uygulamanın çalışması için DUMP izninin verilmesi gerekiyor. Ne yazık ki, bu yalnızca bilgisayarınızdaki ADB Shell ile mümkündür:\n\nadb -d shell pm grant com.franco.demomode android.permission.DUMP\n\nŞeffaflık için bu uygulamanın kaynak kodu mevcuttur.
- Bu uygulamanın çalışması için WRITE_SECURE_SETTINGS izni verilmesi gerekiyor. Ne yazık ki, bu yalnızca bilgisayarınızdaki ADB Shell ile mümkündür:\n\nadb -d shell pm grant com.franco.demomode android.permission.WRITE_SECURE_SETTINGS\n\nŞeffaflık için bu uygulamanın kaynak kodu mevcuttur.
- Hayır
- EVET
- android.permission.DUMP
- android.permission.WRITE_SECURE_SETTINGS
- Verilmemiş
- İzinler
- Verildi
- Beni takip et
- Kaynak kodu
- Bloğun çalışması için her iki izinin de verilmesi gerekir
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1194ad3..b636baa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,7 +4,6 @@
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.
- No
OK
DUMP
WRITE_SECURE_SETTINGS
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index fb14d31..7a6748f 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,6 +1,6 @@
-