Version 1.0.0 for release
Upgrade and fixes - Fixes #2 change default pwd - Fixes #5 change kios info display layout, removes refresh button - Fixes #4 make ping status more visible - Fixes #3 Make actual wifi network visible on wifi list - Fix EventObserver LifeCycle on KioskActivity - update git ignore - Change Json schema validate lib + resolve fucking pro guard rules with it - Fix password validation if password is too weak on server
This commit is contained in:
parent
d5dfdbdaaa
commit
41c25ca049
11 changed files with 181 additions and 248 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -39,3 +39,10 @@ gastest.o
|
|||
|
||||
#Private data
|
||||
private/
|
||||
|
||||
# Release APK
|
||||
app/release/
|
||||
|
||||
# Proguard generated files
|
||||
app/seeds.txt
|
||||
app/usage.txt
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ android {
|
|||
targetSdkVersion 33
|
||||
versionCode 14
|
||||
//versionName "2.2.3"
|
||||
versionName "1.0.0"
|
||||
versionName "1.0.1"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
|
|
@ -82,10 +82,8 @@ android {
|
|||
}
|
||||
|
||||
packagingOptions {
|
||||
pickFirst 'META-INF/ASL-2.0.txt'
|
||||
pickFirst 'META-INF/LGPL-3.0.txt'
|
||||
pickFirst 'draftv4/schema'
|
||||
pickFirst 'draftv3/schema'
|
||||
exclude 'META-INF/ASL-2.0.txt'
|
||||
exclude 'META-INF/LGPL-3.0.txt'
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
|
|
@ -125,19 +123,17 @@ dependencies {
|
|||
implementation files('libs/com.serialIntCaster-1.1.0.jar')
|
||||
|
||||
// Life-cycle
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.5.1'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-process:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-common:2.4.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
|
||||
|
||||
// Json
|
||||
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
|
||||
implementation "com.fasterxml.jackson.core:jackson-core:2.9.8"
|
||||
implementation "com.fasterxml.jackson.core:jackson-annotations:2.9.8"
|
||||
implementation "com.github.fge:jackson-coreutils:1.8"
|
||||
implementation "com.github.fge:json-schema-core:1.2.5"
|
||||
implementation "com.github.fge:json-schema-validator:2.2.6"
|
||||
implementation "com.networknt:json-schema-validator:1.0.70"
|
||||
|
||||
kapt "androidx.room:room-compiler:2.4.3"
|
||||
implementation "com.google.guava:guava:30.0-android"
|
||||
|
||||
|
||||
implementation "com.google.android.material:material:1.7.0"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ class KioskActivity : AppCompatActivity(), LifecycleObserver {
|
|||
*/
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
setContentView(R.layout.activity_kiosk)
|
||||
|
||||
// * Setup AppInfo
|
||||
|
|
@ -97,6 +96,8 @@ class KioskActivity : AppCompatActivity(), LifecycleObserver {
|
|||
|
||||
// Check NetWork Connection
|
||||
listenToNetworkConnectionChanges()
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@ import android.content.DialogInterface
|
|||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.location.LocationManager
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Bundle
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
|
|
@ -70,6 +73,9 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener {
|
|||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_kiosk_diagnostic)
|
||||
|
||||
// * Setup AppInfo
|
||||
appInfo = ApplicationInfo(PreferenceManager.getDefaultSharedPreferences(applicationContext))
|
||||
|
||||
// * Request Permissions
|
||||
permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
isInternetPermissionGranted = permissions[Manifest.permission.INTERNET] ?: isInternetPermissionGranted
|
||||
|
|
@ -94,8 +100,6 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener {
|
|||
btnRefresh.setOnClickListener(this)
|
||||
btnGoBack.setOnClickListener(this)
|
||||
|
||||
// * Setup AppInfo
|
||||
appInfo = ApplicationInfo(PreferenceManager.getDefaultSharedPreferences(applicationContext))
|
||||
|
||||
// * Wont be able to => Hide
|
||||
btnReboot.visibility = View.INVISIBLE
|
||||
|
|
@ -193,6 +197,14 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener {
|
|||
// * Scan changed
|
||||
resetWifiTableView()
|
||||
|
||||
val actualNetworkName =
|
||||
if(mWifiManager.connectionInfo.ssid.length === 0)
|
||||
mWifiManager.connectionInfo.bssid.replace('"', ' ').trim()
|
||||
else mWifiManager.connectionInfo.ssid.replace('"', ' ').trim()
|
||||
val actualNetworkFreq = getWifiType(mWifiManager.connectionInfo.frequency)
|
||||
|
||||
Log.d("ACTUAL NETWORK", actualNetworkName)
|
||||
|
||||
mWifiManager.scanResults.forEach{
|
||||
/** From -100 to 0
|
||||
* https://stackoverflow.com/questions/15797920/how-to-convert-wifi-signal-strength-from-quality-percent-to-rssi-dbm/15798024#15798024
|
||||
|
|
@ -200,11 +212,19 @@ class KioskDiagnosticActivity : AppCompatActivity(), View.OnClickListener {
|
|||
var precisePercent = if (it.level <= -100) 0 else if(it.level >= -50) 100 else 2 * (it.level + 100);
|
||||
val row = LayoutInflater.from(this@KioskDiagnosticActivity)
|
||||
.inflate(R.layout.activity_kiosk_diagnostic_wifi_row, null) as TableRow
|
||||
val networkName = if(it.SSID.length === 0) it.BSSID else it.SSID
|
||||
val networkName = if(it.SSID.length === 0)
|
||||
it.BSSID.replace('"', ' ').trim()
|
||||
else it.SSID.replace('"', ' ').trim()
|
||||
Log.d("NETWORK", networkName)
|
||||
(row.findViewById<View>(R.id.tableCellSSID) as TextView).text = networkName.substring(0, min(networkName.length, 18))
|
||||
(row.findViewById<View>(R.id.tableCellSignal) as TextView).text = it.level.toString()
|
||||
(row.findViewById<View>(R.id.tableCellSignalPercent) as TextView).text = "$precisePercent %"
|
||||
(row.findViewById<View>(R.id.tableCellSignalFreq) as TextView).text = getWifiType(it.frequency)
|
||||
if (actualNetworkName == networkName && actualNetworkFreq == getWifiType(it.frequency)) {
|
||||
val ssidTextView = (row.findViewById<View>(R.id.tableCellSSID) as TextView)
|
||||
ssidTextView.setTypeface(ssidTextView.typeface, Typeface.BOLD_ITALIC)
|
||||
ssidTextView.setTextColor(Color.BLACK)
|
||||
}
|
||||
tableLayoutWifiRows.addView(row)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class KioskPingActivity : AppCompatActivity(), View.OnClickListener {
|
|||
toastMessage(this, "FQDN AVG $avg ms")
|
||||
runOnUiThread {
|
||||
textResult.text = "Accessible ${inetToPing.hostAddress}"
|
||||
textResult.setTextColor(Color.GREEN)
|
||||
textResult.setTextColor("#009933".toColorInt())
|
||||
}
|
||||
return@Thread
|
||||
} catch(e: PingFailedException) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.app.Activity
|
|||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -18,6 +19,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.viewModels
|
||||
import com.fasterxml.jackson.core.JsonProcessingException
|
||||
import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.fasterxml.jackson.databind.JsonMappingException
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.gaurav.avnc.R
|
||||
import com.gaurav.avnc.model.ServerProfile
|
||||
|
|
@ -25,11 +27,13 @@ import com.gaurav.avnc.ui.ldc.KioskActivity
|
|||
import com.gaurav.avnc.ui.ldc.KioskParameterPasswordActivity
|
||||
import com.gaurav.avnc.ui.ldc.events.AppSwitchedToForegroundEvent
|
||||
import com.gaurav.avnc.ui.ldc.events.NetworkStateChangedEvent
|
||||
import com.gaurav.avnc.ui.ldc.lib.exceptions.PasswordValidationException
|
||||
import com.gaurav.avnc.ui.vnc.startVncActivity
|
||||
import com.gaurav.avnc.viewmodel.HomeViewModel
|
||||
import com.github.fge.jsonschema.main.JsonSchema
|
||||
import com.github.fge.jsonschema.main.JsonSchemaFactory
|
||||
import com.google.common.net.InetAddresses
|
||||
import com.networknt.schema.JsonSchemaFactory
|
||||
import com.networknt.schema.SchemaValidatorsConfig
|
||||
import com.networknt.schema.SpecVersion
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.OkHttpClient
|
||||
|
|
@ -88,9 +92,6 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
|
|||
*/
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// * Register event bus
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -126,6 +127,9 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
|
|||
btnVNC.setOnClickListener(this)
|
||||
btnParameters.setOnClickListener(this)
|
||||
|
||||
// * Register event bus
|
||||
EventBus.getDefault().register(this)
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
|
@ -321,8 +325,13 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
|
|||
|
||||
if(!isJSONValid(activity, bodyResponse)) {
|
||||
toastMessage(activity, "Erreur réponse invalide du serveur")
|
||||
return
|
||||
} else {
|
||||
saveJSONPassword(activity, bodyResponse)
|
||||
try {
|
||||
saveJSONPassword(activity, bodyResponse)
|
||||
} catch(e: PasswordValidationException) {
|
||||
toastMessage(activity, "Erreur mot de passe sur le serveur est invalide")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -348,21 +357,39 @@ class KioskHomeFragment : Fragment(), View.OnClickListener {
|
|||
|
||||
// * Validate JSON Schema
|
||||
return try {
|
||||
val factory: JsonSchemaFactory = JsonSchemaFactory.byDefault()
|
||||
val inputStream: InputStream = activity.assets.open("security.schema.json");
|
||||
val schemaString = inputStream.bufferedReader().use{it.readText()}
|
||||
val inputStream: InputStream = resources.assets.open("security.schema.json");
|
||||
val schemaString = inputStream.reader().readText()
|
||||
val schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)
|
||||
val schema = schemaFactory.getSchema(schemaString)
|
||||
|
||||
val m = ObjectMapper()
|
||||
val jsonSchema: JsonSchema = factory.getJsonSchema(m.readTree(schemaString))
|
||||
val config: SchemaValidatorsConfig = SchemaValidatorsConfig()
|
||||
Log.d("test", config.toString())
|
||||
|
||||
jsonSchema.validate(m.readTree(jsonString)).isSuccess
|
||||
val jsonNode = ObjectMapper().readTree(jsonString)
|
||||
|
||||
// * Validate json against schema
|
||||
val errors = schema.validate(jsonNode)
|
||||
|
||||
if (errors.size > 0) {
|
||||
Log.d("JSON", "Invalid JSON against schema")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch(e: IOException) {
|
||||
false
|
||||
} catch(e: JsonProcessingException) {
|
||||
Log.d("JSON", e.message)
|
||||
false
|
||||
} catch(e: JsonMappingException) {
|
||||
Log.d("JSON", e.message)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Json password
|
||||
* @throws com.gaurav.avnc.ui.ldc.lib.exceptions.PasswordValidationException
|
||||
*/
|
||||
private fun saveJSONPassword(activity: KioskActivity, jsonString: String) {
|
||||
val mapper = ObjectMapper()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ import android.util.Log
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.GridLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -24,8 +23,7 @@ import org.greenrobot.eventbus.ThreadMode
|
|||
class KioskInformationFragment : Fragment(), View.OnClickListener {
|
||||
|
||||
// * View Elements
|
||||
private lateinit var infoGridLayout: GridLayout
|
||||
private lateinit var btnReloadInfo: Button
|
||||
private lateinit var infoLinearLayout: LinearLayout
|
||||
|
||||
/**
|
||||
* On Start
|
||||
|
|
@ -71,11 +69,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
|
|||
// Inflate the layout for this fragment
|
||||
val view:View = inflater.inflate(R.layout.fragment_kiosk_information, container, false)
|
||||
|
||||
infoGridLayout = view.findViewById<GridLayout>(R.id.infoGridLayout)
|
||||
btnReloadInfo = view.findViewById<Button>(R.id.btnReloadInfo)
|
||||
|
||||
btnReloadInfo.setOnClickListener(this)
|
||||
btnReloadInfo.visibility = View.INVISIBLE
|
||||
infoLinearLayout = view.findViewById<LinearLayout>(R.id.infoLinearLayout)
|
||||
|
||||
return view;
|
||||
}
|
||||
|
|
@ -95,9 +89,6 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
|
|||
// * Action UI events
|
||||
override fun onClick(v: View) {
|
||||
Log.d("click", "click")
|
||||
when (v.id) {
|
||||
R.id.btnReloadInfo -> reloadNetWorkInfo(v, this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -123,7 +114,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
|
|||
private fun displayTextInfo() {
|
||||
// * Load actual network configuration
|
||||
val activity = (activity as KioskActivity)
|
||||
val cells = infoGridLayout.children as Sequence<TextView>
|
||||
val cells = infoLinearLayout.children as Sequence<TextView>
|
||||
|
||||
val ip = activity.appInfo.ip
|
||||
val gateway = activity.appInfo.gateway
|
||||
|
|
@ -139,8 +130,7 @@ class KioskInformationFragment : Fragment(), View.OnClickListener {
|
|||
)
|
||||
|
||||
info.onEachIndexed(fun (index, infoLine) {
|
||||
(cells.elementAt(index * 2) as TextView).text = infoLine.key
|
||||
(cells.elementAt(index * 2 + 1) as TextView).text = infoLine.value
|
||||
(cells.elementAt(index ) as TextView).text = infoLine.key + "\t" + infoLine.value
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
|
|||
var vncArgPort: Int = 5900
|
||||
private set
|
||||
/** The default password for configuration */
|
||||
var configPassword: String = "5XtpqEz!A5"
|
||||
var configPassword: String = "73ezheJ8"
|
||||
private set
|
||||
/** The server FQDN from where config should be fetched */
|
||||
private var configServerFqdn: String = "http://localtid"
|
||||
|
|
@ -272,6 +272,7 @@ class ApplicationInfo(private var preferences: SharedPreferences) {
|
|||
|
||||
/**
|
||||
* Assign settings password
|
||||
* @throws PasswordValidationException
|
||||
*/
|
||||
fun setPassword(password: String) {
|
||||
// * Must contain lower, upper and number min 8 max 30
|
||||
|
|
|
|||
11
app/src/main/res/drawable/bg_rect.xml
Normal file
11
app/src/main/res/drawable/bg_rect.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<shape android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#000"/>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
||||
|
||||
</inset>
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
android:text="Succès !"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#000000"
|
||||
android:textSize="15sp"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="parent" />
|
||||
|
|
|
|||
|
|
@ -27,213 +27,93 @@
|
|||
|
||||
<LinearLayout
|
||||
android:id="@+id/infoLinearLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginLeft="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btnReloadInfo">
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
|
||||
|
||||
<GridLayout
|
||||
android:id="@+id/infoGridLayout"
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:columnCount="2"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
|
||||
android:maxEms="15"
|
||||
android:maxLines="4"
|
||||
android:padding="10dp"
|
||||
android:singleLine="false"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom_no_top_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_top"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnSpan="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_top_no_left"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
</GridLayout>
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect_no_bottom"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill"
|
||||
android:background="@drawable/bg_rect"
|
||||
android:padding="10dp"
|
||||
android:text="TEXT"
|
||||
android:textColor="#000000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:lineHeight="18sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnReloadInfo"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:backgroundTint="#D4021D"
|
||||
android:foreground="@drawable/ic_refresh"
|
||||
android:foregroundTint="@color/design_default_color_background"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Loading…
Add table
Reference in a new issue