Skip to content
This repository has been archived by the owner on May 22, 2021. It is now read-only.

Cleanup Android project (Minor refactorings, etc.) #1244

Merged
merged 9 commits into from
Apr 4, 2019
4 changes: 1 addition & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
Expand Down Expand Up @@ -31,7 +29,7 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.github.delight-im:Android-AdvancedWebView:v3.0.0'
implementation "org.mozilla.components:service-firefox-accounts:${rootProject.ext.android_components_version}"
implementation "org.mozilla.components:service-firefox-accounts:$android_components_version"
}

task generateAndLinkBundle(type: Exec, description: 'Generate the android.js bundle and link it into the assets directory') {
Expand Down
208 changes: 104 additions & 104 deletions android/app/src/main/java/org/mozilla/firefoxsend/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
package org.mozilla.firefoxsend


import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import im.delight.android.webview.AdvancedWebView
import android.graphics.Bitmap
import android.content.Intent
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.webkit.WebView
import android.webkit.WebMessage
import android.util.Log
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Base64
import android.util.Log
import android.view.View
import android.webkit.ConsoleMessage
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.*
import im.delight.android.webview.AdvancedWebView
import kotlinx.android.synthetic.main.activity_main.*
import mozilla.components.service.fxa.Config
import mozilla.components.service.fxa.FirefoxAccount
import mozilla.components.service.fxa.Profile
import mozilla.components.service.fxa.FxaResult
import org.json.JSONObject

internal class LoggingWebChromeClient : WebChromeClient() {
override fun onConsoleMessage(cm: ConsoleMessage): Boolean {
Log.w("CONTENT", String.format("%s @ %d: %s",
Log.d(TAG, String.format("%s @ %d: %s",
cm.message(), cm.lineNumber(), cm.sourceId()))
return true
}

companion object {
private const val TAG = "CONTENT"
}
}

class WebAppInterface(private val mContext: MainActivity) {
@JavascriptInterface
fun beginOAuthFlow() {
mContext.beginOAuthFlow();
mContext.beginOAuthFlow()
}

@JavascriptInterface
Expand All @@ -43,176 +43,176 @@ class WebAppInterface(private val mContext: MainActivity) {
}

class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
private var mWebView: AdvancedWebView? = null

private var mToShare: String? = null
private var mToCall: String? = null
private var mAccount: FirefoxAccount? = null

@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews
// WebView.setWebContentsDebuggingEnabled(true); // TODO only dev builds

mWebView = findViewById<WebView>(R.id.webview) as AdvancedWebView
mWebView!!.setListener(this, this)
mWebView!!.setWebChromeClient(LoggingWebChromeClient())
mWebView!!.addJavascriptInterface(WebAppInterface(this), "Android")
mWebView!!.setLayerType(View.LAYER_TYPE_HARDWARE, null);

val webSettings = mWebView!!.getSettings()
webSettings.setUserAgentString("Send Android")
webSettings.setAllowUniversalAccessFromFileURLs(true)
webSettings.setJavaScriptEnabled(true)

val intent = getIntent()
val action = intent.getAction()
val type = intent.getType()
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
webView.apply {
setListener(this@MainActivity, this@MainActivity)
addJavascriptInterface(WebAppInterface(this@MainActivity), JS_INTERFACE_NAME)
setLayerType(View.LAYER_TYPE_HARDWARE, null)
webChromeClient = LoggingWebChromeClient()

settings.apply {
userAgentString = "Send Android"
allowUniversalAccessFromFileURLs = true
javaScriptEnabled = true
}
}

if (Intent.ACTION_SEND.equals(action) && type != null) {
if (type.equals("text/plain")) {
val type = intent.type
if (Intent.ACTION_SEND == intent.action && type != null) {
if (type == "text/plain") {
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
Log.w("INTENT", "text/plain " + sharedText)
Log.d(TAG_INTENT, "text/plain $sharedText")
mToShare = "data:text/plain;base64," + Base64.encodeToString(sharedText.toByteArray(), 16).trim()
} else if (type.startsWith("image/")) {
val imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri
Log.w("INTENT", "image/ " + imageUri)
Log.d(TAG_INTENT, "image/ $imageUri")
mToShare = "data:text/plain;base64," + Base64.encodeToString(imageUri.path.toByteArray(), 16).trim()
}
}
mWebView!!.loadUrl("file:///android_asset/android.html")

webView.loadUrl("file:///android_asset/android.html")
}

fun beginOAuthFlow() {
Config.release().then(fun (value: Config): FxaResult<Unit> {
Config.release().then { value ->
mAccount = FirefoxAccount(value, "20f7931c9054d833", "https://send.firefox.com/fxa/android-redirect.html")
mAccount?.beginOAuthFlow(arrayOf("profile", "https://identity.mozilla.com/apps/send"), true)?.then(fun (url: String): FxaResult<Unit> {
Log.w("CONFIG", "GOT A URL " + url)
[email protected]({
mWebView!!.loadUrl(url)
})
return FxaResult.fromValue(Unit)
})
Log.w("CONFIG", "CREATED FIREFOXACCOUNT")
return FxaResult.fromValue(Unit)
})
mAccount?.beginOAuthFlow(arrayOf("profile", "https://identity.mozilla.com/apps/send"), true)
?.then { url ->
Log.d(TAG_CONFIG, "GOT A URL $url")
[email protected] {
webView.loadUrl(url)
}
FxaResult.fromValue(Unit)
}
Log.d(TAG_CONFIG, "CREATED FIREFOXACCOUNT")
FxaResult.fromValue(Unit)
}
}

fun shareUrl(url: String) {
val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_TEXT, url)
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, url)
}

val components = arrayOf(ComponentName(applicationContext, MainActivity::class.java))
val chooser = Intent.createChooser(shareIntent, "")
chooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, arrayOf(ComponentName(applicationContext, MainActivity::class.java)))
.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, components)

startActivity(chooser)
}

