So I am using CameraSource to preview camera scan in my application, but the problem is that the camera preview is always horizontal. TO be more clear look at this picture:
Preview
I mean the preview is just always tilted. How do I make the camera scan preview upwards (normal) ?
This is my current code:
private fun setupCameraSource() {
cameraSource = CameraSource.Builder(activity, cameraSourceCustomDetector)
.setAutoFocusEnabled(true).setRequestedFps(10F)
.setFacing(CameraSource.CAMERA_FACING_BACK).build()
}
Or if the whole code helps, I don't know if I'm doing it wrong.
class colorDetector(activity: Activity, cameraPreview: ImageView?, editCameraPreview: ImageView?) {
private val TAG = "colorDetector"
private var bitmap:Bitmap? = null
private val FPS: Number = 20
private var cameraSource: CameraSource? = null
private var cameraSourceCustomDetector: CustomDetector? = null
private var editCameraPreview: ImageView? = null
//private var visionUtilities: VisionUtilities? = null
private var activity: Activity? = null
private var cameraPreview: ImageView? = null
init {
this.activity = activity
this.cameraPreview = cameraPreview
this.editCameraPreview = editCameraPreview
cameraSourceCustomDetector = CustomDetector()
setupCameraSource()
}
private fun setupCameraSource() {
cameraSource = CameraSource.Builder(activity, cameraSourceCustomDetector)
.setAutoFocusEnabled(true).setRequestedFps(10F)
.setFacing(CameraSource.CAMERA_FACING_BACK).build()
}
fun start(context: Context) {
try {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
cameraSource?.start()
}
} catch (e: IOException) {
Log.d(TAG, "Couldn't start camera")
}
}
fun stop() {
cameraSource!!.stop()
}
fun saveImageToStorage() {
saveImgInStorage(bitmap!!,activity!!)
}
fun uploadImageToFirebase(type: uploadType) {
uploadPictureToFirebaseStorage(activity!!,bitmap,null,type)
}
inner class CustomDetector : Detector<Point>() {
#RequiresApi(Build.VERSION_CODES.O)
override fun detect(frame: Frame?): SparseArray<Point>? {
val byteBuffer: ByteBuffer = frame!!.grayscaleImageData
val bytes: ByteArray = byteBuffer.array()
val w = frame.metadata.width
val h = frame.metadata.height
val yuvimage = YuvImage(bytes, ImageFormat.NV21, w, h, null)
val baos = ByteArrayOutputStream()
yuvimage.compressToJpeg(
Rect(0, 0, w, h),
100,
baos
) // Where 100 is the quality of the generated jpeg
val jpegArray = baos.toByteArray()
bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.size)
activity?.runOnUiThread(Runnable{ getEditedImg(bitmap!!,w,h, cameraPreview!!, editCameraPreview!!,
activity!!
) })
return null
}
}
}
Well, in the end after a really long search, I've decided to do it like that, I'm not sure if it's the ideal way, but if someone wants, here is the solution I did:
I created a function called rotate:
// rotates a 'bitmap' clockwise direction by 'degree'
fun rotate(bitmap: Bitmap, degree: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(degree)
val resizedBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width, bitmap.width, false)
return Bitmap.createBitmap(resizedBitmap, 0, 0, resizedBitmap.width, resizedBitmap.height, matrix, true)
}
And replaced the 3 places where bitmap with rotate(bitmap, 90F).
Related
How do I get original size image after capture in Kotlin so that I can send the original size photo to a server? Here is my code:
DeliveryPresenter:
import com.stevenmorris.delivery.util.ImageStorageUtils
override fun capturePhoto() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
override fun onCapturePhotoResults(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val imageBitmap = data?.extras?.get("data") as Bitmap
view.onPhotoCaptured(imageBitmap);
}
}
DeliveryActivity:
private lateinit var imgPhoto: AppCompatImageView
private var photo: Bitmap? = null;
override fun onPhotoCaptured(photo: Bitmap) {
this.photo = photo
imgPhoto.setImageBitmap(photo)
}
ImageStorageUtils.kt
object ImageStorageUtils {
val TAG = javaClass.simpleName
fun savePhoto(activity: Activity,photo: Bitmap, fileName: String): Boolean {
val root = activity.filesDir.absolutePath;
val myDir = File("$root/photos")
myDir.mkdirs()
val file = File(myDir, fileName)
if (file.exists()) file.delete()
try {
val out = FileOutputStream(file)
photo.compress(Bitmap.CompressFormat.JPEG, 100, out)
out.flush()
out.close()
return true
} catch (e: Exception) {
AppLogger.e(TAG, e.message, e)
return false
}
}
}
Initial thoughts were can I save the photo without compressing it? or is there a way to save the photo in its original size directly?
I want to make an app where you have to guess two numbers that eaquals a random number. But my app crash at the start because of java.lang.NumberFormatException: For input string: ""
val intNumber1 = etNumber1.text.toString().toInt() is the line that causes the crash. But I dont know what to do.
Here is my main activity:
//Buttons und Text initialisieren
private lateinit var btnCheck: Button
private lateinit var tvRndNumber: TextView
private lateinit var etNumber1: EditText
private lateinit var etNumber2: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Buttons und Text verknüpfen
btnCheck = findViewById(R.id.checkButton)
tvRndNumber = findViewById(R.id.randomNumber)
etNumber1 = findViewById(R.id.inputNumber1)
etNumber2 = findViewById(R.id.inputNumber2)
val intNumber1 = etNumber1.text.toString().toInt()
val intNumber2 = etNumber2.text.toString().toInt()
fun getRandomNumber(): Int {
return Random.nextInt(0,100)
}
var intRdnNumber = getRandomNumber()
tvRndNumber.text = intRdnNumber.toString()
fun checkNumbers(num1: Int, num2: Int){
if (num1 + num2 == intRdnNumber) {
tvRndNumber.text = "Richtig"
}
else {
Toast.makeText(this,"Probier es nochmal", Toast.LENGTH_LONG).show()
}
}
btnCheck.setOnClickListener {
checkNumbers(intNumber1, intNumber2)
}
Try like the following
//....
val intNumber1 = etNumber1.text.toString()
val intNumber2 = etNumber2.text.toString()
//.....
btnCheck.setOnClickListener {
if(intNumber1.isNotEmpty && intNumber2.isNotEmpty{
checkNumbers(intNumber1.toInt(), intNumber2.toInt())
}else{
// input filed is empty
// show message or do nothing
}
}
val intNumber1 = if(etNumber1.text.isNotEmpty()) {
etNumber1.text.toString().toInt()
} else {
0
}
val intNumber2 = if(etNumber2.text.isNotEmpty()) {
etNumber2.text.toString().toInt()
} else {
0
}
I want to change language programmatically in Jetpack Compose. I've read quite some posts and watch videos but still can't find the way to do it. (The post and video are in Android view system.)
How to change language in kotlin (locale)
https://www.youtube.com/watch?v=xxPzi2h0Vvc
I want my app works like below image. After clicking the language, the whole app will change the language. Below code is the clickable's part. What should I do in this clickable part and MainActivity.kt?
#Composable
fun LanguageScreen(
navController: NavController,
) {
val context = LocalContext.current
val langList = arrayOf("English", "繁體中文", "简体中文", "日本語")
var items by remember {
mutableStateOf(
langList.map {
LanguageItem(
title = it,
isSelected = false
)
}
)
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
items(items.size) { i ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
items = items.mapIndexed { j, item ->
if (i == j) {
item.copy(isSelected = true)
} else item.copy(isSelected = false)
}
if (i == 0) {
setLocaleLang("", context)
} else if (i == 1) {
setLocaleLang("zh-rTW", context)
} else if (i == 2) {
setLocaleLang("zh-rCN", context)
} else {
setLocaleLang("ja", context)
}
}
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(text = items[i].title, fontSize = 20.sp)
if (items[i].isSelected) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Selected",
tint = Color.Blue,
modifier = Modifier.size(24.dp)
)
}
}
Spacer(
modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(Color.LightGray)
)
}
}
}
fun setLocaleLang(lang: String, context: Context) {
val locale = Locale(lang)
Locale.setDefault(locale)
val resources = context.resources
val configuration = resources.configuration
configuration.setLocale(locale)
resources.updateConfiguration(configuration, resources.displayMetrics)
val editor = context.getSharedPreferences("Settings", Context.MODE_PRIVATE).edit()
editor.putString("My_Lang", lang)
editor.apply()
}
fun loadLocale(context: Context) {
val sharedPreferences = context.getSharedPreferences("Settings", Activity.MODE_PRIVATE)
val language = sharedPreferences.getString("My_Lang", "")
setLocaleLang(language!!, context)
}
MainActivity.kt
class MainActivity : ComponentActivity() {
#ExperimentalFoundationApi
override fun onCreate(savedInstanceState: Bundle?) {
loadLocale(this)
super.onCreate(savedInstanceState)
setContent {
SpanishTravelTheme {
Image: https://i.stack.imgur.com/y5kcO.png
Try this
val context = LocalContext.current
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
val locale = Locale(language) //Here I assume you have access to the language you want
Locale.setDefault(locale)
val resources = context.getResources()
val configuration = resources.getConfiguration()
configuration.locale = locale
resources.updateConfiguration(configuration, resources.getDisplayMetrics())
}
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
)
You can try this
Create a helper object
LocaleUtils.kt
object LocaleUtils {
// [AppPrefs] is sharedpreferences or datastore
fun setLocale(c: Context, pref: AppPrefs) = updateResources(c, pref.language ?: "en") //use locale codes
private fun updateResources(context: Context, language: String) {
context.resources.apply {
val locale = Locale(language)
val config = Configuration(configuration)
context.createConfigurationContext(configuration)
Locale.setDefault(locale)
config.setLocale(locale)
context.resources.updateConfiguration(config, displayMetrics)
}
}
}
Call setLocale inside setContent to change the language at runtime.
setContent {
LocaleUtils.setLocale(LocalContext.current, viewModel.pref)
To change the App language
fun changeAppLanguage(languageISO: String) {
sharedPrefs.edit().putString(LANGUAGE_KEY, languageISO).apply()
}
Please remember to use language ISO 639-1 Code
here's a list of Locale codes
https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/localization
I am a student, new to kotlin, so I am converting java codes to kotlin to learn and see how it works, but I didnt understand what the error says.
private val _songs = ArrayList<SongInfo>()
internal lateinit var recyclerView: RecyclerView
internal lateinit var seekBar: SeekBar
internal lateinit var songAdapter: SongAdapter
internal var mediaPlayer: MediaPlayer? = null
private val myHandler = Handler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerView) as RecyclerView
seekBar = findViewById(R.id.seekBar) as SeekBar
songAdapter = SongAdapter(this, _songs)
recyclerView.adapter = songAdapter
val linearLayoutManager = LinearLayoutManager(this)
val dividerItemDecoration = DividerItemDecoration(recyclerView.context,
linearLayoutManager.orientation)
recyclerView.layoutManager = linearLayoutManager
recyclerView.addItemDecoration(dividerItemDecoration)
songAdapter.setOnItemClickListener { b, view, obj, position ->
if (b.text == "Stop") {
mediaPlayer!!.stop()
mediaPlayer!!.reset()
mediaPlayer!!.release()
mediaPlayer = null
b.text = "Play"
} else {
val runnable = Runnable {
try {
mediaPlayer = MediaPlayer()
mediaPlayer!!.setDataSource(obj.songUrl)
mediaPlayer!!.prepareAsync()
mediaPlayer!!.setOnPreparedListener { mp ->
mp.start()
seekBar.progress = 0
seekBar.max = mediaPlayer!!.duration
Log.d("Prog", "run: " + mediaPlayer!!.duration)
}
b.text = "Stop"
} catch (e: Exception) {
}
}
myHandler.postDelayed(runnable, 100)
}
}
checkUserPermission()
val t = runThread()
t.start()
}
inner class runThread : Thread() {
override fun run() {
while (true) {
try {
Thread.sleep(1000)
} catch (e: InterruptedException) {
e.printStackTrace()
}
Log.d("Runwa", "run: " + 1)
if (mediaPlayer != null) {
seekBar.post { seekBar.progress = mediaPlayer!!.currentPosition }
Log.d("Runwa", "run: " + mediaPlayer!!.currentPosition)
}
}
}
}
private fun checkUserPermission() {
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 123)
return
}
}
loadSongs()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
123 -> if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
loadSongs()
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
checkUserPermission()
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
private fun loadSongs() {
val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val selection = MediaStore.Audio.Media.IS_MUSIC + "!=0"
val cursor = contentResolver.query(uri, null, selection, null, null)
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
val name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))
val artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))
val url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))
val s = SongInfo(name, artist, url)
_songs.add(s)
} while (cursor.moveToNext())
}
cursor.close()
songAdapter = SongAdapter(this#MainActivity, _songs)
}
}
}
This is the error:
"Error:(46, 44) Type mismatch: inferred type is (???, ???, ???, ???)
-> Any but SongAdapter.OnItemClickListener was expected Error:(46, 46) Cannot infer a type for this parameter. Please specify it explicitly."
Batch conversion to Kotlin is not the best way to learn the language. I suggest you to re-implement your Android component in Kotlin manually, to get the feeling of language.
The error you see says: "I can not understand how this lambda with 4 parameters can be an instance of SongAdapter.OnItemClickListener, please help". You can try anonymous class in this place.
I have a MvxDialogViewController and I'm trying to use the progress indicator shown in the Xamarin example by adding bindable properties.
I can get the indicator to appear when I set Visble to true programatically but not when I bind to a vm property.
Here is the view code:
var bindings = this.CreateInlineBindingTarget<LoginViewModel>();
Root = new RootElement("Login")
{
new Section("Login Credentials")
{
new EntryElement("Username", "Enter user name").Bind(bindings, vm => vm.UserName),
new EntryElement("Password", "Enter password", "", true).Bind(bindings, vm => vm.Password)
}
};
_bindableProgress = new BindableProgress(UIScreen.MainScreen.Bounds).Bind(bindings, b => b.Visible, vm => vm.IsBusy);
_bindableProgress.Title = "Logging in...";
View.Add(_bindableProgress);
I also tried to bind like this:
var set = this.CreateBindingSet<LoginView, LoginViewModel>();
set.Bind(_bindableProgress).For(b => b.Title).To(vm => vm.ProgressTitle);
set.Bind(_bindableProgress).For(b => b.Visible).To(vm => vm.IsBusy);
set.Apply();
But neither way worked.
Here is by BindableProgress class:
public class BindableProgress : UIView
{
private UIActivityIndicatorView _activitySpinner;
private UILabel _loadingLabel;
public string Title { get; set; }
private bool _visible;
public bool Visible
{
get { return _visible; }
set
{
_visible = value;
if (_visible)
{
Show();
}
else
{
Hide();
}
}
}
public BindableProgress(RectangleF frame) : base(frame)
{
// configurable bits
BackgroundColor = UIColor.Black;
Alpha = 0;
AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
float labelHeight = 22;
float labelWidth = Frame.Width - 20;
// derive the center x and y
float centerX = Frame.Width/2;
float centerY = Frame.Height/2;
// create the activity spinner, center it horizontally and put it 5 points above center x
_activitySpinner = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.WhiteLarge);
_activitySpinner.Frame = new RectangleF(
centerX - (_activitySpinner.Frame.Width / 2),
centerY - _activitySpinner.Frame.Height - 20,
_activitySpinner.Frame.Width,
_activitySpinner.Frame.Height);
_activitySpinner.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
AddSubview(_activitySpinner);
// create and configure the label
_loadingLabel = new UILabel(new RectangleF(
centerX - (labelWidth/2),
centerY + 20,
labelWidth,
labelHeight
));
_loadingLabel.BackgroundColor = UIColor.Clear;
_loadingLabel.TextColor = UIColor.White;
_loadingLabel.TextAlignment = UITextAlignment.Center;
_loadingLabel.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
AddSubview(_loadingLabel);
}
private void Show()
{
_loadingLabel.Text = Title;
Alpha = 0.75f;
_activitySpinner.StartAnimating();
}
/// <summary>
/// Fades out the control and then removes it from the super view
/// </summary>
private void Hide()
{
_activitySpinner.StopAnimating();
Animate(
0.5, // duration
() => { Alpha = 0; },
() => { RemoveFromSuperview(); }
);
}
}
Any ideas?
UPDATE
My vm property looks like this
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set { _isBusy = value; RaisePropertyChanged(() => IsBusy); }
}
It works fine in Android so I'm guessing the problem in not with that.
IsBusy is probably false at binding time. So _visible is set to false and Hide() is called. Now the view is removed from the superview and you can't show it anymore, because Show() doesn't add it to the superview again. Try to omit the RemoveFromSuperview();. Or modify the Visible property like this:
public bool Visible
{
get { return _visible; }
set
{
if(_visible == value)
return;
_visible = value;
if (_visible)
{
Show();
}
else
{
Hide();
}
}
}