diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 80f4985979679..1c9acae239ed8 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -48,6 +48,7 @@ import android.os.Parcelable; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.service.notification.StatusBarNotification; import android.text.BidiFormatter; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -3854,10 +3855,24 @@ public class Notification implements Parcelable * 3. Standard template view */ public RemoteViews createContentView() { + return createContentView(false /* increasedheight */ ); + } + + /** + * Construct a RemoteViews for the smaller content view. + * + * @param increasedHeight true if this layout be created with an increased height. Some + * styles may support showing more then just that basic 1U size + * and the system may decide to render important notifications + * slightly bigger even when collapsed. + * + * @hide + */ + public RemoteViews createContentView(boolean increasedHeight) { if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) { return mN.contentView; } else if (mStyle != null) { - final RemoteViews styleView = mStyle.makeContentView(); + final RemoteViews styleView = mStyle.makeContentView(increasedHeight); if (styleView != null) { return styleView; } @@ -4486,6 +4501,19 @@ public class Notification implements Parcelable return (flags & ongoingFlags) != 0; } + /** + * @return the style class of this notification + * @hide + */ + public Class getNotificationStyle() { + String templateClass = extras.getString(Notification.EXTRA_TEMPLATE); + + if (!TextUtils.isEmpty(templateClass)) { + return Notification.getNotificationStyleClass(templateClass); + } + return null; + } + /** * @return true if this notification is colorized. This also factors in wheather the * notification is ongoing. @@ -4607,11 +4635,13 @@ public class Notification implements Parcelable } /** - * Construct a Style-specific RemoteViews for the final 1U notification layout. + * Construct a Style-specific RemoteViews for the collapsed notification layout. * The default implementation has nothing additional to add. + * + * @param increasedHeight true if this layout be created with an increased height. * @hide */ - public RemoteViews makeContentView() { + public RemoteViews makeContentView(boolean increasedHeight) { return null; } @@ -4956,6 +4986,23 @@ public class Notification implements Parcelable mBigText = extras.getCharSequence(EXTRA_BIG_TEXT); } + /** + * @param increasedHeight true if this layout be created with an increased height. + * + * @hide + */ + @Override + public RemoteViews makeContentView(boolean increasedHeight) { + if (increasedHeight) { + ArrayList actions = mBuilder.mActions; + mBuilder.mActions = new ArrayList<>(); + RemoteViews remoteViews = makeBigContentView(); + mBuilder.mActions = actions; + return remoteViews; + } + return super.makeContentView(increasedHeight); + } + /** * @hide */ @@ -5220,17 +5267,25 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeContentView() { - Message m = findLatestIncomingMessage(); - CharSequence title = mConversationTitle != null - ? mConversationTitle - : (m == null) ? null : m.mSender; - CharSequence text = (m == null) - ? null - : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText; + public RemoteViews makeContentView(boolean increasedHeight) { + if (!increasedHeight) { + Message m = findLatestIncomingMessage(); + CharSequence title = mConversationTitle != null + ? mConversationTitle + : (m == null) ? null : m.mSender; + CharSequence text = (m == null) + ? null + : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText; - return mBuilder.applyStandardTemplateWithActions(mBuilder.getBaseLayoutResource(), - mBuilder.mParams.reset().hasProgress(false).title(title).text(text)); + return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(), + mBuilder.mParams.reset().hasProgress(false).title(title).text(text)); + } else { + ArrayList actions = mBuilder.mActions; + mBuilder.mActions = new ArrayList<>(); + RemoteViews remoteViews = makeBigContentView(); + mBuilder.mActions = actions; + return remoteViews; + } } private Message findLatestIncomingMessage() { @@ -5795,7 +5850,7 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeContentView() { + public RemoteViews makeContentView(boolean increasedHeight) { return makeMediaContentView(); } @@ -5971,7 +6026,7 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeContentView() { + public RemoteViews makeContentView(boolean increasedHeight) { return makeStandardTemplateWithCustomContent(mBuilder.mN.contentView); } @@ -6085,8 +6140,8 @@ public class Notification implements Parcelable * @hide */ @Override - public RemoteViews makeContentView() { - RemoteViews remoteViews = super.makeContentView(); + public RemoteViews makeContentView(boolean increasedHeight) { + RemoteViews remoteViews = super.makeContentView(false /* increasedHeight */); return buildIntoRemoteView(remoteViews, R.id.notification_content_container, mBuilder.mN.contentView); } @@ -6108,7 +6163,7 @@ public class Notification implements Parcelable return buildIntoRemoteView(remoteViews, R.id.notification_main_column, customRemoteView); } else if (customRemoteView != mBuilder.mN.contentView){ - remoteViews = super.makeContentView(); + remoteViews = super.makeContentView(false /* increasedHeight */); return buildIntoRemoteView(remoteViews, R.id.notification_content_container, customRemoteView); } else { diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java new file mode 100644 index 0000000000000..518cf41ee37a8 --- /dev/null +++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.util; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.provider.Settings; +import android.service.notification.StatusBarNotification; +import android.text.TextUtils; +import android.util.ArrayMap; + +import java.util.Objects; + +/** + * A util to look up messaging related functions for notifications. This is used for both the + * ranking and the actual layout. + */ +public class NotificationMessagingUtil { + + private static final String DEFAULT_SMS_APP_SETTING = Settings.Secure.SMS_DEFAULT_APPLICATION; + private final Context mContext; + private ArrayMap mDefaultSmsApp = new ArrayMap<>(); + + public NotificationMessagingUtil(Context context) { + mContext = context; + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver); + } + + @SuppressWarnings("deprecation") + private boolean isDefaultMessagingApp(StatusBarNotification sbn) { + final int userId = sbn.getUserId(); + if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false; + if (mDefaultSmsApp.get(userId) == null) { + cacheDefaultSmsApp(userId); + } + return Objects.equals(mDefaultSmsApp.get(userId), sbn.getPackageName()); + } + + private void cacheDefaultSmsApp(int userId) { + mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.SMS_DEFAULT_APPLICATION, userId)); + } + + private final ContentObserver mSmsContentObserver = new ContentObserver( + new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) { + cacheDefaultSmsApp(userId); + } + } + }; + + public boolean isImportantMessaging(StatusBarNotification sbn, int importance) { + if (importance < NotificationManager.IMPORTANCE_LOW) { + return false; + } + + Class style = sbn.getNotification().getNotificationStyle(); + if (Notification.MessagingStyle.class.equals(style)) { + return true; + } + + if (Notification.CATEGORY_MESSAGE.equals(sbn.getNotification().category) + && isDefaultMessagingApp(sbn)) { + return true; + } + + return false; + } +} diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ddcc4baf8350f..cf183739a345b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -69,6 +69,9 @@ 92dp + + 132dp + 64dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index d1245b133962e..f19d6d7f65ac0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -77,6 +77,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { private int mMaxHeadsUpHeightLegacy; private int mMaxHeadsUpHeight; private int mNotificationMinHeight; + private int mNotificationMinHeightLarge; private int mNotificationMaxHeight; private int mNotificationAmbientHeight; private int mIncreasedPaddingBetweenElements; @@ -207,6 +208,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { private Runnable mOnDismissRunnable; private boolean mIsLowPriority; private boolean mIsColorized; + private boolean mUseIncreasedCollapsedHeight; @Override public boolean isGroupExpansionChanging() { @@ -341,8 +343,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { boolean customView = layout.getContractedChild().getId() != com.android.internal.R.id.status_bar_latest_event_content; boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N; - int minHeight = customView && beforeN && !mIsSummaryWithChildren ? - mNotificationMinHeightLegacy : mNotificationMinHeight; + int minHeight; + if (customView && beforeN && !mIsSummaryWithChildren) { + minHeight = mNotificationMinHeightLegacy; + } else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) { + minHeight = mNotificationMinHeightLarge; + } else { + minHeight = mNotificationMinHeight; + } boolean headsUpCustom = layout.getHeadsUpChild() != null && layout.getHeadsUpChild().getId() != com.android.internal.R.id.status_bar_latest_event_content; @@ -979,6 +987,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } } + public void setUseIncreasedCollapsedHeight(boolean use) { + mUseIncreasedCollapsedHeight = use; + } + public interface ExpansionLogger { public void logNotificationExpansion(String key, boolean userAction, boolean expanded); } @@ -992,6 +1004,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { private void initDimens() { mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy); mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height); + mNotificationMinHeightLarge = getFontScaledHeight( + R.dimen.notification_min_height_large); mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height); mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height); mMaxHeadsUpHeightLegacy = getFontScaledHeight( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index bbfcf31e7c2ff..bb9b0707f76f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -122,13 +122,13 @@ public class NotificationData { } public boolean cacheContentViews(Context ctx, Notification updatedNotification, - boolean isLowPriority) { + boolean isLowPriority, boolean useIncreasedCollapsedView) { boolean applyInPlace = false; if (updatedNotification != null) { final Notification.Builder updatedNotificationBuilder = Notification.Builder.recoverBuilder(ctx, updatedNotification); final RemoteViews newContentView = createContentView(updatedNotificationBuilder, - isLowPriority); + isLowPriority, useIncreasedCollapsedView); final RemoteViews newBigContentView = createBigContentView( updatedNotificationBuilder, isLowPriority); final RemoteViews newHeadsUpContentView = @@ -158,7 +158,8 @@ public class NotificationData { final Notification.Builder builder = Notification.Builder.recoverBuilder(ctx, notification.getNotification()); - cachedContentView = createContentView(builder, isLowPriority); + cachedContentView = createContentView(builder, isLowPriority, + useIncreasedCollapsedView); cachedBigContentView = createBigContentView(builder, isLowPriority); cachedHeadsUpContentView = builder.createHeadsUpContentView(); cachedPublicContentView = builder.makePublicContentView(); @@ -184,11 +185,11 @@ public class NotificationData { } private RemoteViews createContentView(Notification.Builder builder, - boolean isAmbient) { - if (isAmbient) { + boolean isLowPriority, boolean useLarge) { + if (isLowPriority) { return builder.makeLowPriorityContentView(false /* useRegularSubtext */); } - return builder.createContentView(); + return builder.createContentView(useLarge); } // Returns true if the RemoteViews are the same. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 018d8885842dd..6ace9872f5cf1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1,3 +1,5 @@ + + /* * Copyright (C) 2010 The Android Open Source Project * @@ -112,6 +114,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.util.NotificationMessagingUtil; import com.android.keyguard.KeyguardHostView.OnDismissAction; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; @@ -701,6 +704,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; + private NotificationMessagingUtil mMessagingUtil; private KeyguardUserSwitcher mKeyguardUserSwitcher; private UserSwitcherController mUserSwitcherController; private NetworkController mNetworkController; @@ -763,6 +767,7 @@ public class StatusBar extends SystemUI implements DemoMode, Context.DEVICE_POLICY_SERVICE); mNotificationData = new NotificationData(this); + mMessagingUtil = new NotificationMessagingUtil(mContext); mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -6318,8 +6323,10 @@ public class StatusBar extends SystemUI implements DemoMode, final StatusBarNotification sbn = entry.notification; boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey()); + boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn, + mNotificationData.getImportance(sbn.getKey())); try { - entry.cacheContentViews(mContext, null, isLowPriority); + entry.cacheContentViews(mContext, null, isLowPriority, useIncreasedCollapsedHeight); } catch (RuntimeException e) { Log.e(TAG, "Unable to get notification remote views", e); return false; @@ -6489,6 +6496,7 @@ public class StatusBar extends SystemUI implements DemoMode, row.setUserExpanded(userExpanded); } row.setUserLocked(userLocked); + row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); row.onNotificationUpdated(entry); return true; } @@ -6978,10 +6986,13 @@ public class StatusBar extends SystemUI implements DemoMode, Notification n = notification.getNotification(); mNotificationData.updateRanking(ranking); + boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(notification, + mNotificationData.getImportance(notification.getKey())); + entry.row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); boolean applyInPlace; try { applyInPlace = entry.cacheContentViews(mContext, notification.getNotification(), - mNotificationData.isAmbient(key)); + mNotificationData.isAmbient(key), useIncreasedCollapsedHeight); } catch (RuntimeException e) { Log.e(TAG, "Unable to get notification remote views", e); applyInPlace = false; diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java index 6f49df4795655..279bf9005fe38 100644 --- a/services/core/java/com/android/server/notification/NotificationComparator.java +++ b/services/core/java/com/android/server/notification/NotificationComparator.java @@ -31,6 +31,8 @@ import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.ArrayMap; +import com.android.internal.util.NotificationMessagingUtil; + import java.util.Comparator; import java.util.Objects; @@ -40,18 +42,15 @@ import java.util.Objects; public class NotificationComparator implements Comparator { - private final String DEFAULT_SMS_APP_SETTING = Settings.Secure.SMS_DEFAULT_APPLICATION; - private final Context mContext; + private final NotificationMessagingUtil mMessagingUtil; private String mDefaultPhoneApp; - private ArrayMap mDefaultSmsApp = new ArrayMap<>(); public NotificationComparator(Context context) { mContext = context; mContext.registerReceiver(mPhoneAppBroadcastReceiver, new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED)); - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver); + mMessagingUtil = new NotificationMessagingUtil(mContext); } @Override @@ -73,9 +72,15 @@ public class NotificationComparator return -1 * Boolean.compare(leftImportantOngoing, rightImportantOngoing); } + boolean leftMessaging = isImportantMessaging(left); + boolean rightMessaging = isImportantMessaging(right); + if (leftMessaging != rightMessaging) { + return -1 * Boolean.compare(leftMessaging, rightMessaging); + } + // Next: sufficiently import person to person communication - boolean leftPeople = isImportantMessaging(left); - boolean rightPeople = isImportantMessaging(right); + boolean leftPeople = isImportantPeople(left); + boolean rightPeople = isImportantPeople(right); if (leftPeople && rightPeople){ // by contact proximity, close to far. if same proximity, check further fields. @@ -128,50 +133,31 @@ public class NotificationComparator if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) { return false; } - // TODO: add whitelist return isCall(record) || isMediaNotification(record); } - protected boolean isImportantMessaging(NotificationRecord record) { + protected boolean isImportantPeople(NotificationRecord record) { if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) { return false; } - - Class style = getNotificationStyle(record); - if (Notification.MessagingStyle.class.equals(style)) { - return true; - } - if (record.getContactAffinity() > ValidateNotificationPeople.NONE) { return true; } - - if (record.getNotification().category == Notification.CATEGORY_MESSAGE - && isDefaultMessagingApp(record)) { - return true; - } - return false; } + protected boolean isImportantMessaging(NotificationRecord record) { + return mMessagingUtil.isImportantMessaging(record.sbn, record.getImportance()); + } + private boolean isOngoing(NotificationRecord record) { final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_ONGOING_EVENT; return (record.getNotification().flags & ongoingFlags) != 0; } - private Class getNotificationStyle(NotificationRecord record) { - String templateClass = - record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE); - - if (!TextUtils.isEmpty(templateClass)) { - return Notification.getNotificationStyleClass(templateClass); - } - return null; - } - private boolean isMediaNotification(NotificationRecord record) { return record.getNotification().extras.getParcelable( Notification.EXTRA_MEDIA_SESSION) != null; @@ -191,18 +177,6 @@ public class NotificationComparator return Objects.equals(pkg, mDefaultPhoneApp); } - @SuppressWarnings("deprecation") - private boolean isDefaultMessagingApp(NotificationRecord record) { - final int userId = record.getUserId(); - if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false; - if (mDefaultSmsApp.get(userId) == null) { - mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.SMS_DEFAULT_APPLICATION, userId)); - } - return Objects.equals(mDefaultSmsApp.get(userId), record.sbn.getPackageName()); - } - private final BroadcastReceiver mPhoneAppBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -210,17 +184,4 @@ public class NotificationComparator intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME); } }; - - private final ContentObserver mSmsContentObserver = new ContentObserver( - new Handler(Looper.getMainLooper())) { - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) { - mDefaultSmsApp.put(userId, Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.SMS_DEFAULT_APPLICATION, userId)); - - } - } - }; }