Development record of developer who study hard everyday.

레이블이 Android인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Android인 게시물을 표시합니다. 모든 게시물 표시
, ,

How to watch CPU usage using adb in android

 How to watch CPU usage using adb in android


1. Show CPU usage respectively in apps.

adb shell top -n 1 -s cpu


->details about top options

-m num : Maximum number of processes to display

-n num : Updates to show before exiting

-d num : Seconds to wait between updates

-s col : Column to sort by (cpu, vss, rss, thr)

-H : Show threads instead of prcesses

-h : Display this help screen


2. Show CPU usage in specific app

adb shell top -n 60 -d 1 | FINDSTR <package name>

This command shows CPU usages during 60 seconds by 1 second.





Share:
Read More
,

(Sloved) Android Studio APK install error: "local path doesn't exist"

 


I encounter the error "Android Studio APK install error: "local path doesn't exist" while building android source.

The solution is

  • Go to your project directory.In that directory search for .apk file....
  • You will find a apk with name of your project+debug-unalighned.apk.
  • Open .iml file insideyour project folder that contain project source directory.
  • Open and add write <option name="APK_PATH" value="/build/apk/(apk file name that was found earlier with apk extension)" /> inside <configration> <configration/> tags.
  • Now go and run your project...


Share:
Read More
, ,

How to separate string data by sentences

How to separate string data by sentences

안드로이드 블로그

When I am developing android app using Kotlin, I had to separate string data by one sentence.

There might be so many solutions, but I want short code using regular expression.

My solution is

1
2
3
4
5
6
7
8
9
10
fun main() {
    val text = "감오리는 사막이나 농촌지역에서 주로 발견되며, 땅속에 다닐 수 있는 능력이 있어 땅속에서 먹이를 찾기 위해 파묻기를 합니다. 감오리는 매우 활발한 동물로 매일 새로운 먹이를 찾으며 유혈자로 알려져 있습니다. 감오리는 오래 살아 가는 동물이며, 50년에서 70년까지 살 수 있습니다. 감오리의 수명은 종류에 따라 다르지만, 평균적으로 10년 정도입니다. 감오리는 인간과 친밀한 관계를 맺을 수 있는 동물로, 그들은 상호 의존적인 관계에서 존재합니다."
 
    val pattern = Regex("[^.!?]+[.!?]")        
    val matches = pattern.findAll(text)
 
    val sentences = matches.map { it.value.trim() }.toList()
 
    println(sentences)
}
cs


Share:
Read More
,

Useful ADB shortkeys

Useful ADB shortkeys



Android Debug Bridge(ADB) is CLI tool which communicate with device.
Android SDK Platform includes ADB package.


- Move directory

adb shell cd "path"


- Reboot device

adb reboot


- Show connected devices

adb devices


- Start server

adb start-server


- Kill server

adb kill-server


- Exectue command to specific device

adb -s "example device name" "example command"


- Connect wifi (Available Under Android 10)

adb connect "example device ip address"


- Move file to device

adb push "example local file" "example device directory"


- Take device file to local

adb pull "example device file" "example local directory"


- Get writing and reading permission

adb shell mount -o remount,rw /system


- Turn on wifi

adb shell svc wifi enable


-Turn off wifi

adb shell svc wifi disable


- Turn on mobile data

adb shell svc data enable


- Turn off mobile data

adb shell svc data disable


- Change device's date

1) adb shell "su 0 toybox date 042523592021.59"
(toybox date use MMDDhhmm[[CC]YY][.ss] format)

2) adb shell "su 0 toolbox date -s 20210425.235959"
(toolbox date use YYYYMMDD.HHmmss format)


- Symbolic link

adb shell ln -sf "example original file" "example target file"


- Show system property list

adb shell getprop


- Start activity

adb shell am start -a android.intent.action.MAIN -n "example/package/activity_name"


- Start service

adb shell am startservice -n "example/package/service_name"


- Start broadcast

adb shell am broadcast -a "example broadcast name"


- Start Broadcast extra

1) adb shell am broadcast -a $(example_action_name) -es ${example_extra_key} ${example_extra_string_value}

2) adb shell am broadcast -a $(example_action_name) -ez ${example_extra_key} $(extra_boolean_value)

