FileDocCategorySizeDatePackage
BaseStatusBar.javaAPI DocAndroid 5.1 API92227Thu Mar 12 22:22:42 GMT 2015com.android.systemui.statusbar

BaseStatusBar

public abstract class BaseStatusBar extends com.android.systemui.SystemUI implements CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener, RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment

Fields Summary
public static final String
TAG
public static final boolean
DEBUG
public static final boolean
MULTIUSER_DEBUG
private static final boolean
NOTIFICATION_CLICK_DEBUG
protected static final int
MSG_SHOW_RECENT_APPS
protected static final int
MSG_HIDE_RECENT_APPS
protected static final int
MSG_TOGGLE_RECENTS_APPS
protected static final int
MSG_PRELOAD_RECENT_APPS
protected static final int
MSG_CANCEL_PRELOAD_RECENT_APPS
protected static final int
MSG_SHOW_NEXT_AFFILIATED_TASK
protected static final int
MSG_SHOW_PREV_AFFILIATED_TASK
protected static final int
MSG_CLOSE_SEARCH_PANEL
protected static final int
MSG_SHOW_HEADS_UP
protected static final int
MSG_HIDE_HEADS_UP
protected static final int
MSG_ESCALATE_HEADS_UP
protected static final int
MSG_DECAY_HEADS_UP
protected static final boolean
ENABLE_HEADS_UP
protected static final int
INTERRUPTION_THRESHOLD
protected static final String
SETTING_HEADS_UP_TICKER
public static final String
SYSTEM_DIALOG_REASON_RECENT_APPS
public static final int
EXPANDED_LEAVE_ALONE
public static final int
EXPANDED_FULL_OPEN
private static final int
HIDDEN_NOTIFICATION_ID
private static final String
BANNER_ACTION_CANCEL
private static final String
BANNER_ACTION_SETUP
protected CommandQueue
mCommandQueue
protected com.android.internal.statusbar.IStatusBarService
mBarService
protected H
mHandler
protected NotificationData
mNotificationData
protected com.android.systemui.statusbar.stack.NotificationStackScrollLayout
mStackScroller
protected com.android.systemui.statusbar.policy.HeadsUpNotificationView
mHeadsUpNotificationView
protected int
mHeadsUpNotificationDecay
protected com.android.systemui.SearchPanelView
mSearchPanelView
protected int
mCurrentUserId
protected final android.util.SparseArray
mCurrentProfiles
protected int
mLayoutDirection
protected android.view.accessibility.AccessibilityManager
mAccessibilityManager
protected com.android.systemui.statusbar.phone.NavigationBarView
mNavigationBarView
protected Boolean
mScreenOn
protected boolean
mScreenOnFromKeyguard
protected boolean
mVisible
private boolean
mVisibleToUser
private Locale
mLocale
private float
mFontScale
protected boolean
mUseHeadsUp
protected boolean
mHeadsUpTicker
protected boolean
mDisableNotificationAlerts
protected android.app.admin.DevicePolicyManager
mDevicePolicyManager
protected android.service.dreams.IDreamManager
mDreamManager
android.os.PowerManager
mPowerManager
protected com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
mStatusBarKeyguardViewManager
protected int
mRowMinHeight
protected int
mRowMaxHeight
private boolean
mLockscreenPublicMode
private final android.util.SparseBooleanArray
mUsersAllowingPrivateNotifications
private com.android.internal.util.NotificationColorUtil
mNotificationColorUtil
private android.os.UserManager
mUserManager
protected android.view.WindowManager
mWindowManager
protected android.view.IWindowManager
mWindowManagerService
protected android.view.Display
mDisplay
private boolean
mDeviceProvisioned
private com.android.systemui.RecentsComponent
mRecents
protected int
mZenMode
private NotificationGuts
mNotificationGutsExposed
private android.animation.TimeInterpolator
mLinearOutSlowIn
private android.animation.TimeInterpolator
mFastOutLinearIn
protected int
mState
The {@link StatusBarState} of the status bar.
protected boolean
mBouncerShowing
protected boolean
mShowLockscreenNotifications
protected NotificationOverflowContainer
mKeyguardIconOverflowContainer
protected DismissView
mDismissView
protected EmptyShadeView
mEmptyShadeView
protected final android.database.ContentObserver
mSettingsObserver
private final android.database.ContentObserver
mLockscreenSettingsObserver
private RemoteViews.OnClickHandler
mOnClickHandler
private final android.content.BroadcastReceiver
mBroadcastReceiver
private final android.service.notification.NotificationListenerService
mNotificationListener
protected View.OnTouchListener
mRecentsPreloadOnTouchListener
Constructors Summary
Methods Summary
public abstract voidaddNotification(android.service.notification.StatusBarNotification notification, android.service.notification.NotificationListenerService.RankingMap ranking)

protected voidaddNotificationViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.service.notification.NotificationListenerService.RankingMap ranking)

        if (entry == null) {
            return;
        }
        // Add the expanded view and icon.
        mNotificationData.add(entry, ranking);
        updateNotifications();
    
private booleanalertAgain(com.android.systemui.statusbar.NotificationData.Entry oldEntry, android.app.Notification newNotification)

        return oldEntry == null || !oldEntry.hasInterrupted()
                || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
    
public voidanimateCollapsePanels(int flags, boolean force)

    
protected voidapplyColorsAndBackgrounds(android.service.notification.StatusBarNotification sbn, com.android.systemui.statusbar.NotificationData.Entry entry)


        if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
            // Using custom RemoteViews
            if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
                    && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) {
                entry.row.setShowingLegacyBackground(true);
                entry.legacy = true;
            }
        } else {
            // Using platform templates
            final int color = sbn.getNotification().color;
            if (isMediaNotification(entry)) {
                entry.row.setTintColor(color == Notification.COLOR_DEFAULT
                        ? mContext.getResources().getColor(
                                R.color.notification_material_background_media_default_color)
                        : color);
            }
        }

        if (entry.icon != null) {
            if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP) {
                entry.icon.setColorFilter(mContext.getResources().getColor(android.R.color.white));
            } else {
                entry.icon.setColorFilter(null);
            }
        }
    
public voidcancelPreloadRecentApps()

        int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
protected voidcancelPreloadingRecents()

        if (mRecents != null) {
            mRecents.cancelPreloadingRecents();
        }
    
