Skip to content
This repository was archived by the owner on Sep 3, 2023. It is now read-only.

Commit

Permalink
Link 'Show Taps' option in settings to developer options, resolves #37
Browse files Browse the repository at this point in the history
  • Loading branch information
afollestad committed May 19, 2019
1 parent 9d111ce commit 2c0dd60
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 24 deletions.
1 change: 0 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ dependencies {
implementation 'androidx.preference:preference:' + versions.androidxPrefs
implementation 'androidx.lifecycle:lifecycle-extensions:' + versions.lifecycle
kapt 'androidx.lifecycle:lifecycle-compiler:' + versions.lifecycle
implementation 'androidx.browser:browser:' + versions.androidxBrowser

// Koin
implementation 'org.koin:koin-androidx-scope:' + versions.koin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ import android.content.Intent.ACTION_VIEW
import android.content.Intent.EXTRA_STREAM
import android.os.Bundle
import android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION
import androidx.browser.customtabs.CustomTabsIntent
import androidx.lifecycle.Observer
import com.afollestad.assent.Permission.WRITE_EXTERNAL_STORAGE
import com.afollestad.assent.askForPermissions
import com.afollestad.inlineactivityresult.startActivityForResult
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.callbacks.onCancel
import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.utils.MDUtil.resolveColor
import com.afollestad.mnmlscreenrecord.R
import com.afollestad.mnmlscreenrecord.common.intent.UrlLauncher
import com.afollestad.mnmlscreenrecord.common.misc.startActivity
import com.afollestad.mnmlscreenrecord.common.misc.toUri
import com.afollestad.mnmlscreenrecord.common.misc.toast
Expand Down Expand Up @@ -67,14 +66,18 @@ import kotlinx.android.synthetic.main.activity_main.fab
import kotlinx.android.synthetic.main.activity_main.list
import kotlinx.android.synthetic.main.include_appbar.toolbar
import kotlinx.android.synthetic.main.list_item_recording.view.thumbnail
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import kotlinx.android.synthetic.main.include_appbar.app_toolbar as appToolbar
import kotlinx.android.synthetic.main.include_appbar.toolbar_title as toolbarTitle

/** @author Aidan Follestad (afollestad) */
class MainActivity : DarkModeSwitchActivity(), OverlayExplanationCallback {

private val viewModel by viewModel<MainViewModel>()
private val urlLauncher by inject<UrlLauncher> { parametersOf(this) }

private val dataSource =
emptySelectableDataSourceTyped<Recording>().apply {
onSelectionChange {
Expand Down Expand Up @@ -191,7 +194,9 @@ class MainActivity : DarkModeSwitchActivity(), OverlayExplanationCallback {
setOnMenuItemDebouncedClickListener { item ->
when (item.itemId) {
R.id.about -> AboutDialog.show(this@MainActivity)
R.id.provide_feedback -> viewUrl("https://github.com/afollestad/mnml/issues/new/choose")
R.id.provide_feedback -> urlLauncher.viewUrl(
"https://github.com/afollestad/mnml/issues/new/choose"
)
R.id.settings -> startActivity<SettingsActivity>()
R.id.share -> shareRecording(dataSource.getSelectedItems().single())
R.id.delete -> {
Expand Down Expand Up @@ -260,19 +265,6 @@ class MainActivity : DarkModeSwitchActivity(), OverlayExplanationCallback {
})
}

private fun viewUrl(url: String) {
val customTabsIntent = CustomTabsIntent.Builder()
.apply {
setToolbarColor(resolveColor(this@MainActivity, attr = R.attr.colorPrimary))
}
.build()
try {
customTabsIntent.launchUrl(this, url.toUri())
} catch (_: ActivityNotFoundException) {
toast(R.string.install_web_browser)
}
}

private fun checkForMediaProjectionAvailability() {
try {
Class.forName("android.media.projection.MediaProjectionManager")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION
import androidx.preference.SwitchPreference
import com.afollestad.mnmlscreenrecord.R
import com.afollestad.mnmlscreenrecord.common.misc.toUri
import com.afollestad.mnmlscreenrecord.common.permissions.PermissionChecker
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SCREEN_OFF
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SHAKE
Expand All @@ -34,8 +33,6 @@ import org.koin.core.qualifier.named

/** @author Aidan Follestad (@afollestad) */
class SettingsControlsFragment : BaseSettingsFragment(), OverlayExplanationCallback {

private val permissionChecker by inject<PermissionChecker>()
private val stopOnScreenOffPref by inject<Pref<Boolean>>(named(PREF_STOP_ON_SCREEN_OFF))
private val alwaysShowControlsPref by inject<Pref<Boolean>>(
named(PREF_ALWAYS_SHOW_CONTROLS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@
*/
package com.afollestad.mnmlscreenrecord.ui.settings.sub

import android.content.Intent
import android.content.pm.PackageManager.FEATURE_MICROPHONE
import android.os.Bundle
import android.provider.Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS
import androidx.preference.SwitchPreference
import com.afollestad.assent.Permission.RECORD_AUDIO
import com.afollestad.assent.runWithPermissions
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.mnmlscreenrecord.R
import com.afollestad.mnmlscreenrecord.common.intent.UrlLauncher
import com.afollestad.mnmlscreenrecord.common.permissions.PermissionChecker
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_COUNTDOWN
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_RECORDINGS_FOLDER
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_RECORD_AUDIO
Expand All @@ -30,11 +35,14 @@ import com.afollestad.mnmlscreenrecord.ui.settings.showNumberSelector
import com.afollestad.mnmlscreenrecord.ui.settings.showOutputFolderSelector
import com.afollestad.rxkprefs.Pref
import org.koin.android.ext.android.inject
import org.koin.core.parameter.parametersOf
import org.koin.core.qualifier.named

/** @author Aidan Follestad (@afollestad) */
class SettingsRecordingFragment : BaseSettingsFragment() {

private val permissionChecker by inject<PermissionChecker>()
private val urlLauncher by inject<UrlLauncher> { parametersOf(activity!!) }
private val countdownPref by inject<Pref<Int>>(named(PREF_COUNTDOWN))
private val recordAudioPref by inject<Pref<Boolean>>(named(PREF_RECORD_AUDIO))
internal val recordingsFolderPref by inject<Pref<String>>(named(PREF_RECORDINGS_FOLDER))
Expand All @@ -48,6 +56,21 @@ class SettingsRecordingFragment : BaseSettingsFragment() {
setupCountdownPref()
setupRecordAudioPref()
setupRecordingsFolderPref()

findPreference("show_touches").setOnPreferenceClickListener {
if (permissionChecker.hasDeveloperOptions()) {
startActivity(Intent(ACTION_APPLICATION_DEVELOPMENT_SETTINGS))
} else {
MaterialDialog(activity!!).show {
title(R.string.settings_show_touches_dev_options)
message(R.string.settings_show_touches_dev_options_desc)
positiveButton(R.string.settings_show_touches_dev_options_how) {
urlLauncher.viewUrl(HOW_TO_DEV_OPTIONS_URL)
}
}
}
true
}
}

private fun setupCountdownPref() {
Expand Down Expand Up @@ -119,4 +142,9 @@ class SettingsRecordingFragment : BaseSettingsFragment() {
}
.attachLifecycle(this)
}

private companion object {
private const val HOW_TO_DEV_OPTIONS_URL =
"https://developer.android.com/studio/debug/dev-options"
}
}
12 changes: 9 additions & 3 deletions app/src/main/res/values/strings_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,17 @@
<string name="setting_recordings_folder">Recordings Folder</string>
<string name="setting_recordings_folder_desc">Recordings are saved to \"%1$s\"</string>

<string name="setting_show_touches">Show Touches</string>
<string name="setting_show_touches">Show Taps</string>
<string name="setting_show_touches_desc">
MNML targets the latest versions of Android and Google now restricts access to this
setting, unfortunately. You can manually enable it from your phone\'s settings.
MNML targets the latest versions of Android, which restricts access to this
setting. You can manually enable it from your phone\'s settings.
</string>
<string name="settings_show_touches_dev_options">Developer Mode Needed</string>
<string name="settings_show_touches_dev_options_desc">
You must put your phone into developer mode so that MNML can show you developer options.
Developer options allow you to enable \'Show Taps\' manually.
</string>
<string name="settings_show_touches_dev_options_how">Show Me How</string>

<!-- Controls -->
<string name="setting_category_controls">Controls</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/xml/settings_recording.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
android:title="@string/setting_recordings_folder"/>

<Preference
android:enabled="false"
android:key="show_touches"
android:layout="@layout/custom_preference"
android:summary="@string/setting_show_touches_desc"
Expand Down
1 change: 1 addition & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies {

// Google/AndroidX
api 'androidx.appcompat:appcompat:' + versions.androidxCore
api 'androidx.browser:browser:' + versions.androidxBrowser
implementation 'androidx.recyclerview:recyclerview:' + versions.androidxRecyclerView

// Koin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
*/
package com.afollestad.mnmlscreenrecord.common

import android.app.Activity
import com.afollestad.mnmlscreenrecord.common.Qualifiers.IO_DISPATCHER
import com.afollestad.mnmlscreenrecord.common.Qualifiers.MAIN_DISPATCHER
import com.afollestad.mnmlscreenrecord.common.intent.RealUrlLauncher
import com.afollestad.mnmlscreenrecord.common.intent.UrlLauncher
import com.afollestad.mnmlscreenrecord.common.permissions.PermissionChecker
import com.afollestad.mnmlscreenrecord.common.permissions.RealPermissionChecker
import com.afollestad.mnmlscreenrecord.common.providers.RealSdkProvider
Expand All @@ -42,4 +45,6 @@ val commonModule = module {
factory { RealPermissionChecker(get()) } bind PermissionChecker::class

factory { RealSdkProvider() } bind SdkProvider::class

factory { (activity: Activity) -> RealUrlLauncher(activity) } bind UrlLauncher::class
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Designed and developed by Aidan Follestad (@afollestad)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.afollestad.mnmlscreenrecord.common.intent

import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.Intent.ACTION_VIEW
import androidx.annotation.AttrRes
import androidx.browser.customtabs.CustomTabsIntent
import com.afollestad.mnmlscreenrecord.common.R
import com.afollestad.mnmlscreenrecord.common.misc.toUri

/** @author Aidan Follestad (@afollestad) */
interface UrlLauncher {
fun viewUrl(url: String)
}

class RealUrlLauncher(
private val currentActivity: Activity
) : UrlLauncher {

override fun viewUrl(url: String) {
val customTabsIntent = CustomTabsIntent.Builder()
.setToolbarColor(resolveColor(R.attr.colorPrimary))
.build()
try {
customTabsIntent.launchUrl(currentActivity, url.toUri())
} catch (_: ActivityNotFoundException) {
val chooser = Intent.createChooser(
Intent(ACTION_VIEW)
.setData(url.toUri()), "View URL"
)
currentActivity.startActivity(chooser)
}
}

private fun resolveColor(@AttrRes attr: Int): Int {
val a = currentActivity.theme.obtainStyledAttributes(intArrayOf(attr))
try {
return a.getColor(0, 0)
} finally {
a.recycle()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
package com.afollestad.mnmlscreenrecord.common.permissions

import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Application
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Build
import android.provider.Settings
import android.provider.Settings.Global
import android.provider.Settings.Secure

/**
* An abstraction layer for checking common permission access.
Expand All @@ -36,6 +41,11 @@ interface PermissionChecker {
* Returns true if the app has permission to write external storage.
*/
fun hasStoragePermission(): Boolean

/**
* Returns true if the user has enabled Developer mode.
*/
fun hasDeveloperOptions(): Boolean
}

/** @author Aidan Follestad (@afollestad) */
Expand All @@ -50,4 +60,21 @@ class RealPermissionChecker(
override fun hasStoragePermission(): Boolean {
return app.checkSelfPermission(WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED
}

@Suppress("DEPRECATION")
@SuppressLint("ObsoleteSdkInt")
@TargetApi(17)
override fun hasDeveloperOptions(): Boolean {
return when {
Build.VERSION.SDK_INT == 16 -> Secure.getInt(
app.contentResolver,
Secure.DEVELOPMENT_SETTINGS_ENABLED, 0
) != 0
Build.VERSION.SDK_INT >= 17 -> Secure.getInt(
app.contentResolver,
Global.DEVELOPMENT_SETTINGS_ENABLED, 0
) != 0
else -> false
}
}
}

0 comments on commit 2c0dd60

Please sign in to comment.