3434import android .os .RemoteException ;
3535import android .os .ServiceManager ;
3636import android .provider .Settings ;
37+ import android .text .TextUtils ;
3738import android .util .Log ;
3839import android .util .Slog ;
3940import android .view .Display ;
4647import android .view .ViewGroup .LayoutParams ;
4748import android .view .WindowManager ;
4849import android .view .WindowManagerImpl ;
50+ import android .widget .ImageView ;
4951import android .widget .LinearLayout ;
5052import android .widget .RemoteViews ;
5153import android .widget .PopupMenu ;
6163import com .android .systemui .recent .RecentTasksLoader ;
6264import com .android .systemui .recent .TaskDescription ;
6365import com .android .systemui .statusbar .CommandQueue ;
66+ import com .android .systemui .statusbar .policy .NotificationRowLayout ;
6467import com .android .systemui .statusbar .tablet .StatusBarPanel ;
6568
6669import com .android .systemui .R ;
@@ -76,11 +79,24 @@ public abstract class BaseStatusBar extends SystemUI implements
7679 protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023 ;
7780 protected static final int MSG_OPEN_SEARCH_PANEL = 1024 ;
7881 protected static final int MSG_CLOSE_SEARCH_PANEL = 1025 ;
82+ protected static final int MSG_SHOW_INTRUDER = 1026 ;
83+ protected static final int MSG_HIDE_INTRUDER = 1027 ;
84+
85+ protected static final boolean ENABLE_INTRUDERS = false ;
86+
87+ public static final int EXPANDED_LEAVE_ALONE = -10000 ;
88+ public static final int EXPANDED_FULL_OPEN = -10001 ;
7989
8090 protected CommandQueue mCommandQueue ;
8191 protected IStatusBarService mBarService ;
8292 protected H mHandler = createHandler ();
8393
94+ // all notifications
95+ protected NotificationData mNotificationData = new NotificationData ();
96+ protected NotificationRowLayout mPile ;
97+
98+ protected StatusBarNotification mCurrentlyIntrudingNotification ;
99+
84100 // used to notify status bar for suppressing notification LED
85101 protected boolean mPanelSlightlyVisible ;
86102
@@ -633,4 +649,190 @@ protected void visibilityChanged(boolean visible) {
633649 }
634650 }
635651
652+ /**
653+ * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
654+ * about the failure.
655+ *
656+ * WARNING: this will call back into us. Don't hold any locks.
657+ */
658+ void handleNotificationError (IBinder key , StatusBarNotification n , String message ) {
659+ removeNotification (key );
660+ try {
661+ mBarService .onNotificationError (n .pkg , n .tag , n .id , n .uid , n .initialPid , message );
662+ } catch (RemoteException ex ) {
663+ // The end is nigh.
664+ }
665+ }
666+
667+ protected StatusBarNotification removeNotificationViews (IBinder key ) {
668+ NotificationData .Entry entry = mNotificationData .remove (key );
669+ if (entry == null ) {
670+ Slog .w (TAG , "removeNotification for unknown key: " + key );
671+ return null ;
672+ }
673+ // Remove the expanded view.
674+ ViewGroup rowParent = (ViewGroup )entry .row .getParent ();
675+ if (rowParent != null ) rowParent .removeView (entry .row );
676+ updateNotificationIcons ();
677+
678+ return entry .notification ;
679+ }
680+
681+ protected StatusBarIconView addNotificationViews (IBinder key ,
682+ StatusBarNotification notification ) {
683+ if (DEBUG ) {
684+ Slog .d (TAG , "addNotificationViews(key=" + key + ", notification=" + notification );
685+ }
686+ // Construct the icon.
687+ final StatusBarIconView iconView = new StatusBarIconView (mContext ,
688+ notification .pkg + "/0x" + Integer .toHexString (notification .id ),
689+ notification .notification );
690+ iconView .setScaleType (ImageView .ScaleType .CENTER_INSIDE );
691+
692+ final StatusBarIcon ic = new StatusBarIcon (notification .pkg ,
693+ notification .notification .icon ,
694+ notification .notification .iconLevel ,
695+ notification .notification .number ,
696+ notification .notification .tickerText );
697+ if (!iconView .set (ic )) {
698+ handleNotificationError (key , notification , "Couldn't create icon: " + ic );
699+ return null ;
700+ }
701+ // Construct the expanded view.
702+ NotificationData .Entry entry = new NotificationData .Entry (key , notification , iconView );
703+ if (!inflateViews (entry , mPile )) {
704+ handleNotificationError (key , notification , "Couldn't expand RemoteViews for: "
705+ + notification );
706+ return null ;
707+ }
708+
709+ // Add the expanded view and icon.
710+ int pos = mNotificationData .add (entry );
711+ if (DEBUG ) {
712+ Slog .d (TAG , "addNotificationViews: added at " + pos );
713+ }
714+ updateNotificationIcons ();
715+
716+ return iconView ;
717+ }
718+
719+ protected abstract void haltTicker ();
720+ protected abstract void setAreThereNotifications ();
721+ protected abstract void updateNotificationIcons ();
722+ protected abstract void tick (IBinder key , StatusBarNotification n , boolean firstTime );
723+ protected abstract void updateExpandedViewPos (int expandedPosition );
724+
725+ protected boolean isTopNotification (ViewGroup parent , NotificationData .Entry entry ) {
726+ return parent .indexOfChild (entry .row ) == 0 ;
727+ }
728+
729+ public void updateNotification (IBinder key , StatusBarNotification notification ) {
730+ if (DEBUG ) Slog .d (TAG , "updateNotification(" + key + " -> " + notification + ")" );
731+
732+ final NotificationData .Entry oldEntry = mNotificationData .findByKey (key );
733+ if (oldEntry == null ) {
734+ Slog .w (TAG , "updateNotification for unknown key: " + key );
735+ return ;
736+ }
737+
738+ final StatusBarNotification oldNotification = oldEntry .notification ;
739+
740+ // XXX: modify when we do something more intelligent with the two content views
741+ final RemoteViews oldContentView = (oldNotification .notification .bigContentView != null )
742+ ? oldNotification .notification .bigContentView
743+ : oldNotification .notification .contentView ;
744+ final RemoteViews contentView = (notification .notification .bigContentView != null )
745+ ? notification .notification .bigContentView
746+ : notification .notification .contentView ;
747+
748+ if (DEBUG ) {
749+ Slog .d (TAG , "old notification: when=" + oldNotification .notification .when
750+ + " ongoing=" + oldNotification .isOngoing ()
751+ + " expanded=" + oldEntry .expanded
752+ + " contentView=" + oldContentView
753+ + " rowParent=" + oldEntry .row .getParent ());
754+ Slog .d (TAG , "new notification: when=" + notification .notification .when
755+ + " ongoing=" + oldNotification .isOngoing ()
756+ + " contentView=" + contentView );
757+ }
758+
759+ // Can we just reapply the RemoteViews in place? If when didn't change, the order
760+ // didn't change.
761+ boolean contentsUnchanged = oldEntry .expanded != null
762+ && contentView != null && oldContentView != null
763+ && contentView .getPackage () != null
764+ && oldContentView .getPackage () != null
765+ && oldContentView .getPackage ().equals (contentView .getPackage ())
766+ && oldContentView .getLayoutId () == contentView .getLayoutId ();
767+ ViewGroup rowParent = (ViewGroup ) oldEntry .row .getParent ();
768+ boolean orderUnchanged = notification .notification .when ==oldNotification .notification .when
769+ && notification .score == oldNotification .score ;
770+ // score now encompasses/supersedes isOngoing()
771+
772+ boolean updateTicker = notification .notification .tickerText != null
773+ && !TextUtils .equals (notification .notification .tickerText ,
774+ oldEntry .notification .notification .tickerText );
775+ boolean isTopAnyway = isTopNotification (rowParent , oldEntry );
776+ if (contentsUnchanged && (orderUnchanged || isTopAnyway )) {
777+ if (DEBUG ) Slog .d (TAG , "reusing notification for key: " + key );
778+ oldEntry .notification = notification ;
779+ try {
780+ // Reapply the RemoteViews
781+ contentView .reapply (mContext , oldEntry .content );
782+ // update the contentIntent
783+ final PendingIntent contentIntent = notification .notification .contentIntent ;
784+ if (contentIntent != null ) {
785+ final View .OnClickListener listener = makeClicker (contentIntent ,
786+ notification .pkg , notification .tag , notification .id );
787+ oldEntry .content .setOnClickListener (listener );
788+ } else {
789+ oldEntry .content .setOnClickListener (null );
790+ }
791+ // Update the icon.
792+ final StatusBarIcon ic = new StatusBarIcon (notification .pkg ,
793+ notification .notification .icon , notification .notification .iconLevel ,
794+ notification .notification .number ,
795+ notification .notification .tickerText );
796+ if (!oldEntry .icon .set (ic )) {
797+ handleNotificationError (key , notification , "Couldn't update icon: " + ic );
798+ return ;
799+ }
800+ }
801+ catch (RuntimeException e ) {
802+ // It failed to add cleanly. Log, and remove the view from the panel.
803+ Slog .w (TAG , "Couldn't reapply views for package " + contentView .getPackage (), e );
804+ removeNotificationViews (key );
805+ addNotificationViews (key , notification );
806+ }
807+ } else {
808+ if (DEBUG ) Slog .d (TAG , "not reusing notification for key: " + key );
809+ removeNotificationViews (key );
810+ addNotificationViews (key , notification );
811+ }
812+
813+ // Update the veto button accordingly (and as a result, whether this row is
814+ // swipe-dismissable)
815+ updateNotificationVetoButton (oldEntry .row , notification );
816+
817+ // Restart the ticker if it's still running
818+ if (updateTicker ) {
819+ haltTicker ();
820+ tick (key , notification , false );
821+ }
822+
823+ // Recalculate the position of the sliding windows and the titles.
824+ setAreThereNotifications ();
825+ updateExpandedViewPos (EXPANDED_LEAVE_ALONE );
826+
827+ // See if we need to update the intruder.
828+ if (ENABLE_INTRUDERS && oldNotification == mCurrentlyIntrudingNotification ) {
829+ if (DEBUG ) Slog .d (TAG , "updating the current intruder:" + notification );
830+ // XXX: this is a hack for Alarms. The real implementation will need to *update*
831+ // the intruder.
832+ if (notification .notification .fullScreenIntent == null ) { // TODO(dsandler): consistent logic with add()
833+ if (DEBUG ) Slog .d (TAG , "no longer intrudes!" );
834+ mHandler .sendEmptyMessage (MSG_HIDE_INTRUDER );
835+ }
836+ }
837+ }
636838}
0 commit comments