protected abstract voidcreateAndAddWindows()
Create all windows necessary for the status bar (including navigation, overlay panels, etc) and add them to the window manager.

protected com.android.systemui.statusbar.BaseStatusBar$HcreateHandler()

         return new H();
    
protected com.android.systemui.statusbar.NotificationData.EntrycreateNotificationViews(android.service.notification.StatusBarNotification sbn)

        if (DEBUG) {
            Log.d(TAG, "createNotificationViews(notification=" + sbn);
        }
        // Construct the icon.
        Notification n = sbn.getNotification();
        final StatusBarIconView iconView = new StatusBarIconView(mContext,
                sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
        iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

        final StatusBarIcon ic = new StatusBarIcon(sbn.getPackageName(),
                sbn.getUser(),
                    n.icon,
                    n.iconLevel,
                    n.number,
                    n.tickerText);
        if (!iconView.set(ic)) {
            handleNotificationError(sbn, "Couldn't create icon: " + ic);
            return null;
        }
        // Construct the expanded view.
        NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
        if (!inflateViews(entry, mStackScroller)) {
            handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
            return null;
        }
        return entry;
    
public voiddestroy()

        if (mSearchPanelView != null) {
            mWindowManager.removeViewImmediate(mSearchPanelView);
        }
        mContext.unregisterReceiver(mBroadcastReceiver);
        try {
            mNotificationListener.unregisterAsSystemService();
        } catch (RemoteException e) {
            // Ignore.
        }
    
protected voiddismissKeyguardThenExecute(com.android.keyguard.KeyguardHostView.OnDismissAction action, boolean afterKeyguardGone)
Takes the necessary steps to prepare the status bar for starting an activity, then starts it.

param
action A dismiss action that is called if it's safe to start the activity.
param
afterKeyguardGone Whether the action should be executed after the Keyguard is gone.

        action.onDismiss();
    
public voiddismissPopups()

        if (mNotificationGutsExposed != null) {
            final NotificationGuts v = mNotificationGutsExposed;
            mNotificationGutsExposed = null;

            if (v.getWindowToken() == null) return;

            final int x = (v.getLeft() + v.getRight()) / 2;
            final int y = (v.getTop() + v.getActualHeight() / 2);
            final Animator a = ViewAnimationUtils.createCircularReveal(v,
                    x, y, x, 0);
            a.setDuration(200);
            a.setInterpolator(mFastOutLinearIn);
            a.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    v.setVisibility(View.GONE);
                }
            });
            a.start();
        }
    
public java.lang.StringgetCurrentMediaNotificationKey()

        return null;
    
protected abstract intgetMaxKeyguardNotifications()

return
The number of notifications we show on Keyguard.

protected SwipeHelper.LongPressListenergetNotificationLongClicker()

        return new SwipeHelper.LongPressListener() {
            @Override
            public boolean onLongPress(View v, int x, int y) {
                dismissPopups();

                if (!(v instanceof ExpandableNotificationRow)) {
                    return false;
                }
                if (v.getWindowToken() == null) {
                    Log.e(TAG, "Trying to show notification guts, but not attached to window");
                    return false;
                }

                inflateGuts((ExpandableNotificationRow) v);

                // Assume we are a status_bar_notification_row
                final NotificationGuts guts = (NotificationGuts) v.findViewById(
                        R.id.notification_guts);
                if (guts == null) {
                    // This view has no guts. Examples are the more card or the dismiss all view
                    return false;
                }

                // Already showing?
                if (guts.getVisibility() == View.VISIBLE) {
                    Log.e(TAG, "Trying to show notification guts, but already visible");
                    return false;
                }

                guts.setVisibility(View.VISIBLE);
                final double horz = Math.max(guts.getWidth() - x, x);
                final double vert = Math.max(guts.getActualHeight() - y, y);
                final float r = (float) Math.hypot(horz, vert);
                final Animator a
                        = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
                a.setDuration(400);
                a.setInterpolator(mLinearOutSlowIn);
                a.start();

                mNotificationGutsExposed = guts;

                return true;
            }
        };
    
protected android.content.pm.PackageManagergetPackageManagerForUser(int userId)

return
a PackageManger for userId or if userId is < 0 (USER_ALL etc) then return PackageManager for mContext

        Context contextForUser = mContext;
        // UserHandle defines special userId as negative values, e.g. USER_ALL
        if (userId >= 0) {
            try {
                // Create a context for the correct user so if a package isn't installed
                // for user 0 we can still load information about the package.
                contextForUser =
                        mContext.createPackageContextAsUser(mContext.getPackageName(),
                        Context.CONTEXT_RESTRICTED,
                        new UserHandle(userId));
            } catch (NameNotFoundException e) {
                // Shouldn't fail to find the package name for system ui.
            }
        }
        return contextForUser.getPackageManager();
    
protected abstract WindowManager.LayoutParamsgetSearchLayoutParams(android.view.ViewGroup.LayoutParams layoutParams)

protected abstract android.view.ViewgetStatusBarView()

protected abstract voidhaltTicker()

voidhandleNotificationError(android.service.notification.StatusBarNotification n, java.lang.String message)
Cancel this notification and tell the StatusBarManagerService / NotificationManagerService about the failure. WARNING: this will call back into us. Don't hold any locks.

        removeNotification(n.getKey(), null);
        try {
            mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
                    n.getInitialPid(), message, n.getUserId());
        } catch (RemoteException ex) {
            // The end is nigh.
        }
    
protected voidhandleVisibleToUserChanged(boolean visibleToUser)
The LEDs are turned off when the notification panel is shown, even just a little bit. This was added last-minute and is inconsistent with the way the rest of the notifications are handled, because the notification isn't really cancelled. The lights are just turned off. If any other notifications happen, the lights will turn back on. Steve says this is what he wants. (see bug 1131461)

        try {
            if (visibleToUser) {
                // Only stop blinking, vibrating, ringing when the user went into the shade
                // manually (SHADE or SHADE_LOCKED).
                boolean clearNotificationEffects =
                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
                mBarService.onPanelRevealed(clearNotificationEffects);
            } else {
                mBarService.onPanelHidden();
            }
        } catch (RemoteException ex) {
            // Won't fail unless the world has ended.
        }
    
public voidhideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)

        int msg = MSG_HIDE_RECENT_APPS;
        mHandler.removeMessages(msg);
        mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0,
                triggeredFromHomeKey ? 1 : 0).sendToTarget();
    
protected voidhideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)

        if (mRecents != null) {
            mRecents.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
        }
    
public voidhideSearchPanel()

        int msg = MSG_CLOSE_SEARCH_PANEL;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
private voidinflateGuts(ExpandableNotificationRow row)

        ViewStub stub = (ViewStub) row.findViewById(R.id.notification_guts_stub);
        if (stub != null) {
            stub.inflate();
        }
        final StatusBarNotification sbn = row.getStatusBarNotification();
        PackageManager pmUser = getPackageManagerForUser(
                sbn.getUser().getIdentifier());
        row.setTag(sbn.getPackageName());
        final View guts = row.findViewById(R.id.notification_guts);
        final String pkg = sbn.getPackageName();
        String appname = pkg;
        Drawable pkgicon = null;
        int appUid = -1;
        try {
            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
                    PackageManager.GET_UNINSTALLED_PACKAGES
                            | PackageManager.GET_DISABLED_COMPONENTS);
            if (info != null) {
                appname = String.valueOf(pmUser.getApplicationLabel(info));
                pkgicon = pmUser.getApplicationIcon(info);
                appUid = info.uid;
            }
        } catch (NameNotFoundException e) {
            // app is gone, just show package name and generic icon
            pkgicon = pmUser.getDefaultActivityIcon();
        }
        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
        ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
        ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
        final View appSettingsButton
                = guts.findViewById(R.id.notification_inspect_app_provided_settings);
        if (appUid >= 0) {
            final int appUidF = appUid;
            settingsButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    startAppNotificationSettingsActivity(pkg, appUidF);
                }
            });

            final Intent appSettingsQueryIntent
                    = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
                    .setPackage(pkg);
            List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
            if (infos.size() > 0) {
                appSettingsButton.setVisibility(View.VISIBLE);
                appSettingsButton.setContentDescription(
                        mContext.getResources().getString(
                                R.string.status_bar_notification_app_settings_title,
                                appname
                        ));
                final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
                        .setClassName(pkg, infos.get(0).activityInfo.name);
                appSettingsButton.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
                                sbn.getId(),
                                sbn.getTag(),
                                appUidF);
                    }
                });
            } else {
                appSettingsButton.setVisibility(View.GONE);
            }
        } else {
            settingsButton.setVisibility(View.GONE);
            appSettingsButton.setVisibility(View.GONE);
        }

    
private booleaninflateViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.view.ViewGroup parent)

            return inflateViews(entry, parent, false);
    
private booleaninflateViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.view.ViewGroup parent, boolean isHeadsUp)

        PackageManager pmUser = getPackageManagerForUser(
                entry.notification.getUser().getIdentifier());

        int maxHeight = mRowMaxHeight;
        final StatusBarNotification sbn = entry.notification;
        RemoteViews contentView = sbn.getNotification().contentView;
        RemoteViews bigContentView = sbn.getNotification().bigContentView;

        if (isHeadsUp) {
            maxHeight =
                    mContext.getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
            bigContentView = sbn.getNotification().headsUpContentView;
        }

        if (contentView == null) {
            return false;
        }

        if (DEBUG) {
            Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
        }

        Notification publicNotification = sbn.getNotification().publicVersion;

        ExpandableNotificationRow row;

        // Stash away previous user expansion state so we can restore it at
        // the end.
        boolean hasUserChangedExpansion = false;
        boolean userExpanded = false;
        boolean userLocked = false;

        if (entry.row != null) {
            row = entry.row;
            hasUserChangedExpansion = row.hasUserChangedExpansion();
            userExpanded = row.isUserExpanded();
            userLocked = row.isUserLocked();
            entry.reset();
            if (hasUserChangedExpansion) {
                row.setUserExpanded(userExpanded);
            }
        } else {
            // create the row view
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
                    parent, false);
            row.setExpansionLogger(this, entry.notification.getKey());
        }

        workAroundBadLayerDrawableOpacity(row);
        View vetoButton = updateNotificationVetoButton(row, sbn);
        vetoButton.setContentDescription(mContext.getString(
                R.string.accessibility_remove_notification));

        // NB: the large icon is now handled entirely by the template

        // bind the click event to the content area
        NotificationContentView expanded =
                (NotificationContentView) row.findViewById(R.id.expanded);
        NotificationContentView expandedPublic =
                (NotificationContentView) row.findViewById(R.id.expandedPublic);

        row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

        PendingIntent contentIntent = sbn.getNotification().contentIntent;
        if (contentIntent != null) {
            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
                    isHeadsUp);
            row.setOnClickListener(listener);
        } else {
            row.setOnClickListener(null);
        }

        // set up the adaptive layout
        View contentViewLocal = null;
        View bigContentViewLocal = null;
        try {
            contentViewLocal = contentView.apply(mContext, expanded,
                    mOnClickHandler);
            if (bigContentView != null) {
                bigContentViewLocal = bigContentView.apply(mContext, expanded,
                        mOnClickHandler);
            }
        }
        catch (RuntimeException e) {
            final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
            Log.e(TAG, "couldn't inflate view for notification " + ident, e);
            return false;
        }

        if (contentViewLocal != null) {
            contentViewLocal.setIsRootNamespace(true);
            expanded.setContractedChild(contentViewLocal);
        }
        if (bigContentViewLocal != null) {
            bigContentViewLocal.setIsRootNamespace(true);
            expanded.setExpandedChild(bigContentViewLocal);
        }

        // now the public version
        View publicViewLocal = null;
        if (publicNotification != null) {
            try {
                publicViewLocal = publicNotification.contentView.apply(mContext, expandedPublic,
                        mOnClickHandler);

                if (publicViewLocal != null) {
                    publicViewLocal.setIsRootNamespace(true);
                    expandedPublic.setContractedChild(publicViewLocal);
                }
            }
            catch (RuntimeException e) {
                final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
                Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
                publicViewLocal = null;
            }
        }

        // Extract target SDK version.
        try {
            ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
            entry.targetSdk = info.targetSdkVersion;
        } catch (NameNotFoundException ex) {
            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
        }

        if (publicViewLocal == null) {
            // Add a basic notification template
            publicViewLocal = LayoutInflater.from(mContext).inflate(
                    R.layout.notification_public_default,
                    expandedPublic, false);
            publicViewLocal.setIsRootNamespace(true);
            expandedPublic.setContractedChild(publicViewLocal);

            final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
            try {
                title.setText(pmUser.getApplicationLabel(
                        pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
            } catch (NameNotFoundException e) {
                title.setText(entry.notification.getPackageName());
            }

            final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
            final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
                    R.id.profile_badge_line3);

            final StatusBarIcon ic = new StatusBarIcon(entry.notification.getPackageName(),
                    entry.notification.getUser(),
                    entry.notification.getNotification().icon,
                    entry.notification.getNotification().iconLevel,
                    entry.notification.getNotification().number,
                    entry.notification.getNotification().tickerText);

            Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
            icon.setImageDrawable(iconDrawable);
            if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP
                    || mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) {
                icon.setBackgroundResource(
                        com.android.internal.R.drawable.notification_icon_legacy_bg);
                int padding = mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.notification_large_icon_circle_padding);
                icon.setPadding(padding, padding, padding, padding);
                if (sbn.getNotification().color != Notification.COLOR_DEFAULT) {
                    icon.getBackground().setColorFilter(
                            sbn.getNotification().color, PorterDuff.Mode.SRC_ATOP);
                }
            }

            if (profileBadge != null) {
                Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity(
                        entry.notification.getUser(), 0);
                if (profileDrawable != null) {
                    profileBadge.setImageDrawable(profileDrawable);
                    profileBadge.setVisibility(View.VISIBLE);
                } else {
                    profileBadge.setVisibility(View.GONE);
                }
            }

            final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
            final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
            if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
                time.setVisibility(View.VISIBLE);
                time.setTime(entry.notification.getNotification().when);
            }

            final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
            if (text != null) {
                text.setText(R.string.notification_hidden_text);
                text.setTextAppearance(mContext,
                        R.style.TextAppearance_Material_Notification_Parenthetical);
            }

            int topPadding = Notification.Builder.calculateTopPadding(mContext,
                    false /* hasThreeLines */,
                    mContext.getResources().getConfiguration().fontScale);
            title.setPadding(0, topPadding, 0, 0);

            entry.autoRedacted = true;
        }

        if (MULTIUSER_DEBUG) {
            TextView debug = (TextView) row.findViewById(R.id.debug_info);
            if (debug != null) {
                debug.setVisibility(View.VISIBLE);
                debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId());
            }
        }
        entry.row = row;
        entry.row.setHeightRange(mRowMinHeight, maxHeight);
        entry.row.setOnActivatedListener(this);
        entry.expanded = contentViewLocal;
        entry.expandedPublic = publicViewLocal;
        entry.setBigContentView(bigContentViewLocal);

        applyColorsAndBackgrounds(sbn, entry);

        // Restore previous flags.
        if (hasUserChangedExpansion) {
            // Note: setUserExpanded() conveniently ignores calls with
            //       userExpanded=true if !isExpandable().
            row.setUserExpanded(userExpanded);
        }
        row.setUserLocked(userLocked);
        row.setStatusBarNotification(entry.notification);
        return true;
    
