Merge "Talkback for focus on collapsed bubble stack" into qt-dev

This commit is contained in:
TreeHugger Robot
2019-05-15 23:09:47 +00:00
committed by Android (Google) Code Review
6 changed files with 99 additions and 38 deletions

View File

@@ -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;
}

View File

@@ -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();
}
/**

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);
}
}
}