Merge "Notify VPN status from SystemUI as notifications"

This commit is contained in:
TreeHugger Robot
2020-11-05 14:35:58 +00:00
committed by Android (Google) Code Review
3 changed files with 147 additions and 0 deletions

View File

@@ -30,6 +30,7 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
<item>com.android.systemui.statusbar.tv.TvNotificationPanel</item>
<item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>

View File

@@ -20,4 +20,10 @@
<!-- Title and subtitle for AudioRecordingIndicator -->
<string name="mic_active">Microphone Active</string>
<string name="app_accessed_mic">%1$s accessed your microphone</string>
<string name="notification_vpn_connected">VPN is connected</string>
<string name="notification_vpn_disconnected">VPN is disconnected</string>
<!-- Disclosure text in the connected notification that indicates that the device is connected to a VPN. The placeholder is the VPN name. [CHAR LIMIT=40] -->
<string name="notification_disclosure_vpn_text">Via <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g></string>
</resources>

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("VpnStatusObserver")
package com.android.systemui.statusbar.tv
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import com.android.internal.messages.nano.SystemMessageProto
import com.android.internal.net.VpnConfig
import com.android.systemui.Dependency
import com.android.systemui.R
import com.android.systemui.SystemUI
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.policy.SecurityController
import javax.inject.Inject
/**
* Observes if a vpn connection is active and displays a notification to the user
*/
@SysUISingleton
class VpnStatusObserver @Inject constructor(context: Context) : SystemUI(context),
SecurityController.SecurityControllerCallback {
private var vpnConnected = false
private val securityController: SecurityController =
Dependency.get(SecurityController::class.java)
private val notificationManager = NotificationManager.from(context)
private val notificationChannel = createNotificationChannel()
private val vpnConnectedNotificationBuilder = createVpnConnectedNotificationBuilder()
private val vpnDisconnectedNotification = createVpnDisconnectedNotification()
private val vpnIconId: Int
get() = if (securityController.isVpnBranded) {
R.drawable.stat_sys_branded_vpn
} else {
R.drawable.stat_sys_vpn_ic
}
private val vpnName: String?
get() = securityController.primaryVpnName ?: securityController.workProfileVpnName
override fun start() {
// register callback to vpn state changes
securityController.addCallback(this)
}
override fun onStateChanged() {
securityController.isVpnEnabled.let { newVpnConnected ->
if (vpnConnected != newVpnConnected) {
if (newVpnConnected) {
notifyVpnConnected()
} else {
notifyVpnDisconnected()
}
vpnConnected = newVpnConnected
}
}
}
private fun notifyVpnConnected() = notificationManager.notify(
NOTIFICATION_TAG,
SystemMessageProto.SystemMessage.NOTE_VPN_STATUS,
createVpnConnectedNotification()
)
private fun notifyVpnDisconnected() = notificationManager.run {
// remove existing connected notification
cancel(NOTIFICATION_TAG, SystemMessageProto.SystemMessage.NOTE_VPN_STATUS)
// show the disconnected notification only for a short while
notify(NOTIFICATION_TAG, SystemMessageProto.SystemMessage.NOTE_VPN_DISCONNECTED,
vpnDisconnectedNotification)
}
private fun createNotificationChannel() =
NotificationChannel(
NOTIFICATION_CHANNEL_TV_VPN,
NOTIFICATION_CHANNEL_TV_VPN,
NotificationManager.IMPORTANCE_HIGH
).also {
notificationManager.createNotificationChannel(it)
}
private fun createVpnConnectedNotification() =
vpnConnectedNotificationBuilder
.apply {
vpnName?.let {
setContentText(
mContext.getString(
R.string.notification_disclosure_vpn_text, it
)
)
}
}
.build()
private fun createVpnConnectedNotificationBuilder() =
Notification.Builder(mContext, NOTIFICATION_CHANNEL_TV_VPN)
.setSmallIcon(vpnIconId)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_SYSTEM)
.extend(Notification.TvExtender())
.setOngoing(true)
.setContentTitle(mContext.getString(R.string.notification_vpn_connected))
.setContentIntent(VpnConfig.getIntentForStatusPanel(mContext))
private fun createVpnDisconnectedNotification() =
Notification.Builder(mContext, NOTIFICATION_CHANNEL_TV_VPN)
.setSmallIcon(vpnIconId)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_SYSTEM)
.extend(Notification.TvExtender())
.setTimeoutAfter(VPN_DISCONNECTED_NOTIFICATION_TIMEOUT_MS)
.setContentTitle(mContext.getString(R.string.notification_vpn_disconnected))
.build()
companion object {
const val NOTIFICATION_CHANNEL_TV_VPN = "VPN Status"
val NOTIFICATION_TAG: String = VpnStatusObserver::class.java.simpleName
private const val TAG = "TvVpnNotification"
private const val VPN_DISCONNECTED_NOTIFICATION_TIMEOUT_MS = 5_000L
}
}