protected booleaninflateViewsForHeadsUp(com.android.systemui.statusbar.NotificationData.Entry entry, android.view.ViewGroup parent)

            return inflateViews(entry, parent, true);
    
public booleanisBouncerShowing()

return
Whether the security bouncer from Keyguard is showing.

        return mBouncerShowing;
    
protected booleanisCurrentProfile(int userId)

        synchronized (mCurrentProfiles) {
            return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
        }
    
public booleanisDeviceProvisioned()


      // NotificationData.Environment
       
        return mDeviceProvisioned;
    
public booleanisHeadsUp(java.lang.String key)

      return mHeadsUpNotificationView != null && mHeadsUpNotificationView.isShowing(key);
    
public booleanisKeyguardSecure()

        return mStatusBarKeyguardViewManager.isSecure();
    
public booleanisLockscreenPublicMode()

        return mLockscreenPublicMode;
    
public booleanisMediaNotification(com.android.systemui.statusbar.NotificationData.Entry entry)

        // TODO: confirm that there's a valid media key
        return entry.expandedBig != null &&
               entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null;
    
public booleanisNotificationForCurrentProfiles(android.service.notification.StatusBarNotification n)

        final int thisUserId = mCurrentUserId;
        final int notificationUserId = n.getUserId();
        if (DEBUG && MULTIUSER_DEBUG) {
            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
                    n, thisUserId, notificationUserId));
        }
        return isCurrentProfile(notificationUserId);
    
public voidlogNotificationExpansion(java.lang.String key, boolean userAction, boolean expanded)

        try {
            mBarService.onNotificationExpansionChanged(key, userAction, expanded);
        } catch (RemoteException e) {
            // Ignore.
        }
    
public com.android.systemui.statusbar.BaseStatusBar$NotificationClickermakeClicker(android.app.PendingIntent intent, java.lang.String notificationKey, boolean forHun)

        return new NotificationClicker(intent, notificationKey, forHun);
    
protected voidnotifyHeadsUpScreenOn(boolean screenOn)

        if (!screenOn) {
            scheduleHeadsUpEscalation();
        }
    