3) adb shell am broadcast -a $(example_action_name) -ei $(example_extra_key) $(example_extra_int_value)


- Verify specific package's PID

adb shell pidof "example package name"


-Kill Process

adb shell am force-stop "example package name"
adb shell kill -9 PID (Available only if root)


- Show installed packages

adb shell cmd package list packages


- Find package's path

adb shell pm path "example package name"


- Screen capture

adb shell screencap -p /sdcard/Download/"example file name"
adb pull /sdcard/Download/"example file name" "local directory"


- Remove file

adb shell rm "example file"


- Remove directory

adb shell -r "example file"





Share:
Read More
,

Text-To-Speech(TTS) not worked above Android 13

 Text-To-Speech(TTS) not worked above Android 13

Android development blog


Text-to-speech(TTS) is the underlying software used by screen readers when they convert text into spoken content..

However, you can not have TTS service basically from Android 13.

You must take action following below guide.

  1. Open your device Settings .
  2. Select Accessibility and then Text-to-speech output.
  3. Choose your preferred engine, language, speech rate, and pitch.
    • The default text-to-speech engine choices vary by device. Options can include Google's Text-to-speech engine, the device manufacturer's engine, and any third-party text-to-speech engines that you've downloaded from the Google Play Store.





Share:
Read More
,

Variety of Stream in Java(자바 스트림 종류)

Variety of Stream in Java

자바 스트림 종류

Android development blog


종류IO 대상 기준자료의 종류 기준스트림의 기능 기준
FileInputStream입력 스트림바이트 단위기반 스트림
FileReader입력 스트림문자 단위기반 스트림
BufferedInputStream입력 스트림바이트 단위보조 스트림
BufferedReader입력 스트림문자 단위보조 스트림
FileOutputStream출력 스트림바이트 단위기반 스트림
FileWriter출력 스트림문자 단위기반 스트림
BufferedOutputStream출력 스트림바이트 단위보조 스트림
BufferedWriter출력 스트림문자 단위보조 스트림


✊ 문자 기반 스트림

자바의 Char 형은 2 byte를 사용하는데, 바이트 단위는 입출력 단위가 1 byte이므로 문자를 처리하기 어려웠다.

이를 보완하기 위해 등장한 것이 바로 문자 기반 스트림이다.


✋ 보조 스트림

기반 스트림은 대상에 직접 자료를 읽고 쓰는 기능의 스트림이다.

보토 스트림은 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있는 스트림을 말한다.

오로지 보완하는 용도이기에 실제데이터를 주고 받지 않고, 데이터를 입출력하는 기능은 없다.

따라서 스트림을 먼저 생성한 후, 보조 스트림을 생성하여 사용한다.


출처: 여기











Share:
Read More
,

Get Uri from android drawable resource

 Get Uri from android drawable resource

Android development blog

1. What I have in my android drawable folder

android project drawable folder


2. Get Uri from drawable

val imgResourceId = context.resources.getIdentifier("album" + song.image.substringBefore("."), "drawable", context.packageName)
val imageUri = Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(context.resources.getResourcePackageName(imgResourceId))
.appendPath(context.resources.getResourceTypeName(imgResourceId))
.appendPath(context.resources.getResourceEntryName(imgResourceId))
.build()


3. Result

android.resource://net.twobeone.battlesinger/drawable/album00290

android.resource://net.twobeone.battlesinger/drawable/album01468

android.resource://net.twobeone.battlesinger/drawable/album49492


Share:
Read More
, , ,

SideEffect in Android Composable(collectAsStateWithLifecycle, LaunchedEffect, rememberCoroutineScope)

 SideEffect in Android Composable


Android developer blog

✋✋✋ SideEffect

A side-effect in Compose is a change to the state of the app that happens outside the scope of a composable function.

For example, opening a new screen when the user taps on a button, or showing a message when the app doesn't have Internet connection.


1. collectAsStateWithLifecycle

dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.0"
}

First, add dependency of "androidx.lifecycle:lifecycle-runtime-compose"


