summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-06-24 11:23:48 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2019-06-24 11:23:48 -0300
commit70779ba7aa7aa41a24558f99698d8b106a4ec457 (patch)
tree9e7da4c3685bcd8568154aa25a19abdb21e7f249 /android
parentfa066de0989e814532112bc1f521582dc5940063 (diff)
parent67be4c180a615f2e89f394ec0f2ad2ee10d92a6a (diff)
downloadmullvadvpn-70779ba7aa7aa41a24558f99698d8b106a4ec457.tar.xz
mullvadvpn-70779ba7aa7aa41a24558f99698d8b106a4ec457.zip
Merge branch 'problem-report-on-android'
Diffstat (limited to 'android')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ProblemReportFragment.kt206
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt11
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt78
-rw-r--r--android/src/main/res/drawable/blue_button_background.xml16
-rw-r--r--android/src/main/res/drawable/input_text_background.xml8
-rw-r--r--android/src/main/res/layout/problem_report.xml195
-rw-r--r--android/src/main/res/layout/settings.xml28
-rw-r--r--android/src/main/res/values/colors.xml2
-rw-r--r--android/src/main/res/values/strings.xml21
-rw-r--r--android/src/main/res/values/styles.xml13
11 files changed, 577 insertions, 3 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
index 4b5414da71..1731ce2a56 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
@@ -18,6 +18,7 @@ import android.support.v4.app.FragmentActivity
import net.mullvad.mullvadvpn.dataproxy.AccountCache
import net.mullvad.mullvadvpn.dataproxy.LocationInfoCache
+import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport
import net.mullvad.mullvadvpn.dataproxy.RelayListListener
import net.mullvad.mullvadvpn.model.RelaySettings
import net.mullvad.mullvadvpn.model.Settings
@@ -36,6 +37,7 @@ class MainActivity : FragmentActivity() {
val accountCache = AccountCache(this)
val locationInfoCache = LocationInfoCache(asyncDaemon)
+ val problemReport = MullvadProblemReport()
var relayListListener = RelayListListener(this)
private var waitForDaemonJob: Job? = null
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ProblemReportFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ProblemReportFragment.kt
new file mode 100644
index 0000000000..1e72aef5f6
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ProblemReportFragment.kt
@@ -0,0 +1,206 @@
+package net.mullvad.mullvadvpn
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+
+import android.content.Context
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.EditText
+import android.widget.TextView
+import android.widget.ViewSwitcher
+
+import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport
+
+class ProblemReportFragment : Fragment() {
+ private lateinit var problemReport: MullvadProblemReport
+
+ private lateinit var bodyContainer: ViewSwitcher
+ private lateinit var userEmailInput: EditText
+ private lateinit var userMessageInput: EditText
+ private lateinit var sendButton: Button
+
+ private lateinit var sendingSpinner: View
+ private lateinit var sentSuccessfullyIcon: View
+ private lateinit var failedToSendIcon: View
+
+ private lateinit var sendStatusLabel: TextView
+ private lateinit var sendDetailsLabel: TextView
+ private lateinit var responseMessageLabel: TextView
+ private lateinit var responseEmailLabel: TextView
+
+ private lateinit var editMessageButton: Button
+ private lateinit var tryAgainButton: Button
+
+ private var sendReportJob: Job? = null
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+
+ val parentActivity = context as MainActivity
+
+ problemReport = parentActivity.problemReport
+ problemReport.collect()
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val view = inflater.inflate(R.layout.problem_report, container, false)
+
+ view.findViewById<View>(R.id.back).setOnClickListener {
+ activity?.onBackPressed()
+ }
+
+ bodyContainer = view.findViewById<ViewSwitcher>(R.id.body_container)
+ userEmailInput = view.findViewById<EditText>(R.id.user_email)
+ userMessageInput = view.findViewById<EditText>(R.id.user_message)
+ sendButton = view.findViewById<Button>(R.id.send_button)
+
+ sendingSpinner = view.findViewById<View>(R.id.sending_spinner)
+ sentSuccessfullyIcon = view.findViewById<View>(R.id.sent_successfully_icon)
+ failedToSendIcon = view.findViewById<View>(R.id.failed_to_send_icon)
+
+ sendStatusLabel = view.findViewById<TextView>(R.id.send_status)
+ sendDetailsLabel = view.findViewById<TextView>(R.id.send_details)
+ responseMessageLabel = view.findViewById<TextView>(R.id.response_message)
+ responseEmailLabel = view.findViewById<TextView>(R.id.response_email)
+
+ editMessageButton = view.findViewById<Button>(R.id.edit_message_button)
+ tryAgainButton = view.findViewById<Button>(R.id.try_again_button)
+
+ sendButton.setOnClickListener {
+ sendReportJob?.cancel()
+ sendReportJob = sendReport()
+ }
+
+ editMessageButton.setOnClickListener {
+ showForm()
+ }
+
+ tryAgainButton.setOnClickListener {
+ sendReportJob = sendReport()
+ }
+
+ userEmailInput.setText(problemReport.userEmail)
+ userMessageInput.setText(problemReport.userMessage)
+
+ setSendButtonEnabled(!userMessageInput.text.isEmpty())
+ userMessageInput.addTextChangedListener(InputWatcher())
+
+ return view
+ }
+
+ override fun onDestroyView() {
+ sendReportJob?.cancel()
+
+ problemReport.userEmail = userEmailInput.text.toString()
+ problemReport.userMessage = userMessageInput.text.toString()
+ problemReport.deleteReportFile()
+
+ super.onDestroyView()
+ }
+
+ private fun sendReport() = GlobalScope.launch(Dispatchers.Main) {
+ val userEmail = userEmailInput.text.toString()
+
+ problemReport.userEmail = userEmail
+ problemReport.userMessage = userMessageInput.text.toString()
+
+ showSendingScreen()
+
+ if (problemReport.send().await()) {
+ clearForm()
+ showSuccessScreen(userEmail)
+ } else {
+ showErrorScreen()
+ }
+ }
+
+ private fun clearForm() {
+ userEmailInput.setText("")
+ userMessageInput.setText("")
+
+ problemReport.userEmail = ""
+ problemReport.userMessage = ""
+ }
+
+ private fun showForm() {
+ bodyContainer.displayedChild = 0
+ }
+
+ private fun showSendingScreen() {
+ bodyContainer.displayedChild = 1
+
+ sendingSpinner.visibility = View.VISIBLE
+ sentSuccessfullyIcon.visibility = View.GONE
+ failedToSendIcon.visibility = View.GONE
+
+ sendStatusLabel.visibility = View.VISIBLE
+ sendDetailsLabel.visibility = View.GONE
+ responseMessageLabel.visibility = View.GONE
+ responseEmailLabel.visibility = View.GONE
+
+ sendStatusLabel.setText(R.string.sending)
+
+ editMessageButton.visibility = View.GONE
+ tryAgainButton.visibility = View.GONE
+ }
+
+ private fun showSuccessScreen(userEmail: String) {
+ sendingSpinner.visibility = View.GONE
+
+ sentSuccessfullyIcon.visibility = View.VISIBLE
+ sendStatusLabel.visibility = View.VISIBLE
+ sendDetailsLabel.visibility = View.VISIBLE
+
+ if (!userEmail.isEmpty()) {
+ responseMessageLabel.visibility = View.VISIBLE
+ responseEmailLabel.visibility = View.VISIBLE
+ responseEmailLabel.text = userEmail
+ }
+
+ sendStatusLabel.setText(R.string.sent)
+ sendDetailsLabel.setText(R.string.sent_thanks)
+ }
+
+ private fun showErrorScreen() {
+ sendingSpinner.visibility = View.GONE
+
+ failedToSendIcon.visibility = View.VISIBLE
+ sendStatusLabel.visibility = View.VISIBLE
+ sendDetailsLabel.visibility = View.VISIBLE
+
+ sendStatusLabel.setText(R.string.failed_to_send)
+ sendDetailsLabel.setText(R.string.failed_to_send_details)
+
+ editMessageButton.visibility = View.VISIBLE
+ tryAgainButton.visibility = View.VISIBLE
+ }
+
+ private fun setSendButtonEnabled(enabled: Boolean) {
+ sendButton.setEnabled(enabled)
+ sendButton.alpha = if (enabled) 1.0F else 0.5F
+ }
+
+ inner class InputWatcher : TextWatcher {
+ override fun beforeTextChanged(text: CharSequence, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(text: CharSequence, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(text: Editable) {
+ setSendButtonEnabled(!text.isEmpty())
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
index ee89ed7945..3400d43e58 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
@@ -34,7 +34,12 @@ class SettingsFragment : Fragment() {
activity?.finishAndRemoveTask()
}
- view.findViewById<View>(R.id.account).setOnClickListener { openAccountSettings() }
+ view.findViewById<View>(R.id.account).setOnClickListener {
+ openSubFragment(AccountFragment())
+ }
+ view.findViewById<View>(R.id.report_a_problem).setOnClickListener {
+ openSubFragment(ProblemReportFragment())
+ }
remainingTimeLabel = RemainingTimeLabel(parentActivity, view)
@@ -51,7 +56,7 @@ class SettingsFragment : Fragment() {
super.onDestroyView()
}
- private fun openAccountSettings() {
+ private fun openSubFragment(fragment: Fragment) {
fragmentManager?.beginTransaction()?.apply {
setCustomAnimations(
R.anim.fragment_enter_from_right,
@@ -59,7 +64,7 @@ class SettingsFragment : Fragment() {
R.anim.fragment_half_enter_from_left,
R.anim.fragment_exit_to_right
)
- replace(R.id.main_fragment, AccountFragment())
+ replace(R.id.main_fragment, fragment)
addToBackStack(null)
commit()
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt
new file mode 100644
index 0000000000..d1794fbc3f
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt
@@ -0,0 +1,78 @@
+package net.mullvad.mullvadvpn.dataproxy
+
+import java.io.File
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+
+const val PROBLEM_REPORT_PATH = "/data/data/net.mullvad.mullvadvpn/problem_report.txt"
+
+class MullvadProblemReport {
+ private var collectJob: Deferred<Boolean>? = null
+ private var sendJob: Deferred<Boolean>? = null
+
+ var userEmail = ""
+ var userMessage = ""
+
+ val isActive: Boolean
+ get() {
+ synchronized(this) {
+ val collectJob = this.collectJob
+ val sendJob = this.sendJob
+
+ return (collectJob != null && collectJob.isActive) ||
+ (sendJob != null && sendJob.isActive)
+ }
+ }
+
+ init {
+ System.loadLibrary("mullvad_jni")
+ }
+
+ fun collect() {
+ synchronized(this) {
+ if (!isActive) {
+ collectJob = GlobalScope.async(Dispatchers.Default) {
+ deleteReportFile()
+ collectReport(PROBLEM_REPORT_PATH)
+ }
+ }
+ }
+ }
+
+ fun send(): Deferred<Boolean> {
+ synchronized(this) {
+ var currentJob = sendJob
+
+ if (currentJob == null || currentJob.isCompleted) {
+ currentJob = GlobalScope.async(Dispatchers.Default) {
+ val result = (collectJob?.await() ?: false) &&
+ sendProblemReport(userEmail, userMessage, PROBLEM_REPORT_PATH)
+
+ if (result) {
+ deleteReportFile()
+ }
+
+ result
+ }
+
+ sendJob = currentJob
+ }
+
+ return currentJob
+ }
+ }
+
+ fun deleteReportFile() {
+ File(PROBLEM_REPORT_PATH).delete()
+ }
+
+ private external fun collectReport(reportPath: String): Boolean
+ private external fun sendProblemReport(
+ userEmail: String,
+ userMessage: String,
+ reportPath: String
+ ): Boolean
+}
diff --git a/android/src/main/res/drawable/blue_button_background.xml b/android/src/main/res/drawable/blue_button_background.xml
new file mode 100644
index 0000000000..e53b0be561
--- /dev/null
+++ b/android/src/main/res/drawable/blue_button_background.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="false">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp"/>
+ <solid android:color="@color/blue80"/>
+ </shape>
+ </item>
+
+ <item android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp"/>
+ <solid android:color="@color/blue60"/>
+ </shape>
+ </item>
+</selector>
diff --git a/android/src/main/res/drawable/input_text_background.xml b/android/src/main/res/drawable/input_text_background.xml
new file mode 100644
index 0000000000..545bc362f8
--- /dev/null
+++ b/android/src/main/res/drawable/input_text_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ >
+ <corners android:radius="4dp"/>
+ <solid android:color="@color/white"/>
+</shape>
diff --git a/android/src/main/res/layout/problem_report.xml b/android/src/main/res/layout/problem_report.xml
new file mode 100644
index 0000000000..c3d782e7ad
--- /dev/null
+++ b/android/src/main/res/layout/problem_report.xml
@@ -0,0 +1,195 @@
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/darkBlue"
+ android:orientation="vertical"
+ android:gravity="left"
+ android:elevation="2dp"
+ >
+ <LinearLayout android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="12dp"
+ android:orientation="horizontal"
+ android:gravity="center_vertical | left"
+ android:clickable="true"
+ android:background="?android:attr/selectableItemBackground"
+ >
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginRight="8dp"
+ android:src="@drawable/icon_back"
+ />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white60"
+ android:textSize="13sp"
+ android:textStyle="bold"
+ android:text="@string/settings"
+ />
+ </LinearLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginHorizontal="24dp"
+ android:textColor="@color/white"
+ android:textSize="32sp"
+ android:textStyle="bold"
+ android:text="@string/report_a_problem"
+ />
+ <ViewSwitcher android:id="@+id/body_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:layout_marginBottom="24dp"
+ android:layout_marginHorizontal="24dp"
+ android:textColor="@color/white80"
+ android:textSize="13sp"
+ android:text="@string/problem_report_description"
+ />
+ <EditText android:id="@+id/user_email"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:layout_marginBottom="12dp"
+ android:layout_marginHorizontal="22dp"
+ android:singleLine="true"
+ android:hint="@string/user_email_hint"
+ style="@style/InputText"
+ />
+ <EditText android:id="@+id/user_message"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_marginHorizontal="22dp"
+ android:singleLine="false"
+ android:hint="@string/user_message_hint"
+ android:gravity="top"
+ style="@style/InputText"
+ />
+ <Button android:id="@+id/send_button"
+ android:layout_marginHorizontal="24dp"
+ android:layout_marginVertical="16dp"
+ android:enabled="false"
+ android:text="@string/send"
+ style="@style/GreenButton"
+ />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginVertical="16dp"
+ android:layout_marginHorizontal="24dp"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:layout_width="60dp"
+ android:layout_height="60dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="32dp"
+ >
+ <ProgressBar android:id="@+id/sending_spinner"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ android:indeterminateOnly="true"
+ android:indeterminateDuration="600"
+ android:indeterminateDrawable="@drawable/icon_spinner"
+ />
+ <ImageView android:id="@+id/sent_successfully_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:src="@drawable/icon_success"
+ android:visibility="gone"
+ />
+ <ImageView android:id="@+id/failed_to_send_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:src="@drawable/icon_fail"
+ android:visibility="gone"
+ />
+ </FrameLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:textColor="@color/green"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:text="@string/secure_connection"
+ android:textAllCaps="true"
+ />
+ <TextView android:id="@+id/send_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:textColor="@color/white"
+ android:textSize="34sp"
+ android:textStyle="bold"
+ android:text="@string/sending"
+ />
+ <TextView android:id="@+id/send_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white60"
+ android:textSize="13sp"
+ android:text="@string/sent_thanks"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/response_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white60"
+ android:textSize="13sp"
+ android:text="@string/sent_contact"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/response_email"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white"
+ android:textSize="13sp"
+ android:textStyle="bold"
+ android:visibility="gone"
+ />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+
+ <Button android:id="@+id/edit_message_button"
+ android:layout_marginTop="16dp"
+ android:text="@string/edit_message"
+ android:visibility="gone"
+ style="@style/BlueButton"
+ />
+ <Button android:id="@+id/try_again_button"
+ android:layout_marginTop="16dp"
+ android:text="@string/try_again"
+ android:visibility="gone"
+ style="@style/GreenButton"
+ />
+ </LinearLayout>
+ </ViewSwitcher>
+</LinearLayout>
diff --git a/android/src/main/res/layout/settings.xml b/android/src/main/res/layout/settings.xml
index 664a2dc790..84c94dcf95 100644
--- a/android/src/main/res/layout/settings.xml
+++ b/android/src/main/res/layout/settings.xml
@@ -66,6 +66,34 @@
android:src="@drawable/icon_chevron"
/>
</LinearLayout>
+ <LinearLayout android:id="@+id/report_a_problem"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:paddingHorizontal="16dp"
+ android:background="@drawable/cell_button_background"
+ android:clickable="true"
+ android:gravity="center"
+ >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingHorizontal="8dp"
+ android:paddingVertical="17dp"
+ android:textColor="@color/white"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:text="@string/report_a_problem"
+ />
+ <ImageView
+ android:layout_width="14dp"
+ android:layout_height="24dp"
+ android:layout_weight="0"
+ android:alpha="0.6"
+ android:src="@drawable/icon_chevron"
+ />
+ </LinearLayout>
<Button android:id="@+id/quit_button"
android:layout_marginTop="24dp"
android:layout_marginLeft="24dp"
diff --git a/android/src/main/res/values/colors.xml b/android/src/main/res/values/colors.xml
index 0e7b0cea4e..e882682904 100644
--- a/android/src/main/res/values/colors.xml
+++ b/android/src/main/res/values/colors.xml
@@ -2,10 +2,12 @@
<color name="colorPrimary">#294D73</color>
<color name="blue">#294D73</color>
<color name="blue80">#CC294D73</color>
+ <color name="blue60">#99294D73</color>
<color name="blue40">#66294D73</color>
<color name="blue20">#33294D73</color>
<color name="darkBlue">#192E45</color>
<color name="white">#FFFFFF</color>
+ <color name="white80">#CCFFFFFF</color>
<color name="white60">#99FFFFFF</color>
<color name="white40">#66FFFFFF</color>
<color name="white20">#33FFFFFF</color>
diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml
index eef3679d2a..b0087e1942 100644
--- a/android/src/main/res/values/strings.xml
+++ b/android/src/main/res/values/strings.xml
@@ -16,6 +16,7 @@
<string name="settings_account">Account</string>
<string name="less_than_a_day_left">less than a day left</string>
<string name="out_of_time">Out of time</string>
+ <string name="report_a_problem">Report a problem</string>
<string name="quit">Quit</string>
<string name="account_number">Account number</string>
@@ -24,6 +25,26 @@
<string name="paid_until">Paid until</string>
<string name="log_out">Log out</string>
+ <string name="problem_report_description">
+ To help you more effectively, your app\'s log file will be attached to this message. Your
+ data will remain secure and private, as it is anonymised before being sent over an encrypted
+ channel.
+ </string>
+ <string name="user_email_hint">Your email (optional)</string>
+ <string name="user_message_hint">Describe your problem</string>
+ <string name="send">Send</string>
+ <string name="sending">Sending...</string>
+ <string name="sent">Sent</string>
+ <string name="failed_to_send">Failed to send</string>
+ <string name="sent_thanks">Thanks! We will look into this.</string>
+ <string name="sent_contact">If needed we will contact you on</string>
+ <string name="failed_to_send_details">
+ You may need to go back to the app\'s main screen and click Disconnect before trying again.
+ Don\'t worry, the information you entered will remain in the form.
+ </string>
+ <string name="edit_message">Edit message</string>
+ <string name="try_again">Try again</string>
+
<string name="unsecured_connection">Unsecured connection</string>
<string name="creating_secure_connection">Creating secure connection</string>
<string name="secure_connection">Secure connection</string>
diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml
index 43c29dc1bb..2ace57e88b 100644
--- a/android/src/main/res/values/styles.xml
+++ b/android/src/main/res/values/styles.xml
@@ -4,6 +4,15 @@
<item name="android:windowBackground">@color/blue</item>
</style>
+ <style name="InputText" parent="Widget.AppCompat.EditText">
+ <item name="android:padding">14dp</item>
+ <item name="android:background">@drawable/input_text_background</item>
+ <item name="android:textCursorDrawable">@drawable/text_input_cursor</item>
+ <item name="android:textColorHint">@color/blue40</item>
+ <item name="android:textColor">@color/blue</item>
+ <item name="android:textSize">13sp</item>
+ </style>
+
<style name="Button" parent="Widget.AppCompat.Button.Borderless">
<item name="android:layout_height">44dp</item>
<item name="android:layout_width">match_parent</item>
@@ -21,6 +30,10 @@
<item name="android:background">@drawable/red_button_background</item>
</style>
+ <style name="BlueButton" parent="Button">
+ <item name="android:background">@drawable/blue_button_background</item>
+ </style>
+
<style name="White20Button" parent="Button">
<item name="android:background">@drawable/white20_button_background</item>
</style>