protected voidnotifyUserAboutHiddenNotifications()

        if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
            Log.d(TAG, "user hasn't seen notification about hidden notifications");
            final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
            if (!lockPatternUtils.isSecure()) {
                Log.d(TAG, "insecure lockscreen, skipping notification");
                Settings.Secure.putInt(mContext.getContentResolver(),
                        Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
                return;
            }
            Log.d(TAG, "disabling lockecreen notifications and alerting the user");
            // disable lockscreen notifications until user acts on the banner.
            Settings.Secure.putInt(mContext.getContentResolver(),
                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
            Settings.Secure.putInt(mContext.getContentResolver(),
                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);

            final String packageName = mContext.getPackageName();
            PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0,
                    new Intent(BANNER_ACTION_CANCEL).setPackage(packageName),
                    PendingIntent.FLAG_CANCEL_CURRENT);
            PendingIntent setupIntent = PendingIntent.getBroadcast(mContext, 0,
                    new Intent(BANNER_ACTION_SETUP).setPackage(packageName),
                    PendingIntent.FLAG_CANCEL_CURRENT);

            final Resources res = mContext.getResources();
            final int colorRes = com.android.internal.R.color.system_notification_accent_color;
            Notification.Builder note = new Notification.Builder(mContext)
                    .setSmallIcon(R.drawable.ic_android)
                    .setContentTitle(mContext.getString(R.string.hidden_notifications_title))
                    .setContentText(mContext.getString(R.string.hidden_notifications_text))
                    .setPriority(Notification.PRIORITY_HIGH)
                    .setOngoing(true)
                    .setColor(res.getColor(colorRes))
                    .setContentIntent(setupIntent)
                    .addAction(R.drawable.ic_close,
                            mContext.getString(R.string.hidden_notifications_cancel),
                            cancelIntent)
                    .addAction(R.drawable.ic_settings,
                            mContext.getString(R.string.hidden_notifications_setup),
                            setupIntent);

            NotificationManager noMan =
                    (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
            noMan.notify(HIDDEN_NOTIFICATION_ID, note.build());
        }
    
protected voidonConfigurationChanged(android.content.res.Configuration newConfig)

        final Locale locale = mContext.getResources().getConfiguration().locale;
        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
        final float fontScale = newConfig.fontScale;

        if (! locale.equals(mLocale) || ld != mLayoutDirection || fontScale != mFontScale) {
            if (DEBUG) {
                Log.v(TAG, String.format(
                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
                        locale, ld));
            }
            mLocale = locale;
            mLayoutDirection = ld;
            refreshLayout(ld);
        }
    
public voidonHeadsUpDismissed()

    
public voidonNotificationClear(android.service.notification.StatusBarNotification notification)

        try {
            mBarService.onNotificationClear(
                    notification.getPackageName(),
                    notification.getTag(),
                    notification.getId(),
                    notification.getUserId());
        } catch (android.os.RemoteException ex) {
            // oh well
        }
    
public voidonVisibilityChanged(boolean visible)

        // Do nothing
    
public voidoverrideActivityPendingAppTransition(boolean keyguardShowing)

        if (keyguardShowing) {
            try {
                mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
            } catch (RemoteException e) {
                Log.w(TAG, "Error overriding app transition: " + e);
            }
        }
    
public voidpreloadRecentApps()

        int msg = MSG_PRELOAD_RECENT_APPS;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
protected voidpreloadRecents()

        if (mRecents != null) {
            mRecents.preloadRecents();
        }
    
protected abstract voidrefreshLayout(int layoutDirection)

public abstract voidremoveNotification(java.lang.String key, android.service.notification.NotificationListenerService.RankingMap ranking)

protected android.service.notification.StatusBarNotificationremoveNotificationViews(java.lang.String key, android.service.notification.NotificationListenerService.RankingMap ranking)

        NotificationData.Entry entry = mNotificationData.remove(key, ranking);
        if (entry == null) {
            Log.w(TAG, "removeNotification for unknown key: " + key);
            return null;
        }
        updateNotifications();
        return entry.notification;
    
public abstract voidresetHeadsUpDecayTimer()

public abstract voidscheduleHeadsUpClose()

public abstract voidscheduleHeadsUpEscalation()

public abstract voidscheduleHeadsUpOpen()

static voidsendCloseSystemWindows(android.content.Context context, java.lang.String reason)

        if (ActivityManagerNative.isSystemReady()) {
            try {
                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
            } catch (RemoteException e) {
            }
        }
    
protected abstract voidsetAreThereNotifications()

public voidsetBouncerShowing(boolean bouncerShowing)

        mBouncerShowing = bouncerShowing;
    
private voidsetHeadsUpUser(int newUserId)

        if (mHeadsUpNotificationView != null) {
            mHeadsUpNotificationView.setUser(newUserId);
        }
    
public voidsetInteracting(int barWindow, boolean interacting)

        // hook for subclasses
    
public voidsetLockscreenPublicMode(boolean publicMode)
Save the current "public" (locked and secure) state of the lockscreen.

        mLockscreenPublicMode = publicMode;
    
protected voidsetShowLockscreenNotifications(boolean show)

        mShowLockscreenNotifications = show;
    
protected voidsetZenMode(int mode)

        if (!isDeviceProvisioned()) return;
        mZenMode = mode;
        updateNotifications();
    
protected abstract booleanshouldDisableNavbarGestures()

public booleanshouldHideSensitiveContents(int userid)
Returns true if we're on a secure lockscreen and the user wants to hide "sensitive" notification data. If so, private notifications should show their (possibly auto-generated) publicVersion, and secret notifications should be totally invisible.

        return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
    
protected booleanshouldInterrupt(android.service.notification.StatusBarNotification sbn)

        if (mNotificationData.shouldFilterOut(sbn)) {
            if (DEBUG) {
                Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out.");
            }
            return false;
        }

        if (mHeadsUpNotificationView.isSnoozed(sbn.getPackageName())) {
            return false;
        }

        Notification notification = sbn.getNotification();
        // some predicates to make the boolean logic legible
        boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
                || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
                || notification.sound != null
                || notification.vibrate != null;
        boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
        boolean isFullscreen = notification.fullScreenIntent != null;
        boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
        boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
                Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
        boolean accessibilityForcesLaunch = isFullscreen
                && mAccessibilityManager.isTouchExplorationEnabled();

        boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
                && isAllowed
                && !accessibilityForcesLaunch
                && mPowerManager.isScreenOn()
                && (!mStatusBarKeyguardViewManager.isShowing()
                        || mStatusBarKeyguardViewManager.isOccluded())
                && !mStatusBarKeyguardViewManager.isInputRestricted();
        try {
            interrupt = interrupt && !mDreamManager.isDreaming();
        } catch (RemoteException e) {
            Log.d(TAG, "failed to query dream manager", e);
        }
        if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
        return interrupt;
    
private booleanshouldShowOnKeyguard(android.service.notification.StatusBarNotification sbn)

        return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
    
public voidshowNextAffiliatedTask()
Jumps to the next affiliated task in the group.

        int msg = MSG_SHOW_NEXT_AFFILIATED_TASK;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
public voidshowPreviousAffiliatedTask()
Jumps to the previous affiliated task in the group.

        int msg = MSG_SHOW_PREV_AFFILIATED_TASK;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
public voidshowRecentApps(boolean triggeredFromAltTab)

        int msg = MSG_SHOW_RECENT_APPS;
        mHandler.removeMessages(msg);
        mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
    
protected voidshowRecents(boolean triggeredFromAltTab)
Proxy for RecentsComponent


        

        
        if (mRecents != null) {
            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
            mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
        }
    
protected voidshowRecentsNextAffiliatedTask()

        if (mRecents != null) {
            mRecents.showNextAffiliatedTask();
        }
    
protected voidshowRecentsPreviousAffiliatedTask()

        if (mRecents != null) {
            mRecents.showPrevAffiliatedTask();
        }
    
public voidshowSearchPanel()

        if (mSearchPanelView != null && mSearchPanelView.isAssistantAvailable()) {
            mSearchPanelView.show(true, true);
        }
    
public voidstart()

        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDisplay = mWindowManager.getDefaultDisplay();
        mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);

        mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);

        mNotificationData = new NotificationData(this);

        mAccessibilityManager = (AccessibilityManager)
                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

        mDreamManager = IDreamManager.Stub.asInterface(
                ServiceManager.checkService(DreamService.DREAM_SERVICE));
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

        mSettingsObserver.onChange(false); // set up
        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
                mSettingsObserver);
        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
                mSettingsObserver);
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
                mSettingsObserver,
                UserHandle.USER_ALL);

        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
                true,
                mLockscreenSettingsObserver,
                UserHandle.USER_ALL);

        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));

        mRecents = getComponent(RecentsComponent.class);
        mRecents.setCallback(this);

        final Configuration currentConfig = mContext.getResources().getConfiguration();
        mLocale = currentConfig.locale;
        mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
        mFontScale = currentConfig.fontScale;

        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);

        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
                android.R.interpolator.linear_out_slow_in);
        mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
                android.R.interpolator.fast_out_linear_in);

        // Connect in to the status bar manager service
        StatusBarIconList iconList = new StatusBarIconList();
        mCommandQueue = new CommandQueue(this, iconList);

        int[] switches = new int[8];
        ArrayList<IBinder> binders = new ArrayList<IBinder>();
        try {
            mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
        } catch (RemoteException ex) {
            // If the system process isn't there we're doomed anyway.
        }

        createAndAddWindows();

        disable(switches[0], false /* animate */);
        setSystemUiVisibility(switches[1], 0xffffffff);
        topAppWindowChanged(switches[2] != 0);
        // StatusBarManagerService has a back up of IME token and it's restored here.
        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);

        // Set up the initial icon state
        int N = iconList.size();
        int viewIndex = 0;
        for (int i=0; i<N; i++) {
            StatusBarIcon icon = iconList.getIcon(i);
            if (icon != null) {
                addIcon(iconList.getSlot(i), i, viewIndex, icon);
                viewIndex++;
            }
        }

        // Set up the initial notification state.
        try {
            mNotificationListener.registerAsSystemService(mContext,
                    new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
                    UserHandle.USER_ALL);
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to register notification listener", e);
        }


        if (DEBUG) {
            Log.d(TAG, String.format(
                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
                   iconList.size(),
                   switches[0],
                   switches[1],
                   switches[2],
                   switches[3]
                   ));
        }

        mCurrentUserId = ActivityManager.getCurrentUser();
        setHeadsUpUser(mCurrentUserId);

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(BANNER_ACTION_CANCEL);
        filter.addAction(BANNER_ACTION_SETUP);
        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
        mContext.registerReceiver(mBroadcastReceiver, filter);

        updateCurrentProfilesCache();
    
