Skip to content

Commit 9b19834

Browse files
committed
REFACTOR: Migrate to Kotlin.
1 parent 4799be4 commit 9b19834

23 files changed

+1426
-1614
lines changed

build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ buildscript {
55
}
66

77
dependencies {
8-
classpath 'com.android.tools.build:gradle:4.0.1'
8+
classpath 'com.android.tools.build:gradle:7.0.4'
99

1010
// NOTE: Do not place your application dependencies here; they belong
1111
// in the individual module build.gradle files
@@ -45,6 +45,7 @@ android {
4545

4646
dependencies {
4747
implementation project(':sdk') //implementation 'com.oasisfeng.nevo:sdk:2.0.0-rc01'
48-
implementation 'androidx.core:core-ktx:1.3.1'
48+
implementation 'androidx.core:core-ktx:1.7.0'
4949
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7'
50+
androidTestImplementation 'junit:junit:4.13.2'
5051
}

src/androidTest/java/com/oasisfeng/nevo/decorators/wechat/EmojiTranslatorTest.java

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.oasisfeng.nevo.decorators.wechat
2+
3+
import com.oasisfeng.nevo.decorators.wechat.EmojiTranslator.translate
4+
import org.junit.Assert
5+
import org.junit.Test
6+
7+
/**
8+
* Created by Oasis on 2018-8-9.
9+
*/
10+
class EmojiTranslatorTest {
11+
12+
@Test fun testConvert() {
13+
test("[Smile]", "😃")
14+
test("Left[Smile]", "Left😃")
15+
test("[Smile] Right", "😃 Right")
16+
test("Left[Smile] Right", "Left😃 Right")
17+
test("Left [色][色][发呆]Right", "Left 😍😍😳Right")
18+
test("Left[[Smile]", "Left[😃")
19+
test("Left[Smile]]", "Left😃]")
20+
test("Left[[Smile]]", "Left[😃]")
21+
test("Left[NotEmoji][][[Smile][", "Left[NotEmoji][][😃[")
22+
}
23+
24+
companion object {
25+
private fun test(input: String, expected: String) = Assert.assertEquals(expected, translate(input).toString())
26+
}
27+
}

src/main/java/com/oasisfeng/nevo/decorators/wechat/AgentShortcuts.kt

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ import android.util.LruCache
2121
import androidx.annotation.RequiresApi
2222
import androidx.core.content.getSystemService
2323
import com.oasisfeng.nevo.decorators.wechat.ConversationManager.Conversation
24-
import com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.AGENT_PACKAGE
25-
import com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.TAG
26-
import com.oasisfeng.nevo.decorators.wechat.WeChatDecorator.WECHAT_PACKAGE
24+
import com.oasisfeng.nevo.decorators.wechat.IconHelper.toLocalAdaptiveIcon
2725
import java.lang.reflect.Method
2826

2927
@RequiresApi(N_MR1) class AgentShortcuts(private val context: Context) {
3028

3129
companion object {
30+
private const val FLAG_ALLOW_EMBEDDED = -0x80000000
3231
fun buildShortcutId(key: String) = "C:$key"
3332
}
3433

@@ -62,13 +61,15 @@ import java.lang.reflect.Method
6261
}
6362

6463
val shortcut = ShortcutInfo.Builder(agentContext, id).setActivity(ComponentName(AGENT_PACKAGE, activity))
65-
.setShortLabel(conversation.title).setRank(if (conversation.isGroupChat) 1 else 0) // Always keep last direct message conversation on top.
64+
.setShortLabel(conversation.title!!).setRank(if (conversation.isGroupChat()) 1 else 0) // Always keep last direct message conversation on top.
6665
.setIntent(intent.apply { if (action == null) action = Intent.ACTION_MAIN })
6766
.setCategories(setOf(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION)).apply {
68-
if (conversation.icon != null) setIcon(conversation.icon.toLocalAdaptiveIcon(context, sm))
69-
if (SDK_INT >= Q) @SuppressLint("RestrictedApi") {
67+
conversation.icon?.run { setIcon(toLocalAdaptiveIcon(context, sm)) }
68+
if (SDK_INT >= Q) {
7069
setLongLived(true).setLocusId(LocusId(id))
71-
if (! conversation.isGroupChat) setPerson(conversation.sender().build().toAndroidPerson()) }}.build()
70+
if (! conversation.isGroupChat()) setPerson(conversation.sender().build().toNative())
71+
}
72+
}.build()
7273
Log.i(TAG, "Updating shortcut \"${shortcut.id}\"${if (BuildConfig.DEBUG) ": " + shortcut.intent.toString() else ""}")
7374
return if (sm.addDynamicShortcuts(listOf(shortcut))) true.also { Log.i(TAG, "Shortcut updated: $id") }
7475
else false.also { Log.e(TAG, "Unexpected rate limit.") }
@@ -82,12 +83,12 @@ import java.lang.reflect.Method
8283
catch (e: RuntimeException) { null.also { Log.e(TAG, "Error creating context for agent in user ${profile.hashCode()}", e) }}
8384

8485
/** @return whether shortcut is ready */
85-
@RequiresApi(N_MR1) fun updateShortcutIfNeeded(id: String, conversation: Conversation, profile: UserHandle): Boolean {
86-
if (! conversation.isChat || conversation.isBotMessage) return false
86+
fun updateShortcutIfNeeded(id: String, conversation: Conversation, profile: UserHandle): Boolean {
87+
if (! conversation.isChat() || conversation.isBotMessage()) return false
8788
val agentContext = mAgentContextByProfile[profile] ?: return false
8889
if (mDynamicShortcutContacts.get(id) != null) return true
8990
try { if (updateShortcut(id, conversation, agentContext))
90-
return true.also { if (conversation.icon.type != TYPE_RESOURCE) mDynamicShortcutContacts.put(id, Unit) }} // If no large icon, wait for the next update
91+
return true.also { if (conversation.icon?.type != TYPE_RESOURCE) mDynamicShortcutContacts.put(id, Unit) }} // If no large icon, wait for the next update
9192
catch (e: RuntimeException) { Log.e(TAG, "Error publishing shortcut: $id", e) }
9293
return false
9394
}
@@ -126,5 +127,3 @@ import java.lang.reflect.Method
126127
mAgentContextByProfile.clear()
127128
}
128129
}
129-
130-
const val FLAG_ALLOW_EMBEDDED = -0x80000000

