1616
1717package com .android .server .display ;
1818
19+ import com .android .internal .R ;
1920import com .android .internal .util .DumpUtils ;
2021import com .android .internal .util .IndentingPrintWriter ;
2122
23+ import android .app .Notification ;
24+ import android .app .NotificationManager ;
25+ import android .app .PendingIntent ;
26+ import android .content .BroadcastReceiver ;
2227import android .content .Context ;
2328import android .content .Intent ;
29+ import android .content .IntentFilter ;
30+ import android .content .res .Resources ;
2431import android .hardware .display .DisplayManager ;
2532import android .hardware .display .WifiDisplay ;
2633import android .hardware .display .WifiDisplayStatus ;
2734import android .media .RemoteDisplay ;
2835import android .os .Handler ;
2936import android .os .IBinder ;
37+ import android .os .Looper ;
38+ import android .os .Message ;
39+ import android .os .UserHandle ;
40+ import android .provider .Settings ;
3041import android .util .Slog ;
3142import android .view .Surface ;
3243
@@ -52,8 +63,18 @@ final class WifiDisplayAdapter extends DisplayAdapter {
5263
5364 private static final boolean DEBUG = false ;
5465
66+ private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1 ;
67+ private static final int MSG_UPDATE_NOTIFICATION = 2 ;
68+
69+ private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT" ;
70+
71+ private final WifiDisplayHandler mHandler ;
5572 private final PersistentDataStore mPersistentDataStore ;
5673 private final boolean mSupportsProtectedBuffers ;
74+ private final NotificationManager mNotificationManager ;
75+
76+ private final PendingIntent mSettingsPendingIntent ;
77+ private final PendingIntent mDisconnectPendingIntent ;
5778
5879 private WifiDisplayController mDisplayController ;
5980 private WifiDisplayDevice mDisplayDevice ;
@@ -67,14 +88,32 @@ final class WifiDisplayAdapter extends DisplayAdapter {
6788 private WifiDisplay [] mRememberedDisplays = WifiDisplay .EMPTY_ARRAY ;
6889
6990 private boolean mPendingStatusChangeBroadcast ;
91+ private boolean mPendingNotificationUpdate ;
7092
7193 public WifiDisplayAdapter (DisplayManagerService .SyncRoot syncRoot ,
7294 Context context , Handler handler , Listener listener ,
7395 PersistentDataStore persistentDataStore ) {
7496 super (syncRoot , context , handler , listener , TAG );
97+ mHandler = new WifiDisplayHandler (handler .getLooper ());
7598 mPersistentDataStore = persistentDataStore ;
7699 mSupportsProtectedBuffers = context .getResources ().getBoolean (
77100 com .android .internal .R .bool .config_wifiDisplaySupportsProtectedBuffers );
101+ mNotificationManager = (NotificationManager )context .getSystemService (
102+ Context .NOTIFICATION_SERVICE );
103+
104+ Intent settingsIntent = new Intent (Settings .ACTION_WIFI_DISPLAY_SETTINGS );
105+ settingsIntent .setFlags (Intent .FLAG_ACTIVITY_NEW_TASK
106+ | Intent .FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
107+ | Intent .FLAG_ACTIVITY_CLEAR_TOP );
108+ mSettingsPendingIntent = PendingIntent .getActivityAsUser (
109+ context , 0 , settingsIntent , 0 , null , UserHandle .CURRENT );
110+
111+ Intent disconnectIntent = new Intent (ACTION_DISCONNECT );
112+ mDisconnectPendingIntent = PendingIntent .getBroadcastAsUser (
113+ context , 0 , disconnectIntent , 0 , UserHandle .CURRENT );
114+
115+ context .registerReceiverAsUser (mBroadcastReceiver , UserHandle .ALL ,
116+ new IntentFilter (ACTION_DISCONNECT ), null , mHandler );
78117 }
79118
80119 @ Override
@@ -89,6 +128,7 @@ public void dumpLocked(PrintWriter pw) {
89128 pw .println ("mAvailableDisplays=" + Arrays .toString (mAvailableDisplays ));
90129 pw .println ("mRememberedDisplays=" + Arrays .toString (mRememberedDisplays ));
91130 pw .println ("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast );
131+ pw .println ("mPendingNotificationUpdate=" + mPendingNotificationUpdate );
92132 pw .println ("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers );
93133
94134 // Try to dump the controller state.
@@ -266,42 +306,99 @@ private void handleConnectLocked(WifiDisplay display,
266306 mDisplayDevice = new WifiDisplayDevice (displayToken , name , width , height ,
267307 refreshRate , deviceFlags , surface );
268308 sendDisplayDeviceEventLocked (mDisplayDevice , DISPLAY_DEVICE_EVENT_ADDED );
309+
310+ scheduleUpdateNotificationLocked ();
269311 }
270312
271313 private void handleDisconnectLocked () {
272314 if (mDisplayDevice != null ) {
273315 mDisplayDevice .clearSurfaceLocked ();
274316 sendDisplayDeviceEventLocked (mDisplayDevice , DISPLAY_DEVICE_EVENT_REMOVED );
275317 mDisplayDevice = null ;
318+
319+ scheduleUpdateNotificationLocked ();
276320 }
277321 }
278322
279323 private void scheduleStatusChangedBroadcastLocked () {
280324 mCurrentStatus = null ;
281325 if (!mPendingStatusChangeBroadcast ) {
282326 mPendingStatusChangeBroadcast = true ;
283- getHandler (). post ( mStatusChangeBroadcast );
327+ mHandler . sendEmptyMessage ( MSG_SEND_STATUS_CHANGE_BROADCAST );
284328 }
285329 }
286330
287- private final Runnable mStatusChangeBroadcast = new Runnable () {
288- @ Override
289- public void run () {
290- final Intent intent ;
291- synchronized (getSyncRoot ()) {
292- if (!mPendingStatusChangeBroadcast ) {
293- return ;
294- }
331+ private void scheduleUpdateNotificationLocked () {
332+ if (!mPendingNotificationUpdate ) {
333+ mPendingNotificationUpdate = true ;
334+ mHandler .sendEmptyMessage (MSG_UPDATE_NOTIFICATION );
335+ }
336+ }
337+
338+ // Runs on the handler.
339+ private void handleSendStatusChangeBroadcast () {
340+ final Intent intent ;
341+ synchronized (getSyncRoot ()) {
342+ if (!mPendingStatusChangeBroadcast ) {
343+ return ;
344+ }
345+
346+ mPendingStatusChangeBroadcast = false ;
347+ intent = new Intent (DisplayManager .ACTION_WIFI_DISPLAY_STATUS_CHANGED );
348+ intent .addFlags (Intent .FLAG_RECEIVER_REGISTERED_ONLY );
349+ intent .putExtra (DisplayManager .EXTRA_WIFI_DISPLAY_STATUS ,
350+ getWifiDisplayStatusLocked ());
351+ }
295352
296- mPendingStatusChangeBroadcast = false ;
297- intent = new Intent (DisplayManager .ACTION_WIFI_DISPLAY_STATUS_CHANGED );
298- intent .addFlags (Intent .FLAG_RECEIVER_REGISTERED_ONLY );
299- intent .putExtra (DisplayManager .EXTRA_WIFI_DISPLAY_STATUS ,
300- getWifiDisplayStatusLocked ());
353+ // Send protected broadcast about wifi display status to registered receivers.
354+ getContext ().sendBroadcastAsUser (intent , UserHandle .ALL );
355+ }
356+
357+ // Runs on the handler.
358+ private void handleUpdateNotification () {
359+ final boolean isConnected ;
360+ synchronized (getSyncRoot ()) {
361+ if (!mPendingNotificationUpdate ) {
362+ return ;
301363 }
302364
303- // Send protected broadcast about wifi display status to registered receivers.
304- getContext ().sendBroadcast (intent );
365+ mPendingNotificationUpdate = false ;
366+ isConnected = (mDisplayDevice != null );
367+ }
368+
369+ mNotificationManager .cancelAsUser (null ,
370+ R .string .wifi_display_notification_title , UserHandle .ALL );
371+
372+ if (isConnected ) {
373+ Context context = getContext ();
374+
375+ Resources r = context .getResources ();
376+ Notification notification = new Notification .Builder (context )
377+ .setContentTitle (r .getString (
378+ R .string .wifi_display_notification_title ))
379+ .setContentText (r .getString (
380+ R .string .wifi_display_notification_message ))
381+ .setContentIntent (mSettingsPendingIntent )
382+ .setSmallIcon (R .drawable .ic_notify_wifidisplay )
383+ .setOngoing (true )
384+ .addAction (android .R .drawable .ic_menu_close_clear_cancel ,
385+ r .getString (R .string .wifi_display_notification_disconnect ),
386+ mDisconnectPendingIntent )
387+ .build ();
388+ mNotificationManager .notifyAsUser (null ,
389+ R .string .wifi_display_notification_title ,
390+ notification , UserHandle .ALL );
391+ }
392+ }
393+
394+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver () {
395+ @ Override
396+ public void onReceive (Context context , Intent intent ) {
397+ if (intent .getAction ().equals (ACTION_DISCONNECT )) {
398+ synchronized (getSyncRoot ()) {
399+ requestDisconnectLocked ();
400+ }
401+ }
305402 }
306403 };
307404
@@ -454,4 +551,23 @@ public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
454551 return mInfo ;
455552 }
456553 }
554+
555+ private final class WifiDisplayHandler extends Handler {
556+ public WifiDisplayHandler (Looper looper ) {
557+ super (looper , null , true /*async*/ );
558+ }
559+
560+ @ Override
561+ public void handleMessage (Message msg ) {
562+ switch (msg .what ) {
563+ case MSG_SEND_STATUS_CHANGE_BROADCAST :
564+ handleSendStatusChangeBroadcast ();
565+ break ;
566+
567+ case MSG_UPDATE_NOTIFICATION :
568+ handleUpdateNotification ();
569+ break ;
570+ }
571+ }
572+ }
457573}
0 commit comments