Merge "Support for notification panel key on ATV"

This commit is contained in:
Philip Junker
2020-09-15 07:19:05 +00:00
committed by Android (Google) Code Review
12 changed files with 221 additions and 24 deletions

View File

@@ -671,6 +671,9 @@ package android.app {
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
}
public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {

View File

@@ -19,6 +19,7 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -130,6 +131,73 @@ public class NotificationManager {
public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED =
"android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
/**
* Activity action: Toggle notification panel of the specified handler.
*
* <p><strong>Important:</strong>You must protect the activity that handles this action with
* the {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission to ensure that only
* the SystemUI can launch this activity. Activities that are not properly protected will not
* be launched.
*
* <p class="note">This is currently only used on TV to allow a system app to handle the
* notification panel. The package handling the notification panel has to be specified by
* config_notificationHandlerPackage in values/config.xml.
*
* Input: nothing
* Output: nothing
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL =
"android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
/**
* Activity action: Open notification panel of the specified handler.
*
* <p><strong>Important:</strong>You must protect the activity that handles this action with
* the {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission to ensure that only
* the SystemUI can launch this activity. Activities that are not properly protected will
* not be launched.
*
* <p class="note"> This is currently only used on TV to allow a system app to handle the
* notification panel. The package handling the notification panel has to be specified by
* config_notificationHandlerPackage in values/config.xml.
*
* Input: nothing
* Output: nothing
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL =
"android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
/**
* Intent that is broadcast when the notification panel of the specified handler is to be
* closed.
*
* <p><strong>Important:</strong>You should protect the receiver that handles this action with
* the {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission to ensure that only
* the SystemUI can send this broadcast to the notification handler.
*
* <p class="note"> This is currently only used on TV to allow a system app to handle the
* notification panel. The package handling the notification panel has to be specified by
* config_notificationHandlerPackage in values/config.xml. This is a protected intent that can
* only be sent by the system.
*
* Input: nothing.
* Output: nothing.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL =
"android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
/**
* Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} containing the id of the
* {@link NotificationChannel} which has a new blocked state.

View File

@@ -107,6 +107,8 @@
<!-- @deprecated This is rarely used and will be phased out soon. -->
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
<protected-broadcast android:name="android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL" />
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />

View File

@@ -1166,6 +1166,7 @@
0 - Nothing
1 - Launch all apps intent
2 - Launch assist intent
3 - Launch notification panel
This needs to match the constants in
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
-->
@@ -3390,6 +3391,9 @@
service. -->
<string name="config_tvRemoteServicePackage" translatable="false"></string>
<!-- The package name of the package implementing the custom notification panel -->
<string name="config_notificationHandlerPackage" translatable="false"></string>
<!-- True if the device supports persisting security logs across reboots.
This requires the device's kernel to have pstore and pmsg enabled,
and DRAM to be powered and refreshed through all stages of reboot. -->

View File

@@ -3047,6 +3047,9 @@
<java-symbol type="string" name="config_tvRemoteServicePackage" />
<java-symbol type="string" name="notification_messaging_title_template" />
<!-- Notification handler / dashboard package -->
<java-symbol type="string" name="config_notificationHandlerPackage" />
<java-symbol type="bool" name="config_supportPreRebootSecurityLogs" />
<java-symbol type="dimen" name="notification_media_image_margin_end" />

View File

@@ -223,7 +223,7 @@ key 200 MEDIA_PLAY
key 201 MEDIA_PAUSE
# key 202 "KEY_PROG3"
# key 203 "KEY_PROG4"
# key 204 (undefined)
key 204 NOTIFICATION
# key 205 "KEY_SUSPEND"
# key 206 "KEY_CLOSE"
key 207 MEDIA_PLAY

View File

@@ -671,6 +671,9 @@ package android.app {
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
}
public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {

View File

@@ -29,6 +29,7 @@
<item>com.android.systemui.util.NotificationChannels</item>
<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.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>

View File

@@ -35,6 +35,7 @@ import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.tv.TvNotificationPanel;
import com.android.systemui.statusbar.tv.TvStatusBar;
import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
@@ -156,6 +157,12 @@ public abstract class SystemUIBinder {
@ClassKey(TvStatusBar.class)
public abstract SystemUI bindsTvStatusBar(TvStatusBar sysui);
/** Inject into TvNotificationPanel. */
@Binds
@IntoMap
@ClassKey(TvNotificationPanel.class)
public abstract SystemUI bindsTvNotificationPanel(TvNotificationPanel sysui);
/** Inject into VolumeUI. */
@Binds
@IntoMap

View File

@@ -0,0 +1,115 @@
/*
* 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.
*/
package com.android.systemui.statusbar.tv;
import android.Manifest;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.util.Log;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.CommandQueue;
import javax.inject.Inject;
/**
* Offers control methods for the notification panel handler on TV devices.
*/
@SysUISingleton
public class TvNotificationPanel extends SystemUI implements CommandQueue.Callbacks {
private static final String TAG = "TvNotificationPanel";
private final CommandQueue mCommandQueue;
private final String mNotificationHandlerPackage;
@Inject
public TvNotificationPanel(Context context, CommandQueue commandQueue) {
super(context);
mCommandQueue = commandQueue;
mNotificationHandlerPackage = mContext.getResources().getString(
com.android.internal.R.string.config_notificationHandlerPackage);
}
@Override
public void start() {
mCommandQueue.addCallback(this);
}
@Override
public void togglePanel() {
if (!mNotificationHandlerPackage.isEmpty()) {
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL));
}
}
@Override
public void animateExpandNotificationsPanel() {
if (!mNotificationHandlerPackage.isEmpty()) {
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL));
}
}
@Override
public void animateCollapsePanels(int flags, boolean force) {
if (!mNotificationHandlerPackage.isEmpty()
&& (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
Intent closeNotificationIntent = new Intent(
NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL);
closeNotificationIntent.setPackage(mNotificationHandlerPackage);
mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT);
}
}
/**
* Starts the activity intent if all of the following are true
* <ul>
* <li> the notification handler package is a system component </li>
* <li> the provided intent is handled by the notification handler package </li>
* <li> the notification handler requests the
* {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission for the given intent</li>
* </ul>
*
* @param intent The intent for starting the desired activity
*/
private void startNotificationHandlerActivity(Intent intent) {
intent.setPackage(mNotificationHandlerPackage);
PackageManager pm = mContext.getPackageManager();
ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY);
if (ri != null && ri.activityInfo != null) {
if (ri.activityInfo.permission != null && ri.activityInfo.permission.equals(
Manifest.permission.STATUS_BAR_SERVICE)) {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
} else {
Log.e(TAG,
"Not launching notification handler activity: Notification handler does "
+ "not require the STATUS_BAR_SERVICE permission for intent "
+ intent.getAction());
}
} else {
Log.e(TAG,
"Not launching notification handler activity: Could not resolve activityInfo "
+ "for intent "
+ intent.getAction());
}
}
}

