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

Commit 9801e853 authored by Mady Mellor's avatar Mady Mellor
Browse files

Update header to have content intent & settings buttons

* Sets notification entry on BubbleExpandedViewContainer and use that to
  to populate the contents
* Adds settings + app deeplink buttons to header
* Header will use bubble metadata text if it exists or the app name

Bug: 111236845
Test: manual - tested with notify activity view based bubble that
      (1) - tapping deep link button opens content intent
      (2) - tapping settings button opens notif settings for app
Change-Id: I07d6beced7da001e233237b91053b0fc4b18505b
parent e075a65a
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
<!-- Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24"
        android:viewportHeight="24">
    <path
        android:fillColor="#FF000000"
        android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"/>
</vector>
+43 −11
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:id="@+id/bubble_expanded_view">

    <View
@@ -26,17 +27,48 @@
        android:layout_height="@dimen/bubble_pointer_height"
    />

    <LinearLayout
        android:id="@+id/header_layout"
        android:layout_height="@dimen/bubble_expanded_header_height"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:background="@drawable/bubble_expanded_header_bg">

        <TextView
        android:id="@+id/bubble_content_header"
        android:background="@drawable/bubble_expanded_header_bg"
            android:id="@+id/header_text"
            android:textAppearance="@*android:style/TextAppearance.Material.Title"
            android:textSize="18sp"
        android:layout_width="match_parent"
        android:layout_height="@dimen/bubble_expanded_header_height"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:gravity="start|center_vertical"
            android:singleLine="true"
            android:paddingLeft="@dimen/bubble_expanded_header_horizontal_padding"
            android:paddingRight="@dimen/bubble_expanded_header_horizontal_padding"
        />

        <ImageButton
            android:id="@+id/deep_link_button"
            android:layout_width="@dimen/bubble_header_icon_size"
            android:layout_height="@dimen/bubble_header_icon_size"
            android:gravity="end|center_vertical"
            android:src="@drawable/ic_open_in_new"
            android:scaleType="center"
            android:tint="?android:attr/colorForeground"
            android:background="?android:attr/selectableItemBackground"
        />

        <ImageButton
            android:id="@id/settings_button"
            android:layout_width="@dimen/bubble_header_icon_size"
            android:layout_height="@dimen/bubble_header_icon_size"
            android:src="@drawable/ic_settings"
            android:gravity="end|center_vertical"
            android:scaleType="center"
            android:tint="?android:attr/colorForeground"
            android:background="?android:attr/selectableItemBackground"
        />

    </LinearLayout>

</com.android.systemui.bubbles.BubbleExpandedViewContainer>
+2 −0
Original line number Diff line number Diff line
@@ -1030,4 +1030,6 @@
    <dimen name="bubble_stack_offscreen">5dp</dimen>
    <!-- How far down the screen the stack starts. -->
    <dimen name="bubble_stack_starting_offset_y">100dp</dimen>
    <!-- Size of image buttons in the bubble header -->
    <dimen name="bubble_header_icon_size">48dp</dimen>
</resources>
+8 −0
Original line number Diff line number Diff line
@@ -2346,4 +2346,12 @@

    <!-- What to show on the ambient display player when song doesn't have a title. [CHAR LIMIT=20] -->
    <string name="music_controls_no_title">No title</string>

    <!-- Text used for content description of deep link button in the header of expanded bubble
         view. [CHAR_LIMIT=NONE] -->
    <string name="bubbles_deep_link_button_description">Open <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
    <!-- Text used for content description of settings button in the header of expanded bubble
         view. [CHAR_LIMIT=NONE] -->
    <string name="bubbles_settings_button_description">Open notification settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>

</resources>
+102 −4
Original line number Diff line number Diff line
@@ -17,31 +17,52 @@
package com.android.systemui.bubbles;

import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

/**
 * Container for the expanded bubble view, handles rendering the caret and header of the view.
 */
public class BubbleExpandedViewContainer extends LinearLayout {
public class BubbleExpandedViewContainer extends LinearLayout implements View.OnClickListener {
    private static final String TAG = "BubbleExpandedView";

