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