@SuppressLint("NewApi")
override fun onResume() {
super.onResume()
mWebView!!.onResume()
// ...
webView.onResume()
}

@SuppressLint("NewApi")
override fun onPause() {
mWebView!!.onPause()
// ...
webView.onPause()
super.onPause()
}

override fun onDestroy() {
mWebView!!.onDestroy()
// ...
webView.onDestroy()
super.onDestroy()
}

override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
mWebView!!.onActivityResult(requestCode, resultCode, intent)
// ...
webView.onActivityResult(requestCode, resultCode, intent)
}

override fun onBackPressed() {
if (!mWebView!!.onBackPressed()) {
if (!webView.onBackPressed()) {
return
}
// ...
super.onBackPressed()
}

override fun onPageStarted(url: String, favicon: Bitmap?) {
if (url.startsWith("https://send.firefox.com/fxa/android-redirect.html")) {
// We load this here so the user doesn't see the android-redirect.html page
mWebView!!.loadUrl("file:///android_asset/android.html")
webView.loadUrl("file:///android_asset/android.html")

val parsed = Uri.parse(url)
val code = parsed.getQueryParameter("code")
val state = parsed.getQueryParameter("state")

code?.let { code ->
state?.let { state ->
val uri = Uri.parse(url)
uri.getQueryParameter("code")?.let { code ->
uri.getQueryParameter("state")?.let { state ->
mAccount?.completeOAuthFlow(code, state)?.whenComplete { info ->
//displayAndPersistProfile(code, state)
val profile = mAccount?.getProfile(false)?.then(fun (profile: Profile): FxaResult<Unit> {
val accessToken = info.accessToken
val keys = info.keys
val avatar = profile.avatar
val displayName = profile.displayName
val email = profile.email
val uid = profile.uid
val toPass = "{\"accessToken\": \"${accessToken}\", \"keys\": '${keys}', \"avatar\": \"${avatar}\", \"displayName\": \"${displayName}\", \"email\": \"${email}\", \"uid\": \"${uid}\"}"
mToCall = "finishLogin(${toPass})"
[email protected]({
mAccount?.getProfile(false)?.then { profile ->
val profileJsonPayload = JSONObject()
.put("accessToken", info.accessToken)
.put("keys", info.keys)
.put("avatar", profile.avatar)
.put("displayName", profile.displayName)
.put("email", profile.email)
.put("uid", profile.uid).toString()
mToCall = "finishLogin($profileJsonPayload)"
[email protected] {
// Clear the history so that the user can't use the back button to see broken pages
// that were inserted into the history by the login process.
mWebView!!.clearHistory()
webView.clearHistory()

// We also reload this here because we need to make sure onPageFinished runs after mToCall has been set.
// We can't guarantee that onPageFinished wasn't already called at this point.
mWebView!!.loadUrl("file:///android_asset/android.html")
})


return FxaResult.fromValue(Unit)
})
webView.loadUrl("file:///android_asset/android.html")
}
FxaResult.fromValue(Unit)
}
}
}
}
}
Log.w("MAIN", "onPageStarted");
Log.d(TAG_MAIN, "onPageStarted")
}

override fun onPageFinished(url: String) {
Log.w("MAIN", "onPageFinished")
Log.d(TAG_MAIN, "onPageFinished")
if (mToShare != null) {
Log.w("INTENT", mToShare)
Log.d(TAG_INTENT, mToShare)

mWebView?.postWebMessage(WebMessage(mToShare), Uri.EMPTY)
webView.postWebMessage(WebMessage(mToShare), Uri.EMPTY)
mToShare = null
}
if (mToCall != null) {
[email protected]({
mWebView?.evaluateJavascript(mToCall, fun (value: String) {
[email protected] {
webView.evaluateJavascript(mToCall) {
mToCall = null
})
})
}
}
}
}

override fun onPageError(errorCode: Int, description: String, failingUrl: String) {
Log.w("MAIN", "onPageError " + description)
Log.d(TAG_MAIN, "onPageError($errorCode, $description, $failingUrl)")
}

override fun onDownloadRequested(url: String, suggestedFilename: String, mimeType: String, contentLength: Long, contentDisposition: String, userAgent: String) {
Log.w("MAIN", "onDownloadRequested")
override fun onDownloadRequested(url: String,
suggestedFilename: String,
mimeType: String,
contentLength: Long,
contentDisposition: String,
userAgent: String) {
Log.d(TAG_MAIN, "onDownloadRequested")
}

override fun onExternalPageRequest(url: String) {
Log.w("MAIN", "onExternalPageRequest")
Log.d(TAG_MAIN, "onExternalPageRequest($url)")
}

companion object {
private const val TAG_MAIN = "MAIN"
private const val TAG_INTENT = "INTENT"
private const val TAG_CONFIG = "CONFIG"
private const val JS_INTERFACE_NAME = "Android"
}
}
12 changes: 3 additions & 9 deletions android/app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<im.delight.android.webview.AdvancedWebView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<im.delight.android.webview.AdvancedWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
tools:context=".MainActivity" />
11 changes: 3 additions & 8 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,15 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
}
}

allprojects {
repositories {
google()
maven {
url "https://maven.mozilla.org/maven2"
}
maven { url "https://maven.mozilla.org/maven2" }
jcenter()
maven { url "https://jitpack.io" }
}
Expand Down