Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 005847b0 authored by Joe Onorato's avatar Joe Onorato
Browse files

Handle errors inflating notifications (and their icons).

On an inflation error, the StatusBarService cleans up, removes / doesn't add
the views, and calls into the StatusBarManagerService, which tells the
NotificationManagerService to remove the notification.

That then calls all the way back into the StatusBarService, but I think being
extra careful is okay.  Throughout the status bar, it's all keyed off of the
IBinder key, so if the app comes in with a good notification while we're
cleaning up, we won't lose the new notification or anything like that.

Change-Id: Iea78a637495a8b67810c214b951d5ddb93becacb
parent d956ae8b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -36,5 +36,6 @@ interface IStatusBarService
            out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications);
    void visibilityChanged(boolean visible);
    void onNotificationClick(String pkg, String tag, int id);
    void onNotificationError(String pkg, String tag, int id, String message);
    void onClearAllNotifications();
}
+38 −8
Original line number Diff line number Diff line
@@ -373,6 +373,14 @@ public class PhoneStatusBarService extends StatusBarService {
                    oldEntry.content.setOnClickListener(new Launcher(contentIntent,
                                notification.pkg, notification.tag, notification.id));
                }
                // Update the icon.
                final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
                        notification.notification.icon, notification.notification.iconLevel,
                        notification.notification.number);
                if (!oldEntry.icon.set(ic)) {
                    handleNotificationError(key, notification, "Couldn't update icon: " + ic);
                    return;
                }
            }
            catch (RuntimeException e) {
                // It failed to add cleanly.  Log, and remove the view from the panel.
@@ -380,9 +388,6 @@ public class PhoneStatusBarService extends StatusBarService {
                removeNotificationViews(key);
                addNotificationViews(key, notification);
            }
            // Update the icon.
            oldEntry.icon.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
                    notification.notification.iconLevel, notification.notification.number));
        } else {
            Slog.d(TAG, "not reusing notification");
            removeNotificationViews(key);
@@ -451,8 +456,9 @@ public class PhoneStatusBarService extends StatusBarService {
            exception = e;
        }
        if (expanded == null) {
            Slog.e(TAG, "couldn't inflate view for package " + notification.pkg, exception);
            row.setVisibility(View.GONE);
            String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
            Slog.e(TAG, "couldn't inflate view for notification " + ident);
            return null;
        } else {
            content.addView(expanded);
            row.setDrawingCacheEnabled(true);
@@ -474,14 +480,23 @@ public class PhoneStatusBarService extends StatusBarService {
        }
        // Construct the expanded view.
        final View[] views = makeNotificationView(notification, parent);
        if (views == null) {
            handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
                    + notification);
            return;
        }
        final View row = views[0];
        final View content = views[1];
        final View expanded = views[2];
        // Construct the icon.
        StatusBarIconView iconView = new StatusBarIconView(this,
        final StatusBarIconView iconView = new StatusBarIconView(this,
                notification.pkg + "/0x" + Integer.toHexString(notification.id));
        iconView.set(new StatusBarIcon(notification.pkg, notification.notification.icon,
                    notification.notification.iconLevel, notification.notification.number));
        final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
                    notification.notification.iconLevel, notification.notification.number);
        if (!iconView.set(ic)) {
            handleNotificationError(key, notification, "Coulding create icon: " + ic);
            return;
        }
        // Add the expanded view.
        final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
        parent.addView(row, viewIndex);
@@ -967,6 +982,21 @@ public class PhoneStatusBarService extends StatusBarService {
        }
    }

    /**
     * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
     * about the failure.
     *
     * WARNING: this will call back into us.  Don't hold any locks.
     */
    void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
        removeNotification(key);
        try {
            mBarService.onNotificationError(n.pkg, n.tag, n.id, message);
        } catch (RemoteException ex) {
            // The end is nigh.
        }
    }

    private class MyTicker extends Ticker {
        MyTicker(Context context, StatusBarView sb) {
            super(context, sb);
+25 −32
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ public class StatusBarIconView extends AnimatedImageView {

    private StatusBarIcon mIcon;
    @ViewDebug.ExportedProperty private String mSlot;
    @ViewDebug.ExportedProperty private boolean mError;

    public StatusBarIconView(Context context, String slot) {
        super(context);
@@ -52,25 +51,22 @@ public class StatusBarIconView extends AnimatedImageView {
        return a.equals(b);
    }

    public void set(StatusBarIcon icon) {
        error: {
            final boolean iconEquals = !mError
                    && mIcon != null
    /**
     * Returns whether the set succeeded.
     */
    public boolean set(StatusBarIcon icon) {
        final boolean iconEquals = mIcon != null
                && streq(mIcon.iconPackage, icon.iconPackage)
                && mIcon.iconId == icon.iconId;
            final boolean levelEquals = !mError
                    && iconEquals
        final boolean levelEquals = iconEquals
                && mIcon.iconLevel == icon.iconLevel;
            final boolean visibilityEquals = !mError
                    && mIcon != null
        final boolean visibilityEquals = mIcon != null
                && mIcon.visible == icon.visible;
            mError = false;
        if (!iconEquals) {
            Drawable drawable = getIcon(icon);
            if (drawable == null) {
                    mError = true;
                    Slog.w(PhoneStatusBarService.TAG, "No icon ID for slot " + mSlot);
                    break error;
                Slog.w(PhoneStatusBarService.TAG, "No icon for slot " + mSlot);
                return false;
            }
            setImageDrawable(drawable);
        }
@@ -81,10 +77,7 @@ public class StatusBarIconView extends AnimatedImageView {
            setVisibility(icon.visible ? VISIBLE : GONE);
        }
        mIcon = icon.clone();
        }
        if (mError) {
            setVisibility(GONE);
        }
        return true;
    }

    private Drawable getIcon(StatusBarIcon icon) {
@@ -106,7 +99,7 @@ public class StatusBarIconView extends AnimatedImageView {
            try {
                r = context.getPackageManager().getResourcesForApplication(icon.iconPackage);
            } catch (PackageManager.NameNotFoundException ex) {
                Slog.e(PhoneStatusBarService.TAG, "Icon package not found: "+icon.iconPackage, ex);
                Slog.e(PhoneStatusBarService.TAG, "Icon package not found: " + icon.iconPackage);
                return null;
            }
        } else {
+6 −0
Original line number Diff line number Diff line
@@ -303,6 +303,12 @@ class NotificationManagerService extends INotificationManager.Stub
                updateLightsLocked();
            }
        }

        public void onNotificationError(String pkg, String tag, int id, String message) {
            Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id);
            cancelNotification(pkg, tag, id, 0, 0);
            // TODO: Tell the activity manager.
        }
    };

    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+7 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
        void onClearAll();
        void onNotificationClick(String pkg, String tag, int id);
        void onPanelRevealed();
        void onNotificationError(String pkg, String tag, int id, String message);
    }

    /**
@@ -279,6 +280,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub
        mNotificationCallbacks.onNotificationClick(pkg, tag, id);
    }

    public void onNotificationError(String pkg, String tag, int id, String message) {
        Slog.d(TAG, "onNotificationError message=" + message);
        // WARNING: this will call back into us to do the remove.  Don't hold any locks.
        mNotificationCallbacks.onNotificationError(pkg, tag, id, message);
    }

    public void onClearAllNotifications() {
        mNotificationCallbacks.onClearAll();
    }
Loading