EDIT Error still shows even without copy and paste.
I'm trying to build a simple converter app and everything works fine but I discovered a problem which I can't seem to find the way forward. Here's the logcat:
2020-01-22 22:45:50.905 15060-15060/com.example.unitconverter E/may be Problem: 10.220462
2020-01-22 22:45:50.911 15060-15060/com.example.unitconverter E/text: 4.635924 //shows the text is set correctly
2020-01-22 22:45:50.924 15060-15060/com.example.unitconverter E/AndroidRuntime: FATAL EXCEPTION:
main
Process: com.example.unitconverter, PID: 15060
java.lang.IndexOutOfBoundsException
at android.graphics.Paint.getRunAdvance(Paint.java:2861)
at android.text.TextLine.getRunAdvance(TextLine.java:848)
at android.text.TextLine.handleText(TextLine.java:897)
at android.text.TextLine.handleRun(TextLine.java:1144)
at android.text.TextLine.measureRun(TextLine.java:531)
at android.text.TextLine.measure(TextLine.java:327)
at android.text.Layout.getHorizontal(Layout.java:1199)
at android.text.Layout.getHorizontal(Layout.java:1177)
at android.text.Layout.getPrimaryHorizontal(Layout.java:1148)
at android.text.Layout.getCursorPath(Layout.java:1816)
at android.widget.TextView.getUpdatedHighlightPath(TextView.java:7784)
at android.widget.TextView.onDraw(TextView.java:8091)
at android.view.View.draw(View.java:21875)
at android.view.View.updateDisplayListIfDirty(View.java:20748)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.View.draw(View.java:21601)
at android.view.ViewGroup.drawChild(ViewGroup.java:4558)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4333)
at android.view.View.draw(View.java:21878)
at com.google.android.material.textfield.TextInputLayout.draw(TextInputLayout.java:3614)
at android.view.View.updateDisplayListIfDirty(View.java:20748)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4542)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4514)
at android.view.View.updateDisplayListIfDirty(View.java:20703)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:725)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:731)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:840)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:3951)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3725)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3034)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1897)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8516)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:986)
at android.view.Choreographer.doCallbacks(Choreographer.java:764)
at android.view.Choreographer.doFrame(Choreographer.java:699)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:965)
2020-01-22 22:45:50.925 15060-15060/com.example.unitconverter E/AndroidRuntime: at
android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7099)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Since the links attached doesn't point to my code (most of them point to comment blocks in the android source code) I'm not sure what code to post..
Here's the XML file containing the activity.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/convert_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#DD9911"
app:layoutDescription="@xml/convert_scene"
app:motionProgress="1"
tools:context=".ConvertActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/convert_app_bar"
android:layout_width="match_parent"
android:layout_height="66dp"
android:elevation="4dp"
android:gravity="center"
android:paddingStart="0dp"
android:paddingEnd="8dp"
android:paddingBottom="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:layout_constraintBottom_toTopOf="@id/convertScroll"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight" />
<TextView
android:id="@+id/convert_header"
android:layout_width="0dp"
android:layout_height="50dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:lineSpacingMultiplier="0.88"
android:text="@string/angularAcceleration"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="#030303"
android:textSize="38sp" />
<TextView
android:id="@+id/app_bar_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0"
android:text="@string/mass"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="#030303"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="@+id/convert_app_bar"
tools:layout_editor_absoluteY="219dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/convert_app_barGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<com.example.unitconverter.subclasses.ConvertScrollView
android:id="@+id/convertScroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/rounded_front"
android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/convert_app_bar">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/convert_inner"
android:layout_width="match_parent"
android:splitMotionEvents="false"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/topGuide"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/firstBox"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:boxCornerRadiusBottomEnd="10dp"
app:boxCornerRadiusBottomStart="10dp"
app:boxCornerRadiusTopEnd="10dp"
app:boxCornerRadiusTopStart="10dp"
app:boxStrokeColor="#F8BBD0"
app:hintTextColor="@android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/topGuide"
app:layout_constraintWidth_percent="0.85">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/firstEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:letterSpacing="0.06"
android:paddingStart="17dp"
android:paddingEnd="52dp"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/secondBox"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
app:boxCornerRadiusBottomEnd="10dp"
app:boxCornerRadiusBottomStart="10dp"
app:boxCornerRadiusTopEnd="10dp"
app:boxCornerRadiusTopStart="10dp"
app:boxStrokeColor="#F8BBD0"
app:boxStrokeErrorColor="@color/design_default_color_primary_dark"
app:hintTextColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/firstBox"
app:layout_constraintWidth_percent="0.85">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/secondEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:letterSpacing="0.06"
android:paddingStart="17dp"
android:paddingEnd="52dp"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/topTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:maxWidth="43dp"
app:layout_constraintBottom_toBottomOf="@+id/firstBox"
app:layout_constraintEnd_toEndOf="@+id/firstBox"
app:layout_constraintHorizontal_bias="0.97"
app:layout_constraintStart_toStartOf="@id/firstBox"
app:layout_constraintTop_toTopOf="@+id/firstBox"
app:layout_constraintVertical_bias="0.52" />
<TextView
android:id="@+id/bottomTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:maxWidth="43dp"
app:layout_constraintBottom_toBottomOf="@+id/secondBox"
app:layout_constraintEnd_toEndOf="@id/secondBox"
app:layout_constraintHorizontal_bias="0.97"
app:layout_constraintStart_toStartOf="@id/secondBox"
app:layout_constraintTop_toTopOf="@+id/secondBox"
app:layout_constraintVertical_bias="0.49" />
<com.google.android.material.button.MaterialButton
android:id="@+id/top_button"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="42dp"
android:layout_height="52dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:insetLeft="2dp"
android:insetRight="0dp"
android:paddingLeft="-7dp"
android:paddingTop="0dp"
android:paddingRight="0dp"
android:paddingBottom="0dp"
app:cornerRadius="12dp"
app:icon="@drawable/arrow_down"
app:layout_constraintBottom_toBottomOf="@+id/firstBox"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/firstBox"
app:layout_constraintTop_toTopOf="@id/topGuide"
app:strokeWidth="2dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/bottom_button"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="42dp"
android:layout_height="52dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:insetLeft="2dp"
android:insetRight="0dp"
android:paddingLeft="-7dp"
android:paddingTop="0dp"
android:paddingRight="0dp"
android:paddingBottom="0dp"
app:cornerRadius="12dp"
app:icon="@drawable/arrow_down"
app:layout_constraintBottom_toBottomOf="@+id/secondBox"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/secondBox"
app:layout_constraintTop_toTopOf="@id/secondBox"
app:strokeWidth="2dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.example.unitconverter.subclasses.ConvertScrollView>
</androidx.constraintlayout.motion.widget.MotionLayout>
Here's the filter used on the edit text
//filters
fun filters(comma: Char, fullStop: Char, editText: TextInputEditText): Array<InputFilter> {
val filter = InputFilter { source, start, end, _, _, _ ->
val stringBuilder = StringBuilder(end - start)
var count = 0
for (i in start until end) {
if (source[i].isDigit() ||
source[i] == comma ||
source[i] == fullStop
) {
if (source[i] == fullStop) {
// ensures only one decimal separator is in the text
count++
if (count >= 2) continue
if (source.length > 1 && editText.isFocused) {
val text = editText.text
if (text != null
&& text.contains(fullStop)
) continue
}
}
stringBuilder.append(source[i])
}
}
stringBuilder
}
val lengthFilter = InputFilter.LengthFilter(50)
return arrayOf(filter, lengthFilter)
}
And then in the activity.kt
class ConvertActivity : AppCompatActivity(), ConvertFragment.ConvertDialogInterface {
private var swap = false
private var randomColor = -1
private var viewId = -1
private lateinit var dialog: ConvertFragment
private var isPrefix = false
private val bundle = Bundle()
lateinit var function: (String) -> String
var groupingSeparator by Delegates.notNull<Char>()
var decimalSeparator by Delegates.notNull<Char>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_convert)
setSupportActionBar(convert_app_bar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowTitleEnabled(false)
}
setSeparators()
firstEditText.apply {
setRawInputType(Configuration.KEYBOARD_12KEY)
filters = filters(groupingSeparator, decimalSeparator,this)
}
secondEditText.apply {
filters = filters(groupingSeparator, decimalSeparator,this)
setRawInputType(Configuration.KEYBOARD_12KEY)
}
getTextWhileTyping()
}
... // other methods
inner class CommonWatcher(editText: EditText, private val secondEditText: EditText) :
SeparateThousands(editText, groupingSeparator, decimalSeparator) {
override fun afterTextChanged(s: Editable?) {
super.afterTextChanged(s)
s?.toString()?.apply {
this.removeCommas(decimalSeparator)?.also {
Log.e("may be Problem", it)
secondEditText.setText(callBack(function, it))
Log.e("text","${secondEditText.text}")
}
}
}
}// end of inner class
private fun getTextWhileTyping() {
firstEditText.apply {
firstWatcher = CommonWatcher(this, secondEditText)
setOnFocusChangeListener { _, hasFocus ->
firstBoolean = hasFocus
if (hasFocus) {
addTextChangedListener(firstWatcher)
secondEditText.removeTextChangedListener(secondCommonWatcher)
reverse = false
}
}
}
secondEditText.apply {
secondCommonWatcher = CommonWatcher(this, firstEditText)
setOnFocusChangeListener { _, hasFocus ->
secondBoolean = hasFocus
if (hasFocus) {
addTextChangedListener(secondCommonWatcher)
firstEditText.removeTextChangedListener(firstWatcher)
reverse = true
}
}
}
}
}