noFcmのアイコン見た目を変える。2 variantを連続ビルドするスクリプト。リリースビルドで軽く試験。

This commit is contained in:
tateisu 2023-02-09 04:50:08 +09:00
parent 995e7a7504
commit 54efd01282
46 changed files with 166 additions and 102 deletions

3
.gitignore vendored
View File

@ -134,3 +134,6 @@ detektReport/
app/detekt-*.xml
.idea/androidTestResultsUserPreferences.xml
keystore.properties

View File

@ -238,7 +238,7 @@ inline fun AnkoLogger.warn(message: () -> Any?) {
*
* @see [Log.e].
*/
inline fun AnkoLogger.error(message: () -> Any?) {
fun AnkoLogger.error(message: () -> Any?) {
val tag = loggerTag
if (Log.isLoggable(tag, Log.ERROR)) {
Log.e(tag, message()?.toString() ?: "null")
@ -248,7 +248,7 @@ inline fun AnkoLogger.error(message: () -> Any?) {
/**
* Return the stack trace [String] of a throwable.
*/
inline fun Throwable.getStackTraceString(): String = Log.getStackTraceString(this)
fun Throwable.getStackTraceString(): String = Log.getStackTraceString(this)
private inline fun log(
logger: AnkoLogger,

22
apkGen.pl Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/perl --
use strict;
use warnings;
sub cmd($){
print "+ ",$_[0],"\n";
my $rv=system $_[0];
if ($? == -1) {
die "failed to execute: $!\n";
}elsif ($? & 127) {
die "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without';
}else {
my $rv = $? >> 8;
$rv and die "child exited with value $rv\n";
}
}
cmd "./gradlew clean";
cmd "./gradlew assembleNoFcmRelease";
cmd "./gradlew assembleFcmRelease";
cmd "mv app/build/outputs/apk/SubwayTooter*.apk app/";
cmd " ls -1t app/SubwayTooter*.apk |head -n 5";

View File

@ -13,6 +13,10 @@ plugins {
id("io.gitlab.arturbosch.detekt")
}
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion stCompileSdkVersion
buildToolsVersion stBuildToolsVersion
@ -59,6 +63,15 @@ android {
// kotlinCompilerExtensionVersion compose_version
// }
signingConfigs {
release {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
buildTypes {
release {
minifyEnabled false
@ -68,15 +81,9 @@ android {
lintOptions {
disable "MissingTranslation"
}
// You need to specify either an absolute path or include the
// keystore file in the same directory as the build.gradle file.
storeFile file("D:\\GoogleDrive\\_private\\AndroidSignKeys\\SubwayTooter.jks")
storePassword "password"
keyAlias "my-alias"
keyPassword "password"
signingConfig signingConfigs.release
}
debug {
}
}
@ -87,10 +94,16 @@ android {
nofcm {
dimension "fcmType"
versionNameSuffix "-noFcm"
applicationIdSuffix ".noFcm"
def scheme = "subwaytooternofcm"
manifestPlaceholders = [customScheme: scheme]
buildConfigField("String", "customScheme", "\"$scheme\"")
}
fcm {
dimension "fcmType"
versionNameSuffix "-play"
def scheme = "subwaytooter"
manifestPlaceholders = [customScheme: scheme]
buildConfigField("String", "customScheme", "\"$scheme\"")
}
}

View File

@ -6,7 +6,7 @@ import androidx.core.net.toUri
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import jp.juggler.subwaytooter.api.auth.AuthBase
import jp.juggler.subwaytooter.api.auth.MastodonAuth
import jp.juggler.subwaytooter.api.auth.AuthMastodon
import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootInstance
import jp.juggler.subwaytooter.table.SavedAccount
@ -1069,7 +1069,7 @@ class TestTootApiClient {
val (ti, ri) = TootInstance.get(client)
ti ?: error("can't get server information. ${ri?.error}")
val auth = AuthBase.findAuthForAuthStep1(client, ti, ri) as MastodonAuth
val auth = AuthBase.findAuthForAuthStep1(client, ti, ri) as AuthMastodon
val authUri = auth.authStep1(ti, forceUpdateClient = false)
println("authUri=$authUri")
@ -1137,7 +1137,7 @@ class TestTootApiClient {
Triple("?code=a&state=host:${testHost.ascii},other:a", null, "ignored"),
).forEach {
val (suffix, exClass, exMessage) = it
val callbackUrl = "${MastodonAuth.callbackUrl}$suffix".toUri()
val callbackUrl = "${AuthMastodon.callbackUrl}$suffix".toUri()
if (exClass == null) {
// expect not throw
auth.authStep2(callbackUrl)
@ -1151,7 +1151,7 @@ class TestTootApiClient {
// 正常ケース
val auth2Result =
auth.authStep2("${MastodonAuth.callbackUrl}?code=a&state=host:${testHost.ascii}".toUri())
auth.authStep2("${AuthMastodon.callbackUrl}?code=a&state=host:${testHost.ascii}".toUri())
assertEquals(
"auth2Result.tokenJson",

View File

@ -10,5 +10,13 @@
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/Light_colorAppCompatAccent" />
</application>
</manifest>

View File

@ -121,7 +121,7 @@
<data
android:host="*"
android:pathPattern=".*"
android:scheme="subwaytooter" />
android:scheme="${customScheme}" />
</intent-filter>
<intent-filter>
@ -327,21 +327,13 @@
android:name="android.max_aspect"
android:value="100.0" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/Light_colorAppCompatAccent" />
<meta-data
android:name="android.allow_multiple_resumed_activities"
android:value="true" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="jp.juggler.subwaytooter.FileProvider"
android:authorities="${applicationId}.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data

View File

@ -36,6 +36,7 @@ import jp.juggler.subwaytooter.databinding.ActAppSettingBinding
import jp.juggler.subwaytooter.databinding.LvSettingItemBinding
import jp.juggler.subwaytooter.dialog.DlgAppPicker
import jp.juggler.subwaytooter.notification.restartAllWorker
import jp.juggler.subwaytooter.pref.FILE_PROVIDER_AUTHORITY
import jp.juggler.subwaytooter.pref.impl.BooleanPref
import jp.juggler.subwaytooter.pref.impl.FloatPref
import jp.juggler.subwaytooter.pref.impl.IntPref
@ -844,7 +845,7 @@ class ActAppSetting : AppCompatActivity(), ColorPickerDialogListener, View.OnCli
file
},
afterProc = {
val uri = FileProvider.getUriForFile(activity, App1.FILE_PROVIDER_AUTHORITY, it)
val uri = FileProvider.getUriForFile(activity, FILE_PROVIDER_AUTHORITY, it)
val intent = Intent(Intent.ACTION_SEND)
intent.type = contentResolver.getType(uri)
intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter app data")

View File

@ -5,6 +5,7 @@ import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import jp.juggler.subwaytooter.pref.FILE_PROVIDER_AUTHORITY
import jp.juggler.util.*
import jp.juggler.util.data.digestSHA256Hex
import jp.juggler.util.log.LogCategory
@ -211,7 +212,7 @@ class ActCallback : AppCompatActivity() {
inStream.copyTo(outStream)
}
}
return FileProvider.getUriForFile(this, App1.FILE_PROVIDER_AUTHORITY, dst)
return FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, dst)
}
private fun sweepOldCache() {

View File

@ -18,6 +18,7 @@ import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.column.Column
import jp.juggler.subwaytooter.databinding.ActLanguageFilterBinding
import jp.juggler.subwaytooter.dialog.actionsDialog
import jp.juggler.subwaytooter.pref.FILE_PROVIDER_AUTHORITY
import jp.juggler.util.*
import jp.juggler.util.coroutine.launchAndShowError
import jp.juggler.util.coroutine.launchProgress
@ -425,7 +426,7 @@ class ActLanguageFilter : AppCompatActivity(), View.OnClickListener {
afterProc = {
val uri = FileProvider.getUriForFile(
this@ActLanguageFilter,
App1.FILE_PROVIDER_AUTHORITY,
FILE_PROVIDER_AUTHORITY,
it
)
val intent = Intent(Intent.ACTION_SEND)

View File

@ -77,8 +77,6 @@ class App1 : Application() {
internal val log = LogCategory("App1")
const val FILE_PROVIDER_AUTHORITY = "jp.juggler.subwaytooter.FileProvider"
// private val APPROVED_CIPHER_SUITES = arrayOf(
//
// // 以下は okhttp 3 のデフォルト
@ -462,7 +460,10 @@ class App1 : Application() {
}
if (!response.isSuccessful) {
log.e(caller,TootApiClient.formatResponse(response, "getHttp response error. $url"))
log.e(
caller,
TootApiClient.formatResponse(response, "getHttp response error. $url")
)
return null
}

View File

@ -63,6 +63,7 @@ fun ActMain.accountAdd() {
when (action) {
LoginForm.Action.Login -> {
val authUri = runApiTask2(apiHost) { it.authStep1() }
log.i("authUri=$authUri")
openBrowser(authUri)
dialogHost.dismissSafe()
}

View File

@ -7,6 +7,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.action.conversationOtherInstance
import jp.juggler.subwaytooter.action.openActPostImpl
@ -54,7 +55,7 @@ fun ActMain.handleIntentUri(uri: Uri) {
try {
log.i("handleIntentUri $uri")
when (uri.scheme) {
"subwaytooter", "misskeyclientproto" -> handleCustomSchemaUri(uri)
BuildConfig.customScheme -> handleCustomSchemaUri(uri)
else -> handleOtherUri(uri)
}
} catch (ex: Throwable) {
@ -175,7 +176,7 @@ private fun ActMain.handleCustomSchemaUri(uri: Uri) = launchAndShowError {
// subwaytooter://oauth(\d*)/?...
handleOAuth2Callback(uri)
} else {
// subwaytooter://notification_click/?db_id=(db_id)
// ${BuildConfig.customScheme}://notification_click/?db_id=(db_id)
handleNotificationClick(uri, dataIdString)
}
}

View File

@ -14,7 +14,7 @@ import jp.juggler.util.network.toFormRequestBody
import jp.juggler.util.network.toPost
import okhttp3.Request
class MastodonAuthApi(
class ApiAuthMastodon(
val client: TootApiClient,
) {
/**

View File

@ -9,7 +9,7 @@ import jp.juggler.util.data.buildJsonObject
import jp.juggler.util.data.jsonObjectOf
import jp.juggler.util.network.toPostRequestBuilder
class MisskeyAuthApi10(val client: TootApiClient) {
class ApiAuthMisskey10(val client: TootApiClient) {
suspend fun appCreate(
apiHost: Host,

View File

@ -10,7 +10,7 @@ import jp.juggler.util.data.JsonObject
import jp.juggler.util.data.jsonObjectOf
import jp.juggler.util.network.toPostRequestBuilder
class MisskeyAuthApi13(val client: TootApiClient) {
class ApiAuthMisskey13(val client: TootApiClient) {
/**
* miauth のブラウザ認証URLを作成する

View File

@ -44,8 +44,8 @@ abstract class AuthBase {
// https://github.com/misskey-dev/misskey/issues/9825
// https://github.com/misskey-dev/misskey/commit/788ae2f6ca37d297e912bfba02821543e8566522
// misskeyVersionMajor >= 13 -> MisskeyAuth13(client)
misskeyVersionMajor > 0 -> MisskeyAuth10(client)
else -> MastodonAuth(client)
misskeyVersionMajor > 0 -> AuthMisskey10(client)
else -> AuthMastodon(client)
}
fun findAuthForAuthStep1(client: TootApiClient, ti: TootInstance?, ri: TootApiResult?) =
@ -54,20 +54,20 @@ abstract class AuthBase {
// インスタンス情報を取得できないが、マストドンだと分かる場合がある
// https://github.com/tateisu/SubwayTooter/issues/155
// Mastodon's WHITELIST_MODE
401 -> MastodonAuth(client)
401 -> AuthMastodon(client)
else -> null
}
fun findAuthForAuthCallback(client: TootApiClient, callbackUrl: String) =
when {
MisskeyAuth10.isCallbackUrl(callbackUrl) -> MisskeyAuth10(client)
MisskeyAuth13.isCallbackUrl(callbackUrl) -> MisskeyAuth13(client)
else -> MastodonAuth(client)
AuthMisskey10.isCallbackUrl(callbackUrl) -> AuthMisskey10(client)
AuthMisskey13.isCallbackUrl(callbackUrl) -> AuthMisskey13(client)
else -> AuthMastodon(client)
}
fun findAuthForCreateUser(client: TootApiClient, ti: TootInstance?) =
when (ti?.instanceType) {
InstanceType.Mastodon -> MastodonAuth(client)
InstanceType.Mastodon -> AuthMastodon(client)
else -> null
}
}

View File

@ -1,6 +1,7 @@
package jp.juggler.subwaytooter.api.auth
import android.net.Uri
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.subwaytooter.api.SendException
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootParser
@ -17,12 +18,12 @@ import jp.juggler.util.data.notEmpty
import jp.juggler.util.log.LogCategory
import jp.juggler.util.log.errorEx
class MastodonAuth(override val client: TootApiClient) : AuthBase() {
class AuthMastodon(override val client: TootApiClient) : AuthBase() {
companion object {
private val log = LogCategory("MastodonAuth")
const val callbackUrl = "subwaytooter://oauth/"
const val callbackUrl = "${BuildConfig.customScheme}://oauth/"
fun mastodonScope(ti: TootInstance?) = when {
// 古いサーバ
@ -36,7 +37,7 @@ class MastodonAuth(override val client: TootApiClient) : AuthBase() {
}
}
val api = MastodonAuthApi(client)
val api = ApiAuthMastodon(client)
// クライアントアプリの登録を確認するためのトークンを生成する
// oAuth2 Client Credentials の取得

View File

@ -2,6 +2,7 @@ package jp.juggler.subwaytooter.api.auth
import android.net.Uri
import androidx.core.net.toUri
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootParser
@ -15,10 +16,10 @@ import jp.juggler.subwaytooter.util.LinkHelper
import jp.juggler.util.data.*
import jp.juggler.util.log.LogCategory
class MisskeyAuth10(override val client: TootApiClient) : AuthBase() {
class AuthMisskey10(override val client: TootApiClient) : AuthBase() {
companion object {
private val log = LogCategory("MisskeyOldAuth")
private const val callbackUrl = "subwaytooter://misskey/auth_callback"
private const val callbackUrl = "${BuildConfig.customScheme}://misskey/auth_callback"
fun isCallbackUrl(uriStr: String) =
uriStr.startsWith(callbackUrl) ||
@ -88,7 +89,7 @@ class MisskeyAuth10(override val client: TootApiClient) : AuthBase() {
a.encodeScopeArray() == b?.encodeScopeArray()
}
val api = MisskeyAuthApi10(client)
val api = ApiAuthMisskey10(client)
/**
* Misskey v12 までの認証に使うURLを生成する

View File

@ -1,10 +1,11 @@
package jp.juggler.subwaytooter.api.auth
import android.net.Uri
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.api.auth.MisskeyAuth10.Companion.encodeScopeArray
import jp.juggler.subwaytooter.api.auth.MisskeyAuth10.Companion.getScopeArrayMisskey
import jp.juggler.subwaytooter.api.auth.AuthMisskey10.Companion.encodeScopeArray
import jp.juggler.subwaytooter.api.auth.AuthMisskey10.Companion.getScopeArrayMisskey
import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootInstance
import jp.juggler.subwaytooter.pref.prefDevice
@ -19,17 +20,17 @@ import java.util.*
* miauth と呼ばれている認証手順
* STではMisskey 13から使用する
*/
class MisskeyAuth13(override val client: TootApiClient) : AuthBase() {
class AuthMisskey13(override val client: TootApiClient) : AuthBase() {
companion object {
private val log = LogCategory("MisskeyMiAuth")
private const val appIconUrl = "https://m1j.zzz.ac/subwaytooter-miauth-icon.png"
private const val callbackUrl = "subwaytooter://miauth/auth_callback"
private const val callbackUrl = "${BuildConfig.customScheme}://miauth/auth_callback"
fun isCallbackUrl(uriStr: String) = uriStr.startsWith(callbackUrl)
}
private val api10 = MisskeyAuthApi10(client)
private val api13 = MisskeyAuthApi13(client)
private val api10 = ApiAuthMisskey10(client)
private val api13 = ApiAuthMisskey13(client)
// 認証されたアカウントのユーザ情報を取得する
override suspend fun verifyAccount(

View File

@ -15,6 +15,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.startup.Initializer
import androidx.work.ForegroundInfo
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.pref.LazyContextInitializer
import jp.juggler.util.*
@ -37,6 +38,8 @@ enum class NotificationChannels(
val pircDelete: Int,
// 通知削除のUri prefix
val uriPrefixDelete: String,
// 通知タップのUri prefix
val uriPrefixTap: String,
) {
PullNotification(
id = "SnsNotification",
@ -47,7 +50,8 @@ enum class NotificationChannels(
notificationId = 1,
pircTap = 1,
pircDelete = 1, // uriでtapとdeleteを区別している
uriPrefixDelete = "subwaytooter://sns-notification",
uriPrefixDelete = "${BuildConfig.customScheme}://notification_delete/",
uriPrefixTap = "${BuildConfig.customScheme}://notification_click/",
),
PullWorker(
id = "PollingForegrounder",
@ -58,7 +62,8 @@ enum class NotificationChannels(
notificationId = 2,
pircTap = 2,
pircDelete = -1,
uriPrefixDelete = "subwaytooter://checker",
uriPrefixDelete = "${BuildConfig.customScheme}://checker",
uriPrefixTap = "${BuildConfig.customScheme}://checker-tap",
),
ServerTimeout(
id = "ErrorNotification",
@ -69,7 +74,8 @@ enum class NotificationChannels(
notificationId = 3,
pircTap = 3,
pircDelete = 4,
uriPrefixDelete = "subwaytooter://server-timeout",
uriPrefixDelete = "${BuildConfig.customScheme}://server-timeout",
uriPrefixTap = "${BuildConfig.customScheme}://server-timeout-tap",
),
PushMessage(
id = "PushMessage",
@ -80,7 +86,8 @@ enum class NotificationChannels(
notificationId = 5,
pircTap = 5,
pircDelete = 6,
uriPrefixDelete = "subwaytooter://pushMessage",
uriPrefixDelete = "${BuildConfig.customScheme}://pushMessage",
uriPrefixTap = "${BuildConfig.customScheme}://notification_click/",
),
Alert(
id = "Alert",
@ -91,7 +98,8 @@ enum class NotificationChannels(
notificationId = 7,
pircTap = 7,
pircDelete = 8,
uriPrefixDelete = "subwaytooter://alert",
uriPrefixDelete = "${BuildConfig.customScheme}://alert",
uriPrefixTap = "${BuildConfig.customScheme}://alert-tap",
),
PushWorker(
id = "PushMessageWorker",
@ -102,22 +110,9 @@ enum class NotificationChannels(
notificationId = 9,
pircTap = 9,
pircDelete = 10,
uriPrefixDelete = "subwaytooter://pushWorker",
uriPrefixDelete = "${BuildConfig.customScheme}://pushWorker",
uriPrefixTap = "${BuildConfig.customScheme}://pushWorker-tag",
),
/////////////////////////////
// 以下、通知IDやpirc を吟味していない
// SubscriptionUpdate(
// id = "SubscriptionUpdate",
// titleId = R.string.push_subscription_update,
// descId = R.string.push_subscription_update_desc,
// importance = NotificationManagerCompat.IMPORTANCE_LOW,
// priority = NotificationCompat.PRIORITY_LOW,
// notificationId = 3,
// pircTap = 4,
// pircDelete = 5,
// uriPrefixDelete = "pushreceiverapp://subscriptionUpdate",
// ),
;
@ -175,11 +170,11 @@ enum class NotificationChannels(
text: String? = context.getString(descId),
piTap: PendingIntent? = null,
piDelete: PendingIntent? = null,
force:Boolean = false,
force: Boolean = false,
): ForegroundInfo? {
val notificationManager = NotificationManagerCompat.from(context)
if(!force){
if (!force) {
if (Build.VERSION.SDK_INT >= 33) {
if (ActivityCompat.checkSelfPermission(
context,

View File

@ -23,15 +23,15 @@ object PullNotification {
const val TRACKING_NAME_DEFAULT = ""
const val TRACKING_NAME_REPLY = "reply"
private val nc = NotificationChannels.PullNotification
private val ncPullNotification = NotificationChannels.PullNotification
/**
* メッセージ通知を消す
*/
fun NotificationManager.removeMessageNotification(id: String?, tag: String) {
when (id) {
null -> cancel(tag, nc.notificationId)
else -> cancel("$tag/$id", nc.notificationId)
null -> cancel(tag, ncPullNotification.notificationId)
else -> cancel("$tag/$id", ncPullNotification.notificationId)
}
}
@ -41,13 +41,13 @@ object PullNotification {
fun NotificationManager.removeMessageNotification(account: SavedAccount, tag: String) {
if (PrefB.bpDivideNotification.value) {
activeNotifications?.filterNotNull()?.filter {
it.id == nc.notificationId && it.tag.startsWith("$tag/")
it.id == ncPullNotification.notificationId && it.tag.startsWith("$tag/")
}?.forEach {
log.d("cancel: ${it.tag} context=${account.acct.pretty} $tag")
cancel(it.tag, nc.notificationId)
cancel(it.tag, ncPullNotification.notificationId)
}
} else {
cancel(tag, nc.notificationId)
cancel(tag, ncPullNotification.notificationId)
}
}
@ -56,7 +56,7 @@ object PullNotification {
*/
fun NotificationManager.getMessageNotifications(tag: String) =
activeNotifications?.filterNotNull()?.filter {
it.id == nc.notificationId && it.tag.startsWith("$tag/")
it.id == ncPullNotification.notificationId && it.tag.startsWith("$tag/")
}?.map { Pair(it.tag, it) }?.toMutableMap() ?: mutableMapOf()
fun showMessageNotification(
@ -81,29 +81,29 @@ object PullNotification {
}.joinToString("&")
val iTap = Intent(context, ActCallback::class.java).apply {
data = "subwaytooter://notification_click/?$params".toUri()
data = "${ncPullNotification.uriPrefixTap}?$params".toUri()
// FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY を付与してはいけない
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val piTap = PendingIntent.getActivity(
context,
nc.pircTap,
ncPullNotification.pircTap,
iTap,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val iDelete = Intent(context, EventReceiver::class.java).apply {
action = EventReceiver.ACTION_NOTIFICATION_DELETE
data = "subwaytooter://notification_delete/?$params".toUri()
data = "${ncPullNotification.uriPrefixDelete}?$params".toUri()
}
val piDelete = PendingIntent.getBroadcast(
context,
nc.pircDelete,
ncPullNotification.pircDelete,
iDelete,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
nc.notify(context, notificationTag) {
ncPullNotification.notify(context, notificationTag) {
setContentIntent(piTap)
setDeleteIntent(piDelete)
setAutoCancel(true)
@ -125,9 +125,8 @@ object PullNotification {
}
fun openNotificationChannelSetting(context: Context) {
val nc = NotificationChannels.PullNotification
val intent = Intent("android.settings.CHANNEL_NOTIFICATION_SETTINGS")
intent.putExtra(Settings.EXTRA_CHANNEL_ID, nc.id)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, ncPullNotification.id)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
context.startActivity(intent)
}

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import androidx.startup.Initializer
import jp.juggler.subwaytooter.BuildConfig
import jp.juggler.util.os.applicationContextSafe
import java.util.concurrent.atomic.AtomicReference
@ -20,6 +21,8 @@ val lazyPref
?: LazyContextHolder.prefNullable
?: error("LazyContextHolder not initialized")
const val FILE_PROVIDER_AUTHORITY ="${BuildConfig.APPLICATION_ID}.FileProvider"
@SuppressLint("StaticFieldLeak")
object LazyContextHolder {
var contextNullable: Context? = null

View File

@ -670,7 +670,7 @@ class PushRepo(
}
val iTap = Intent(context, ActCallback::class.java).apply {
data = "subwaytooter://notification_click/?$params".toUri()
data = "${ncPushMessage.uriPrefixTap}?$params".toUri()
// FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY を付与してはいけない
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
@ -684,13 +684,12 @@ class PushRepo(
val urlDelete = "${ncPushMessage.uriPrefixDelete}/${pm.id}"
val iDelete = context.intentNotificationDelete(urlDelete.toUri())
val piDelete =
PendingIntent.getBroadcast(
context,
ncPushMessage.pircDelete,
iDelete,
PendingIntent.FLAG_IMMUTABLE
)
val piDelete = PendingIntent.getBroadcast(
context,
ncPushMessage.pircDelete,
iDelete,
PendingIntent.FLAG_IMMUTABLE
)
// val iTap = intentActMessage(pm.messageDbId)
// val piTap = PendingIntent.getActivity(this, nc.pircTap, iTap, PendingIntent.FLAG_IMMUTABLE)

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="256"
android:viewportWidth="256">
<!--
推奨図柄サイズ(44dp)/表示サイズ(108dp)=0.4074,
データ中の余白を含むサイズ(256)/余白を削ったサイズ(226)=1.1327433
scaleは 0.4074*1.1327433=0.46147962
translateは (1-0.46147962)/2*256=68.93060864
-->
<group
android:scaleX="0.46147962"
android:scaleY="0.46147962"
android:translateX="68.93"
android:translateY="68.93">
<path
android:fillColor="#ffffff"
android:pathData="m97,39c-19,3 -39,21 -46,39 -6,16 -1,36 15,44 -4,6 -9,10 -15,14l-9,6c-2,4 2,7 5,9 -4,8 -10,15 -15,23l-5,12 -6,5c-4,5 -7,11 -7,17 -1,12 3,23 15,27 5,2 10,4 14,-2l16,10 8,-2 18,5 30,4h16c13,1 30,3 42,-2 7,-3 15,-9 20,-15 2,-3 3,-8 6,-10 6,-4 13,0 19,-1 8,-2 17,-15 20,-22 3,-7 -3,-9 -5,-15 -1,-3 1,-7 -2,-10 -3,-3 -10,-1 -11,3l-16,-9c1,-3 2,-8 -1,-11 -3,-3 -10,-3 -12,1 -6,-2 -10,-4 -11,-11 9,4 25,5 34,0 8,-5 12,-14 14,-23 1,-9 -4,-18 -4,-27V83c1,-6 5,-10 2,-17 -1,-4 -5,-6 -6,-9l-2,-8C216,42 209,38 202,38 201,26 190,20 179,19 179,14 177,9 171,8l-7,1c-4,-1 -6,-4 -10,-4 -5,0 -7,5 -11,5 -15,2 -39,-2 -45,17l-1,12m6,4c1,4 3,6 6,9 3,2 6,3 6,7 -1,5 -5,5 -9,6 -6,1 -11,2 -16,5C75,78 63,94 63,111 53,103 53,89 58,79 66,61 84,47 103,43m16,21c4,2 8,1 11,3 5,2 8,6 14,8 5,1 11,-1 16,1l11,7c5,2 10,2 16,3 6,1 11,4 17,4l-2,13c-2,6 -5,9 -1,15l-2,3c-4,8 7,1 9,0l-1,3c-1,9 6,0 8,-1l7,-1 -2,9c-9,23 -36,12 -53,6 2,-9 -2,-16 -7,-23 -1,-2 -3,-6 -6,-7 -5,-1 -8,9 -9,12 -1,8 0,19 9,22 5,2 11,0 16,4 7,5 8,20 2,26 -4,-2 -7,-5 -12,-6 2,7 9,11 15,14l9,5c6,8 -4,21 -11,23 -10,4 -24,-3 -31,-9 -2,-1 -9,-10 -12,-8 -2,1 -1,3 0,4 2,4 6,6 9,9 11,8 24,13 38,10 5,8 4,21 -4,27 -5,4 -11,5 -17,5l-23,-1c-22,-1 -43,-3 -64,-9H59c-4,0 -6,-4 -9,-6 -3,-3 -7,-4 -10,-8 -4,-6 -4,-13 -5,-20l-3,-7c0,-5 3,-12 5,-16 3,-6 8,-10 11,-15 3,-5 10,-15 1,-17 4,-5 10,-8 15,-12 3,-3 6,-7 9,-8 4,-2 10,0 15,-1 13,-3 31,-12 37,-25 2,-4 -2,-9 -4,-13 -1,-4 1,-6 1,-10 -1,-5 -5,-8 -3,-13m-6,5 l2,9v9c1,4 4,8 3,12 -1,4 -5,7 -8,9 -8,6 -17,11 -27,12 -4,0 -9,0 -12,-3 -4,-4 -2,-15 0,-20 8,-17 24,-26 42,-28m104,15c2,4 3,8 0,12l-4,4c-2,4 -1,6 -6,7 2,-9 0,-20 10,-23m3,19 l1,13h-3c-10,-1 -1,-8 0,-13h2m-55,2c-4,3 -1,10 4,7 3,-3 1,-9 -4,-7m42,5v2h-2v-2h2m-54,4 l4,5c-3,2 -5,4 -1,6l-1,5h8c-1,7 -8,9 -12,2 -2,-5 -1,-13 2,-18m30,48 l35,22c4,3 12,5 14,10 1,2 0,4 -1,6 -3,4 -9,15 -15,15 -3,0 -6,-2 -8,-3l-19,-11c1,-8 6,-18 -4,-23 -2,-2 -5,-2 -7,-3 3,-4 3,-9 5,-13m17,0v2h-3v-2h3m28,18v2h-3v-2h3M26,195c1,12 9,23 11,35l-7,-2c-2,-1 -5,-1 -6,-3 -2,-1 -2,-5 -3,-7 -3,-9 -1,-16 5,-23m158,37c2,-8 2,-15 -3,-22 5,-7 11,-2 12,5 1,7 -3,14 -9,17z" />
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -8,10 +8,10 @@ sub cmd($){
if ($? == -1) {
die "failed to execute: $!\n";
}elsif ($? & 127) {
die "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without';
}else {
my $rv = $? >> 8;
$rv and die "child exited with value $rv\n";
die sprintf "child died with signal %d\n", ($? & 127);
}elseif($?){
$rv = $? >> 8;
die "child exited with value $rv\n";
}
}