    // The triangle pointing to the expanded view
    private View mPointerView;
    // The view displayed between the pointer and the expanded view
    private TextView mHeaderView;
    // Tappable header icon deeplinking into the app
    private ImageButton mDeepLinkIcon;
    // Tappable header icon deeplinking into notification settings
    private ImageButton mSettingsIcon;
    // The view that is being displayed for the expanded state
    private View mExpandedView;

    private NotificationEntry mEntry;
    private PackageManager mPm;
    private String mAppName;

    // Need reference to let it know to collapse when new task is launched
    private BubbleStackView mStackView;

    public BubbleExpandedViewContainer(Context context) {
        this(context, null);
    }
@@ -57,7 +78,7 @@ public class BubbleExpandedViewContainer extends LinearLayout {
    public BubbleExpandedViewContainer(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setOrientation(VERTICAL);
        mPm = context.getPackageManager();
    }

    @Override
@@ -72,7 +93,75 @@ public class BubbleExpandedViewContainer extends LinearLayout {
                TriangleShape.create(width, height, true /* pointUp */));
        triangleDrawable.setTint(Color.WHITE); // TODO: dark mode
        mPointerView.setBackground(triangleDrawable);
        mHeaderView = findViewById(R.id.bubble_content_header);

        mHeaderView = findViewById(R.id.header_text);
        mDeepLinkIcon = findViewById(R.id.deep_link_button);
        mSettingsIcon = findViewById(R.id.settings_button);
        mDeepLinkIcon.setOnClickListener(this);
        mSettingsIcon.setOnClickListener(this);
    }

    /**
     * Sets the notification entry used to populate this view.
     */
    public void setEntry(NotificationEntry entry, BubbleStackView stackView) {
        mStackView = stackView;
        mEntry = entry;

        ApplicationInfo info;
        try {
            info = mPm.getApplicationInfo(
                    entry.notification.getPackageName(),
                    PackageManager.MATCH_UNINSTALLED_PACKAGES
                            | PackageManager.MATCH_DISABLED_COMPONENTS
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (info != null) {
                mAppName = String.valueOf(mPm.getApplicationLabel(info));
            }
        } catch (PackageManager.NameNotFoundException e) {
            // Ahh... just use package name
            mAppName = entry.notification.getPackageName();
        }

        updateHeaderView();
    }

    private void updateHeaderView() {
        mSettingsIcon.setContentDescription(getResources().getString(
                R.string.bubbles_settings_button_description, mAppName));
        mDeepLinkIcon.setContentDescription(getResources().getString(
                R.string.bubbles_deep_link_button_description, mAppName));
        if (mEntry != null && mEntry.getBubbleMetadata() != null) {
            setHeaderText(mEntry.getBubbleMetadata().getTitle());
        } else {
            // This should only happen if we're auto-bubbling notification content that isn't
            // explicitly a bubble
            setHeaderText(mAppName);
        }
    }

    @Override
    public void onClick(View view) {
        if (mEntry == null) {
            return;
        }
        Notification n = mEntry.notification.getNotification();
        int id = view.getId();
        if (id == R.id.deep_link_button) {
            mStackView.collapseStack(() -> {
                try {
                    n.contentIntent.send();
                } catch (PendingIntent.CanceledException e) {
                    Log.w(TAG, "Failed to send intent for bubble with key: "
                            + (mEntry != null ? mEntry.key : " null entry"));
                }
            });
        } else if (id == R.id.settings_button) {
            Intent intent = getSettingsIntent(mEntry.notification.getPackageName(),
                    mEntry.notification.getUid());
            mStackView.collapseStack(() -> mContext.startActivity(intent));
        }
    }

    /**
@@ -87,7 +176,7 @@ public class BubbleExpandedViewContainer extends LinearLayout {
    /**
     * Set the text displayed within the header.
     */
    public void setHeaderText(CharSequence text) {
    private void setHeaderText(CharSequence text) {
        mHeaderView.setText(text);
        mHeaderView.setVisibility(TextUtils.isEmpty(text) ? GONE : VISIBLE);
    }
@@ -115,4 +204,13 @@ public class BubbleExpandedViewContainer extends LinearLayout {
    public View getExpandedView() {
        return mExpandedView;
    }

    private Intent getSettingsIntent(String packageName, final 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);
        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return intent;
    }
}
Loading