Merge "Cache EGLImage and VkImage used by SurfaceTexture"
diff --git a/api/current.txt b/api/current.txt
index 11f7ce1..c06d618 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11271,11 +11271,11 @@
method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
- method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle);
+ method public void startPackageInstallerSessionDetailsActivity(@NonNull android.content.pm.PackageInstaller.SessionInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
- method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
+ method public void unregisterPackageInstallerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
@@ -11465,7 +11465,7 @@
method public long getSize();
method public int getStagedSessionErrorCode();
method @NonNull public String getStagedSessionErrorMessage();
- method public android.os.UserHandle getUser();
+ method @NonNull public android.os.UserHandle getUser();
method public boolean isActive();
method public boolean isMultiPackage();
method public boolean isSealed();
diff --git a/api/system-current.txt b/api/system-current.txt
index aec8cc1..28104d5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -546,10 +546,10 @@
public class NotificationManager {
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
- method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle);
+ method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(@NonNull android.os.UserHandle);
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
- method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean);
- method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean);
+ method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method public void setNotificationAssistantAccessGrantedForUser(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, boolean);
}
public final class StatsManager {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ed7aa4a..204fb6a 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1277,7 +1277,8 @@
* @hide
*/
@SystemApi
- public void setNotificationAssistantAccessGranted(ComponentName assistant, boolean granted) {
+ public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant,
+ boolean granted) {
INotificationManager service = getService();
try {
service.setNotificationAssistantAccessGranted(assistant, granted);
@@ -1296,8 +1297,8 @@
* @hide
*/
@SystemApi
- public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
- UserHandle user, boolean granted) {
+ public void setNotificationAssistantAccessGrantedForUser(@Nullable ComponentName assistant,
+ @NonNull UserHandle user, boolean granted) {
INotificationManager service = getService();
try {
service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(),
@@ -1319,7 +1320,8 @@
/** @hide */
@SystemApi
- public @Nullable ComponentName getAllowedNotificationAssistantForUser(UserHandle user) {
+ public @Nullable ComponentName getAllowedNotificationAssistantForUser(
+ @NonNull UserHandle user) {
INotificationManager service = getService();
try {
return service.getAllowedNotificationAssistantForUser(user.getIdentifier());
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 0cc5f39..2a19763 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -585,8 +585,8 @@
* @param sourceBounds The Rect containing the source bounds of the clicked icon
* @param opts Options to pass to startActivity
*/
- public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo,
- Rect sourceBounds, Bundle opts) {
+ public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
+ @Nullable Rect sourceBounds, @Nullable Bundle opts) {
try {
mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
mContext.getPackageName(), sessionInfo, sourceBounds, opts,
@@ -1503,7 +1503,7 @@
* @param callback The callback to unregister.
* @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
*/
- public void unregisterPackageInstallerSessionCallback(SessionCallback callback) {
+ public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
synchronized (mDelegates) {
for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
final SessionCallbackDelegate delegate = i.next();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 7b4dd19..f14b228 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1833,7 +1833,7 @@
/**
* Return the user associated with this session.
*/
- public UserHandle getUser() {
+ public @NonNull UserHandle getUser() {
return new UserHandle(userId);
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 45860b3..95d66bb 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -62,7 +62,7 @@
*
* The handshake timeout does not apply to actual TCP socket connection.
* If you want a connection timeout as well, use {@link #createSocket()}
- * and {@link Socket#connect(SocketAddress, int)}, after which you
+ * and {@link Socket#connect(java.net.SocketAddress, int)}, after which you
* must verify the identity of the server you are connected to.
*
* <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not
@@ -211,14 +211,14 @@
}
/**
- * Verify the hostname of the certificate used by the other end of a
- * connected socket. You MUST call this if you did not supply a hostname
- * to {@link #createSocket()}. It is harmless to call this method
- * redundantly if the hostname has already been verified.
+ * Verify the hostname of the certificate used by the other end of a connected socket using the
+ * {@link HostnameVerifier} obtained from {@code
+ * HttpsURLConnection.getDefaultHostnameVerifier()}. You MUST call this if you did not supply a
+ * hostname to {@link #createSocket()}. It is harmless to call this method redundantly if the
+ * hostname has already been verified.
*
- * <p>Wildcard certificates are allowed to verify any matching hostname,
- * so "foo.bar.example.com" is verified if the peer has a certificate
- * for "*.example.com".
+ * <p>Wildcard certificates are allowed to verify any matching hostname, so
+ * "foo.bar.example.com" is verified if the peer has a certificate for "*.example.com".
*
* @param socket An SSL socket which has been connected to a server
* @param hostname The expected hostname of the remote server
@@ -483,7 +483,8 @@
* {@inheritDoc}
*
* <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
- * certificate hostname after connecting; if this instance was created with
+ * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+ * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
* {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
* instead.
*/
@@ -562,7 +563,8 @@
* {@inheritDoc}
*
* <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
- * certificate hostname after connecting; if this instance was created with
+ * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+ * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
* {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
* instead.
*/
@@ -585,7 +587,8 @@
* {@inheritDoc}
*
* <p>By default, this method returns a <i>connected</i> socket and verifies the peer's
- * certificate hostname after connecting; if this instance was created with
+ * certificate hostname after connecting using the {@link HostnameVerifier} obtained from
+ * {@code HttpsURLConnection.getDefaultHostnameVerifier()}; if this instance was created with
* {@link #getInsecure(int, SSLSessionCache)}, it returns a socket that is <i>not connected</i>
* instead.
*/
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index efdc968..ddbff7b 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -18,9 +18,11 @@
import android.annotation.Nullable;
import android.app.Person;
+import android.app.RemoteAction;
import android.content.Context;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
@@ -118,12 +120,60 @@
@Nullable
public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
- return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI
- ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity;
+ return (labeledIntent, resolveInfo) -> {
+ if (resolveInfo.handleAllWebDataURI) {
+ return labeledIntent.titleWithEntity;
+ }
+ if ("android".equals(resolveInfo.activityInfo.packageName)) {
+ return labeledIntent.titleWithEntity;
+ }
+ return labeledIntent.titleWithoutEntity;
+ };
}
return null;
}
+ /**
+ * Returns a list of {@link ConversationAction}s that have 0 duplicates. Two actions are
+ * duplicates if they may look the same to users. This function assumes every
+ * ConversationActions with a non-null RemoteAction also have a non-null intent in the extras.
+ */
+ public static List<ConversationAction> removeActionsWithDuplicates(
+ List<ConversationAction> conversationActions) {
+ // Ideally, we should compare title and icon here, but comparing icon is expensive and thus
+ // we use the component name of the target handler as the heuristic.
+ Map<Pair<String, String>, Integer> counter = new ArrayMap<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ Pair<String, String> representation = getRepresentation(conversationAction);
+ if (representation == null) {
+ continue;
+ }
+ Integer existingCount = counter.getOrDefault(representation, 0);
+ counter.put(representation, existingCount + 1);
+ }
+ List<ConversationAction> result = new ArrayList<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ Pair<String, String> representation = getRepresentation(conversationAction);
+ if (representation == null || counter.getOrDefault(representation, 0) == 1) {
+ result.add(conversationAction);
+ }
+ }
+ return result;
+ }
+
+ @Nullable
+ private static Pair<String, String> getRepresentation(
+ ConversationAction conversationAction) {
+ RemoteAction remoteAction = conversationAction.getAction();
+ if (remoteAction == null) {
+ return null;
+ }
+ return new Pair<>(
+ conversationAction.getAction().getTitle().toString(),
+ ExtrasUtils.getActionIntent(
+ conversationAction.getExtras()).getComponent().getPackageName());
+ }
+
private static final class PersonEncoder {
private final Map<Person, Integer> mMapping = new ArrayMap<>();
private int mNextUserId = FIRST_NON_LOCAL_USER;
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 2ad17a8..df548ae 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -29,6 +29,7 @@
*/
public final class ExtrasUtils {
+ private static final String ACTION_INTENT = "action-intent";
private static final String ACTIONS_INTENTS = "actions-intents";
private static final String FOREIGN_LANGUAGE = "foreign-language";
private static final String ENTITY_TYPE = "entity-type";
@@ -77,6 +78,22 @@
}
/**
+ * Stores {@code actionIntents} information in TextClassifier response object's extras
+ * {@code container}.
+ */
+ public static void putActionIntent(Bundle container, @Nullable Intent actionIntent) {
+ container.putParcelable(ACTION_INTENT, actionIntent);
+ }
+
+ /**
+ * Returns {@code actionIntent} information contained in a TextClassifier response object.
+ */
+ @Nullable
+ public static Intent getActionIntent(Bundle container) {
+ return container.getParcelable(ACTION_INTENT);
+ }
+
+ /**
* Returns {@code actionIntents} information contained in the TextClassification object.
*/
@Nullable
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/LabeledIntent.java
index 7544dc1..d2897b2 100644
--- a/core/java/android/view/textclassifier/LabeledIntent.java
+++ b/core/java/android/view/textclassifier/LabeledIntent.java
@@ -91,15 +91,22 @@
Context context, @Nullable TitleChooser titleChooser) {
final PackageManager pm = context.getPackageManager();
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
- final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
- ? resolveInfo.activityInfo.packageName : null;
- Icon icon = null;
+
+ if (resolveInfo == null || resolveInfo.activityInfo == null) {
+ Log.w(TAG, "resolveInfo or activityInfo is null");
+ return null;
+ }
+ final String packageName = resolveInfo.activityInfo.packageName;
+ final String className = resolveInfo.activityInfo.name;
+ if (packageName == null || className == null) {
+ Log.w(TAG, "packageName or className is null");
+ return null;
+ }
Intent resolvedIntent = new Intent(intent);
+ resolvedIntent.setComponent(new ComponentName(packageName, className));
boolean shouldShowIcon = false;
- if (packageName != null && !"android".equals(packageName)) {
- // There is a default activity handling the intent.
- resolvedIntent.setComponent(
- new ComponentName(packageName, resolveInfo.activityInfo.name));
+ Icon icon = null;
+ if (!"android".equals(packageName)) {
if (resolveInfo.activityInfo.getIconResource() != 0) {
icon = Icon.createWithResource(
packageName, resolveInfo.activityInfo.getIconResource());
@@ -113,9 +120,6 @@
}
final PendingIntent pendingIntent =
TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
- if (pendingIntent == null) {
- return null;
- }
if (titleChooser == null) {
titleChooser = DEFAULT_TITLE_CHOOSER;
}
@@ -150,6 +154,7 @@
public interface TitleChooser {
/**
* Picks a title from a {@link LabeledIntent} by looking into resolved info.
+ * {@code resolveInfo} is guaranteed to have a non-null {@code activityInfo}.
*/
@Nullable
CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 034da01..a275f0f 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -25,8 +25,6 @@
import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.drawable.AdaptiveIconDrawable;
@@ -304,53 +302,10 @@
* @throws IllegalArgumentException if context or intent is null
* @hide
*/
- @Nullable
public static PendingIntent createPendingIntent(
@NonNull final Context context, @NonNull final Intent intent, int requestCode) {
- final int flags = PendingIntent.FLAG_UPDATE_CURRENT;
- switch (getIntentType(intent, context)) {
- case IntentType.ACTIVITY:
- return PendingIntent.getActivity(context, requestCode, intent, flags);
- case IntentType.SERVICE:
- return PendingIntent.getService(context, requestCode, intent, flags);
- default:
- return null;
- }
- }
-
- @IntentType
- private static int getIntentType(@NonNull Intent intent, @NonNull Context context) {
- Preconditions.checkArgument(context != null);
- Preconditions.checkArgument(intent != null);
-
- final ResolveInfo activityRI = context.getPackageManager().resolveActivity(intent, 0);
- if (activityRI != null) {
- if (context.getPackageName().equals(activityRI.activityInfo.packageName)) {
- return IntentType.ACTIVITY;
- }
- final boolean exported = activityRI.activityInfo.exported;
- if (exported && hasPermission(context, activityRI.activityInfo.permission)) {
- return IntentType.ACTIVITY;
- }
- }
-
- final ResolveInfo serviceRI = context.getPackageManager().resolveService(intent, 0);
- if (serviceRI != null) {
- if (context.getPackageName().equals(serviceRI.serviceInfo.packageName)) {
- return IntentType.SERVICE;
- }
- final boolean exported = serviceRI.serviceInfo.exported;
- if (exported && hasPermission(context, serviceRI.serviceInfo.permission)) {
- return IntentType.SERVICE;
- }
- }
-
- return IntentType.UNSUPPORTED;
- }
-
- private static boolean hasPermission(@NonNull Context context, @NonNull String permission) {
- return permission == null
- || context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
+ return PendingIntent.getActivity(
+ context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 632328b..35cd678 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -84,12 +84,17 @@
private final GenerateLinksLogger mGenerateLinksLogger;
private final Object mLock = new Object();
+
@GuardedBy("mLock") // Do not access outside this lock.
private ModelFileManager.ModelFile mAnnotatorModelInUse;
@GuardedBy("mLock") // Do not access outside this lock.
private AnnotatorModel mAnnotatorImpl;
+
+ @GuardedBy("mLock") // Do not access outside this lock.
+ private ModelFileManager.ModelFile mLangIdModelInUse;
@GuardedBy("mLock") // Do not access outside this lock.
private LangIdModel mLangIdImpl;
+
@GuardedBy("mLock") // Do not access outside this lock.
private ModelFileManager.ModelFile mActionModelInUse;
@GuardedBy("mLock") // Do not access outside this lock.
@@ -403,6 +408,12 @@
return mFallback.suggestConversationActions(request);
}
+ /**
+ * Returns the {@link ConversationAction} result, with a non-null extras.
+ * <p>
+ * Whenever the RemoteAction is non-null, you can expect its corresponding intent
+ * with a non-null component name is in the extras.
+ */
private ConversationActions createConversationActionResult(
ConversationActions.Request request,
ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions) {
@@ -419,6 +430,7 @@
}
List<LabeledIntent> labeledIntents =
mTemplateIntentFactory.create(nativeSuggestion.getRemoteActionTemplates());
+ Bundle extras = new Bundle();
RemoteAction remoteAction = null;
// Given that we only support implicit intent here, we should expect there is just one
// intent for each action type.
@@ -428,6 +440,7 @@
LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
if (result != null) {
remoteAction = result.remoteAction;
+ ExtrasUtils.putActionIntent(extras, result.resolvedIntent);
}
}
conversationActions.add(
@@ -435,8 +448,11 @@
.setConfidenceScore(nativeSuggestion.getScore())
.setTextReply(nativeSuggestion.getResponseText())
.setAction(remoteAction)
+ .setExtras(extras)
.build());
}
+ conversationActions =
+ ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions);
String resultId = ActionsSuggestionsHelper.createResultId(
mContext,
request.getConversation(),
@@ -504,17 +520,19 @@
private LangIdModel getLangIdImpl() throws FileNotFoundException {
synchronized (mLock) {
- if (mLangIdImpl == null) {
- final ModelFileManager.ModelFile bestModel =
- mLangIdModelFileManager.findBestModelFile(null);
- if (bestModel == null) {
- throw new FileNotFoundException("No LangID model is found");
- }
+ final ModelFileManager.ModelFile bestModel =
+ mLangIdModelFileManager.findBestModelFile(null);
+ if (bestModel == null) {
+ throw new FileNotFoundException("No LangID model is found");
+ }
+ if (mLangIdImpl == null || !Objects.equals(mLangIdModelInUse, bestModel)) {
+ Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
try {
if (pfd != null) {
mLangIdImpl = new LangIdModel(pfd.getFd());
+ mLangIdModelInUse = bestModel;
}
} finally {
maybeCloseAndLogError(pfd);
@@ -527,13 +545,14 @@
@Nullable
private ActionsSuggestionsModel getActionsImpl() throws FileNotFoundException {
synchronized (mLock) {
- if (mActionsImpl == null) {
- // TODO: Use LangID to determine the locale we should use here?
- final ModelFileManager.ModelFile bestModel =
- mActionsModelFileManager.findBestModelFile(LocaleList.getDefault());
- if (bestModel == null) {
- return null;
- }
+ // TODO: Use LangID to determine the locale we should use here?
+ final ModelFileManager.ModelFile bestModel =
+ mActionsModelFileManager.findBestModelFile(LocaleList.getDefault());
+ if (bestModel == null) {
+ return null;
+ }
+ if (mActionsImpl == null || !Objects.equals(mActionModelInUse, bestModel)) {
+ Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
try {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 44f44d4..dbea13e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1996,7 +1996,9 @@
{@link #AndroidManifestApplication application} tag. -->
<declare-styleable name="AndroidManifestUsesPackage" parent="AndroidManifestApplication">
<!-- Required type of association with the package, for example "android.package.ad_service"
- if it provides an advertising service. -->
+ if it provides an advertising service. This should use the standard scoped naming
+ convention as used for other things such as package names, based on the Java naming
+ convention. -->
<attr name="packageType" format="string" />
<!-- Required name of the package you use. -->
<attr name="name" />
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 5022e30..f440953 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -21,8 +21,15 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.PendingIntent;
import android.app.Person;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +43,7 @@
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Locale;
import java.util.function.Function;
@@ -129,6 +137,73 @@
assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 1, 2000);
}
+ @Test
+ public void testDeduplicateActions() {
+ Bundle phoneExtras = new Bundle();
+ Intent phoneIntent = new Intent();
+ phoneIntent.setComponent(new ComponentName("phone", "intent"));
+ ExtrasUtils.putActionIntent(phoneExtras, phoneIntent);
+
+ Bundle anotherPhoneExtras = new Bundle();
+ Intent anotherPhoneIntent = new Intent();
+ anotherPhoneIntent.setComponent(new ComponentName("phone", "another.intent"));
+ ExtrasUtils.putActionIntent(anotherPhoneExtras, anotherPhoneIntent);
+
+ Bundle urlExtras = new Bundle();
+ Intent urlIntent = new Intent();
+ urlIntent.setComponent(new ComponentName("url", "intent"));
+ ExtrasUtils.putActionIntent(urlExtras, urlIntent);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ InstrumentationRegistry.getTargetContext(),
+ 0,
+ phoneIntent,
+ 0);
+ Icon icon = Icon.createWithData(new byte[0], 0, 0);
+ ConversationAction action =
+ new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+ .setAction(new RemoteAction(icon, "label", "1", pendingIntent))
+ .setExtras(phoneExtras)
+ .build();
+ ConversationAction actionWithSameLabel =
+ new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+ .setAction(new RemoteAction(
+ icon, "label", "2", pendingIntent))
+ .setExtras(phoneExtras)
+ .build();
+ ConversationAction actionWithSamePackageButDifferentClass =
+ new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+ .setAction(new RemoteAction(
+ icon, "label", "3", pendingIntent))
+ .setExtras(anotherPhoneExtras)
+ .build();
+ ConversationAction actionWithDifferentLabel =
+ new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
+ .setAction(new RemoteAction(
+ icon, "another_label", "4", pendingIntent))
+ .setExtras(phoneExtras)
+ .build();
+ ConversationAction actionWithDifferentPackage =
+ new ConversationAction.Builder(ConversationAction.TYPE_OPEN_URL)
+ .setAction(new RemoteAction(icon, "label", "5", pendingIntent))
+ .setExtras(urlExtras)
+ .build();
+ ConversationAction actionWithoutRemoteAction =
+ new ConversationAction.Builder(ConversationAction.TYPE_CREATE_REMINDER)
+ .build();
+
+ List<ConversationAction> conversationActions =
+ ActionsSuggestionsHelper.removeActionsWithDuplicates(
+ Arrays.asList(action, actionWithSameLabel,
+ actionWithSamePackageButDifferentClass, actionWithDifferentLabel,
+ actionWithDifferentPackage, actionWithoutRemoteAction));
+
+ assertThat(conversationActions).hasSize(3);
+ assertThat(conversationActions.get(0).getAction().getContentDescription()).isEqualTo("4");
+ assertThat(conversationActions.get(1).getAction().getContentDescription()).isEqualTo("5");
+ assertThat(conversationActions.get(2).getAction()).isNull();
+ }
+
private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC"));
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
index e4e9cde..6520c8f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
@@ -132,7 +132,6 @@
assertThat(intent.getComponent()).isNotNull();
}
-
@Test
public void resolve_missingTitle() {
assertThrows(
@@ -146,4 +145,19 @@
REQUEST_CODE
));
}
+
+ @Test
+ public void resolve_noIntentHandler() {
+ Intent intent = new Intent("some.thing.does.not.exist");
+ LabeledIntent labeledIntent = new LabeledIntent(
+ TITLE_WITHOUT_ENTITY,
+ null,
+ DESCRIPTION,
+ intent,
+ REQUEST_CODE);
+
+ LabeledIntent.Result result = labeledIntent.resolve(mContext, null);
+
+ assertThat(result).isNull();
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index d2d03e56..bcaf663 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -24,6 +24,7 @@
import android.app.RemoteAction;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.Spannable;
@@ -32,6 +33,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.google.common.truth.Truth;
+
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -403,7 +406,6 @@
ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
assertTrue(conversationActions.getConversationActions().size() > 0);
- assertTrue(conversationActions.getConversationActions().size() == 1);
for (ConversationAction conversationAction :
conversationActions.getConversationActions()) {
assertThat(conversationAction,
@@ -438,6 +440,34 @@
}
}
+ @Test
+ public void testSuggestConversationActions_openUrl() {
+ if (isTextClassifierDisabled()) return;
+ ConversationActions.Message message =
+ new ConversationActions.Message.Builder(
+ ConversationActions.Message.PERSON_USER_OTHERS)
+ .setText("Check this out: https://www.android.com")
+ .build();
+ TextClassifier.EntityConfig typeConfig =
+ new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
+ .setIncludedTypes(
+ Collections.singletonList(ConversationAction.TYPE_OPEN_URL))
+ .build();
+ ConversationActions.Request request =
+ new ConversationActions.Request.Builder(Collections.singletonList(message))
+ .setMaxSuggestions(1)
+ .setTypeConfig(typeConfig)
+ .build();
+
+ ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+ Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
+ ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
+ Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_OPEN_URL);
+ Intent actionIntent = ExtrasUtils.getActionIntent(conversationAction.getExtras());
+ Truth.assertThat(actionIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
+ Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com"));
+ }
+
private boolean isTextClassifierDisabled() {
return mClassifier == null || mClassifier == TextClassifier.NO_OP;
diff --git a/packages/SystemUI/res/drawable/circle_blue_40dp.xml b/packages/SystemUI/res/drawable/circle_blue_40dp.xml
new file mode 100644
index 0000000..00d2c52
--- /dev/null
+++ b/packages/SystemUI/res/drawable/circle_blue_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size android:height="40dp"
+ android:width="40dp" />
+ <solid android:color="#4285f4" />
+ <stroke android:color="#f1f3f4" android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/circle_white_40dp.xml b/packages/SystemUI/res/drawable/circle_white_40dp.xml
new file mode 100644
index 0000000..bcb1640
--- /dev/null
+++ b/packages/SystemUI/res/drawable/circle_white_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size android:height="40dp"
+ android:width="40dp" />
+ <solid android:color="#ffffff" />
+ <stroke android:color="#f1f3f4" android:width="1dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7e0f3ae..725ace4 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -220,48 +220,142 @@
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
-
-
</RelativeLayout>
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_guts_button_spacing"
- android:layout_marginStart="@dimen/notification_guts_button_side_margin"
- android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:gravity="center"
- android:orientation="horizontal"
+ android:orientation="vertical"
android:visibility="gone">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:layout_marginStart="@dimen/notification_guts_button_side_margin"
+ android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
+ android:gravity="center"
+ android:orientation="horizontal">
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <FrameLayout
+ android:id="@+id/int_block_wrapper"
+ android:padding="4dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:gravity="center">
+ <ImageButton
+ android:id="@+id/int_block"
+ android:background="@drawable/circle_white_40dp"
+ android:src="@drawable/ic_notification_block"
+ android:layout_gravity="center"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:clickable="false"
+ android:tint="@color/GM2_grey_400"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </FrameLayout>
+ <TextView
+ android:id="@+id/int_block_label"
+ android:text="@string/inline_block_button"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <FrameLayout
+ android:id="@+id/int_silent_wrapper"
+ android:padding="4dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:gravity="center">
+ <ImageButton
+ android:id="@+id/int_silent"
+ android:background="@drawable/circle_white_40dp"
+ android:src="@drawable/ic_notifications_silence"
+ android:layout_gravity="center"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:clickable="false"
+ android:tint="@color/GM2_grey_400"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </FrameLayout>
+ <TextView
+ android:id="@+id/int_silent_label"
+ android:text="@string/inline_silent_button_silent"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <FrameLayout
+ android:id="@+id/int_alert_wrapper"
+ android:padding="4dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:gravity="center">
+ <ImageButton
+ android:id="@+id/int_alert"
+ android:background="@drawable/circle_white_40dp"
+ android:src="@drawable/ic_notifications_alert"
+ android:layout_gravity="center"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:clickable="false"
+ android:tint="@color/GM2_grey_400"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </FrameLayout>
+ <TextView
+ android:id="@+id/int_alert_label"
+ android:text="@string/inline_silent_button_alert"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+ </LinearLayout>
+ </LinearLayout>
<TextView
- android:id="@+id/int_block"
- android:text="@string/inline_block_button"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:drawableTop="@drawable/ic_notification_block"
- android:drawableTint="?android:attr/colorAccent"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationInfo.Button"/>
+ android:id="@+id/hint_text"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationInfo.HintText" />
<TextView
- android:id="@+id/int_silent"
- android:text="@string/inline_minimize_button"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:drawableTop="@drawable/ic_notifications_silence"
- android:drawableTint="?android:attr/colorAccent"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/int_alert"
- android:text="@string/inline_keep_button"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:drawableTop="@drawable/ic_notifications_alert"
- android:drawableTint="?android:attr/colorAccent"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationInfo.Button"/>
+ android:id="@+id/done_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:paddingRight="24dp"
+ android:text="@string/inline_done_button"
+ style="@style/TextAppearance.NotificationInfo.Button" />
</LinearLayout>
</LinearLayout>
+
<com.android.systemui.statusbar.notification.row.NotificationUndoLayout
android:id="@+id/confirmation"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 223e7b0..16222f7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1608,7 +1608,7 @@
<string name="inline_silent_button_stay_silent">Stay silent</string>
<!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_alert">Alert me</string>
+ <string name="inline_silent_button_alert">Alert</string>
<!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
<string name="inline_silent_button_keep_alerting">Keep alerting</string>
@@ -1616,6 +1616,15 @@
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
+ <!-- Hint text for block button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+ <string name="hint_text_block">Blocked notifications do not appear anywhere or play a sound. You can unblock notifications in settings.</string>
+
+ <!-- Hint text for silent button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+ <string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string>
+
+ <!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
+ <string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string>
+
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4adece9..0f5df45 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -444,6 +444,19 @@
<item name="android:alpha">0.54</item>
</style>
+ <style name="TextAppearance.NotificationInfo.ButtonLabel">
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:alpha">0.54</item>
+ <item name="android:paddingTop">4dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ </style>
+
+ <style name="TextAppearance.NotificationInfo.HintText">
+ <item name="android:textSize">12sp</item>
+ <item name="android:alpha">0.54</item>
+ </style>
+
<style name="TextAppearance.NotificationInfo.Secondary.Warning">
<item name="android:textColor">?android:attr/colorError</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 3723731..2e4325b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.row;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -38,6 +37,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.os.Handler;
@@ -81,10 +81,11 @@
}
public static final int ACTION_NONE = 0;
- public static final int ACTION_UNDO = 1;
- public static final int ACTION_TOGGLE_SILENT = 2;
- public static final int ACTION_BLOCK = 3;
- public static final int ACTION_DELIVER_SILENTLY = 4;
+ static final int ACTION_UNDO = 1;
+ static final int ACTION_TOGGLE_SILENT = 2;
+ static final int ACTION_BLOCK = 3;
+ static final int ACTION_DELIVER_SILENTLY = 4;
+ private static final int ACTION_ALERT = 5;
private INotificationManager mINotificationManager;
private PackageManager mPm;
@@ -98,6 +99,7 @@
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
private boolean mWasShownHighPriority;
+ private int mNotificationBlockState = ACTION_NONE;
/**
* The last importance level chosen by the user. Null if the user has not chosen an importance
* level; non-null once the user takes an action which indicates an explicit preference.
@@ -117,7 +119,6 @@
/** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
- private boolean mNegativeUserSentiment;
/**
* String that describes how the user exit or quit out of this view, also used as a counter tag.
@@ -126,8 +127,8 @@
private OnClickListener mOnKeepShowing = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
- closeControls(v);
if (mIsForBlockingHelper) {
+ closeControls(v);
mMetricsLogger.write(getLogMaker().setCategory(
MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
@@ -135,23 +136,36 @@
}
};
- private OnClickListener mOnToggleSilent = v -> {
- handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME);
+ private OnClickListener mOnAlert = v -> {
+ mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ mChosenImportance = IMPORTANCE_DEFAULT;
+ updateButtonsAndHelpText(ACTION_ALERT);
+ };
+
+ private OnClickListener mOnDismissSettings = v -> {
+ closeControls(v);
};
private OnClickListener mOnDeliverSilently = v -> {
handleSaveImportance(
ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
+ if (!mIsForBlockingHelper) {
+ updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
+ }
};
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
+ if (!mIsForBlockingHelper) {
+ updateButtonsAndHelpText(ACTION_BLOCK);
+ }
};
private void handleSaveImportance(int action, int metricsSubtype) {
Runnable saveImportance = () -> {
- swapContent(action, true /* animate */);
+ saveImportanceAndExitReason(action);
if (mIsForBlockingHelper) {
+ swapContent(action, true /* animate */);
mMetricsLogger.write(getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
@@ -177,6 +191,7 @@
} else {
mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
}
+ saveImportanceAndExitReason(ACTION_UNDO);
swapContent(ACTION_UNDO, true /* animate */);
};
@@ -252,7 +267,6 @@
mSingleNotificationChannel = notificationChannel;
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
- mNegativeUserSentiment = isUserSentimentNegative;
mIsNonblockable = isNonblockable;
mIsForeground =
(mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
@@ -329,14 +343,6 @@
bindGroup();
if (mIsNonblockable) {
blockPrompt.setText(R.string.notification_unblockable_desc);
- } else {
- if (mNegativeUserSentiment) {
- blockPrompt.setText(R.string.inline_blocking_helper);
- } else if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
- blockPrompt.setText(R.string.inline_keep_showing_app);
- } else {
- blockPrompt.setText(R.string.inline_keep_showing);
- }
}
}
@@ -403,6 +409,7 @@
}
}
+
@VisibleForTesting
void logBlockingHelperCounter(String counterTag) {
if (mIsForBlockingHelper) {
@@ -454,21 +461,20 @@
if (showInterruptivenessSettings) {
findViewById(R.id.block_or_minimize).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
- View block = findViewById(R.id.int_block);
- TextView silent = findViewById(R.id.int_silent);
- TextView alert = findViewById(R.id.int_alert);
-
+ View done = findViewById(R.id.done_button);
+ done.setOnClickListener(mOnDismissSettings);
+ View block = findViewById(R.id.int_block_wrapper);
+ View silent = findViewById(R.id.int_silent_wrapper);
+ View alert = findViewById(R.id.int_alert_wrapper);
block.setOnClickListener(mOnStopOrMinimizeNotifications);
- if (mWasShownHighPriority) {
- silent.setOnClickListener(mOnToggleSilent);
- silent.setText(R.string.inline_silent_button_silent);
- alert.setOnClickListener(mOnKeepShowing);
- alert.setText(R.string.inline_silent_button_keep_alerting);
+ silent.setOnClickListener(mOnDeliverSilently);
+ alert.setOnClickListener(mOnAlert);
+ if (mNotificationBlockState != ACTION_NONE) {
+ updateButtonsAndHelpText(mNotificationBlockState);
+ } else if (mWasShownHighPriority) {
+ updateButtonsAndHelpText(ACTION_ALERT);
} else {
- silent.setOnClickListener(mOnKeepShowing);
- silent.setText(R.string.inline_silent_button_stay_silent);
- alert.setOnClickListener(mOnToggleSilent);
- alert.setText(R.string.inline_silent_button_alert);
+ updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
}
} else {
findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
@@ -515,6 +521,73 @@
}
}
+ private void updateButtonsAndHelpText(int blockState) {
+ mNotificationBlockState = blockState;
+ ImageView block = findViewById(R.id.int_block);
+ ImageView silent = findViewById(R.id.int_silent);
+ ImageView alert = findViewById(R.id.int_alert);
+ TextView hintText = findViewById(R.id.hint_text);
+ switch (blockState) {
+ case ACTION_BLOCK:
+ block.setBackgroundResource(R.drawable.circle_blue_40dp);
+ block.setColorFilter(Color.WHITE);
+ silent.setBackgroundResource(R.drawable.circle_white_40dp);
+ silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ alert.setBackgroundResource(R.drawable.circle_white_40dp);
+ alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ hintText.setText(R.string.hint_text_block);
+ break;
+ case ACTION_DELIVER_SILENTLY:
+ silent.setBackgroundResource(R.drawable.circle_blue_40dp);
+ silent.setColorFilter(Color.WHITE);
+ block.setBackgroundResource(R.drawable.circle_white_40dp);
+ block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ alert.setBackgroundResource(R.drawable.circle_white_40dp);
+ alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ hintText.setText(R.string.hint_text_silent);
+ break;
+ case ACTION_ALERT:
+ alert.setBackgroundResource(R.drawable.circle_blue_40dp);
+ alert.setColorFilter(Color.WHITE);
+ block.setBackgroundResource(R.drawable.circle_white_40dp);
+ block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ silent.setBackgroundResource(R.drawable.circle_white_40dp);
+ silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
+ hintText.setText(R.string.hint_text_alert);
+ break;
+ }
+ }
+
+ private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
+ switch (action) {
+ case ACTION_UNDO:
+ mChosenImportance = mStartingChannelImportance;
+ break;
+ case ACTION_DELIVER_SILENTLY:
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
+ mChosenImportance = IMPORTANCE_LOW;
+ break;
+ case ACTION_TOGGLE_SILENT:
+ mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
+ if (mWasShownHighPriority) {
+ mChosenImportance = IMPORTANCE_LOW;
+ } else {
+ mChosenImportance = IMPORTANCE_DEFAULT;
+ }
+ break;
+ case ACTION_BLOCK:
+ mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
+ if (mIsForeground) {
+ mChosenImportance = IMPORTANCE_MIN;
+ } else {
+ mChosenImportance = IMPORTANCE_NONE;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
private void swapContent(@NotificationInfoAction int action, boolean animate) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
@@ -525,32 +598,25 @@
TextView confirmationText = findViewById(R.id.confirmation_text);
View header = findViewById(R.id.header);
+ saveImportanceAndExitReason(action);
+
switch (action) {
case ACTION_UNDO:
- mChosenImportance = mStartingChannelImportance;
break;
case ACTION_DELIVER_SILENTLY:
- mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
- mChosenImportance = IMPORTANCE_LOW;
confirmationText.setText(R.string.notification_channel_silenced);
break;
case ACTION_TOGGLE_SILENT:
- mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
if (mWasShownHighPriority) {
- mChosenImportance = IMPORTANCE_LOW;
confirmationText.setText(R.string.notification_channel_silenced);
} else {
- mChosenImportance = IMPORTANCE_DEFAULT;
confirmationText.setText(R.string.notification_channel_unsilenced);
}
break;
case ACTION_BLOCK:
- mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
if (mIsForeground) {
- mChosenImportance = IMPORTANCE_MIN;
confirmationText.setText(R.string.notification_channel_minimized);
} else {
- mChosenImportance = IMPORTANCE_NONE;
confirmationText.setText(R.string.notification_channel_disabled);
}
break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 19a73f6..fb4fd31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -341,79 +341,62 @@
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
+ final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
assertEquals(VISIBLE, silent.getVisibility());
assertEquals(
mContext.getString(R.string.inline_silent_button_silent), silent.getText());
}
@Test
- public void testBindNotification_SilenceButton_CurrentlySilent() throws Exception {
+ public void testBindNotification_verifyButtonTexts() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
+ final TextView block = mNotificationInfo.findViewById(R.id.int_block_label);
+ final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label);
+ final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
assertEquals(VISIBLE, silent.getVisibility());
+ assertEquals(VISIBLE, block.getVisibility());
+ assertEquals(VISIBLE, alert.getVisibility());
assertEquals(
- mContext.getString(R.string.inline_silent_button_stay_silent),
+ mContext.getString(R.string.inline_silent_button_silent),
silent.getText());
+ assertEquals(
+ mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+ assertEquals(
+ mContext.getString(R.string.inline_block_button), block.getText());
}
@Test
- public void testBindNotification_AlertButton_CurrentlySilent() throws Exception {
+ public void testBindNotification_verifyHintTextForSilent() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
- final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
- assertEquals(VISIBLE, alert.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+ TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+ assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText());
}
@Test
- public void testBindNotification_UnSilenceButton_currentlyAlerting() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
- assertEquals(VISIBLE, alert.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText());
- }
-
- @Test
- public void testBindNotification_ChannelImportanceUnspecified_NotifAlerting() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
- final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
- assertEquals(VISIBLE, silent.getVisibility());
- assertEquals(VISIBLE, alert.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_silent), silent.getText());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_keep_alerting), alert.getText());
- }
-
- @Test
- public void testBindNotification_ChannelImportanceUnspecified_NotifSilent() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+ public void testBindNotification_verifyHintTextForBlock() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent);
- final TextView alert = mNotificationInfo.findViewById(R.id.int_alert);
- assertEquals(VISIBLE, silent.getVisibility());
- assertEquals(VISIBLE, alert.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_stay_silent), silent.getText());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_alert), alert.getText());
+ View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper);
+ blockWrapper.performClick();
+ TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+ assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText());
+ }
+
+ @Test
+ public void testBindNotification_verifyHintTextForAlert() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ IMPORTANCE_DEFAULT, true);
+ TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
+ assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText());
}
@Test
@@ -560,16 +543,6 @@
}
@Test
- public void testbindNotification_BlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false,
- true, true, IMPORTANCE_DEFAULT, true);
- final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
- assertEquals(View.VISIBLE, view.getVisibility());
- assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
- }
-
- @Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
@@ -687,8 +660,8 @@
true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -709,8 +682,8 @@
true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -842,7 +815,7 @@
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- IMPORTANCE_DEFAULT, false);
+ true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -861,8 +834,8 @@
true, false,
IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
@@ -929,7 +902,7 @@
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- IMPORTANCE_DEFAULT, false);
+ true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -944,7 +917,7 @@
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
+ true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -1014,63 +987,14 @@
}
@Test
- public void testBlockUndoDoesNotBlockNotificationChannel_notBlockingHelper() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
- null, null, null,
- true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
- mNotificationInfo.findViewById(R.id.undo).performClick();
- waitForStopButton();
- // mNotificationInfo.handleCloseControls doesn't get called by this interaction.
-
- ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
- verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture());
- assertEquals(MetricsEvent.ACTION_SAVE_IMPORTANCE,
- logMakerCaptor.getValue().getCategory());
- assertEquals(MetricsEvent.TYPE_DISMISS,
- logMakerCaptor.getValue().getType());
- assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
- logMakerCaptor.getValue().getSubtype());
-
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
- public void testMinUndoDoesNotMinNotificationChannel_notBlockingHelper() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
- null, null, null, true,
- true, IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.minimize).performClick();
- waitForUndoButton();
- mNotificationInfo.findViewById(R.id.undo).performClick();
- waitForStopButton();
- // mNotificationInfo.handleCloseControls doesn't get called by this code path
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, times(0)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
public void testSilenceCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.int_silent).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1090,8 +1014,8 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.int_alert).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1112,8 +1036,8 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.int_silent).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1134,8 +1058,8 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
- mNotificationInfo.findViewById(R.id.int_alert).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1153,7 +1077,7 @@
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- IMPORTANCE_DEFAULT, false);
+ true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -1171,8 +1095,8 @@
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(false, false);
mTestableLooper.processAllMessages();
@@ -1188,9 +1112,8 @@
(Runnable saveImportance, StatusBarNotification sbn) -> {
}, null, null, true, true, IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mTestableLooper.processAllMessages();
- ensureNoUndoButton();
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -1207,12 +1130,12 @@
}, null, null, true, false, IMPORTANCE_DEFAULT, false
);
- mNotificationInfo.findViewById(R.id.int_block).performClick();
+ mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
+ mNotificationInfo.findViewById(R.id.done_button).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
- waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1231,78 +1154,11 @@
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- IMPORTANCE_DEFAULT, false);
+ true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
assertTrue(confirmationText.getText().toString().contains("minimized"));
}
-
- @Test
- public void testUndoText_block() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
- TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
- assertTrue(confirmationText.getText().toString().contains("won't see"));
- }
-
- @Test
- public void testUndoText_silence() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
-
- mNotificationInfo.findViewById(R.id.int_silent).performClick();
- waitForUndoButton();
- TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
- assertEquals(mContext.getString(R.string.notification_channel_silenced),
- confirmationText.getText());
- }
-
- @Test
- public void testUndoText_unsilence() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_alert).performClick();
- waitForUndoButton();
- TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
- assertEquals(mContext.getString(R.string.notification_channel_unsilenced),
- confirmationText.getText());
- }
-
- @Test
- public void testNoHeaderOnConfirmation() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
- assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility());
- }
-
- @Test
- public void testHeaderOnUndo() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- waitForUndoButton();
- mNotificationInfo.findViewById(R.id.undo).performClick();
- waitForStopButton();
- assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
- }
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index abc1066a..0387774 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -519,10 +519,10 @@
public void setProcess(ProcessRecord _proc) {
app = _proc;
- if (pendingConnectionGroup > 0) {
- app.connectionService = this;
- app.connectionGroup = pendingConnectionGroup;
- app.connectionImportance = pendingConnectionImportance;
+ if (pendingConnectionGroup > 0 && _proc != null) {
+ _proc.connectionService = this;
+ _proc.connectionGroup = pendingConnectionGroup;
+ _proc.connectionImportance = pendingConnectionImportance;
pendingConnectionGroup = pendingConnectionImportance = 0;
}
if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index c072d4e..83c0af9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,7 +59,7 @@
public void setUpOnDisplay(DisplayContent dc) {
mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
mTask = createTaskInStack(mStack, 0 /* userId */);
- mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
+ mToken = WindowTestUtils.createTestAppWindowToken(dc);
mTask.addChild(mToken, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index a98a604..db04f11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -60,7 +60,7 @@
MockitoAnnotations.initMocks(this);
mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
+ ACTIVITY_TYPE_STANDARD);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 68b40b9..70c8c93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -81,8 +81,7 @@
public void setUp() throws Exception {
mStack = createTaskStackOnDisplay(mDisplayContent);
mTask = createTaskInStack(mStack, 0 /* userId */);
- mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
- false /* skipOnParentChanged */);
+ mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mTask.addChild(mToken, 0);
}
@@ -219,9 +218,6 @@
@Test
public void testSizeCompatBounds() {
- // The real surface transaction is unnecessary.
- mToken.setSkipPrepareSurfaces(true);
-
final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
.getBounds();
fixedBounds.set(0, 0, 1200, 1600);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 0dec8ee..a7a785d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -56,24 +56,15 @@
static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
synchronized (dc.mWmService.mGlobalLock) {
- return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
- }
- }
-
- static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
- boolean skipOnParentChanged) {
- synchronized (dc.mWmService.mGlobalLock) {
- return new TestAppWindowToken(dc, skipOnParentChanged);
+ return new TestAppWindowToken(dc);
}
}
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
static class TestAppWindowToken extends AppWindowToken {
boolean mOnTop = false;
- private boolean mSkipPrepareSurfaces;
- boolean mSkipOnParentChanged = true;
- private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
+ private TestAppWindowToken(DisplayContent dc) {
super(dc.mWmService, new IApplicationToken.Stub() {
@Override
public String getName() {
@@ -81,7 +72,6 @@
}
}, new ComponentName("", ""), false, dc, true /* fillsParent */);
mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
- mSkipOnParentChanged = skipOnParentChanged;
mActivityRecord = mock(ActivityRecord.class);
mActivityRecord.app = mock(WindowProcessController.class);
}
@@ -103,44 +93,10 @@
}
@Override
- void onParentChanged() {
- if (!mSkipOnParentChanged) {
- super.onParentChanged();
- } else {
- updateConfigurationFromParent(this);
- }
- }
-
- @Override
boolean isOnTop() {
return mOnTop;
}
- @Override
- void prepareSurfaces() {
- if (!mSkipPrepareSurfaces) {
- super.prepareSurfaces();
- }
- }
-
- void setSkipPrepareSurfaces(boolean ignore) {
- mSkipPrepareSurfaces = ignore;
- }
- }
-
- /**
- * Used when we don't want to perform surface related operation in
- * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration
- * still needs to propagate from parent.
- *
- * @see ConfigurationContainer#onParentChanged
- */
- static void updateConfigurationFromParent(WindowContainer container) {
- final WindowContainer parent = container.getParent();
- if (parent != null) {
- container.onConfigurationChanged(parent.getConfiguration());
- container.onMergedOverrideConfigurationChanged();
- }
}
static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
@@ -246,10 +202,5 @@
mHasSurface = hadSurface;
}
-
- @Override
- void onParentChanged() {
- updateConfigurationFromParent(this);
- }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 032eba1..fb698d9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -269,16 +269,10 @@
WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
windowingMode, int activityType) {
- return createTestAppWindowToken(dc, windowingMode, activityType,
- false /*skipOnParentChanged */);
- }
-
- WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
- windowingMode, int activityType, boolean skipOnParentChanged) {
final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
final Task task = createTaskInStack(stack, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken appWindowToken =
- WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
+ WindowTestUtils.createTestAppWindowToken(dc);
task.addChild(appWindowToken, 0);
return appWindowToken;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2fc6efa..7d7c3985 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -43,7 +43,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -212,7 +211,6 @@
return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
mDisplayContent.mInputMethodTarget = null;
@@ -230,7 +228,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -250,7 +247,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -277,7 +273,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -301,7 +296,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -329,7 +323,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -344,7 +337,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
@@ -432,7 +424,6 @@
}
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,