private voidstartAppNotificationSettingsActivity(java.lang.String packageName, int appUid)

        final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
        intent.putExtra(Settings.EXTRA_APP_UID, appUid);
        startNotificationGutsIntent(intent, appUid);
    
private voidstartAppOwnNotificationSettingsActivity(android.content.Intent intent, int notificationId, java.lang.String notificationTag, int appUid)

        intent.putExtra("notification_id", notificationId);
        intent.putExtra("notification_tag", notificationTag);
        startNotificationGutsIntent(intent, appUid);
    
private voidstartNotificationGutsIntent(android.content.Intent intent, int appUid)

        final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
        dismissKeyguardThenExecute(new OnDismissAction() {
            @Override
            public boolean onDismiss() {
                AsyncTask.execute(new Runnable() {
                    public void run() {
                        try {
                            if (keyguardShowing) {
                                ActivityManagerNative.getDefault()
                                        .keyguardWaitingForActivityDrawn();
                            }
                            TaskStackBuilder.create(mContext)
                                    .addNextIntentWithParentStack(intent)
                                    .startActivities(null,
                                            new UserHandle(UserHandle.getUserId(appUid)));
                            overrideActivityPendingAppTransition(keyguardShowing);
                        } catch (RemoteException e) {
                        }
                    }
                });
                animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
                return true;
            }
        }, false /* afterKeyguardGone */);
    
protected abstract voidtick(android.service.notification.StatusBarNotification n, boolean firstTime)

public voidtoggleRecentApps()

        int msg = MSG_TOGGLE_RECENTS_APPS;
        mHandler.removeMessages(msg);
        mHandler.sendEmptyMessage(msg);
    
protected voidtoggleRecents()

        if (mRecents != null) {
            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
            mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
        }
    
private voidupdateCurrentProfilesCache()


       
        synchronized (mCurrentProfiles) {
            mCurrentProfiles.clear();
            if (mUserManager != null) {
                for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
                    mCurrentProfiles.put(user.id, user);
                }
            }
        }
    
protected abstract voidupdateExpandedViewPos(int expandedPosition)

private voidupdateHeadsUpViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.service.notification.StatusBarNotification notification)

        updateNotificationViews(entry, notification, true);
    