src/main/java/com/oasisfeng/nevo/decorators/wechat/AssetFileProvider.java

Lines changed: 0 additions & 47 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.oasisfeng.nevo.decorators.wechat
2+
3+
import android.content.ContentProvider
4+
import android.content.ContentValues
5+
import android.content.res.AssetFileDescriptor
6+
import android.database.Cursor
7+
import android.net.Uri
8+
import android.util.Log
9+
import java.io.FileNotFoundException
10+
import java.io.IOException
11+
12+
/**
13+
* Expose asset file with content URI
14+
*
15+
* Created by Oasis on 2019-1-28.
16+
*/
17+
class AssetFileProvider : ContentProvider() {
18+
19+
@Throws(FileNotFoundException::class) override fun openAssetFile(uri: Uri, mode: String): AssetFileDescriptor? {
20+
val filename = uri.lastPathSegment ?: throw FileNotFoundException()
21+
val context = context!!
22+
return try {
23+
val suffix = context.getString(R.string.repacked_asset_suffix)
24+
val offset = context.resources.getInteger(R.integer.repacked_asset_offset)
25+
val afd = context.assets.openFd(
26+
if (suffix.isNotEmpty() && filename.endsWith(suffix)) filename + context.getString(R.string.repacked_asset_appendix) else filename)
27+
AssetFileDescriptor(afd.parcelFileDescriptor, afd.startOffset + offset, afd.length - offset)
28+
} catch (e: IOException) {
29+
null.also { Log.e(TAG, "Error opening asset", e) }
30+
}
31+
}
32+
33+
override fun onCreate() = true
34+
35+
override fun getType(uri: Uri): String? = null
36+
override fun query(uri: Uri, p: Array<String>?, s: String?, sa: Array<String>?, so: String?): Cursor? = null
37+
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
38+
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0
39+
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?) = 0
40+
}

src/main/java/com/oasisfeng/nevo/decorators/wechat/CompatModeController.kt

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,19 @@ import android.net.Uri
88
import android.os.Handler
99
import android.os.Looper
1010
import android.util.Log
11-
import androidx.core.util.Consumer
1211

1312
object CompatModeController {
1413

15-
@JvmStatic fun query(context: Context, result_callback: (Consumer<Boolean>)?) {
16-
sendRequest(context, null, result_callback)
17-
}
18-
19-
@JvmStatic fun request(context: Context, enabled: Boolean, result_callback: (Consumer<Boolean>)?) {
20-
sendRequest(context, enabled, result_callback)
21-
}
14+
fun query(context: Context, callback: (Boolean) -> Unit) = sendRequest(context, null, callback)
15+
fun request(context: Context, enabled: Boolean, callback: (Boolean) -> Unit) = sendRequest(context, enabled, callback)
2216

23-
private fun sendRequest(context: Context, enabled: Boolean?, callback: (Consumer<Boolean>)?) {
17+
private fun sendRequest(context: Context, enabled: Boolean?, callback: (Boolean) -> Unit) {
2418
val uri = Uri.fromParts("nevo", "compat", if (enabled == null) null else if (enabled) "1" else "0")
2519
context.sendOrderedBroadcast(Intent("", uri), null, object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) {
2620
when (resultCode) {
27-
Activity.RESULT_FIRST_USER -> callback?.accept(true) // Changed (for request) or enabled (for query)
28-
Activity.RESULT_OK -> callback?.accept(false) // Unchanged
29-
else -> Log.e(WeChatDecorator.TAG, "Unexpected result code: $resultCode") }
21+
Activity.RESULT_FIRST_USER -> callback(true) // Changed (for request) or enabled (for query)
22+
Activity.RESULT_OK -> callback(false) // Unchanged
23+
else -> Log.e(TAG, "Unexpected result code: $resultCode") }
3024
}}, Handler(Looper.getMainLooper()), Activity.RESULT_CANCELED, null, null)
3125
}
3226
}

src/main/java/com/oasisfeng/nevo/decorators/wechat/ConversationManager.java

Lines changed: 0 additions & 122 deletions
This file was deleted.

0 commit comments

Comments
 (0)