Merge "Talkback for focus on collapsed bubble stack" into qt-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4360543283
@@ -18,6 +18,9 @@ package com.android.systemui.bubbles;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserHandle;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
@@ -37,6 +40,7 @@ class Bubble {
|
||||
|
||||
private final String mKey;
|
||||
private final String mGroupId;
|
||||
private String mAppName;
|
||||
private final BubbleExpandedView.OnBubbleBlockedListener mListener;
|
||||
|
||||
private boolean mInflated;
|
||||
@@ -45,6 +49,7 @@ class Bubble {
|
||||
BubbleExpandedView expandedView;
|
||||
private long mLastUpdated;
|
||||
private long mLastAccessed;
|
||||
private PackageManager mPm;
|
||||
|
||||
public static String groupId(NotificationEntry entry) {
|
||||
UserHandle user = entry.notification.getUser();
|
||||
@@ -53,16 +58,33 @@ class Bubble {
|
||||
|
||||
/** Used in tests when no UI is required. */
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
Bubble(NotificationEntry e) {
|
||||
this (e, null);
|
||||
Bubble(Context context, NotificationEntry e) {
|
||||
this (context, e, null);
|
||||
}
|
||||
|
||||
Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) {
|
||||
Bubble(Context context, NotificationEntry e,
|
||||
BubbleExpandedView.OnBubbleBlockedListener listener) {
|
||||
entry = e;
|
||||
mKey = e.key;
|
||||
mLastUpdated = e.notification.getPostTime();
|
||||
mGroupId = groupId(e);
|
||||
mListener = listener;
|
||||
|
||||
mPm = context.getPackageManager();
|
||||
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 unused) {
|
||||
mAppName = entry.notification.getPackageName();
|
||||
}
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
@@ -77,6 +99,10 @@ class Bubble {
|
||||
return entry.notification.getPackageName();
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return mAppName;
|
||||
}
|
||||
|
||||
boolean isInflated() {
|
||||
return mInflated;
|
||||
}
|
||||
@@ -97,9 +123,9 @@ class Bubble {
|
||||
|
||||
expandedView = (BubbleExpandedView) inflater.inflate(
|
||||
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
|
||||
expandedView.setEntry(entry, stackView);
|
||||
|
||||
expandedView.setEntry(entry, stackView, mAppName);
|
||||
expandedView.setOnBlockedListener(mListener);
|
||||
|
||||
mInflated = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
if (shouldCollapse) {
|
||||
collapseStack();
|
||||
}
|
||||
updateVisibility();
|
||||
updateStack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,10 +534,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
}
|
||||
}
|
||||
|
||||
// Runs on state change.
|
||||
@Override
|
||||
public void apply() {
|
||||
mNotificationEntryManager.updateNotifications();
|
||||
updateVisibility();
|
||||
updateStack();
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "[BubbleData]");
|
||||
@@ -554,34 +555,31 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
};
|
||||
|
||||
/**
|
||||
* Lets any listeners know if bubble state has changed.
|
||||
* Updates the visibility of the bubbles based on current state.
|
||||
* Does not un-bubble, just hides or un-hides. Notifies any
|
||||
* {@link BubbleStateChangeListener}s of visibility changes.
|
||||
* Updates stack description for TalkBack focus.
|
||||
*/
|
||||
private void updateBubblesShowing() {
|
||||
public void updateStack() {
|
||||
if (mStackView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hadBubbles = mStatusBarWindowController.getBubblesShowing();
|
||||
boolean hasBubblesShowing = hasBubbles() && mStackView.getVisibility() == VISIBLE;
|
||||
mStatusBarWindowController.setBubblesShowing(hasBubblesShowing);
|
||||
if (mStateChangeListener != null && hadBubbles != hasBubblesShowing) {
|
||||
mStateChangeListener.onHasBubblesChanged(hasBubblesShowing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the visibility of the bubbles based on current state.
|
||||
* Does not un-bubble, just hides or un-hides. Will notify any
|
||||
* {@link BubbleStateChangeListener}s if visibility changes.
|
||||
*/
|
||||
public void updateVisibility() {
|
||||
if (mStatusBarStateListener.getCurrentState() == SHADE && hasBubbles()) {
|
||||
// Bubbles only appear in unlocked shade
|
||||
mStackView.setVisibility(hasBubbles() ? VISIBLE : INVISIBLE);
|
||||
} else if (mStackView != null) {
|
||||
mStackView.setVisibility(INVISIBLE);
|
||||
}
|
||||
updateBubblesShowing();
|
||||
|
||||
// Let listeners know if bubble state changed.
|
||||
boolean hadBubbles = mStatusBarWindowController.getBubblesShowing();
|
||||
boolean hasBubblesShowing = hasBubbles() && mStackView.getVisibility() == VISIBLE;
|
||||
mStatusBarWindowController.setBubblesShowing(hasBubblesShowing);
|
||||
if (mStateChangeListener != null && hadBubbles != hasBubblesShowing) {
|
||||
mStateChangeListener.onHasBubblesChanged(hasBubblesShowing);
|
||||
}
|
||||
|
||||
mStackView.updateContentDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -178,7 +178,7 @@ public class BubbleData {
|
||||
Bubble bubble = getBubbleWithKey(entry.key);
|
||||
if (bubble == null) {
|
||||
// Create a new bubble
|
||||
bubble = new Bubble(entry, this::onBubbleBlocked);
|
||||
bubble = new Bubble(mContext, entry, this::onBubbleBlocked);
|
||||
doAdd(bubble);
|
||||
trim();
|
||||
} else {
|
||||
|
||||
@@ -244,9 +244,10 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
/**
|
||||
* Sets the notification entry used to populate this view.
|
||||
*/
|
||||
public void setEntry(NotificationEntry entry, BubbleStackView stackView) {
|
||||
public void setEntry(NotificationEntry entry, BubbleStackView stackView, String appName) {
|
||||
mStackView = stackView;
|
||||
mEntry = entry;
|
||||
mAppName = appName;
|
||||
|
||||
ApplicationInfo info;
|
||||
try {
|
||||
@@ -257,12 +258,10 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
|
||||
if (info != null) {
|
||||
mAppName = String.valueOf(mPm.getApplicationLabel(info));
|
||||
mAppIcon = mPm.getApplicationIcon(info);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Ahh... just use package name
|
||||
mAppName = entry.notification.getPackageName();
|
||||
// Do nothing.
|
||||
}
|
||||
if (mAppIcon == null) {
|
||||
mAppIcon = mPm.getDefaultActivityIcon();
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.ColorMatrix;
|
||||
@@ -553,6 +554,43 @@ public class BubbleStackView extends FrameLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update content description for a11y TalkBack.
|
||||
*/
|
||||
public void updateContentDescription() {
|
||||
if (mBubbleData.getBubbles().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Bubble topBubble = mBubbleData.getBubbles().get(0);
|
||||
String appName = topBubble.getAppName();
|
||||
Notification notification = topBubble.entry.notification.getNotification();
|
||||
CharSequence titleCharSeq = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
|
||||
String titleStr = getResources().getString(R.string.stream_notification);
|
||||
if (titleCharSeq != null) {
|
||||
titleStr = titleCharSeq.toString();
|
||||
}
|
||||
int moreCount = mBubbleContainer.getChildCount() - 1;
|
||||
|
||||
// Example: Title from app name.
|
||||
String singleDescription = getResources().getString(
|
||||
R.string.bubble_content_description_single, titleStr, appName);
|
||||
|
||||
// Example: Title from app name and 4 more.
|
||||
String stackDescription = getResources().getString(
|
||||
R.string.bubble_content_description_stack, titleStr, appName, moreCount);
|
||||
|
||||
if (mIsExpanded) {
|
||||
// TODO(b/129522932) - update content description for each bubble in expanded view.
|
||||
} else {
|
||||
// Collapsed stack.
|
||||
if (moreCount > 0) {
|
||||
mBubbleContainer.setContentDescription(stackDescription);
|
||||
} else {
|
||||
mBubbleContainer.setContentDescription(singleDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSystemGestureExcludeRects() {
|
||||
// Exclude the region occupied by the first BubbleView in the stack
|
||||
Rect excludeZone = mSystemGestureExclusionRects.get(0);
|
||||
|
||||
@@ -103,13 +103,13 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
mEntryB3 = createBubbleEntry(1, "b3", "package.b");
|
||||
mEntryC1 = createBubbleEntry(1, "c1", "package.c");
|
||||
|
||||
mBubbleA1 = new Bubble(mEntryA1);
|
||||
mBubbleA2 = new Bubble(mEntryA2);
|
||||
mBubbleA3 = new Bubble(mEntryA3);
|
||||
mBubbleB1 = new Bubble(mEntryB1);
|
||||
mBubbleB2 = new Bubble(mEntryB2);
|
||||
mBubbleB3 = new Bubble(mEntryB3);
|
||||
mBubbleC1 = new Bubble(mEntryC1);
|
||||
mBubbleA1 = new Bubble(mContext, mEntryA1);
|
||||
mBubbleA2 = new Bubble(mContext, mEntryA2);
|
||||
mBubbleA3 = new Bubble(mContext, mEntryA3);
|
||||
mBubbleB1 = new Bubble(mContext, mEntryB1);
|
||||
mBubbleB2 = new Bubble(mContext, mEntryB2);
|
||||
mBubbleB3 = new Bubble(mContext, mEntryB3);
|
||||
mBubbleC1 = new Bubble(mContext, mEntryC1);
|
||||
|
||||
mBubbleData = new BubbleData(getContext());
|
||||
|
||||
@@ -803,4 +803,4 @@ public class BubbleDataTest extends SysuiTestCase {
|
||||
private static <T> List<T> listOf(T... a) {
|
||||
return ImmutableList.copyOf(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user