refactor: Resolve theoretical Notification NPEs

Use `assert` to note when a nullable value is known to be non-null.

Extract a method call to a variable where necessary to do this.

Update `CharSequence.unicodeWrap()` to handle a null `CharSequence`.
This commit is contained in:
Nik Clayton 2023-09-20 12:48:00 +02:00
parent 7b7976c31b
commit a6bad12271
3 changed files with 21 additions and 5 deletions

View File

@ -71,6 +71,7 @@ import app.pachli.db.AccountManager;
import app.pachli.entity.Notification;
import app.pachli.entity.Poll;
import app.pachli.entity.PollOption;
import app.pachli.entity.Report;
import app.pachli.entity.Status;
import app.pachli.receiver.SendStatusBroadcastReceiver;
import app.pachli.util.StringUtils;
@ -320,6 +321,7 @@ public class NotificationHelper {
// All notifications in this group have the same type, so get it from the first.
Notification.Type notificationType = (Notification.Type)members.get(0).getNotification().extras.getSerializable(EXTRA_NOTIFICATION_TYPE);
assert notificationType != null;
Intent summaryResultIntent = MainActivity.openNotificationIntent(context, accountId, notificationType);
@ -395,6 +397,7 @@ public class NotificationHelper {
private static PendingIntent getStatusReplyIntent(@NonNull Context context, @NonNull Notification body, @NonNull AccountEntity account) {
Status status = body.getStatus();
assert status != null;
String inReplyToId = status.getId();
Status actionableStatus = status.getActionableStatus();
@ -428,6 +431,7 @@ public class NotificationHelper {
private static PendingIntent getStatusComposeIntent(@NonNull Context context, @NonNull Notification body, @NonNull AccountEntity account) {
Status status = body.getStatus();
assert status != null;
String citedLocalAuthor = status.getAccount().getLocalUsername();
String citedText = parseAsMastodonHtml(status.getContent()).toString();
@ -783,7 +787,9 @@ public class NotificationHelper {
accountName);
}
case POLL -> {
if (notification.getStatus().getAccount().getId().equals(account.getAccountId())) {
Status status = notification.getStatus();
assert status != null;
if (status.getAccount().getId().equals(account.getAccountId())) {
return context.getString(R.string.poll_ended_created);
} else {
return context.getString(R.string.poll_ended_voted);
@ -809,19 +815,24 @@ public class NotificationHelper {
return "@" + notification.getAccount().getUsername();
}
case MENTION, FAVOURITE, REBLOG, STATUS -> {
if (!TextUtils.isEmpty(notification.getStatus().getSpoilerText()) && !alwaysOpenSpoiler) {
Status status = notification.getStatus();
assert status != null;
if (!TextUtils.isEmpty(status.getSpoilerText()) && !alwaysOpenSpoiler) {
return notification.getStatus().getSpoilerText();
} else {
return parseAsMastodonHtml(notification.getStatus().getContent()).toString();
}
}
case POLL -> {
if (!TextUtils.isEmpty(notification.getStatus().getSpoilerText()) && !alwaysOpenSpoiler) {
Status status = notification.getStatus();
assert status != null;
if (!TextUtils.isEmpty(status.getSpoilerText()) && !alwaysOpenSpoiler) {
return notification.getStatus().getSpoilerText();
} else {
StringBuilder builder = new StringBuilder(parseAsMastodonHtml(notification.getStatus().getContent()));
builder.append('\n');
Poll poll = notification.getStatus().getPoll();
assert poll != null;
List<PollOption> options = poll.getOptions();
for (int i = 0; i < options.size(); ++i) {
PollOption option = options.get(i);
@ -835,10 +846,12 @@ public class NotificationHelper {
}
}
case REPORT -> {
Report report = notification.getReport();
assert report != null;
return context.getString(
R.string.notification_header_report_format,
StringUtils.unicodeWrap(notification.getAccount().getName()),
StringUtils.unicodeWrap(notification.getReport().getTargetAccount().getName())
StringUtils.unicodeWrap(report.getTargetAccount().getName())
);
}
}

View File

@ -23,6 +23,8 @@ import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import com.google.gson.annotations.JsonAdapter
// TODO: These should be different subclasses per type, so that each subclass can
// carry the non-null data that it needs.
data class Notification(
val type: Type,
val id: String,

View File

@ -59,6 +59,7 @@ fun Spanned.trimTrailingWhitespace(): Spanned {
* So we force isolation manually
* https://unicode.org/reports/tr9/#Explicit_Directional_Isolates
*/
fun CharSequence.unicodeWrap(): String {
fun CharSequence?.unicodeWrap(): String {
this ?: return ""
return "\u2068${this}\u2069"
}