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

Commit 62c63ec7 authored by Steve Elliott's avatar Steve Elliott Committed by Automerger Merge Worker
Browse files

Merge "Enact minimum height requirement for notifications" into tm-qpr-dev am: 0f6acd6f

parents 8b016f2e 0f6acd6f
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -40,7 +40,10 @@
    <com.android.systemui.statusbar.notification.row.NotificationContentView
        android:id="@+id/expanded"
        android:layout_width="match_parent"
       android:layout_height="wrap_content" />
        android:layout_height="wrap_content"
        android:minHeight="@dimen/notification_content_min_height"
        android:gravity="center_vertical"
        />

    <com.android.systemui.statusbar.notification.row.NotificationContentView
        android:id="@+id/expandedPublic"
+9 −0
Original line number Diff line number Diff line
@@ -184,6 +184,15 @@
    <!-- Height of a small notification in the status bar-->
    <dimen name="notification_min_height">@*android:dimen/notification_min_height</dimen>

    <!-- Minimum allowed height of notifications -->
    <dimen name="notification_validation_minimum_allowed_height">10dp</dimen>

    <!-- Minimum height for displaying notification content. -->
    <dimen name="notification_content_min_height">48dp</dimen>

    <!-- Reference width used when validating notification layouts -->
    <dimen name="notification_validation_reference_width">320dp</dimen>

    <!-- Increased height of a small notification in the status bar -->
    <dimen name="notification_min_height_increased">146dp</dimen>

+72 −0
Original line number Diff line number Diff line
@@ -28,8 +28,11 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.Log;
@@ -38,6 +41,7 @@ import android.widget.RemoteViews;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.controls.util.MediaFeatureFlag;
@@ -468,6 +472,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                            result.packageContext,
                            parentLayout,
                            remoteViewClickHandler);
                    validateView(v, entry, row.getResources());
                    v.setIsRootNamespace(true);
                    applyCallback.setResultView(v);
                } else {
@@ -475,6 +480,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
                            result.packageContext,
                            existingView,
                            remoteViewClickHandler);
                    validateView(existingView, entry, row.getResources());
                    existingWrapper.onReinflated();
                }
            } catch (Exception e) {
@@ -496,6 +502,13 @@ public class NotificationContentInflater implements NotificationRowContentBinder

            @Override
            public void onViewApplied(View v) {
                String invalidReason = isValidView(v, entry, row.getResources());
                if (invalidReason != null) {
                    handleInflationError(runningInflations, new InflationException(invalidReason),
                            row.getEntry(), callback);
                    runningInflations.remove(inflationId);
                    return;
                }
                if (isNewView) {
                    v.setIsRootNamespace(true);
                    applyCallback.setResultView(v);
@@ -553,6 +566,65 @@ public class NotificationContentInflater implements NotificationRowContentBinder
        runningInflations.put(inflationId, cancellationSignal);
    }

    /**
     * Checks if the given View is a valid notification View.
     *
     * @return null == valid, non-null == invalid, String represents reason for rejection.
     */
    @VisibleForTesting
    @Nullable
    static String isValidView(View view,
            NotificationEntry entry,
            Resources resources) {
        if (!satisfiesMinHeightRequirement(view, entry, resources)) {
            return "inflated notification does not meet minimum height requirement";
        }
        return null;
    }

    private static boolean satisfiesMinHeightRequirement(View view,
            NotificationEntry entry,
            Resources resources) {
        if (!requiresHeightCheck(entry)) {
            return true;
        }
        Trace.beginSection("NotificationContentInflater#satisfiesMinHeightRequirement");
        int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int referenceWidth = resources.getDimensionPixelSize(
                R.dimen.notification_validation_reference_width);
        int widthSpec = View.MeasureSpec.makeMeasureSpec(referenceWidth, View.MeasureSpec.EXACTLY);
        view.measure(widthSpec, heightSpec);
        int minHeight = resources.getDimensionPixelSize(
                R.dimen.notification_validation_minimum_allowed_height);
        boolean result = view.getMeasuredHeight() >= minHeight;
        Trace.endSection();
        return result;
    }

    private static boolean requiresHeightCheck(NotificationEntry entry) {
        // Undecorated custom views are disallowed from S onwards
        if (entry.targetSdk >= Build.VERSION_CODES.S) {
            return false;
        }
        // No need to check if the app isn't using any custom views
        Notification notification = entry.getSbn().getNotification();
        if (notification.contentView == null
                && notification.bigContentView == null
                && notification.headsUpContentView == null) {
            return false;
        }
        return true;
    }

    private static void validateView(View view,
            NotificationEntry entry,
            Resources resources) throws InflationException {
        String invalidReason = isValidView(view, entry, resources);
        if (invalidReason != null) {
            throw new InflationException(invalidReason);
        }
    }

    private static void handleInflationError(
            HashMap<Integer, CancellationSignal> runningInflations, Exception e,
            NotificationEntry notification, @Nullable InflationCallback callback) {
+18 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="5dp"/>
 No newline at end of file
+34 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -42,6 +43,7 @@ import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
@@ -332,6 +334,38 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
                eq(FLAG_CONTENT_VIEW_HEADS_UP));
    }

    @Test
    public void testNotificationViewHeightTooSmallFailsValidation() {
        View view = mock(View.class);
        when(view.getHeight())
                .thenReturn((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10,
                        mContext.getResources().getDisplayMetrics()));
        String result = NotificationContentInflater.isValidView(view, mRow.getEntry(),
                mContext.getResources());
        assertNotNull(result);
    }

    @Test
    public void testNotificationViewPassesValidation() {
        View view = mock(View.class);
        when(view.getHeight())
                .thenReturn((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 17,
                        mContext.getResources().getDisplayMetrics()));
        String result = NotificationContentInflater.isValidView(view, mRow.getEntry(),
                mContext.getResources());
        assertNull(result);
    }

    @Test
    public void testInvalidNotificationDoesNotInvokeCallback() throws Exception {
        mRow.getPrivateLayout().removeAllViews();
        mRow.getEntry().getSbn().getNotification().contentView =
                new RemoteViews(mContext.getPackageName(), R.layout.invalid_notification_height);
        inflateAndWait(true, mNotificationInflater, FLAG_CONTENT_VIEW_ALL, mRow);
        assertEquals(0, mRow.getPrivateLayout().getChildCount());
        verify(mRow, times(0)).onNotificationUpdated();
    }

    private static void inflateAndWait(NotificationContentInflater inflater,
            @InflationFlag int contentToInflate,
            ExpandableNotificationRow row)