Commit ec340cf0 authored by Mygod's avatar Mygod

Merge branch 'master' into json

parents 16bc4791 e69176de
# https://github.com/arturbosch/detekt/blob/RC6-4/detekt-cli/src/main/resources/default-detekt-config.yml
# https://github.com/arturbosch/detekt/blob/RC8/detekt-cli/src/main/resources/default-detekt-config.yml
autoCorrect: true
comments:
active: false
......@@ -17,7 +18,7 @@ complexity:
threshold: 10
ignoreSingleWhenExpression: false
LabeledExpression:
active: true
active: false
LargeClass:
active: true
threshold: 150
......@@ -46,12 +47,14 @@ complexity:
thresholdInInterfaces: 11
thresholdInObjects: 11
thresholdInEnums: 11
ignoreDeprecated: true
ignorePrivate: false
empty-blocks:
active: true
EmptyCatchBlock:
active: true
allowedExceptionNameRegex: "^(_|ignore|expected).*"
allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
EmptyClassBlock:
active: true
EmptyDefaultConstructor:
......@@ -125,6 +128,90 @@ exceptions:
- Throwable
- RuntimeException
formatting:
active: true
android: true
autoCorrect: true
ChainWrapping:
active: true
autoCorrect: true
CommentSpacing:
active: false
Filename:
active: true
FinalNewline:
active: true
autoCorrect: true
ImportOrdering:
active: true
autoCorrect: false
Indentation:
active: true
autoCorrect: true
indentSize: 4
continuationIndentSize: 4
MaximumLineLength:
active: false
ModifierOrdering:
active: true
autoCorrect: true
NoBlankLineBeforeRbrace:
active: true
autoCorrect: true
NoConsecutiveBlankLines:
active: true
autoCorrect: true
NoEmptyClassBody:
active: true
autoCorrect: true
NoItParamInMultilineLambda:
active: true
NoLineBreakAfterElse:
active: true
autoCorrect: true
NoLineBreakBeforeAssignment:
active: true
autoCorrect: true
NoMultipleSpaces:
active: false
NoSemicolons:
active: true
autoCorrect: true
NoTrailingSpaces:
active: true
autoCorrect: true
NoUnitReturn:
active: true
autoCorrect: true
NoUnusedImports:
active: true
autoCorrect: true
NoWildcardImports:
active: false
ParameterListWrapping:
active: false
SpacingAroundColon:
active: true
autoCorrect: true
SpacingAroundComma:
active: true
autoCorrect: true
SpacingAroundCurly:
active: true
autoCorrect: true
SpacingAroundKeyword:
active: true
autoCorrect: true
SpacingAroundOperators:
active: true
autoCorrect: true
SpacingAroundRangeOperator:
active: true
autoCorrect: true
StringTemplate:
active: true
autoCorrect: true
naming:
active: true
ClassNaming:
......@@ -153,14 +240,15 @@ naming:
ObjectPropertyNaming:
active: true
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
constantPattern: '[A-Za-z][_A-Za-z0-9]*'
PackageNaming:
active: true
packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$'
TopLevelPropertyNaming:
active: true
constantPattern: '[A-Z][_A-Z0-9]*'
propertyPattern: '[a-z][A-Za-z\d]*'
privatePropertyPattern: '(_)?[a-z][A-Za-z0-9]*'
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
privatePropertyPattern: '(_)?[A-Za-z][A-Za-z0-9]*'
VariableMaxLength:
active: true
maximumVariableNameLength: 64
......@@ -223,6 +311,7 @@ style:
active: true
ExpressionBodySyntax:
active: true
includeLineWrapping: false
ForbiddenComment:
active: true
values: 'TODO:,FIXME:,STOPSHIP:'
......@@ -238,11 +327,14 @@ style:
maxJumpCount: 1
MagicNumber:
active: false
MandatoryBracesIfStatements:
active: false
MaxLineLength:
active: true
maxLineLength: 120
excludePackageStatements: false
excludeImportStatements: false
excludePackageStatements: true
excludeImportStatements: true
excludeCommentStatements: true
MayBeConst:
active: true
ModifierOrder:
......@@ -259,6 +351,8 @@ style:
active: true
OptionalWhenBraces:
active: true
PreferToOverPairSyntax:
active: false
ProtectedMemberInFinalClass:
active: true
RedundantVisibilityModifierRule:
......@@ -288,9 +382,12 @@ style:
active: true
UnusedPrivateMember:
active: true
allowedNames: "(_|ignored|expected|serialVersionUID)"
UseDataClass:
active: false
UtilityClassWithPublicConstructor:
active: true
VarCouldBeVal:
active: false
WildcardImport:
active: false
......@@ -34,6 +34,6 @@ class AclTest {
@Test
fun parse() {
Assert.assertEquals(INPUT1, Acl().fromReader(INPUT1.reader()).toString());
Assert.assertEquals(INPUT1, Acl().fromReader(INPUT1.reader()).toString())
}
}
package com.github.shadowsocks.utils
import java.net.InetAddress
import org.junit.Assert
import org.junit.Test
import java.net.InetAddress
class SubnetTest {
@Test
......
......@@ -35,9 +35,9 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.UserManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate
import android.util.Log
import androidx.core.content.getSystemService
import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
......
......@@ -33,21 +33,21 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
import com.google.android.material.snackbar.Snackbar
import androidx.core.app.TaskStackBuilder
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import android.view.*
import android.widget.ImageView
import android.widget.Switch
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.TaskStackBuilder
import androidx.core.content.getSystemService
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.*
import com.google.android.material.snackbar.Snackbar
import java.util.concurrent.atomic.AtomicBoolean
class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
......
......@@ -70,7 +70,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
Key.modeProxy -> Pair(false, false)
Key.modeVpn -> Pair(true, false)
Key.modeTransproxy -> Pair(true, true)
else -> throw IllegalArgumentException()
else -> throw IllegalArgumentException("newValue: $newValue")
}
portLocalDns.isEnabled = enabledLocalDns
portTransproxy.isEnabled = enabledTransproxy
......
......@@ -251,9 +251,9 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
val intent = this.intent
if (intent != null) handleShareIntent(intent)
if (savedInstanceState != null
&& DataStore.nightMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
&& AppCompatDelegate.getDefaultNightMode() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
if (savedInstanceState != null &&
DataStore.nightMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM &&
AppCompatDelegate.getDefaultNightMode() != AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
......
......@@ -171,7 +171,6 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), Toolbar.OnMenuItemClic
onPreferenceChange(null, options)
}
PluginContract.RESULT_FALLBACK -> showPluginEditor()
} else super.onActivityResult(requestCode, resultCode, data)
}
......
......@@ -27,13 +27,13 @@ import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
import android.os.Bundle
import androidx.core.app.TaskStackBuilder
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.util.Log
import android.util.SparseArray
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.TaskStackBuilder
import androidx.core.content.getSystemService
import androidx.core.util.forEach
import com.crashlytics.android.Crashlytics
......
......@@ -22,9 +22,9 @@ package com.github.shadowsocks
import android.os.Bundle
import android.view.Gravity
import androidx.fragment.app.Fragment
import androidx.appcompat.widget.Toolbar
import android.view.View
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
/**
* @author Mygod
......
......@@ -21,8 +21,8 @@
package com.github.shadowsocks.acl
import android.content.Context
import androidx.recyclerview.widget.SortedList
import android.util.Log
import androidx.recyclerview.widget.SortedList
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.preference.DataStore
......@@ -46,7 +46,7 @@ class Acl {
val networkAclParser = "^IMPORT_URL\\s*<(.+)>\\s*$".toRegex()
fun getFile(id: String, context: Context = app.deviceStorage) = File(context.filesDir, id + ".acl")
fun getFile(id: String, context: Context = app.deviceStorage) = File(context.filesDir, "$id.acl")
var customRules: Acl
get() {
......@@ -122,7 +122,7 @@ class Acl {
for (line in it) {
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
val blocks = (line as java.lang.String).split("#", 2)
val url = networkAclParser.matchEntire(blocks.getOrElse(1, {""}))?.groupValues?.getOrNull(1)
val url = networkAclParser.matchEntire(blocks.getOrElse(1) { "" })?.groupValues?.getOrNull(1)
if (url != null) urls.add(URL(url))
val input = blocks[0].trim()
when (input) {
......
......@@ -329,7 +329,8 @@ object BaseService {
val profile = app.currentProfile
this as Context
if (profile == null) {
data.notification = createNotification("") // gracefully shutdown: https://stackoverflow.com/questions/47337857/context-startforegroundservice-did-not-then-call-service-startforeground-eve
// gracefully shutdown: https://stackoverflow.com/q/47337857/2245107
data.notification = createNotification("")
stopRunner(true, getString(R.string.profile_empty))
return Service.START_NOT_STICKY
}
......
......@@ -35,9 +35,8 @@ import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.atomic.AtomicReference
class GuardedProcessPool {
companion object {
companion object Dummy : IOException("Oopsie the developer has made a no-no") {
private const val TAG = "GuardedProcessPool"
private val dummy = IOException()
}
private inner class Guard(private val cmd: List<String>, private val onRestartCallback: (() -> Unit)?) {
......@@ -53,7 +52,7 @@ class GuardedProcessPool {
}
private fun pushException(ioException: IOException?) {
if (pushed) return
excQueue.put(ioException ?: dummy)
excQueue.put(ioException ?: Dummy)
pushed = true
}
......@@ -115,7 +114,7 @@ class GuardedProcessPool {
})
}
val ioException = guard.excQueue.take()
if (ioException !== dummy) throw ioException
if (ioException !== Dummy) throw ioException
return this
}
......
......@@ -24,10 +24,10 @@ import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.parseNumericAddress
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.net.Inet6Address
import org.json.JSONArray
import org.json.JSONObject
object LocalDnsService {
interface Interface : BaseService.Interface {
......
......@@ -29,15 +29,15 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.PowerManager
import android.text.format.Formatter
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import android.text.format.Formatter
import androidx.core.content.getSystemService
import com.github.shadowsocks.MainActivity
import com.github.shadowsocks.R
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.broadcastReceiver
import androidx.core.content.getSystemService
import java.util.*
/**
......
......@@ -23,15 +23,15 @@ package com.github.shadowsocks.bg
import android.app.KeyguardManager
import android.graphics.drawable.Icon
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService as BaseTileService
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R
import com.github.shadowsocks.ShadowsocksConnection
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.preference.DataStore
import androidx.core.content.getSystemService
import android.service.quicksettings.TileService as BaseTileService
@RequiresApi(24)
class TileService : BaseTileService(), ShadowsocksConnection.Interface {
......
......@@ -28,6 +28,7 @@ import android.net.*
import android.os.Build
import android.os.IBinder
import android.os.ParcelFileDescriptor
import androidx.core.content.getSystemService
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.MainActivity
......@@ -38,7 +39,6 @@ import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress
import com.github.shadowsocks.utils.printLog
import androidx.core.content.getSystemService
import java.io.File
import java.io.FileDescriptor
import java.io.IOException
......
......@@ -20,10 +20,10 @@
package com.github.shadowsocks.database
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.migration.RecreateSchemaMigration
import com.github.shadowsocks.utils.Key
......
......@@ -20,11 +20,11 @@
package com.github.shadowsocks.database
import androidx.room.*
import android.net.Uri
import android.util.Base64
import android.util.Log
import androidx.core.net.toUri
import androidx.room.*
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.plugin.PluginOptions
import com.github.shadowsocks.preference.DataStore
......
......@@ -20,8 +20,8 @@
package com.github.shadowsocks.database.migration
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
open class RecreateSchemaMigration(oldVersion: Int, newVersion: Int, private val table: String,
private val schema: String, private val keys: String) :
......
......@@ -33,6 +33,7 @@ import androidx.core.os.bundleOf
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.utils.Commandline
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.signaturesCompat
import eu.chainfire.libsuperuser.Shell
import java.io.File
......@@ -107,7 +108,7 @@ object PluginManager {
private fun buildUri(id: String) = Uri.Builder()
.scheme(PluginContract.SCHEME)
.authority(PluginContract.AUTHORITY)
.path('/' + id)
.path("/$id")
.build()
fun buildIntent(id: String, action: String): Intent = Intent(action, buildUri(id))
......@@ -121,14 +122,13 @@ object PluginManager {
val path = initNative(options)
if (path != null) return path
} catch (t: Throwable) {
t.printStackTrace()
if (throwable == null) throwable = t
if (throwable == null) throwable = t else printLog(t)
}
// add other plugin types here
throw if (throwable != null) throwable else
FileNotFoundException(app.getString(com.github.shadowsocks.R.string.plugin_unknown, options.id))
throw throwable
?: FileNotFoundException(app.getString(com.github.shadowsocks.R.string.plugin_unknown, options.id))
}
private fun initNative(options: PluginOptions): String? {
......@@ -143,9 +143,9 @@ object PluginManager {
return try {
initNativeFast(cr, options, uri)
} catch (t: Throwable) {
t.printStackTrace()
Crashlytics.log(Log.WARN, "PluginManager",
"Initializing native plugin fast mode failed. Falling back to slow mode.")
printLog(t)
initNativeSlow(cr, options, uri)
}
}
......
......@@ -27,18 +27,18 @@ import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import com.google.android.material.bottomsheet.BottomSheetDialog
import androidx.preference.PreferenceDialogFragmentCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.preference.PreferenceDialogFragmentCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.shadowsocks.R
import com.google.android.material.bottomsheet.BottomSheetDialog
class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
private inner class IconListViewHolder(val dialog: BottomSheetDialog, view: View) : RecyclerView.ViewHolder(view),
......@@ -82,7 +82,6 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
false
}
}
}
private inner class IconListAdapter(private val dialog: BottomSheetDialog) :
RecyclerView.Adapter<IconListViewHolder>() {
......@@ -92,7 +91,7 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
override fun onBindViewHolder(holder: IconListViewHolder, position: Int) {
if (preference.selectedEntry < 0) holder.bind(position) else when (position) {
0 -> holder.bind(preference.selectedEntry, true)
in preference.selectedEntry + 1 .. Int.MAX_VALUE -> holder.bind(position)
in preference.selectedEntry + 1..Int.MAX_VALUE -> holder.bind(position)
else -> holder.bind(position - 1)
}
}
......
......@@ -22,8 +22,8 @@ package com.github.shadowsocks.preference
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.preference.ListPreference
import android.util.AttributeSet
import androidx.preference.ListPreference
class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPreference(context, attrs) {
var entryIcons: Array<Drawable?>? = null
......
......@@ -20,9 +20,9 @@
package com.github.shadowsocks.preference
import androidx.appcompat.app.AlertDialog
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import com.github.shadowsocks.ProfileConfigActivity
import com.github.shadowsocks.plugin.PluginContract
import com.github.shadowsocks.plugin.PluginManager
......
......@@ -23,16 +23,16 @@ package com.github.shadowsocks.tasker
import android.app.Activity
import android.content.res.Resources
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckedTextView
import android.widget.Switch
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.shadowsocks.R
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
......
......@@ -41,7 +41,7 @@ class Subnet(val address: InetAddress, val prefixSize: Int) : Comparable<Subnet>
private val addressLength get() = address.address.size shl 3
init {
if (prefixSize < 0 || prefixSize > addressLength) throw IllegalArgumentException()
if (prefixSize < 0 || prefixSize > addressLength) throw IllegalArgumentException("prefixSize: $prefixSize")
}
override fun toString(): String =
......
......@@ -30,9 +30,9 @@ object TcpFastOpen {
val supported by lazy {
val match = """^(\d+)\.(\d+)\.(\d+)""".toRegex().find(System.getProperty("os.version"))
if (match == null) false else when (match.groupValues[1].toInt()) {
in Int.MIN_VALUE .. 2 -> false
in Int.MIN_VALUE..2 -> false
3 -> when (match.groupValues[2].toInt()) {
in Int.MIN_VALUE .. 6 -> false
in Int.MIN_VALUE..6 -> false
7 -> match.groupValues[3].toInt() >= 1
else -> true
}
......
......@@ -22,9 +22,9 @@ package com.github.shadowsocks.widget
import android.content.Context
import android.graphics.Rect
import androidx.appcompat.widget.AppCompatTextView
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.view.isGone
import com.crashlytics.android.Crashlytics
......
......@@ -21,8 +21,8 @@
package com.github.shadowsocks.widget
import android.content.Context
import androidx.gridlayout.widget.GridLayout
import android.util.AttributeSet
import androidx.gridlayout.widget.GridLayout
import com.github.shadowsocks.R
/**
......
......@@ -22,15 +22,15 @@ package com.github.shadowsocks.widget
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.View
import androidx.annotation.DrawableRes
import com.google.android.material.floatingactionbutton.FloatingActionButton
import androidx.appcompat.widget.TooltipCompat
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import androidx.appcompat.widget.TooltipCompat
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.R
import com.github.shadowsocks.bg.BaseService
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.util.*
class ServiceButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
......
......@@ -22,14 +22,14 @@ package com.github.shadowsocks.widget
import android.animation.ValueAnimator
import android.content.Context
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.SnackbarConsts
import android.util.AttributeSet
import android.view.View
import android.view.accessibility.AccessibilityManager
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.getSystemService
import com.google.android.material.animation.AnimationUtils
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.SnackbarConsts
/**
* Full credits go to: https://stackoverflow.com/a/35904421/2245107
......
......@@ -22,9 +22,9 @@ package com.github.shadowsocks.plugin
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import android.widget.Toast
/**
* Activity that's capable of getting EXTRA_OPTIONS input.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment