[android] Youtube style custom notification view

유튜브 맞춤 영상 알림은 오른쪽에 큰 이미지가 나온다. LargeIcon 설정으로는 저렇게 안나와서 찾아보니 결국 답은 커스텀 뷰였다.

big_image_notification_view.xml 파일을 만든다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/notificationContainer"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:gravity="center_vertical"
  android:orientation="horizontal">

  <LinearLayout
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="4.8"
    android:orientation="vertical">

    <LinearLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:gravity="center_vertical"
      android:orientation="horizontal">

      <ImageView
        android:id="@+id/notificationAppIconView"
        android:layout_width="15dp"
        android:layout_height="15dp"
        tools:src="@mipmap/ic_launcher" />

      <TextView
        android:id="@+id/notificationAppNameView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:singleLine="true"
        android:textAppearance="@style/TextAppearance.Compat.Notification"
        tools:text="@string/app_name" />

      <TextView
        android:id="@+id/notificationTimeView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:singleLine="true"
        android:textAppearance="@style/TextAppearance.Compat.Notification.Time"
        tools:text="오후 1:27" />
    </LinearLayout>

    <TextView
      android:id="@+id/notificationTitleView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="5dp"
      android:singleLine="true"
      android:textAppearance="@style/TextAppearance.Compat.Notification.Title"
      tools:text="[로스트아크] 아직 안 산 흑우없제?" />

    <TextView
      android:id="@+id/notificationBodyView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="5dp"
      android:singleLine="true"
      android:textAppearance="@style/TextAppearance.Compat.Notification.Line2"
      tools:text="맞춤 동영상: 꿀땅콩TV" />
  </LinearLayout>

  <ImageView
    android:id="@+id/notificationImageView"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="5dp"
    android:layout_weight="5.2"
    android:adjustViewBounds="true"
    android:scaleType="centerCrop"
    tools:src="@drawable/youtube" />
</LinearLayout>
테스트에 사용할 이미지

유튜브의 썸네일 비율을 확인해보니 52%였다. 그래서 notificationImageView 의 weight를 5.2로 줬다. 미리보기에는 이렇게 표시된다.

val channelId = "kr.susemi99.testcustompushnotification.notification_channel_id"

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  val appName = getString(R.string.app_name)
  var channel = notificationManager.getNotificationChannel(channelId)
  if (channel == null) {
    channel = NotificationChannel(channelId, appName, NotificationManager.IMPORTANCE_HIGH)
    notificationManager.createNotificationChannel(channel)
  }
}

val contentView = RemoteViews(context.packageName, R.layout.big_image_notification_view)
contentView.setImageViewResource(R.id.notificationAppIconView, R.mipmap.ic_launcher)
contentView.setTextViewText(R.id.notificationAppNameView, context.getString(R.string.app_name))
contentView.setTextViewText(R.id.notificationTitleView, "[로스트아크] 아직 안 산 흑우없제?")
contentView.setTextViewText(R.id.notificationBodyView, "맞춤 동영상: 꿀땅콩TV")
contentView.setImageViewBitmap(R.id.notificationImageView, BitmapFactory.decodeResource(context.resources, R.drawable.youtube))

val dateFormat = SimpleDateFormat("aa h:mm")
contentView.setTextViewText(R.id.notificationTimeView, dateFormat.format(Date()))

try {
  val startDimen = context.resources.getIdentifier("notification_content_margin_start", "dimen", "android")
  if (startDimen != 0) {
    val startPadding = context.resources.getDimensionPixelSize(startDimen)
    contentView.setViewPadding(R.id.notificationContainer, startPadding, 0, 0, 0)
  }
} catch (e: Exception) {
}

val notification = NotificationCompat.Builder(context, channelId)
  .setSmallIcon(R.mipmap.ic_launcher)
  .setAutoCancel(true)
  .setContent(contentView)
  .setCustomContentView(contentView)
  .build()

notificationManager.notify(Random.nextInt(), notification)

폰 마다 왼쪽 여백이 달라서 코드에서 처리해야 한다. 이미지 비율이 52%라서 상하여백은 신경 안써도 된다. 커스텀을 하지 않았을 때와 비교하면 이렇게 표시된다.

근데 다크모드일 때 배경이 안 바뀌는 폰도 있는 것 같다… 이래서 커스텀을 쓰는 건 비추한다…

에뮬레이터에서는 색이 정상적으로 바뀌는데, 삼성 갤럭시 S8에서는 다크모드여도 흰색이다.