Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ android {
applicationId "com.kazumaproject.markdownhelperkeyboard"
minSdk 24
targetSdk 36
versionCode 797
versionName "1.7.104"
versionCode 798
versionName "1.7.105"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Expand Down

Large diffs are not rendered by default.

Binary file modified app/src/main/assets/system/token.dat.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,9 @@ class GemmaImeMediaPanelController(
context.getString(R.string.gemma_image_loading_clipboard),
)
mediaLoadJob = controllerScope.launch {
val item = clipboardUtil.getPrimaryClipContent() as? ClipboardItem.Image
val item = withContext(Dispatchers.IO) {
clipboardUtil.getPrimaryClipContent()
} as? ClipboardItem.Image
if (item == null) {
if (isCurrentImageLoad(requestId)) {
state = state.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ internal fun resolveCandidateStripHeightDp(
emptyHeightDp: Int
): Int = if (candidatesShown) candidateHeightDp else emptyHeightDp

internal fun isCandidateStripActive(
candidatesShown: Boolean,
inputStringEmpty: Boolean
): Boolean = candidatesShown && !inputStringEmpty

object CandidateStripPresentationPolicy {

fun resolve(state: CandidateStripPresentationState): CandidateStripPresentation {
Expand All @@ -52,10 +57,16 @@ object CandidateStripPresentationPolicy {
symbolKeyboardShown = state.symbolKeyboardShown
)
)
val candidateStripActive = isCandidateStripActive(
candidatesShown = state.candidatesShown,
inputStringEmpty = state.inputStringEmpty
)
val hideShortcutForCandidates =
state.shortcutToolbarHiddenForCandidates && !state.symbolKeyboardShown
state.shortcutToolbarHiddenForCandidates &&
candidateStripActive &&
!state.symbolKeyboardShown
return CandidateStripPresentation(
showCandidateTab = state.candidateTabVisible && state.candidatesShown,
showCandidateTab = state.candidateTabVisible && candidateStripActive,
resetCandidateTabSelection = state.resetCandidateTabSelection,
showIndependentShortcutToolbar =
shortcutPresentation.showIndependentToolbar && !hideShortcutForCandidates,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,21 @@ class ClipboardUtil(private val context: Context) {
* @return 取得したコンテンツを表す [ClipboardItem]。([ClipboardItem.Image]、[ClipboardItem.Text]、または [ClipboardItem.Empty])
*/
fun getPrimaryClipContent(): ClipboardItem {
return getPrimaryClipContent(maxImageDimension = null)
}

/**
* クリップボードの主要なコンテンツを取得します。
* [maxImageDimension] が指定された場合、画像は指定サイズ以下になるよう縮小します。
* 候補欄のプレビューなど、元画像の解像度を必要としない用途で使用します。
*/
fun getPrimaryClipContent(maxImageDimension: Int?): ClipboardItem {
if (!clipboard.hasPrimaryClip()) {
return ClipboardItem.Empty
}

// 1. 画像の取得を最優先で試みる
getClipboardImageBitmap()?.let { bitmap ->
getClipboardImageBitmap(maxImageDimension)?.let { bitmap ->
return ClipboardItem.Image(id = 0, bitmap = bitmap)
}

Expand All @@ -61,6 +70,10 @@ class ClipboardUtil(private val context: Context) {
return ClipboardItem.Empty
}

fun getPrimaryClipPreviewContent(maxImageDimension: Int = 256): ClipboardItem {
return getPrimaryClipContent(maxImageDimension = maxImageDimension)
}

/**
* クリップボードにテキストが存在するかどうかを確認します。
* @return テキストが存在しない場合はtrue、存在する場合はfalse。
Expand Down Expand Up @@ -127,7 +140,7 @@ class ClipboardUtil(private val context: Context) {
*
* @return 成功した場合はBitmapオブジェクト、失敗した場合はnull。
*/
fun getClipboardImageBitmap(): Bitmap? {
fun getClipboardImageBitmap(maxImageDimension: Int? = null): Bitmap? {
if (!clipboard.hasPrimaryClip()) {
return null
}
Expand All @@ -141,8 +154,31 @@ class ClipboardUtil(private val context: Context) {
val uri = item.uri
if (uri != null) {
try {
if (maxImageDimension == null || maxImageDimension <= 0) {
context.contentResolver.openInputStream(uri)?.use { inputStream ->
return BitmapFactory.decodeStream(inputStream)
}
}

val bounds = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
context.contentResolver.openInputStream(uri)?.use { inputStream ->
BitmapFactory.decodeStream(inputStream, null, bounds)
}
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) continue

var sampleSize = 1
val largestDimension = maxOf(bounds.outWidth, bounds.outHeight)
val targetDimension = checkNotNull(maxImageDimension)
while (largestDimension / sampleSize > targetDimension) {
sampleSize = sampleSize shl 1
}
val options = BitmapFactory.Options().apply {
inSampleSize = sampleSize
}
context.contentResolver.openInputStream(uri)?.use { inputStream ->
return BitmapFactory.decodeStream(inputStream)
return BitmapFactory.decodeStream(inputStream, null, options)
}
} catch (e: Exception) {
Timber.e("ClipboardUtil", "URIからのBitmapデコードに失敗しました: $uri", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import android.os.Process
import android.os.SystemClock
import android.view.Surface
import timber.log.Timber
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.exp

Expand Down Expand Up @@ -113,7 +111,7 @@ internal class CinematicWaveRenderer(
}

override fun detachSurface() {
runBlockingOnRendererThread(maxWaitMillis = 120L) {
postOnRenderer {
handler.removeCallbacks(frameRunnable)
frameScheduled = false
paused = true
Expand Down Expand Up @@ -162,8 +160,8 @@ internal class CinematicWaveRenderer(
}

override fun release() {
runBlockingOnRendererThread(maxWaitMillis = 250L) {
if (released) return@runBlockingOnRendererThread
postOnRenderer {
if (released) return@postOnRenderer
released = true
handler.removeCallbacks(frameRunnable)
frameScheduled = false
Expand All @@ -174,8 +172,8 @@ internal class CinematicWaveRenderer(
simulation = null
releaseEglSurfaceOnly()
surfaceTexture = null
rendererThread.quitSafely()
}
rendererThread.quitSafely()
}

override fun isRendererThreadAliveForTesting(): Boolean {
Expand Down Expand Up @@ -395,22 +393,6 @@ internal class CinematicWaveRenderer(
}
}

private fun runBlockingOnRendererThread(maxWaitMillis: Long, action: () -> Unit) {
if (Looper.myLooper() == handler.looper) {
action()
return
}
if (!rendererThread.isAlive) return
val latch = CountDownLatch(1)
handler.post {
runCatching(action).onFailure {
Timber.w(it, "Failed to run cinematic wave renderer cleanup.")
}
latch.countDown()
}
latch.await(maxWaitMillis, TimeUnit.MILLISECONDS)
}

private fun runRendererCatching(operation: String, action: () -> Unit) {
runCatching(action).onFailure { throwable ->
Timber.w(throwable, "Cinematic wave renderer failed during %s", operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import android.os.Looper
import android.os.Process
import android.view.Surface
import timber.log.Timber
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

internal class FluidInkRenderer(
Expand Down Expand Up @@ -122,7 +120,7 @@ internal class FluidInkRenderer(
}

override fun detachSurface() {
runBlockingOnRendererThread(maxWaitMillis = 120L) {
postOnRenderer {
handler.removeCallbacks(frameRunnable)
frameScheduled = false
paused = true
Expand Down Expand Up @@ -163,8 +161,8 @@ internal class FluidInkRenderer(
}

override fun release() {
runBlockingOnRendererThread(maxWaitMillis = 250L) {
if (released) return@runBlockingOnRendererThread
postOnRenderer {
if (released) return@postOnRenderer
released = true
handler.removeCallbacks(frameRunnable)
frameScheduled = false
Expand All @@ -173,8 +171,8 @@ internal class FluidInkRenderer(
simulation?.release()
simulation = null
releaseEglSurfaceOnly()
rendererThread.quitSafely()
}
rendererThread.quitSafely()
}

override fun isRendererThreadAliveForTesting(): Boolean {
Expand Down Expand Up @@ -278,22 +276,6 @@ internal class FluidInkRenderer(
}
}

private fun runBlockingOnRendererThread(maxWaitMillis: Long, action: () -> Unit) {
if (Looper.myLooper() == handler.looper) {
action()
return
}
if (!rendererThread.isAlive) return
val latch = CountDownLatch(1)
handler.post {
runCatching(action).onFailure {
Timber.w(it, "Failed to run fluid renderer cleanup.")
}
latch.countDown()
}
latch.await(maxWaitMillis, TimeUnit.MILLISECONDS)
}

private fun runRendererCatching(operation: String, action: () -> Unit) {
runCatching(action).onFailure { throwable ->
Timber.w(throwable, "Suminagashi fluid renderer failed during %s", operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import android.os.Looper
import android.os.Process
import android.view.Surface
import timber.log.Timber
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

internal class LiquidRippleRenderer(
Expand Down Expand Up @@ -119,7 +117,7 @@ internal class LiquidRippleRenderer(
}

override fun detachSurface() {
runBlockingOnRendererThread(maxWaitMillis = 120L) {
postOnRenderer {
handler.removeCallbacks(frameRunnable)
frameScheduled = false
paused = true
Expand Down Expand Up @@ -160,8 +158,8 @@ internal class LiquidRippleRenderer(
}

override fun release() {
runBlockingOnRendererThread(maxWaitMillis = 250L) {
if (released) return@runBlockingOnRendererThread
postOnRenderer {
if (released) return@postOnRenderer
released = true
handler.removeCallbacks(frameRunnable)
frameScheduled = false
Expand All @@ -170,8 +168,8 @@ internal class LiquidRippleRenderer(
simulation?.release()
simulation = null
releaseEglSurfaceOnly()
rendererThread.quitSafely()
}
rendererThread.quitSafely()
}

override fun isRendererThreadAliveForTesting(): Boolean {
Expand Down Expand Up @@ -276,22 +274,6 @@ internal class LiquidRippleRenderer(
}
}

private fun runBlockingOnRendererThread(maxWaitMillis: Long, action: () -> Unit) {
if (Looper.myLooper() == handler.looper) {
action()
return
}
if (!rendererThread.isAlive) return
val latch = CountDownLatch(1)
handler.post {
runCatching(action).onFailure {
Timber.w(it, "Failed to run liquid ripple renderer cleanup.")
}
latch.countDown()
}
latch.await(maxWaitMillis, TimeUnit.MILLISECONDS)
}

private fun runRendererCatching(operation: String, action: () -> Unit) {
runCatching(action).onFailure { throwable ->
Timber.w(throwable, "Liquid ripple renderer failed during %s", operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import android.os.Looper
import android.os.Process
import android.view.Surface
import timber.log.Timber
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

internal class LuminousBlobRenderer(
Expand Down Expand Up @@ -118,7 +116,7 @@ internal class LuminousBlobRenderer(
}

override fun detachSurface() {
runBlockingOnRendererThread(maxWaitMillis = 120L) {
postOnRenderer {
handler.removeCallbacks(frameRunnable)
frameScheduled = false
paused = true
Expand Down Expand Up @@ -161,8 +159,8 @@ internal class LuminousBlobRenderer(
}

override fun release() {
runBlockingOnRendererThread(maxWaitMillis = 250L) {
if (released) return@runBlockingOnRendererThread
postOnRenderer {
if (released) return@postOnRenderer
released = true
handler.removeCallbacks(frameRunnable)
frameScheduled = false
Expand All @@ -172,8 +170,8 @@ internal class LuminousBlobRenderer(
simulation?.release()
simulation = null
releaseEglSurfaceOnly()
rendererThread.quitSafely()
}
rendererThread.quitSafely()
}

override fun isRendererThreadAliveForTesting(): Boolean {
Expand Down Expand Up @@ -372,22 +370,6 @@ internal class LuminousBlobRenderer(
}
}

private fun runBlockingOnRendererThread(maxWaitMillis: Long, action: () -> Unit) {
if (Looper.myLooper() == handler.looper) {
action()
return
}
if (!rendererThread.isAlive) return
val latch = CountDownLatch(1)
handler.post {
runCatching(action).onFailure {
Timber.w(it, "Failed to run luminous blob renderer cleanup.")
}
latch.countDown()
}
latch.await(maxWaitMillis, TimeUnit.MILLISECONDS)
}

private fun runRendererCatching(operation: String, action: () -> Unit) {
runCatching(action).onFailure { throwable ->
Timber.w(throwable, "Luminous blob renderer failed during %s", operation)
Expand Down
Loading
Loading