private voidupdateLockscreenNotificationSetting()

        final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                1,
                mCurrentUserId) != 0;
        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
                null /* admin */, mCurrentUserId);
        final boolean allowedByDpm = (dpmFlags
                & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
        setShowLockscreenNotifications(show && allowedByDpm);
    
public voidupdateNotification(android.service.notification.StatusBarNotification notification, android.service.notification.NotificationListenerService.RankingMap ranking)

        if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");

        final String key = notification.getKey();
        boolean wasHeadsUp = isHeadsUp(key);
        Entry oldEntry;
        if (wasHeadsUp) {
            oldEntry = mHeadsUpNotificationView.getEntry();
        } else {
            oldEntry = mNotificationData.get(key);
        }
        if (oldEntry == null) {
            return;
        }

        final StatusBarNotification oldNotification = oldEntry.notification;

        // XXX: modify when we do something more intelligent with the two content views
        final RemoteViews oldContentView = oldNotification.getNotification().contentView;
        Notification n = notification.getNotification();
        final RemoteViews contentView = n.contentView;
        final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
        final RemoteViews bigContentView = n.bigContentView;
        final RemoteViews oldHeadsUpContentView = oldNotification.getNotification().headsUpContentView;
        final RemoteViews headsUpContentView = n.headsUpContentView;
        final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
        final RemoteViews oldPublicContentView = oldPublicNotification != null
                ? oldPublicNotification.contentView : null;
        final Notification publicNotification = n.publicVersion;
        final RemoteViews publicContentView = publicNotification != null
                ? publicNotification.contentView : null;

        if (DEBUG) {
            Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
                    + " ongoing=" + oldNotification.isOngoing()
                    + " expanded=" + oldEntry.expanded
                    + " contentView=" + oldContentView
                    + " bigContentView=" + oldBigContentView
                    + " publicView=" + oldPublicContentView
                    + " rowParent=" + oldEntry.row.getParent());
            Log.d(TAG, "new notification: when=" + n.when
                    + " ongoing=" + oldNotification.isOngoing()
                    + " contentView=" + contentView
                    + " bigContentView=" + bigContentView
                    + " publicView=" + publicContentView);
        }

        // Can we just reapply the RemoteViews in place?

        // 1U is never null
        boolean contentsUnchanged = oldEntry.expanded != null
                && contentView.getPackage() != null
                && oldContentView.getPackage() != null
                && oldContentView.getPackage().equals(contentView.getPackage())
                && oldContentView.getLayoutId() == contentView.getLayoutId();
        // large view may be null
        boolean bigContentsUnchanged =
                (oldEntry.getBigContentView() == null && bigContentView == null)
                || ((oldEntry.getBigContentView() != null && bigContentView != null)
                    && bigContentView.getPackage() != null
                    && oldBigContentView.getPackage() != null
                    && oldBigContentView.getPackage().equals(bigContentView.getPackage())
                    && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
        boolean headsUpContentsUnchanged =
                (oldHeadsUpContentView == null && headsUpContentView == null)
                || ((oldHeadsUpContentView != null && headsUpContentView != null)
                    && headsUpContentView.getPackage() != null
                    && oldHeadsUpContentView.getPackage() != null
                    && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
                    && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
        boolean publicUnchanged  =
                (oldPublicContentView == null && publicContentView == null)
                || ((oldPublicContentView != null && publicContentView != null)
                        && publicContentView.getPackage() != null
                        && oldPublicContentView.getPackage() != null
                        && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
                        && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
        boolean updateTicker = n.tickerText != null
                && !TextUtils.equals(n.tickerText,
                oldEntry.notification.getNotification().tickerText);

        final boolean shouldInterrupt = shouldInterrupt(notification);
        final boolean alertAgain = alertAgain(oldEntry, n);
        boolean updateSuccessful = false;
        if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
                && publicUnchanged) {
            if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
            oldEntry.notification = notification;
            try {
                if (oldEntry.icon != null) {
                    // Update the icon
                    final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
                            notification.getUser(),
                            n.icon,
                            n.iconLevel,
                            n.number,
                            n.tickerText);
                    oldEntry.icon.setNotification(n);
                    if (!oldEntry.icon.set(ic)) {
                        handleNotificationError(notification, "Couldn't update icon: " + ic);
                        return;
                    }
                }

                if (wasHeadsUp) {
                    if (shouldInterrupt) {
                        updateHeadsUpViews(oldEntry, notification);
                        if (alertAgain) {
                            resetHeadsUpDecayTimer();
                        }
                    } else {
                        // we updated the notification above, so release to build a new shade entry
                        mHeadsUpNotificationView.releaseAndClose();
                        return;
                    }
                } else {
                    if (shouldInterrupt && alertAgain) {
                        removeNotificationViews(key, ranking);
                        addNotification(notification, ranking);  //this will pop the headsup
                    } else {
                        updateNotificationViews(oldEntry, notification);
                    }
                }
                mNotificationData.updateRanking(ranking);
                updateNotifications();
                updateSuccessful = true;
            }
            catch (RuntimeException e) {
                // It failed to add cleanly.  Log, and remove the view from the panel.
                Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
            }
        }
        if (!updateSuccessful) {
            if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
            if (wasHeadsUp) {
                if (shouldInterrupt) {
                    if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
                    Entry newEntry = new Entry(notification, null);
                    ViewGroup holder = mHeadsUpNotificationView.getHolder();
                    if (inflateViewsForHeadsUp(newEntry, holder)) {
                        mHeadsUpNotificationView.showNotification(newEntry);
                        if (alertAgain) {
                            resetHeadsUpDecayTimer();
                        }
                    } else {
                        Log.w(TAG, "Couldn't create new updated headsup for package "
                                + contentView.getPackage());
                    }
                } else {
                    if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
                    oldEntry.notification = notification;
                    mHeadsUpNotificationView.releaseAndClose();
                    return;
                }
            } else {
                if (shouldInterrupt && alertAgain) {
                    if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key);
                    removeNotificationViews(key, ranking);
                    addNotification(notification, ranking);  //this will pop the headsup
                } else {
                    if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
                    oldEntry.notification = notification;
                    final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
                            notification.getUser(),
                            n.icon,
                            n.iconLevel,
                            n.number,
                            n.tickerText);
                    oldEntry.icon.setNotification(n);
                    oldEntry.icon.set(ic);
                    inflateViews(oldEntry, mStackScroller, wasHeadsUp);
                    mNotificationData.updateRanking(ranking);
                    updateNotifications();
                }
            }
        }

        // Update the veto button accordingly (and as a result, whether this row is
        // swipe-dismissable)
        updateNotificationVetoButton(oldEntry.row, notification);

        // Is this for you?
        boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
        if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");

        // Restart the ticker if it's still running
        if (updateTicker && isForCurrentUser) {
            haltTicker();
            tick(notification, false);
        }

        // Recalculate the position of the sliding windows and the titles.
        setAreThereNotifications();
        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
    
