1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.tv.notifications; 18 19 import android.Manifest; 20 import android.app.NotificationManager; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.content.pm.ResolveInfo; 25 import android.os.UserHandle; 26 import android.util.Log; 27 28 import com.android.systemui.CoreStartable; 29 import com.android.systemui.dagger.SysUISingleton; 30 import com.android.systemui.statusbar.CommandQueue; 31 32 import javax.inject.Inject; 33 34 /** 35 * Offers control methods for the notification panel handler on TV devices. 36 */ 37 @SysUISingleton 38 public class TvNotificationPanel implements CoreStartable, CommandQueue.Callbacks { 39 private static final String TAG = "TvNotificationPanel"; 40 private final Context mContext; 41 private final CommandQueue mCommandQueue; 42 private final String mNotificationHandlerPackage; 43 44 @Inject TvNotificationPanel(Context context, CommandQueue commandQueue)45 public TvNotificationPanel(Context context, CommandQueue commandQueue) { 46 mContext = context; 47 mCommandQueue = commandQueue; 48 mNotificationHandlerPackage = mContext.getResources().getString( 49 com.android.internal.R.string.config_notificationHandlerPackage); 50 } 51 52 @Override start()53 public void start() { 54 mCommandQueue.addCallback(this); 55 } 56 57 @Override toggleNotificationsPanel()58 public void toggleNotificationsPanel() { 59 if (!mNotificationHandlerPackage.isEmpty()) { 60 startNotificationHandlerActivity( 61 new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL)); 62 } else { 63 openInternalNotificationPanel( 64 NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL); 65 } 66 } 67 68 @Override animateExpandNotificationsPanel()69 public void animateExpandNotificationsPanel() { 70 if (!mNotificationHandlerPackage.isEmpty()) { 71 startNotificationHandlerActivity( 72 new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL)); 73 } else { 74 openInternalNotificationPanel( 75 NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL); 76 } 77 } 78 79 @Override animateCollapsePanels(int flags, boolean force)80 public void animateCollapsePanels(int flags, boolean force) { 81 if (!mNotificationHandlerPackage.isEmpty() 82 && (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) { 83 Intent closeNotificationIntent = new Intent( 84 NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL); 85 closeNotificationIntent.setPackage(mNotificationHandlerPackage); 86 mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT); 87 } else { 88 openInternalNotificationPanel( 89 NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL); 90 } 91 } 92 openInternalNotificationPanel(String action)93 private void openInternalNotificationPanel(String action) { 94 Intent intent = new Intent(mContext, TvNotificationPanelActivity.class); 95 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 96 intent.setAction(action); 97 mContext.startActivityAsUser(intent, UserHandle.SYSTEM); 98 } 99 100 /** 101 * Starts the activity intent if all of the following are true 102 * <ul> 103 * <li> the notification handler package is a system component </li> 104 * <li> the provided intent is handled by the notification handler package </li> 105 * <li> the notification handler requests the 106 * {@link android.Manifest.permission#STATUS_BAR_SERVICE} permission for the given intent</li> 107 * </ul> 108 * 109 * @param intent The intent for starting the desired activity 110 */ startNotificationHandlerActivity(Intent intent)111 private void startNotificationHandlerActivity(Intent intent) { 112 intent.setPackage(mNotificationHandlerPackage); 113 PackageManager pm = mContext.getPackageManager(); 114 ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY); 115 if (ri != null && ri.activityInfo != null) { 116 if (ri.activityInfo.permission != null && ri.activityInfo.permission.equals( 117 Manifest.permission.STATUS_BAR_SERVICE)) { 118 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 119 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 120 } else { 121 Log.e(TAG, 122 "Not launching notification handler activity: Notification handler does " 123 + "not require the STATUS_BAR_SERVICE permission for intent " 124 + intent.getAction()); 125 } 126 } else { 127 Log.e(TAG, 128 "Not launching notification handler activity: Could not resolve activityInfo " 129 + "for intent " 130 + intent.getAction()); 131 } 132 } 133 } 134