...
This commit is contained in:
parent
5a8e2293ca
commit
92d228d2e0
@ -54,7 +54,7 @@ target_link_libraries(native_renderer
|
||||
avutil
|
||||
swscale
|
||||
swresample
|
||||
|
||||
jnigraphics
|
||||
# 안드로이드 기본 라이브러리들
|
||||
${log-lib}
|
||||
${android-lib}
|
||||
|
||||
@ -237,6 +237,26 @@ void Renderer::handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWi
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::updateWeatherBitmap(void* pixels, int width, int height) {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
weatherWidth_ = width;
|
||||
weatherHeight_ = height;
|
||||
|
||||
size_t size = static_cast<size_t>(width * height * 4);
|
||||
weatherPixels_.assign(static_cast<uint8_t*>(pixels), static_cast<uint8_t*>(pixels) + size);
|
||||
|
||||
}
|
||||
|
||||
void Renderer::clearWeatherBitmap() {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
weatherPixels_.clear();
|
||||
}
|
||||
|
||||
void Renderer::setImageRenderFrame(int frame) {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
imageFrame_ = frame;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 메인 렌더링 루프 (교통정리 담당)
|
||||
// ====================================================================
|
||||
@ -252,7 +272,7 @@ void Renderer::renderFrame(ANativeWindow* window) {
|
||||
currentFrameDelay_ = std::chrono::milliseconds(static_cast<long long>(1000.0 / currentMedia_.getFps()));
|
||||
LOGI("Media type: Video. Frame delay set to %lldms for %.2f FPS", currentFrameDelay_.count(), currentMedia_.getFps());
|
||||
} else {
|
||||
currentFrameDelay_ = std::chrono::milliseconds(70); // 이미지일 경우 30fps
|
||||
currentFrameDelay_ = std::chrono::milliseconds(imageFrame_); // 이미지일 경우 30fps
|
||||
LOGI("Media type: Image. Frame delay set to 33ms (~30 FPS)");
|
||||
}
|
||||
currentState_ = RenderState::ANIMATING;
|
||||
@ -288,6 +308,65 @@ void Renderer::renderFrame(ANativeWindow* window) {
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
if (!weatherPixels_.empty()) {
|
||||
// 1. 위치 업데이트 (픽셀 단위 이동)
|
||||
weatherX_ += weatherVelX_;
|
||||
weatherY_ += weatherVelY_;
|
||||
|
||||
// 2. 화면 경계 검사 및 튕기기 (Bounce)
|
||||
// 가로 경계
|
||||
if (weatherX_ < 0) {
|
||||
weatherX_ = 0;
|
||||
weatherVelX_ *= -1.0f;
|
||||
} else if (weatherX_ + weatherWidth_ > surfaceWidth) {
|
||||
weatherX_ = (float)surfaceWidth - weatherWidth_;
|
||||
weatherVelX_ *= -1.0f;
|
||||
}
|
||||
|
||||
// 세로 경계
|
||||
if (weatherY_ < 0) {
|
||||
weatherY_ = 0;
|
||||
weatherVelY_ *= -1.0f;
|
||||
} else if (weatherY_ + weatherHeight_ > surfaceHeight) {
|
||||
weatherY_ = (float)surfaceHeight - weatherHeight_;
|
||||
weatherVelY_ *= -1.0f;
|
||||
}
|
||||
|
||||
// 3. 그리기 (기존의 블렌딩 로직 사용)
|
||||
uint32_t* dstPixels = (uint32_t*)buffer.bits;
|
||||
int dstStride = buffer.stride;
|
||||
|
||||
for (int y = 0; y < weatherHeight_; ++y) {
|
||||
int targetY = static_cast<int>(weatherY_) + y;
|
||||
if (targetY < 0 || targetY >= surfaceHeight) continue;
|
||||
|
||||
for (int x = 0; x < weatherWidth_; ++x) {
|
||||
int targetX = static_cast<int>(weatherX_) + x;
|
||||
if (targetX < 0 || targetX >= surfaceWidth) continue;
|
||||
|
||||
const uint8_t* src = &weatherPixels_[(y * weatherWidth_ + x) * 4];
|
||||
uint8_t alpha = src[3];
|
||||
if (alpha == 0) continue;
|
||||
|
||||
uint32_t* dst = &dstPixels[targetY * dstStride + targetX];
|
||||
|
||||
// 단순 합성을 위해 하드코딩된 ARGB/RGBA 순서 주의
|
||||
uint8_t dr = (*dst >> 16) & 0xFF;
|
||||
uint8_t dg = (*dst >> 8) & 0xFF;
|
||||
uint8_t db = (*dst) & 0xFF;
|
||||
|
||||
uint8_t r = (src[0] * alpha + dr * (255 - alpha)) / 255;
|
||||
uint8_t g = (src[1] * alpha + dg * (255 - alpha)) / 255;
|
||||
uint8_t b = (src[2] * alpha + db * (255 - alpha)) / 255;
|
||||
|
||||
*dst = (0xFF << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ANativeWindow_unlockAndPost(window);
|
||||
}
|
||||
|
||||
|
||||
@ -39,7 +39,9 @@ public:
|
||||
void setFadeDuration(int durationMs);
|
||||
void setPageTurnDelay(int delayMs);
|
||||
void setTransitionMode(int mode);
|
||||
|
||||
void setImageRenderFrame(int frame);
|
||||
void updateWeatherBitmap(void* pixels, int width, int height);
|
||||
void clearWeatherBitmap();
|
||||
void drawMedia(ANativeWindow_Buffer& buffer, MediaAsset& media, float alpha, float finalOffsetX, float finalOffsetY, float finalScale);
|
||||
void renderVideoFrame(MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha);
|
||||
void renderImageFrame(const MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha);
|
||||
@ -84,4 +86,20 @@ private:
|
||||
std::mt19937 randomEngine_;
|
||||
|
||||
void determineActiveAnimationMode();
|
||||
|
||||
|
||||
std::vector<uint8_t> weatherPixels_;
|
||||
int weatherWidth_ = 0;
|
||||
int weatherHeight_ = 0;
|
||||
int imageFrame_ = 33;
|
||||
// 위치 변수
|
||||
float weatherX_ = 100.0f;
|
||||
float weatherY_ = 100.0f;
|
||||
|
||||
// 속도 변수 (방향 및 속도 조절)
|
||||
float weatherVelX_ = 2.5f;
|
||||
float weatherVelY_ = 2.0f;
|
||||
|
||||
std::mutex weatherMutex_;
|
||||
|
||||
};
|
||||
@ -5,7 +5,7 @@
|
||||
#include <thread>
|
||||
#include "Renderer.h"
|
||||
#include "Preloader.h"
|
||||
|
||||
#include <android/bitmap.h>
|
||||
#define LOG_TAG "NativeRenderer"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
@ -113,6 +113,27 @@ Java_bums_lunatic_launcher_wall_NativeRenderer_nativeRender(JNIEnv* env, jobject
|
||||
renderer->renderFrame(window);
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetWeatherBitmap(JNIEnv* env, jobject, jlong nativeHandle, jobject bitmap) {
|
||||
Renderer* renderer = reinterpret_cast<Renderer*>(nativeHandle);
|
||||
if (!renderer) return;
|
||||
|
||||
// 비트맵이 null로 넘어오면 데이터를 지움
|
||||
if (bitmap == nullptr) {
|
||||
renderer->clearWeatherBitmap();
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidBitmapInfo info;
|
||||
void* pixels;
|
||||
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) return;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) return;
|
||||
|
||||
renderer->updateWeatherBitmap(pixels, info.width, info.height);
|
||||
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartNextPreload(JNIEnv* env, jobject, jlong nativeHandle, jint fd) {
|
||||
@ -124,6 +145,18 @@ Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartNextPreload(JNIEnv* en
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetImageRenderFrame(JNIEnv* env, jobject, jlong nativeHandle, jint frame) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
// Preloader가 Renderer의 일부가 되었다고 가정하고 호출 (추후 Renderer 수정 필요)
|
||||
// 여기서는 간단하게 setNextMedia를 호출하는 것으로 변경합니다.
|
||||
renderer->setImageRenderFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetAnimationSpeed(JNIEnv* env, jobject, jlong nativeHandle, jfloat speed) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
|
||||
@ -1,19 +1,27 @@
|
||||
package bums.lunatic.launcher.wall
|
||||
|
||||
import android.app.WallpaperManager
|
||||
import android.content.ContentUris
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Environment
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.os.BatteryManager
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.provider.MediaStore
|
||||
import android.service.wallpaper.WallpaperService
|
||||
import android.util.Log
|
||||
import android.view.SurfaceHolder
|
||||
import androidx.work.ListenableWorker
|
||||
import bums.lunatic.launcher.utils.Blog
|
||||
import bums.lunatic.launcher.workers.LocationUpdateService
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class MyWallpaperService : WallpaperService() {
|
||||
|
||||
@ -25,6 +33,18 @@ class MyWallpaperService : WallpaperService() {
|
||||
Log.d(TAG, "onCreateEngine: New engine instance created.")
|
||||
return NativeRenderEngine()
|
||||
}
|
||||
private fun getBatteryStatus(): Pair<Int, Boolean> {
|
||||
val intent = registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
||||
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
|
||||
val scale = intent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
|
||||
val status = intent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
|
||||
|
||||
val batteryPct = (level / scale.toFloat() * 100).toInt()
|
||||
val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||
status == BatteryManager.BATTERY_STATUS_FULL
|
||||
|
||||
return Pair(batteryPct, isCharging)
|
||||
}
|
||||
|
||||
inner class NativeRenderEngine : Engine() {
|
||||
private lateinit var handlerThread: HandlerThread
|
||||
@ -136,6 +156,16 @@ class MyWallpaperService : WallpaperService() {
|
||||
initializeRenderer()
|
||||
}
|
||||
requestSyncRenderState()
|
||||
|
||||
if (visible) {
|
||||
// 화면이 켜지면 즉시 업데이트하고 타이머 시작
|
||||
handler.removeCallbacks(updateWeatherRunnable)
|
||||
handler.post(updateWeatherRunnable)
|
||||
} else {
|
||||
// 화면이 꺼지면 타이머 중지
|
||||
handler.removeCallbacks(updateWeatherRunnable)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --- ⬇️ 상태 동기화를 요청하는 함수 추가 ⬇️ ---
|
||||
@ -194,12 +224,18 @@ class MyWallpaperService : WallpaperService() {
|
||||
nativeRenderer?.setAnimationMode(NativeRenderer.ANIMATION_MODE_PAN)
|
||||
nativeRenderer?.setTransitionMode(NativeRenderer.TRANSITION_MODE_FADE)
|
||||
nativeRenderer?.setAnimationSpeed(1.0f)
|
||||
nativeRenderer?.setImageRenderFrame(70)
|
||||
NativeRenderer.nativeSetNextMediaCallback(nextMediaCallback)
|
||||
|
||||
|
||||
if (mediaFiles.isEmpty()) {
|
||||
handler.post { loadMediaFiles() }
|
||||
}
|
||||
|
||||
handler.removeCallbacks(updateWeatherRunnable)
|
||||
// 즉시 첫 번째 비트맵 생성 및 전송
|
||||
handler.post(updateWeatherRunnable)
|
||||
|
||||
}
|
||||
|
||||
val requiredSizeRatio = 0.5
|
||||
@ -243,6 +279,110 @@ class MyWallpaperService : WallpaperService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawBitmapFromText(weatherLines: List<String>, isCharging: Boolean = false): Bitmap? {
|
||||
val dateFull = SimpleDateFormat("yyyy.MM.dd", Locale.KOREAN).format(Date())
|
||||
// val timeFull = SimpleDateFormat(if (isCharging) "HH:mm:ss" else "HH:mm", Locale.KOREAN).format(Date())
|
||||
|
||||
val finalLines = mutableListOf<String>()
|
||||
if (weatherLines.isNotEmpty()) finalLines.add(weatherLines[0]) // Index 0: 날씨
|
||||
|
||||
// finalLines.add(timeFull) // Index 2: 시간
|
||||
if (weatherLines.size > 1) {
|
||||
for (i in 1 until weatherLines.size - 1) finalLines.add(weatherLines[i])
|
||||
finalLines.add(weatherLines.last()) // 마지막: 주소
|
||||
}
|
||||
finalLines.add(dateFull) // Index 1: 날짜
|
||||
|
||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = Color.WHITE
|
||||
textAlign = Paint.Align.CENTER
|
||||
typeface = Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL)
|
||||
setShadowLayer(10f, 3f, 3f, Color.BLACK)
|
||||
}
|
||||
|
||||
val titleSize = 80f
|
||||
val dateSize = 50f
|
||||
val addressSize = 30f
|
||||
val lineSpacingMultiplier = 0.2f // 폰트 크기의 20%를 순수 여백으로 사용
|
||||
|
||||
// --- 4. 크기 측정 및 라인별 높이 저장 ---
|
||||
var maxWidth = 0f
|
||||
var totalHeight = 40f // 상단 여백
|
||||
val lineHeights = mutableListOf<Float>() // 각 줄이 차지하는 총 높이
|
||||
val lineBaselines = mutableListOf<Float>() // 각 줄의 글자가 그려질 Baseline 위치
|
||||
|
||||
finalLines.forEachIndexed { index, line ->
|
||||
paint.textSize = when (index) {
|
||||
0 -> titleSize
|
||||
2 -> addressSize
|
||||
else -> dateSize
|
||||
}
|
||||
|
||||
val width = paint.measureText(line)
|
||||
if (width > maxWidth) maxWidth = width
|
||||
|
||||
val metrics = paint.fontMetrics
|
||||
val fontHeight = metrics.descent - metrics.ascent // 실제 글자 높이
|
||||
val leading = paint.textSize * lineSpacingMultiplier // 동적 행간
|
||||
|
||||
val fullLineHeight = fontHeight + leading
|
||||
|
||||
// 현재 줄의 Baseline 계산: 이전까지의 높이 + 글자의 ascent 절대값
|
||||
lineBaselines.add(totalHeight - metrics.ascent)
|
||||
totalHeight += fullLineHeight
|
||||
lineHeights.add(fullLineHeight)
|
||||
}
|
||||
totalHeight += 20f // 하단 여백
|
||||
|
||||
// --- 5. 비트맵 생성 및 그리기 ---
|
||||
val bitmap = Bitmap.createBitmap((maxWidth + 100).toInt(), totalHeight.toInt(), Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap)
|
||||
val centerX = bitmap.width / 2f
|
||||
|
||||
finalLines.forEachIndexed { index, line ->
|
||||
paint.textSize = when (index) {
|
||||
0 -> titleSize
|
||||
2 -> addressSize
|
||||
else -> dateSize
|
||||
}
|
||||
// 미리 계산된 Baseline에 그리기만 하면 끝!
|
||||
canvas.drawText(line, centerX, lineBaselines[index], paint)
|
||||
}
|
||||
|
||||
return bitmap
|
||||
}
|
||||
|
||||
private val updateWeatherRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
// if (!isVisible) return
|
||||
//
|
||||
// val (batteryLevel, isCharging) = getBatteryStatus()
|
||||
//
|
||||
// // --- ⬇️ 제안하신 조건별 로직 적용 ⬇️ ---
|
||||
// var nextDelay = 30000L // 기본 20초
|
||||
//
|
||||
// if (isCharging) {
|
||||
// nextDelay = 1000L // 충전 중이거나 70% 이상이면 10초
|
||||
// nativeRenderer?.setImageRenderFrame(45)
|
||||
// } else if (batteryLevel >= 80) {
|
||||
// nativeRenderer?.setImageRenderFrame(70)
|
||||
// } else {
|
||||
// handler.removeCallbacks(this)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 비트맵 생성 및 전달
|
||||
// val weather = LocationUpdateService.lastWeather
|
||||
// val bitmap = drawBitmapFromText(weather,isCharging)
|
||||
// bitmap?.let {
|
||||
// nativeRenderer?.setWeatherBitmap(it)
|
||||
// }
|
||||
//
|
||||
// Log.d(TAG, "Next update in ${nextDelay / 1000}s (Battery: $batteryLevel%, Charging: $isCharging)")
|
||||
// handler.postDelayed(this, nextDelay)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMediaFiles() {
|
||||
loadFiles()
|
||||
if (mediaFiles.isNotEmpty()) {
|
||||
@ -253,6 +393,7 @@ class MyWallpaperService : WallpaperService() {
|
||||
} ?: run {
|
||||
Log.e(TAG, "Failed to get fd for initial media: ${initialFile.absolutePath}")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
val mediaDir = File(File(this@MyWallpaperService.getExternalFilesDir(null), "completed_torrents"), "Images")
|
||||
@ -269,6 +410,20 @@ class MyWallpaperService : WallpaperService() {
|
||||
} ?: run {
|
||||
Log.e(TAG, "Callback: Failed to get fd for ${nextFile.absolutePath}")
|
||||
}
|
||||
|
||||
val (batteryLevel, isCharging) = getBatteryStatus()
|
||||
|
||||
if (batteryLevel >= 70) {
|
||||
val bitmap = drawBitmapFromText(LocationUpdateService.lastWeather)
|
||||
bitmap?.let { nativeRenderer?.setWeatherBitmap(it) }
|
||||
Log.d(TAG, "Battery Low: Weather updated only on media change.")
|
||||
} else {
|
||||
nativeRenderer?.setImageRenderFrame(99)
|
||||
nativeRenderer?.setWeatherBitmap(null)
|
||||
}
|
||||
if (isCharging || batteryLevel > 90) {
|
||||
// handler.post(updateWeatherRunnable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package bums.lunatic.launcher.wall
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Log
|
||||
import android.view.Surface
|
||||
|
||||
@ -29,7 +30,11 @@ open class NativeRenderer {
|
||||
nativeHandle = 0L
|
||||
}
|
||||
}
|
||||
|
||||
fun setWeatherBitmap(bitmap: Bitmap?) {
|
||||
if (nativeHandle != 0L) {
|
||||
nativeSetWeatherBitmap(nativeHandle, bitmap)
|
||||
}
|
||||
}
|
||||
fun render(surface: Surface) {
|
||||
if (nativeHandle != 0L) {
|
||||
nativeRender(nativeHandle, surface)
|
||||
@ -96,7 +101,13 @@ open class NativeRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun setImageRenderFrame(frame:Int) {
|
||||
if (nativeHandle != 0L) {
|
||||
nativeSetImageRenderFrame(nativeHandle, frame)
|
||||
} else {
|
||||
"Kotlin Wrapper: Native handle is null."
|
||||
}
|
||||
}
|
||||
|
||||
// --- Private JNI declarations ---
|
||||
private external fun nativeStartRenderLoop(nativeHandle: Long, surface: Surface)
|
||||
@ -104,7 +115,9 @@ open class NativeRenderer {
|
||||
private external fun nativeInit(): Long
|
||||
private external fun nativeDestroy(nativeHandle: Long)
|
||||
private external fun nativeRender(nativeHandle: Long, surface: Surface)
|
||||
private external fun nativeSetWeatherBitmap(nativeHandle: Long, bitmap: Bitmap?)
|
||||
private external fun nativeStartNextPreload(nativeHandle: Long, fd: Int)
|
||||
private external fun nativeSetImageRenderFrame(nativeHandle: Long, frame: Int)
|
||||
private external fun nativeSetAnimationSpeed(nativeHandle: Long, speed: Float)
|
||||
private external fun nativeSetAnimationMode(nativeHandle: Long, mode: Int)
|
||||
private external fun nativeSetFadeDuration(nativeHandle: Long, duration: Int)
|
||||
|
||||
@ -41,6 +41,7 @@ class LocationUpdateService : Service(), LocationListener {
|
||||
|
||||
companion object {
|
||||
var longitude: Double = 0.0
|
||||
var lastWeather = mutableListOf<String>()
|
||||
var latitude: Double = 0.0
|
||||
fun pushLocation(context: Context, lat :Double, long : Double) {
|
||||
try {
|
||||
@ -91,7 +92,7 @@ class LocationUpdateService : Service(), LocationListener {
|
||||
// 응답 받아서 처리
|
||||
val body: ResponseBody? = response.body
|
||||
if (body != null) {
|
||||
// Blog.LOGE("Location >>> ${body.string()}")
|
||||
Blog.LOGE("Location >>> ${body.string()}")
|
||||
}
|
||||
} else Blog.LOGE("telegram Error Occurred")
|
||||
}
|
||||
@ -99,6 +100,41 @@ class LocationUpdateService : Service(), LocationListener {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS)
|
||||
|
||||
Blog.LOGE("addresses ${addresses.first()}")
|
||||
Executors.newSingleThreadScheduledExecutor().schedule({
|
||||
try {
|
||||
val url = "https://api.weatherapi.com/v1/current.json?key=${PrefString.weatherApiKey.get()}&q=${lat},${long}&aqi=no"
|
||||
if (url.length > 10) {
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
|
||||
.build()
|
||||
|
||||
// GET 요청 객체 생성
|
||||
val builder: Request.Builder = Request.Builder().url(url).get()
|
||||
val request: Request = builder.build()
|
||||
|
||||
// Blog.LOGE("telegram before request ")
|
||||
// OkHttp 클라이언트로 GET 요청 객체 전송
|
||||
val response: Response = client.newCall(request).execute()
|
||||
if (response.isSuccessful) {
|
||||
// 응답 받아서 처리
|
||||
val body: ResponseBody? = response.body
|
||||
if (body != null) {
|
||||
var result = body.string()
|
||||
var w = Gson().fromJson<CurrentWeather>(result,CurrentWeather::class.java)
|
||||
w.addr = addresses.first().getAddressLine(0).replace("대한민국", "")
|
||||
lastWeather.clear()
|
||||
lastWeather.addAll(w.getSummaryInfo())
|
||||
Blog.LOGE("Location >>> ${result}\n${lastWeather}")
|
||||
}
|
||||
} else Blog.LOGE("telegram Error Occurred")
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS)
|
||||
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -174,9 +210,63 @@ class LocationUpdateService : Service(), LocationListener {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
open class Condition {
|
||||
var text: String? = null
|
||||
var icon: String? = null
|
||||
var code: Int = 0
|
||||
}
|
||||
|
||||
open class Current {
|
||||
var last_updated_epoch: Int = 0
|
||||
var last_updated: String? = null
|
||||
var temp_c: Double = 0.0
|
||||
var temp_f: Double = 0.0
|
||||
var is_day: Int = 0
|
||||
var condition: Condition? = null
|
||||
var wind_mph: Double = 0.0
|
||||
var wind_kph: Double = 0.0
|
||||
var wind_degree: Int = 0
|
||||
var wind_dir: String? = null
|
||||
var pressure_mb: Double = 0.0
|
||||
var pressure_in: Double = 0.0
|
||||
var precip_mm: Double = 0.0
|
||||
var precip_in: Double = 0.0
|
||||
var humidity: Int = 0
|
||||
var cloud: Int = 0
|
||||
var feelslike_c: Double = 0.0
|
||||
var feelslike_f: Double = 0.0
|
||||
var windchill_c: Double = 0.0
|
||||
var windchill_f: Double = 0.0
|
||||
var heatindex_c: Double = 0.0
|
||||
var heatindex_f: Double = 0.0
|
||||
var dewpoint_c: Double = 0.0
|
||||
var dewpoint_f: Double = 0.0
|
||||
var vis_km: Double = 0.0
|
||||
var vis_miles: Double = 0.0
|
||||
var uv: Double = 0.0
|
||||
var gust_mph: Double = 0.0
|
||||
var gust_kph: Double = 0.0
|
||||
}
|
||||
|
||||
open class Location {
|
||||
var name: String? = null
|
||||
var region: String? = null
|
||||
var country: String? = null
|
||||
var lat: Double = 0.0
|
||||
var lon: Double = 0.0
|
||||
var tz_id: String? = null
|
||||
var localtime_epoch: Int = 0
|
||||
var localtime: String? = null
|
||||
}
|
||||
|
||||
open class CurrentWeather {
|
||||
var addr: String? = null
|
||||
var current: Current? = null
|
||||
|
||||
fun getSummaryInfo() = listOf<String>("${this.current?.condition?.text}",
|
||||
"${this.current?.temp_c}℃ ${this.current?.humidity}%"
|
||||
,"${addr}")
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user