@OptIn(ExperimentalMaterialApi::class)
@Composable
fun CraneHomeContent(
onExploreItemClicked: OnExploreItemClicked,
openDrawer: () -> Unit,
modifier: Modifier = Modifier,
viewModel: MainViewModel = viewModel(),
) {
// TODO Codelab: collectAsStateWithLifecycle step - consume stream of data from the ViewModel
// val suggestedDestinations: List<ExploreModel> = remember { emptyList() }
val suggestedDestinations by viewModel.suggestedDestinations.collectAsStateWithLifecycle()

val onPeopleChanged: (Int) -> Unit = { viewModel.updatePeople(it) }
var tabSelected by remember { mutableStateOf(CraneScreen.Fly) }

BackdropScaffold(
modifier = modifier,
scaffoldState = rememberBackdropScaffoldState(BackdropValue.Revealed),
frontLayerScrimColor = Color.Unspecified,
appBar = {
HomeTabBar(openDrawer, tabSelected, onTabSelected = { tabSelected = it })
},
backLayerContent = {
SearchContent(
tabSelected,
viewModel,
onPeopleChanged
)
},
frontLayerContent = {
when (tabSelected) {
CraneScreen.Fly -> {
ExploreSection(
title = "Explore Flights by Destination",
exploreList = suggestedDestinations,
onItemClicked = onExploreItemClicked
)
}
CraneScreen.Sleep -> {
ExploreSection(
title = "Explore Properties by Destination",
exploreList = viewModel.hotels,
onItemClicked = onExploreItemClicked
)
}
CraneScreen.Eat -> {
ExploreSection(
title = "Explore Restaurants by Destination",
exploreList = viewModel.restaurants,
onItemClicked = onExploreItemClicked
)
}
}
}
)
}

Second, in CrameHomeContent composable, you can consume the list of destinations as form of state using collectAsstateWithLifecycle() method.


💪💪💪 Compose also offers APIs for Android's most popular stream-based solutions:

- LiveData.observeAsState() in "androidx.compose.runtime:runtime-livedata"

- Observable.subscribeAsState() in "androidx.compose.runtime:runtime-rxjava2"


2. LaunchedEffect and rememberUpdatedState

To call suspend functions safely from inside a composable, use the LaunchedEffect API, which triggers a coroutine scoped side-effect in Compose.

When LaunchedEffect enters the Composition, it launches a coroutine with the block of code passed as a key parameter.

The coroutine will be canceled if LaunchedEffect leaves the composition.


LaunchedEffect take a variable number of keys as a parameter that are used to restart the effect whenever one of those keys changes.

@Composable
fun LandingScreen(onTimeout: () -> Unit, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
val currentOnTimeOut by rememberUpdatedState(onTimeout)    //1

LaunchedEffect(key1 = Unit) {    //2
delay(SplashWaitTime)
onTimeout.invoke()
}
Image(painterResource(id = R.drawable.ic_crane_drawer), contentDescription = null)
}
}

1 => The rememberUpdatedState() make us refer to the latest onTimeout function that LandingScreen was recomposed with

2 => Create an coroutine scope that matches the lifecycle of LandingScreen.

Because the key parameter is Unit that is not changed, the delay shouldn't start again.


3. rememberCoroutineScope

API to open the navigation drawer is suspend function.

How do we call suspend function in callback function?

@Composable
fun CraneHome(
onExploreItemClicked: OnExploreItemClicked,
modifier: Modifier = Modifier,
) {
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState,
modifier = Modifier.statusBarsPadding(),
drawerContent = {
CraneDrawer()
}
) { padding ->
val scope = rememberCoroutineScope()
CraneHomeContent(
modifier = modifier.padding(padding),
onExploreItemClicked = onExploreItemClicked,
openDrawer = {
scope.launch {
scaffoldState.drawerState.open()
}
}
)
}
}

We want a CoroutineScope that follows the lifecycle of its call-site.

The rememberCoroutineScope API returns a CoroutineScope bound to the point in the Composition where you call it.

The scope will be automatically canceled once it leaves the Composition.


✊✊✊ LaunchedEffect vs rememberCoroutineScope

Using LauncedEffect is not possible to use in regular callback which is outside of the Composition.

Both can produce CoroutineScope but, LaunchedEffect can control when the side-effect would be called.


Share:
Read More
, , , , ,

How to use UnityPlayer in Android Compose

