diff --git a/api/system-current.txt b/api/system-current.txt
index 84a8a1d5c7a61..f4029f0fe25db 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -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 {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 0627bc8559346..fe8936654aa48 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -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.
+ *
+ *
Important: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.
+ *
+ *
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.
+ *
+ *
Important: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.
+ *
+ *
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.
+ *
+ *
Important: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.
+ *
+ *
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.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 560e3c11d2f45..714f8cde55177 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -107,6 +107,8 @@
+
+
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 550162a242dc8..bfa2628d31851 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -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. -->
+
+
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 35ce780d34080..0fbcaf4053edb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3047,6 +3047,9 @@
+
+
+
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index bd2d4af54c831..6ac73b1972d49 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -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
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index a403f4521aa0f..a8e8cd92176d3 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -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 {
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 66304013da460..981a953127369 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -29,6 +29,7 @@
- com.android.systemui.util.NotificationChannels
- com.android.systemui.volume.VolumeUI
- com.android.systemui.statusbar.tv.TvStatusBar
+ - com.android.systemui.statusbar.tv.TvNotificationPanel
- com.android.systemui.usb.StorageNotification
- com.android.systemui.power.PowerUI
- com.android.systemui.media.RingtonePlayer
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 3a5ce4d82540e..1f6288a94ad46 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
new file mode 100644
index 0000000000000..7a78c157e5b4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
@@ -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
+ *
+ * - the notification handler package is a system component
+ * - the provided intent is handled by the notification handler package
+ * - the notification handler requests the
+ * {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission for the given intent
+ *
+ *
+ * @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());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index bcfff60dadf32..2795857383e8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -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 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
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d01a30fbd818a..35b14490eba29 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -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;
}