Skip to content

Commit fdaa9fd

Browse files
committed
1.4: allow sending text
1 parent af21629 commit fdaa9fd

13 files changed

Lines changed: 149 additions & 59 deletions

File tree

app/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ android {
1616
applicationId = "moe.reimu.catshare"
1717
minSdk = 29
1818
targetSdk = 35
19-
versionCode = 4
20-
versionName = "1.3"
19+
versionCode = 5
20+
versionName = "1.4"
2121
}
2222

2323
signingConfigs {
@@ -93,7 +93,7 @@ dependencies {
9393
implementation(libs.androidx.ui.tooling.preview)
9494
implementation(libs.androidx.material3)
9595

96-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
96+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
9797
implementation("no.nordicsemi.android.kotlin.ble:client:1.1.0")
9898

9999
implementation(libs.ktor.client.core)

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,16 @@
6363
<activity
6464
android:name=".ShareActivity"
6565
android:exported="true"
66-
android:label="@string/title_activity_share"
66+
android:label="@string/send"
6767
android:theme="@style/Theme.CatShare">
6868
<intent-filter>
6969
<action android:name="android.intent.action.SEND" />
70-
7170
<category android:name="android.intent.category.DEFAULT" />
72-
7371
<data android:mimeType="*/*" />
7472
</intent-filter>
7573
<intent-filter>
7674
<action android:name="android.intent.action.SEND_MULTIPLE" />
77-
7875
<category android:name="android.intent.category.DEFAULT" />
79-
8076
<data android:mimeType="*/*" />
8177
</intent-filter>
8278
</activity>

app/src/main/java/moe/reimu/catshare/ShareActivity.kt

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,33 +78,37 @@ class ShareActivity : ComponentActivity() {
7878
return
7979
}
8080

81-
val sharedUris = if (intent.action == Intent.ACTION_SEND) {
82-
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
83-
if (uri != null) {
84-
listOf(uri)
81+
val fileInfos = try {
82+
if (intent.action == Intent.ACTION_SEND) {
83+
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
84+
if (uri != null) {
85+
listOf(uri).mapNotNull { extractFileInfo(it) }
86+
} else {
87+
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
88+
listOf(
89+
FileInfo(
90+
Uri.EMPTY, "", "", 0, text
91+
)
92+
)
93+
}
8594
} else {
86-
emptyList()
95+
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
96+
uris?.mapNotNull { extractFileInfo(it) } ?: emptyList()
8797
}
88-
} else {
89-
intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM) ?: emptyList()
90-
}
91-
92-
if (sharedUris.isEmpty()) {
98+
} catch (e: Throwable) {
9399
Toast.makeText(this, R.string.no_file_shared, Toast.LENGTH_SHORT).show()
94100
finish()
95101
return
96102
}
97103

98-
Log.i(TAG, "Shared ${sharedUris.size} files")
99-
100-
val fileInfos = try {
101-
sharedUris.mapNotNull { extractFileInfo(it) }
102-
} catch (e: Throwable) {
104+
if (fileInfos.isEmpty()) {
103105
Toast.makeText(this, R.string.no_file_shared, Toast.LENGTH_SHORT).show()
104106
finish()
105107
return
106108
}
107109

110+
Log.i(TAG, "Shared ${fileInfos.size} files")
111+
108112
ShizukuUtils.bindService()
109113

110114
enableEdgeToEdge()
@@ -133,7 +137,8 @@ class ShareActivity : ComponentActivity() {
133137
} else {
134138
it.getString(mimeIndex)
135139
},
136-
it.getInt(it.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE))
140+
it.getInt(it.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE)),
141+
null
137142
)
138143
} else {
139144
null

app/src/main/java/moe/reimu/catshare/models/DeviceInfo.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package moe.reimu.catshare.models
33
import kotlinx.serialization.Serializable
44

55
@Serializable
6-
data class DeviceInfo(val state: Int, val key: String?, val mac: String)
6+
data class DeviceInfo(val state: Int, val key: String?, val mac: String, val catShare: Int? = null)

app/src/main/java/moe/reimu/catshare/models/FileInfo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ data class FileInfo(
1010
val name: String,
1111
val mimeType: String,
1212
val size: Int,
13+
val textContent: String?,
1314
) : Parcelable
1415

app/src/main/java/moe/reimu/catshare/models/P2pInfo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ data class P2pInfo(
1313
val mac: String,
1414
val port: Int,
1515
val key: String? = null,
16+
val catShare: Int? = null,
1617
) : Parcelable

app/src/main/java/moe/reimu/catshare/services/GattServerService.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import kotlinx.serialization.encodeToString
3131
import kotlinx.serialization.json.Json
3232
import moe.reimu.catshare.AppSettings
3333
import moe.reimu.catshare.BleSecurity
34+
import moe.reimu.catshare.BuildConfig
3435
import moe.reimu.catshare.R
3536
import moe.reimu.catshare.models.DeviceInfo
3637
import moe.reimu.catshare.models.P2pInfo
@@ -56,7 +57,7 @@ class GattServerService : Service() {
5657

5758
private val localDeviceInfoLock = Object()
5859
private var localDeviceInfo = DeviceInfo(
59-
0, BleSecurity.getEncodedPublicKey(), "02:00:00:00:00:00"
60+
0, BleSecurity.getEncodedPublicKey(), "02:00:00:00:00:00", BuildConfig.VERSION_CODE
6061
)
6162
private var localDeviceStatusBytes = Json.encodeToString(localDeviceInfo).toByteArray()
6263

@@ -167,7 +168,8 @@ class GattServerService : Service() {
167168
psk = cipher.decrypt(p2pInfo.psk),
168169
mac = cipher.decrypt(p2pInfo.mac),
169170
port = p2pInfo.port,
170-
key = null
171+
key = null,
172+
catShare = BuildConfig.VERSION_CODE,
171173
)
172174
}
173175
startService(P2pReceiverService.getIntent(this@GattServerService, p2pInfo))
@@ -362,7 +364,8 @@ class GattServerService : Service() {
362364
localDeviceInfo = DeviceInfo(
363365
state = localDeviceInfo.state,
364366
mac = mac,
365-
key = localDeviceInfo.key
367+
key = localDeviceInfo.key,
368+
catShare = BuildConfig.VERSION_CODE,
366369
)
367370
localDeviceStatusBytes = Json.encodeToString(localDeviceInfo).toByteArray()
368371
}

app/src/main/java/moe/reimu/catshare/services/P2pReceiverService.kt

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
44
import android.app.Notification
55
import android.app.PendingIntent
66
import android.content.BroadcastReceiver
7+
import android.content.ClipData
8+
import android.content.ClipboardManager
79
import android.content.ContentValues
810
import android.content.Context
911
import android.content.Intent
@@ -17,11 +19,14 @@ import android.net.wifi.p2p.WifiP2pGroup
1719
import android.net.wifi.p2p.WifiP2pInfo
1820
import android.net.wifi.p2p.WifiP2pManager
1921
import android.os.Environment
22+
import android.os.Handler
2023
import android.os.IBinder
24+
import android.os.Looper
2125
import android.provider.MediaStore
2226
import android.text.format.Formatter
2327
import android.util.Log
2428
import android.webkit.MimeTypeMap
29+
import android.widget.Toast
2530
import androidx.annotation.DrawableRes
2631
import androidx.core.app.NotificationCompat
2732
import androidx.core.app.NotificationManagerCompat
@@ -43,6 +48,7 @@ import kotlinx.coroutines.Job
4348
import kotlinx.coroutines.SupervisorJob
4449
import kotlinx.coroutines.async
4550
import kotlinx.coroutines.coroutineScope
51+
import kotlinx.coroutines.delay
4652
import kotlinx.coroutines.launch
4753
import kotlinx.coroutines.selects.select
4854
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -66,6 +72,7 @@ import moe.reimu.catshare.utils.connectSuspend
6672
import moe.reimu.catshare.utils.registerInternalBroadcastReceiver
6773
import moe.reimu.catshare.utils.removeGroupSuspend
6874
import moe.reimu.catshare.utils.requestGroupInfo
75+
import moe.reimu.catshare.utils.sendStatusIgnoreException
6976
import okhttp3.ConnectionPool
7077
import org.json.JSONObject
7178
import java.io.File
@@ -223,12 +230,17 @@ class P2pReceiverService : BaseP2pService() {
223230
fileName: String,
224231
fileCount: Int,
225232
totalSize: Long,
226-
thumbnail: Bitmap?
233+
thumbnail: Bitmap?,
234+
textContent: String?
227235
): Notification {
228236
val fmtSize = Formatter.formatShortFileSize(this, totalSize)
229-
val contentText = resources.getQuantityString(
230-
R.plurals.noti_request_desc, fileCount, fileCount, fmtSize
231-
)
237+
val contentText = if (textContent == null) {
238+
resources.getQuantityString(
239+
R.plurals.noti_request_desc, fileCount, fileCount, fmtSize
240+
)
241+
} else {
242+
resources.getString(R.string.noti_request_desc_text)
243+
}
232244

233245
val dismissIntent = PendingIntent.getBroadcast(
234246
this,
@@ -253,6 +265,9 @@ class P2pReceiverService : BaseP2pService() {
253265
if (thumbnail != null) {
254266
n.setStyle(NotificationCompat.BigPictureStyle().bigPicture(thumbnail))
255267
}
268+
if (textContent != null) {
269+
n.setStyle(NotificationCompat.BigTextStyle().bigText(textContent))
270+
}
256271

257272
return n.build()
258273
}
@@ -375,8 +390,10 @@ class P2pReceiverService : BaseP2pService() {
375390
}
376391
}
377392

378-
val p2pConfig =
379-
WifiP2pConfig.Builder().setNetworkName(p2pInfo.ssid).setPassphrase(p2pInfo.psk).build()
393+
val p2pConfig = WifiP2pConfig.Builder()
394+
.setNetworkName(p2pInfo.ssid)
395+
.setPassphrase(p2pInfo.psk)
396+
.build()
380397

381398
try {
382399
p2pFuture = CompletableDeferred()
@@ -411,6 +428,11 @@ class P2pReceiverService : BaseP2pService() {
411428
val fileName = sendRequestPayload.getString("fileName")
412429
val totalSize = sendRequestPayload.getLong("totalSize")
413430
val fileCount = sendRequestPayload.getInt("fileCount")
431+
val textContent = if (sendRequestPayload.has("catShareText")) {
432+
sendRequestPayload.getString("catShareText")
433+
} else {
434+
null
435+
}
414436

415437
val thumbPath = sendRequestPayload.optString("thumbnail")
416438
val bigPicture = if (thumbPath.isNotEmpty()) {
@@ -423,7 +445,13 @@ class P2pReceiverService : BaseP2pService() {
423445

424446
updateNotification(
425447
createAskingNotification(
426-
localTaskId, senderName, fileName, fileCount, totalSize, bigPicture
448+
localTaskId,
449+
senderName,
450+
fileName,
451+
fileCount,
452+
totalSize,
453+
bigPicture,
454+
textContent
427455
)
428456
)
429457

@@ -432,20 +460,26 @@ class P2pReceiverService : BaseP2pService() {
432460
}
433461

434462
if (userResponse != true) {
435-
wsSession.send(
436-
Frame.Text(
437-
WebSocketMessage.makeStatus(
438-
99,
439-
taskId,
440-
3,
441-
"user refuse"
442-
).toText()
443-
)
463+
wsSession.sendStatusIgnoreException(
464+
99,
465+
taskId,
466+
3,
467+
"user refuse"
444468
)
445-
wsSession.flush()
446469
throw CancelledByUserException()
447470
}
448471

472+
if (textContent != null) {
473+
val cm = getSystemService(ClipboardManager::class.java)
474+
cm.setPrimaryClip(ClipData.newPlainText("Shared Text", textContent))
475+
476+
showTextCopiedToast()
477+
478+
wsSession.sendStatusIgnoreException(99, taskId, 1, "ok")
479+
delay(1000)
480+
return@async
481+
}
482+
449483
updateNotification(
450484
createProgressNotification(
451485
localTaskId, senderName, totalSize, null
@@ -479,14 +513,8 @@ class P2pReceiverService : BaseP2pService() {
479513
senderName, files, files.size != fileCount
480514
)
481515
)
482-
483-
try {
484-
val st = WebSocketMessage.makeStatus(99, taskId, 1, "")
485-
wsSession.send(Frame.Text(st.toText()))
486-
wsSession.flush()
487-
} catch (e: Throwable) {
488-
// ignore
489-
}
516+
wsSession.sendStatusIgnoreException(99, taskId, 1, "ok")
517+
delay(1000)
490518
} else {
491519
throw IllegalStateException("Failed to receive any file")
492520
}
@@ -673,6 +701,16 @@ class P2pReceiverService : BaseP2pService() {
673701
}
674702
}
675703

704+
private fun showTextCopiedToast() {
705+
Handler(Looper.getMainLooper()).post {
706+
Toast.makeText(
707+
this@P2pReceiverService,
708+
R.string.msg_copied_to_clipboard,
709+
Toast.LENGTH_SHORT
710+
).show()
711+
}
712+
}
713+
676714
companion object {
677715
fun getIntent(context: Context, p2pInfo: P2pInfo): Intent {
678716
return Intent(context, P2pReceiverService::class.java).apply {

0 commit comments

Comments
 (0)