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

Commit 48b5d85

Browse files
christxphDonovan Preston
authored andcommitted
Cleanup Android project (Minor refactorings, etc.) (#1244)
* (Android) Get rid of double bangs by using Kotlin view binding Instead of holding a nullable reference to the WebView, we are now accessing the WebView using the view binding utility of Kotlin's Android Extensions. Further reading: https://kotlinlang.org/docs/tutorials/android-plugin.html * (Android) Enable WebView debugging in debug builds This enables debugging the app's WebView using Chrome's DevTools. https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews * (Android) Make MainActivity.kt adhere to common Kotlin conventions * (Android) Update dependencies and improve formatting of Gradle files This updates the Kotlin plugin to 1.3.21 and the Gradle plugin to 3.3.2 * (Android) Remove unnecessary ConstraintLayout container Layout files should generally have as few nested layers as possible, because every layer affects the performance. * (Android) Use JSONObject class to construct a JSON string It is way safer to construct a JSON string using classes that are meant for doing that, instead of concatenating raw strings. * (Android) Suppress JavaScript lint warning * (Android) Use Kotlin string templates instead of concatenating strings * (Android) Add missing SuppressLint import
1 parent 373da3f commit 48b5d85

4 files changed

Lines changed: 111 additions & 124 deletions

File tree

android/app/build.gradle

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
apply plugin: 'com.android.application'
2-
32
apply plugin: 'kotlin-android'
4-
53
apply plugin: 'kotlin-android-extensions'
64

75
android {
@@ -31,7 +29,7 @@ dependencies {
3129
androidTestImplementation 'com.android.support.test:runner:1.0.2'
3230
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
3331
implementation 'com.github.delight-im:Android-AdvancedWebView:v3.0.0'
34-
implementation "org.mozilla.components:service-firefox-accounts:${rootProject.ext.android_components_version}"
32+
implementation "org.mozilla.components:service-firefox-accounts:$android_components_version"
3533
}
3634

3735
task generateAndLinkBundle(type: Exec, description: 'Generate the android.js bundle and link it into the assets directory') {
Lines changed: 104 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
11
package org.mozilla.firefoxsend
22

3-
4-
import android.support.v7.app.AppCompatActivity
5-
import android.os.Bundle
6-
import im.delight.android.webview.AdvancedWebView
7-
import android.graphics.Bitmap
8-
import android.content.Intent
93
import android.annotation.SuppressLint
104
import android.content.ComponentName
5+
import android.content.Intent
6+
import android.graphics.Bitmap
117
import android.net.Uri
12-
import android.webkit.WebView
13-
import android.webkit.WebMessage
14-
import android.util.Log
8+
import android.os.Bundle
9+
import android.support.v7.app.AppCompatActivity
1510
import android.util.Base64
11+
import android.util.Log
1612
import android.view.View
17-
import android.webkit.ConsoleMessage
18-
import android.webkit.JavascriptInterface
19-
import android.webkit.WebChromeClient
13+
import android.webkit.*
14+
import im.delight.android.webview.AdvancedWebView
15+
import kotlinx.android.synthetic.main.activity_main.*
2016
import mozilla.components.service.fxa.Config
2117
import mozilla.components.service.fxa.FirefoxAccount
22-
import mozilla.components.service.fxa.Profile
2318
import mozilla.components.service.fxa.FxaResult
19+
import org.json.JSONObject
2420

2521
internal class LoggingWebChromeClient : WebChromeClient() {
2622
override fun onConsoleMessage(cm: ConsoleMessage): Boolean {
27-
Log.w("CONTENT", String.format("%s @ %d: %s",
23+
Log.d(TAG, String.format("%s @ %d: %s",
2824
cm.message(), cm.lineNumber(), cm.sourceId()))
2925
return true
3026
}
27+
28+
companion object {
29+
private const val TAG = "CONTENT"
30+
}
3131
}
3232

3333
class WebAppInterface(private val mContext: MainActivity) {
3434
@JavascriptInterface
3535
fun beginOAuthFlow() {
36-
mContext.beginOAuthFlow();
36+
mContext.beginOAuthFlow()
3737
}
3838

3939
@JavascriptInterface
@@ -43,176 +43,176 @@ class WebAppInterface(private val mContext: MainActivity) {
4343
}
4444

4545
class MainActivity : AppCompatActivity(), AdvancedWebView.Listener {
46-
private var mWebView: AdvancedWebView? = null
46+
4747
private var mToShare: String? = null
4848
private var mToCall: String? = null
4949
private var mAccount: FirefoxAccount? = null
5050

51+
@SuppressLint("SetJavaScriptEnabled")
5152
override fun onCreate(savedInstanceState: Bundle?) {
5253
super.onCreate(savedInstanceState)
5354
setContentView(R.layout.activity_main)
5455

55-
// https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews
56-
// WebView.setWebContentsDebuggingEnabled(true); // TODO only dev builds
57-
58-
mWebView = findViewById<WebView>(R.id.webview) as AdvancedWebView
59-
mWebView!!.setListener(this, this)
60-
mWebView!!.setWebChromeClient(LoggingWebChromeClient())
61-
mWebView!!.addJavascriptInterface(WebAppInterface(this), "Android")
62-
mWebView!!.setLayerType(View.LAYER_TYPE_HARDWARE, null);
63-
64-
val webSettings = mWebView!!.getSettings()
65-
webSettings.setUserAgentString("Send Android")
66-
webSettings.setAllowUniversalAccessFromFileURLs(true)
67-
webSettings.setJavaScriptEnabled(true)
68-
69-
val intent = getIntent()
70-
val action = intent.getAction()
71-
val type = intent.getType()
56+
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
57+
webView.apply {
58+
setListener(this@MainActivity, this@MainActivity)
59+
addJavascriptInterface(WebAppInterface(this@MainActivity), JS_INTERFACE_NAME)
60+
setLayerType(View.LAYER_TYPE_HARDWARE, null)
61+
webChromeClient = LoggingWebChromeClient()
62+
63+
settings.apply {
64+
userAgentString = "Send Android"
65+
allowUniversalAccessFromFileURLs = true
66+
javaScriptEnabled = true
67+
}
68+
}
7269

73-
if (Intent.ACTION_SEND.equals(action) && type != null) {
74-
if (type.equals("text/plain")) {
70+
val type = intent.type
71+
if (Intent.ACTION_SEND == intent.action && type != null) {
72+
if (type == "text/plain") {
7573
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
76-
Log.w("INTENT", "text/plain " + sharedText)
74+
Log.d(TAG_INTENT, "text/plain $sharedText")
7775
mToShare = "data:text/plain;base64," + Base64.encodeToString(sharedText.toByteArray(), 16).trim()
7876
} else if (type.startsWith("image/")) {
7977
val imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri
80-
Log.w("INTENT", "image/ " + imageUri)
78+
Log.d(TAG_INTENT, "image/ $imageUri")
8179
mToShare = "data:text/plain;base64," + Base64.encodeToString(imageUri.path.toByteArray(), 16).trim()
8280
}
8381
}
84-
mWebView!!.loadUrl("file:///android_asset/android.html")
85-
82+
webView.loadUrl("file:///android_asset/android.html")
8683
}
8784

8885
fun beginOAuthFlow() {
89-
Config.release().then(fun (value: Config): FxaResult<Unit> {
86+
Config.release().then { value ->
9087
mAccount = FirefoxAccount(value, "20f7931c9054d833", "https://send.firefox.com/fxa/android-redirect.html")
91-
mAccount?.beginOAuthFlow(arrayOf("profile", "https://identity.mozilla.com/apps/send"), true)?.then(fun (url: String): FxaResult<Unit> {
92-
Log.w("CONFIG", "GOT A URL " + url)
93-
this@MainActivity.runOnUiThread({
94-
mWebView!!.loadUrl(url)
95-
})
96-
return FxaResult.fromValue(Unit)
97-
})
98-
Log.w("CONFIG", "CREATED FIREFOXACCOUNT")
99-
return FxaResult.fromValue(Unit)
100-
})
88+
mAccount?.beginOAuthFlow(arrayOf("profile", "https://identity.mozilla.com/apps/send"), true)
89+
?.then { url ->
90+
Log.d(TAG_CONFIG, "GOT A URL $url")
91+
this@MainActivity.runOnUiThread {
92+
webView.loadUrl(url)
93+
}
94+
FxaResult.fromValue(Unit)
95+
}
96+
Log.d(TAG_CONFIG, "CREATED FIREFOXACCOUNT")
97+
FxaResult.fromValue(Unit)
98+
}
10199
}
102100

103101
fun shareUrl(url: String) {
104-
val shareIntent = Intent()
105-
shareIntent.action = Intent.ACTION_SEND
106-
shareIntent.type = "text/plain"
107-
shareIntent.putExtra(Intent.EXTRA_TEXT, url)
102+
val shareIntent = Intent().apply {
103+
action = Intent.ACTION_SEND
104+
type = "text/plain"
105+
putExtra(Intent.EXTRA_TEXT, url)
106+
}
107+
108+
val components = arrayOf(ComponentName(applicationContext, MainActivity::class.java))
108109
val chooser = Intent.createChooser(shareIntent, "")
109-
chooser.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, arrayOf(ComponentName(applicationContext, MainActivity::class.java)))
110+
.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, components)
111+
110112
startActivity(chooser)
111113
}
112114

113-
@SuppressLint("NewApi")
114115
override fun onResume() {
115116
super.onResume()
116-
mWebView!!.onResume()
117-
// ...
117+
webView.onResume()
118118
}
119119

120-
@SuppressLint("NewApi")
121120
override fun onPause() {
122-
mWebView!!.onPause()
123-
// ...
121+
webView.onPause()
124122
super.onPause()
125123
}
126124

127125
override fun onDestroy() {
128-
mWebView!!.onDestroy()
129-
// ...
126+
webView.onDestroy()
130127
super.onDestroy()
131128
}
132129

133130
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
134131
super.onActivityResult(requestCode, resultCode, intent)
135-
mWebView!!.onActivityResult(requestCode, resultCode, intent)
136-
// ...
132+
webView.onActivityResult(requestCode, resultCode, intent)
137133
}
138134

139135
override fun onBackPressed() {
140-
if (!mWebView!!.onBackPressed()) {
136+
if (!webView.onBackPressed()) {
141137
return
142138
}
143-
// ...
144139
super.onBackPressed()
145140
}
146141

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

152-
val parsed = Uri.parse(url)
153-
val code = parsed.getQueryParameter("code")
154-
val state = parsed.getQueryParameter("state")
155-
156-
code?.let { code ->
157-
state?.let { state ->
147+
val uri = Uri.parse(url)
148+
uri.getQueryParameter("code")?.let { code ->
149+
uri.getQueryParameter("state")?.let { state ->
158150
mAccount?.completeOAuthFlow(code, state)?.whenComplete { info ->
159-
//displayAndPersistProfile(code, state)
160-
val profile = mAccount?.getProfile(false)?.then(fun (profile: Profile): FxaResult<Unit> {
161-
val accessToken = info.accessToken
162-
val keys = info.keys
163-
val avatar = profile.avatar
164-
val displayName = profile.displayName
165-
val email = profile.email
166-
val uid = profile.uid
167-
val toPass = "{\"accessToken\": \"${accessToken}\", \"keys\": '${keys}', \"avatar\": \"${avatar}\", \"displayName\": \"${displayName}\", \"email\": \"${email}\", \"uid\": \"${uid}\"}"
168-
mToCall = "finishLogin(${toPass})"
169-
this@MainActivity.runOnUiThread({
151+
mAccount?.getProfile(false)?.then { profile ->
152+
val profileJsonPayload = JSONObject()
153+
.put("accessToken", info.accessToken)
154+
.put("keys", info.keys)
155+
.put("avatar", profile.avatar)
156+
.put("displayName", profile.displayName)
157+
.put("email", profile.email)
158+
.put("uid", profile.uid).toString()
159+
mToCall = "finishLogin($profileJsonPayload)"
160+
this@MainActivity.runOnUiThread {
170161
// Clear the history so that the user can't use the back button to see broken pages
171162
// that were inserted into the history by the login process.
172-
mWebView!!.clearHistory()
163+
webView.clearHistory()
173164

174165
// We also reload this here because we need to make sure onPageFinished runs after mToCall has been set.
175166
// We can't guarantee that onPageFinished wasn't already called at this point.
176-
mWebView!!.loadUrl("file:///android_asset/android.html")
177-
})
178-
179-
180-
return FxaResult.fromValue(Unit)
181-
})
167+
webView.loadUrl("file:///android_asset/android.html")
168+
}
169+
FxaResult.fromValue(Unit)
170+
}
182171
}
183172
}
184173
}
185174
}
186-
Log.w("MAIN", "onPageStarted");
175+
Log.d(TAG_MAIN, "onPageStarted")
187176
}
188177

189178
override fun onPageFinished(url: String) {
190-
Log.w("MAIN", "onPageFinished")
179+
Log.d(TAG_MAIN, "onPageFinished")
191180
if (mToShare != null) {
192-
Log.w("INTENT", mToShare)
181+
Log.d(TAG_INTENT, mToShare)
193182

194-
mWebView?.postWebMessage(WebMessage(mToShare), Uri.EMPTY)
183+
webView.postWebMessage(WebMessage(mToShare), Uri.EMPTY)
195184
mToShare = null
196185
}
197186
if (mToCall != null) {
198-
this@MainActivity.runOnUiThread({
199-
mWebView?.evaluateJavascript(mToCall, fun (value: String) {
187+
this@MainActivity.runOnUiThread {
188+
webView.evaluateJavascript(mToCall) {
200189
mToCall = null
201-
})
202-
})
190+
}
191+
}
203192
}
204193
}
205194

206195
override fun onPageError(errorCode: Int, description: String, failingUrl: String) {
207-
Log.w("MAIN", "onPageError " + description)
196+
Log.d(TAG_MAIN, "onPageError($errorCode, $description, $failingUrl)")
208197
}
209198

210-
override fun onDownloadRequested(url: String, suggestedFilename: String, mimeType: String, contentLength: Long, contentDisposition: String, userAgent: String) {
211-
Log.w("MAIN", "onDownloadRequested")
199+
override fun onDownloadRequested(url: String,
200+
suggestedFilename: String,
201+
mimeType: String,
202+
contentLength: Long,
203+
contentDisposition: String,
204+
userAgent: String) {
205+
Log.d(TAG_MAIN, "onDownloadRequested")
212206
}
213207

214208
override fun onExternalPageRequest(url: String) {
215-
Log.w("MAIN", "onExternalPageRequest")
209+
Log.d(TAG_MAIN, "onExternalPageRequest($url)")
216210
}
217211

212+
companion object {
213+
private const val TAG_MAIN = "MAIN"
214+
private const val TAG_INTENT = "INTENT"
215+
private const val TAG_CONFIG = "CONFIG"
216+
private const val JS_INTERFACE_NAME = "Android"
217+
}
218218
}
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:app="http://schemas.android.com/apk/res-auto"
2+
<im.delight.android.webview.AdvancedWebView xmlns:android="http://schemas.android.com/apk/res/android"
43
xmlns:tools="http://schemas.android.com/tools"
4+
android:id="@+id/webView"
55
android:layout_width="match_parent"
66
android:layout_height="match_parent"
7-
tools:context=".MainActivity">
8-
9-
<im.delight.android.webview.AdvancedWebView
10-
android:id="@+id/webview"
11-
android:layout_width="match_parent"
12-
android:layout_height="match_parent" />
13-
</android.support.constraint.ConstraintLayout>
7+
tools:context=".MainActivity" />

android/build.gradle

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,15 @@ buildscript {
88
jcenter()
99
}
1010
dependencies {
11-
classpath 'com.android.tools.build:gradle:3.3.1'
12-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20"
13-
14-
// NOTE: Do not place your application dependencies here; they belong
15-
// in the individual module build.gradle files
11+
classpath 'com.android.tools.build:gradle:3.3.2'
12+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
1613
}
1714
}
1815

1916
allprojects {
2017
repositories {
2118
google()
22-
maven {
23-
url "https://maven.mozilla.org/maven2"
24-
}
19+
maven { url "https://maven.mozilla.org/maven2" }
2520
jcenter()
2621
maven { url "https://jitpack.io" }
2722
}

0 commit comments

Comments
 (0)