How to use UnityPlayer in Android Compose

Android Development blog

In my company, I have to use 3D avatar animation using UnityPlayer derived from Unity module.

The base code I will use is consist of Android Compose.

So, I want to use UnityPlayer with Android Compose.

However, There were no information about using UnityPlayer with Compose.

This is why I write this post.


☝I introduce this post on the condition that you add UnityModule.

If you not, read this post first!!

https://antwhale94.blogspot.com/2024/03/AddingUnityModuleToAndroid.html


1. Add dependency

android {
...
buildFeatures {
viewBinding true
}     ...
}

dependencies {

implementation 'androidx.compose.ui:ui-viewbinding:1.6.0'

}

You should add viewBinding dependency.

And you should add "androidx.compose.ui:ui-viewbinding" to take xml into Compose.


2.  MainActivity.kt

class MainActivity : ComponentActivity() {
val TAG = MainActivity::class.java.simpleName
lateinit var mUnityPlayer: UnityPlayer

@ExperimentalMaterial3Api
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

mUnityPlayer = UnityPlayer(this)
val glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1)
val trueColor8888 = false
mUnityPlayer.init(glesMode, trueColor8888)

setContent {
Surface(
modifier = Modifier
.fillMaxSize()
) {
MLCChatTheme {
NavView()
}
}
}


}

override fun onDestroy() {
Log.d(TAG, "onDestroy: ")
super.onDestroy()

mUnityPlayer.quit()
}

override fun onPause() {
Log.d(TAG, "onPause: ")
super.onPause()
mUnityPlayer.pause()
}

override fun onResume() {
Log.d(TAG, "onResume: ")
super.onResume()
mUnityPlayer.resume()
}

override fun onLowMemory() {
Log.d(TAG, "onLowMemory: ")
super.onLowMemory()
mUnityPlayer.lowMemory()
}

override fun onTrimMemory(level: Int) {
Log.d(TAG, "onTrimMemory: ")
super.onTrimMemory(level)
if(level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL)
mUnityPlayer.lowMemory()
}

override fun onConfigurationChanged(newConfig: Configuration) {
Log.d(TAG, "onConfigurationChanged: ")
super.onConfigurationChanged(newConfig)
mUnityPlayer.configurationChanged(newConfig)
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
Log.d(TAG, "onWindowFocusChanged: $hasFocus")
super.onWindowFocusChanged(hasFocus)
mUnityPlayer.windowFocusChanged(hasFocus)
}

}

fun Context.getActivity(): ComponentActivity? = when (this) {
is ComponentActivity -> this
is ContextWrapper -> baseContext.getActivity()
else -> null
}

In my experience, The UnityPlayer derived from activity only can play animation.

I don't know why, so I make UnityPlayer object in MainActivity using MainActivity context.

The lowest function getActivity is used to get MainActivity from Composable function.


3. xml layout to put UnityPlayer

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frameLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

</FrameLayout>

This layout file's name is "avatar_view_layout.xml"

Obviously, you can change this file name if you want.


4. Composable function to show UnityPlayer

@Composable
fun AvatarView() {
val TAG = "AvatarView"
val localContext = LocalContext.current

Log.d(TAG, "AvatarView composition")

val unityPlayer = (localContext.getActivity() as MainActivity).mUnityPlayer    //1
AndroidViewBinding(AvatarViewLayoutBinding::inflate) {     //2
if(unityPlayer.parent == null) {
Log.d(TAG,
"AvatarView added")
frameLayout.addView(unityPlayer.view)        //3
unityPlayer.resume()
}
}

DisposableEffect(key1 = localContext) {
onDispose {        //4
Log.d(TAG, "remove AvatarView")
(unityPlayer.
parent as FrameLayout).removeView(unityPlayer.view)

unityPlayer.pause()

}
}
}

1 => Get UnityPlayer object using local context

2 => AndroidViewBinding to use xml in Compose

3 => Add UnityPlayer to FrameLayout and resume UnityPlayer

4 => DisposableEffect to notice when AvatarView composable leave.

You should remove UnityPlayer from framelayout and pause it to restart when recomposing.


I don't know this is good way to use UnityPlayer with Compose, but This is only way I got this.




Share:
Read More