protected abstract voidupdateNotificationRanking(android.service.notification.NotificationListenerService.RankingMap ranking)

protected android.view.ViewupdateNotificationVetoButton(android.view.View row, android.service.notification.StatusBarNotification n)

        View vetoButton = row.findViewById(R.id.veto);
        if (n.isClearable() || (mHeadsUpNotificationView.getEntry() != null
                && mHeadsUpNotificationView.getEntry().row == row)) {
            final String _pkg = n.getPackageName();
            final String _tag = n.getTag();
            final int _id = n.getId();
            final int _userId = n.getUserId();
            vetoButton.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        // Accessibility feedback
                        v.announceForAccessibility(
                                mContext.getString(R.string.accessibility_notification_dismissed));
                        try {
                            mBarService.onNotificationClear(_pkg, _tag, _id, _userId);

                        } catch (RemoteException ex) {
                            // system process is dead if we're here.
                        }
                    }
                });
            vetoButton.setVisibility(View.VISIBLE);
        } else {
            vetoButton.setVisibility(View.GONE);
        }
        vetoButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
        return vetoButton;
    
private voidupdateNotificationViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.service.notification.StatusBarNotification notification)

        updateNotificationViews(entry, notification, false);
    
private voidupdateNotificationViews(com.android.systemui.statusbar.NotificationData.Entry entry, android.service.notification.StatusBarNotification notification, boolean isHeadsUp)

        final RemoteViews contentView = notification.getNotification().contentView;
        final RemoteViews bigContentView = isHeadsUp
                ? notification.getNotification().headsUpContentView
                : notification.getNotification().bigContentView;
        final Notification publicVersion = notification.getNotification().publicVersion;
        final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
                : null;

        // Reapply the RemoteViews
        contentView.reapply(mContext, entry.expanded, mOnClickHandler);
        if (bigContentView != null && entry.getBigContentView() != null) {
            bigContentView.reapply(mContext, entry.getBigContentView(),
                    mOnClickHandler);
        }
        if (publicContentView != null && entry.getPublicContentView() != null) {
            publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
        }
        // update the contentIntent
        final PendingIntent contentIntent = notification.getNotification().contentIntent;
        if (contentIntent != null) {
            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
                    isHeadsUp);
            entry.row.setOnClickListener(listener);
        } else {
            entry.row.setOnClickListener(null);
        }
        entry.row.setStatusBarNotification(notification);
        entry.row.notifyContentUpdated();
        entry.row.resetHeight();
    
protected abstract voidupdateNotifications()

protected voidupdateRowStates()
Updates expanded, dimmed and locked states of notification rows.

        int maxKeyguardNotifications = getMaxKeyguardNotifications();
        mKeyguardIconOverflowContainer.getIconsView().removeAllViews();

        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
        final int N = activeNotifications.size();

        int visibleNotifications = 0;
        boolean onKeyguard = mState == StatusBarState.KEYGUARD;
        for (int i = 0; i < N; i++) {
            NotificationData.Entry entry = activeNotifications.get(i);
            if (onKeyguard) {
                entry.row.setExpansionDisabled(true);
            } else {
                entry.row.setExpansionDisabled(false);
                if (!entry.row.isUserLocked()) {
                    boolean top = (i == 0);
                    entry.row.setSystemExpanded(top);
                }
            }
            boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
            if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
                    (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
                            || !showOnKeyguard))) {
                entry.row.setVisibility(View.GONE);
                if (onKeyguard && showOnKeyguard) {
                    mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
                }
            } else {
                boolean wasGone = entry.row.getVisibility() == View.GONE;
                entry.row.setVisibility(View.VISIBLE);
                if (wasGone) {
                    // notify the scroller of a child addition
                    mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
                }
                visibleNotifications++;
            }
        }

        if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
            mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
        } else {
            mKeyguardIconOverflowContainer.setVisibility(View.GONE);
        }

        mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
                mStackScroller.getChildCount() - 3);
        mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
        mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
    
protected voidupdateSearchPanel()

        // Search Panel
        boolean visible = false;
        if (mSearchPanelView != null) {
            visible = mSearchPanelView.isShowing();
            mWindowManager.removeView(mSearchPanelView);
        }

        // Provide SearchPanel with a temporary parent to allow layout params to work.
        LinearLayout tmpRoot = new LinearLayout(mContext);
        mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_search_panel, tmpRoot, false);
        mSearchPanelView.setOnTouchListener(
                 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
        mSearchPanelView.setVisibility(View.GONE);
        boolean vertical = mNavigationBarView != null && mNavigationBarView.isVertical();
        mSearchPanelView.setHorizontal(vertical);

        WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());

        mWindowManager.addView(mSearchPanelView, lp);
        mSearchPanelView.setBar(this);
        if (visible) {
            mSearchPanelView.show(true, false);
        }
    
protected voidupdateVisibleToUser()

        boolean oldVisibleToUser = mVisibleToUser;
        mVisibleToUser = mVisible && mScreenOnFromKeyguard;

        if (oldVisibleToUser != mVisibleToUser) {
            handleVisibleToUserChanged(mVisibleToUser);
        }
    
public booleanuserAllowsPrivateNotificationsInPublic(int userHandle)
Has the given user chosen to allow their private (full) notifications to be shown even when the lockscreen is in "public" (secure & locked) mode?

        if (userHandle == UserHandle.USER_ALL) {
            return true;
        }

        if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
            final boolean allowed = 0 != Settings.Secure.getIntForUser(
                    mContext.getContentResolver(),
                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
            final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
                    userHandle);
            final boolean allowedByDpm = (dpmFlags
                    & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
            mUsersAllowingPrivateNotifications.append(userHandle, allowed && allowedByDpm);
            return allowed;
        }

        return mUsersAllowingPrivateNotifications.get(userHandle);
    
public voiduserSwitched(int newUserId)

        setHeadsUpUser(newUserId);
    
protected voidvisibilityChanged(boolean visible)

        if (mVisible != visible) {
            mVisible = visible;
            if (!visible) {
                dismissPopups();
            }
        }
        updateVisibleToUser();
    
protected voidworkAroundBadLayerDrawableOpacity(android.view.View v)