View File

@@ -17,13 +17,9 @@
package com.android.systemui.statusbar.tv;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
@@ -49,9 +45,6 @@ import dagger.Lazy;
@SysUISingleton
public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
private static final String ACTION_OPEN_TV_NOTIFICATIONS_PANEL =
"com.android.tv.action.OPEN_NOTIFICATIONS_PANEL";
private final CommandQueue mCommandQueue;
private final Lazy<AssistManager> mAssistManagerLazy;
@@ -74,24 +67,11 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
// If the system process isn't there we're doomed anyway.
}
if (mContext.getResources().getBoolean(R.bool.audio_recording_disclosure_enabled)) {
if (mContext.getResources().getBoolean(R.bool.audio_recording_disclosure_enabled)) {
// Creating AudioRecordingDisclosureBar and just letting it run
new AudioRecordingDisclosureBar(mContext);
}
}
@Override
public void animateExpandNotificationsPanel() {
startSystemActivity(new Intent(ACTION_OPEN_TV_NOTIFICATIONS_PANEL));
}
private void startSystemActivity(Intent intent) {
PackageManager pm = mContext.getPackageManager();
ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY);
if (ri != null && ri.activityInfo != null) {
intent.setPackage(ri.activityInfo.packageName);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
}
@Override

View File

@@ -281,7 +281,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final int LONG_PRESS_HOME_NOTHING = 0;
static final int LONG_PRESS_HOME_ALL_APPS = 1;
static final int LONG_PRESS_HOME_ASSIST = 2;
static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_ASSIST;
static final int LONG_PRESS_HOME_NOTIFICATION_PANEL = 3;
static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_NOTIFICATION_PANEL;
// must match: config_doubleTapOnHomeBehavior in config.xml
static final int DOUBLE_TAP_HOME_NOTHING = 0;
@@ -1694,8 +1695,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case LONG_PRESS_HOME_ASSIST:
launchAssistAction(null, deviceId);
break;
case LONG_PRESS_HOME_NOTIFICATION_PANEL:
IStatusBarService statusBarService = getStatusBarService();
if (statusBarService != null) {
try {
statusBarService.togglePanel();
} catch (RemoteException e) {
// do nothing.
}
}
break;
default:
Log.w(TAG, "Undefined home long press behavior: "
Log.w(TAG, "Undefined long press on home behavior: "
+ mLongPressOnHomeBehavior);
break;
}