Merge "WifiManager#getCountryCode: clarify doc on return format" into rvc-dev
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 4b4fb96..0585825 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -24,6 +24,8 @@
import android.annotation.TestApi;
import android.content.Context;
+import libcore.util.EmptyArray;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
@@ -100,6 +102,28 @@
}
/**
+ * Get a list of app IDs of app that are whitelisted. This does not include temporarily
+ * whitelisted apps.
+ *
+ * @param includingIdle Set to true if the app should be whitelisted from device idle as well
+ * as other power save restrictions
+ * @hide
+ */
+ @NonNull
+ public int[] getWhitelistedAppIds(boolean includingIdle) {
+ try {
+ if (includingIdle) {
+ return mService.getAppIdWhitelist();
+ } else {
+ return mService.getAppIdWhitelistExceptIdle();
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return EmptyArray.INT;
+ }
+ }
+
+ /**
* Add an app to the temporary whitelist for a short amount of time.
*
* @param packageName The package to add to the temp whitelist
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 8c08e75..fc29c9c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2833,6 +2833,13 @@
}
js.overrideState = (force) ? JobStatus.OVERRIDE_FULL : JobStatus.OVERRIDE_SOFT;
+
+ // Re-evaluate constraints after the override is set in case one of the overridden
+ // constraints was preventing another constraint from thinking it needed to update.
+ for (int c = mControllers.size() - 1; c >= 0; --c) {
+ mControllers.get(c).reevaluateStateLocked(uid);
+ }
+
if (!js.isConstraintsSatisfied()) {
js.overrideState = 0;
return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
diff --git a/api/current.txt b/api/current.txt
index 265bed1..e06f329 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -56041,7 +56041,7 @@
field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
- field public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
+ field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 24873b8..7c6eff1 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -72,19 +72,26 @@
* also monitor this Intent in order to be informed of mode changes or
* prevent the normal car UI from being displayed by setting the result
* of the broadcast to {@link Activity#RESULT_CANCELED}.
+ * <p>
+ * This intent is broadcast when {@link #getCurrentModeType()} transitions to
+ * {@link Configuration#UI_MODE_TYPE_CAR} from some other ui mode.
*/
public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE";
/**
- * Broadcast sent when the device's UI has switched to car mode, either by being placed in a car
- * dock or explicit action of the user.
+ * Broadcast sent when an app has entered car mode using either {@link #enableCarMode(int)} or
+ * {@link #enableCarMode(int, int)}.
* <p>
- * In addition to the behavior for {@link #ACTION_ENTER_CAR_MODE}, this broadcast includes the
- * package name of the app which requested to enter car mode in the
- * {@link #EXTRA_CALLING_PACKAGE}. If an app requested to enter car mode using
- * {@link #enableCarMode(int, int)} and specified a priority this will be specified in the
+ * Unlike {@link #ACTION_ENTER_CAR_MODE}, which is only sent when the global car mode state
+ * (i.e. {@link #getCurrentModeType()}) transitions to {@link Configuration#UI_MODE_TYPE_CAR},
+ * this intent is sent any time an app declares it has entered car mode. Thus, this intent is
+ * intended for use by a component which needs to know not only when the global car mode state
+ * changed, but also when the highest priority app declaring car mode has changed.
+ * <p>
+ * This broadcast includes the package name of the app which requested to enter car mode in
+ * {@link #EXTRA_CALLING_PACKAGE}. The priority the app entered car mode at is specified in
* {@link #EXTRA_PRIORITY}.
- *
+ * <p>
* This is primarily intended to be received by other components of the Android OS.
* <p>
* Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES}
@@ -98,17 +105,25 @@
* Broadcast sent when the device's UI has switch away from car mode back
* to normal mode. Typically used by a car mode app, to dismiss itself
* when the user exits car mode.
+ * <p>
+ * This intent is broadcast when {@link #getCurrentModeType()} transitions from
+ * {@link Configuration#UI_MODE_TYPE_CAR} to some other ui mode.
*/
public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE";
/**
- * Broadcast sent when the device's UI has switched away from car mode back to normal mode.
- * Typically used by a car mode app, to dismiss itself when the user exits car mode.
+ * Broadcast sent when an app has exited car mode using {@link #disableCarMode(int)}.
* <p>
- * In addition to the behavior for {@link #ACTION_EXIT_CAR_MODE}, this broadcast includes the
- * package name of the app which requested to exit car mode in {@link #EXTRA_CALLING_PACKAGE}.
- * If an app requested to enter car mode using {@link #enableCarMode(int, int)} and specified a
- * priority this will be specified in the {@link #EXTRA_PRIORITY} when exiting car mode.
+ * Unlike {@link #ACTION_EXIT_CAR_MODE}, which is only sent when the global car mode state
+ * (i.e. {@link #getCurrentModeType()}) transitions to a non-car mode state such as
+ * {@link Configuration#UI_MODE_TYPE_NORMAL}, this intent is sent any time an app declares it
+ * has exited car mode. Thus, this intent is intended for use by a component which needs to
+ * know not only when the global car mode state changed, but also when the highest priority app
+ * declaring car mode has changed.
+ * <p>
+ * This broadcast includes the package name of the app which requested to exit car mode in
+ * {@link #EXTRA_CALLING_PACKAGE}. The priority the app originally entered car mode at is
+ * specified in {@link #EXTRA_PRIORITY}.
* <p>
* If {@link #DISABLE_CAR_MODE_ALL_PRIORITIES} is used when disabling car mode (i.e. this is
* initiated by the user via the persistent car mode notification), this broadcast is sent once
@@ -260,9 +275,7 @@
* An app may request to enter car mode when the system is already in car mode. The app may
* specify a "priority" when entering car mode. The device will remain in car mode
* (i.e. {@link #getCurrentModeType()} is {@link Configuration#UI_MODE_TYPE_CAR}) as long as
- * there is a priority level at which car mode have been enabled. For example assume app A
- * enters car mode at priority level 100, and then app B enters car mode at the default priority
- * (0). If app A exits car mode, the device will remain in car mode until app B exits car mode.
+ * there is a priority level at which car mode have been enabled.
* <p>
* Specifying a priority level when entering car mode is important in cases where multiple apps
* on a device implement a car-mode {@link android.telecom.InCallService} (see
@@ -275,18 +288,28 @@
* correct conditions exist for that app to be in car mode. The device maker should ensure that
* where multiple apps exist on the device which can potentially enter car mode, appropriate
* priorities are used to ensure that calls delivered by the
- * {@link android.telecom.InCallService} API are delivered to the highest priority app.
- * If app A and app B can both potentially enable car mode, and it is desired that app B is the
- * one which should receive call information, the priority for app B should be higher than the
- * one for app A.
+ * {@link android.telecom.InCallService} API are sent to the highest priority app given the
+ * desired behavior of the car mode experience on the device.
* <p>
- * When an app uses a priority to enable car mode, they can disable car mode at the specified
+ * If app A and app B both meet their own criteria to enable car mode, and it is desired that
+ * app B should be the one which should receive call information in that scenario, the priority
+ * for app B should be higher than the one for app A. The higher priority of app B compared to
+ * A means it will be bound to during calls and app A will not. When app B no longer meets its
+ * criteria for providing a car mode experience it uses {@link #disableCarMode(int)} to disable
+ * car mode at its priority level. The system will then unbind from app B and bind to app A as
+ * it has the next highest priority.
+ * <p>
+ * When an app enables car mode at a certain priority, it can disable car mode at the specified
* priority level using {@link #disableCarMode(int)}. An app may only enable car mode at a
* single priority.
* <p>
- * Public apps are assumed to enter/exit car mode at {@link #DEFAULT_PRIORITY}.
+ * Public apps are assumed to enter/exit car mode at the lowest priority,
+ * {@link #DEFAULT_PRIORITY}.
*
- * @param priority The declared priority for the caller.
+ * @param priority The declared priority for the caller, where {@link #DEFAULT_PRIORITY} (0) is
+ * the lowest priority and higher numbers represent a higher priority.
+ * The priorities apps declare when entering car mode is determined by the
+ * device manufacturer based on the desired car mode experience.
* @param flags Car mode flags.
* @hide
*/
@@ -331,11 +354,11 @@
/**
* The default priority used for entering car mode.
* <p>
- * Callers of the {@link UiModeManager#enableCarMode(int)} priority will be assigned the
- * default priority.
+ * Callers of the {@link #enableCarMode(int)} priority will be assigned the default priority.
+ * This is considered the lowest possible priority for enabling car mode.
* <p>
* System apps can specify a priority other than the default priority when using
- * {@link UiModeManager#enableCarMode(int, int)} to enable car mode.
+ * {@link #enableCarMode(int, int)} to enable car mode.
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 40754df..b4f2159 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1795,6 +1795,7 @@
// Default false
.setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
.setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
+ .setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa))
.setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
.setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
.setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 3f8c0fe..ab224a2 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -101,8 +101,7 @@
} catch (IOException e) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException(
- "Failed to add file to IncFS: " + file.getName() + ", reason: "
- + e.getMessage(), e.getCause());
+ "Failed to add file to IncFS: " + file.getName() + ", reason: ", e);
}
} else {
throw new IOException("Unknown file location: " + file.getLocation());
@@ -117,6 +116,7 @@
return result;
} catch (IOException e) {
+ Slog.e(TAG, "Failed to initialize Incremental file storages. Cleaning up...", e);
if (result != null) {
result.cleanUp();
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index dea495b..bf31bc2 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -424,14 +424,18 @@
*/
private static IncrementalSignature parseV4Signature(@Nullable byte[] v4signatureBytes)
throws IOException {
- if (v4signatureBytes == null) {
+ if (v4signatureBytes == null || v4signatureBytes.length == 0) {
return null;
}
final V4Signature signature;
try (DataInputStream input = new DataInputStream(
new ByteArrayInputStream(v4signatureBytes))) {
- signature = V4Signature.readFrom(input);
+ try {
+ signature = V4Signature.readFrom(input);
+ } catch (IOException e) {
+ throw new IOException("Failed to read v4 signature:", e);
+ }
}
if (!signature.isVersionSupported()) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9f83862..454953c 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -555,8 +555,8 @@
*
* @see AccessibilityAction#ACTION_PRESS_AND_HOLD
*/
- public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT =
- "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
+ public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT =
+ "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
/**
* Argument to represent the IME action Id to press the returning key on a node.
@@ -4915,10 +4915,13 @@
* held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK}
* instead of this action, and nodes should not expose both actions.
* <p>
- * Use {@link #ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT} to specify how long the
- * node is pressed. To ensure reasonable behavior, the first value of this argument should
- * be 0 and the others should greater than 0 and less than 10,000. UIs requested to hold for
- * times outside of this range should ignore the action.
+ * When calling {@code performAction(ACTION_PRESS_AND_HOLD, bundle}, use
+ * {@link #ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT} to specify how long the
+ * node is pressed. The first time an accessibility service performs ACTION_PRES_AND_HOLD
+ * on a node, it must specify 0 as ACTION_ARGUMENT_PRESS_AND_HOLD, so the application is
+ * notified that the held state has started. To ensure reasonable behavior, the values
+ * must be increased incrementally and may not exceed 10,000. UIs requested
+ * to hold for times outside of this range should ignore the action.
* <p>
* The total time the element is held could be specified by an accessibility user up-front,
* or may depend on what happens on the UI as the user continues to request the hold.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index aca265b..482d5b25 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1634,14 +1634,20 @@
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
- try {
- Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed "
- + "soon. If you are using android.support.v7.widget.SearchView, please update "
- + "to version 26.0 or newer version.");
- mService.showSoftInput(
- mClient, mCurRootView.getView().getWindowToken(), flags, resultReceiver);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mH) {
+ try {
+ Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
+ + " removed soon. If you are using android.support.v7.widget.SearchView,"
+ + " please update to version 26.0 or newer version.");
+ if (mCurRootView == null || mCurRootView.getView() == null) {
+ Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
+ return;
+ }
+ mService.showSoftInput(
+ mClient, mCurRootView.getView().getWindowToken(), flags, resultReceiver);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@@ -1986,11 +1992,17 @@
@UnsupportedAppUsage
void closeCurrentInput() {
- try {
- mService.hideSoftInput(
- mClient, mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mH) {
+ if (mCurRootView == null || mCurRootView.getView() == null) {
+ Log.w(TAG, "No current root view, ignoring closeCurrentInput()");
+ return;
+ }
+ try {
+ mService.hideSoftInput(
+ mClient, mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 76f8fdb..f00f4fc 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -228,6 +228,9 @@
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
+ <!-- Permissions required for reading and logging compat changes -->
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
</privapp-permissions>
<privapp-permissions package="com.android.networkstack">
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 58c73b5..bbd7399 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -654,6 +654,13 @@
* the right tracks. Also, it needs to make sure the samples for each track
* are written in chronological order (e.g. in the order they are provided
* by the encoder.)</p>
+ * <p> For MPEG4 media format, the duration of the last sample in a track can be set by passing
+ * an additional empty buffer(bufferInfo.size = 0) with MediaCodec.BUFFER_FLAG_END_OF_STREAM
+ * flag and a suitable presentation timestamp set in bufferInfo parameter as the last sample of
+ * that track. This last sample's presentation timestamp shall be a sum of the presentation
+ * timestamp and the duration preferred for the original last sample. If no explicit
+ * END_OF_STREAM sample was passed, then the duration of the last sample would be the same as
+ * that of the sample before that.</p>
* @param byteBuf The encoded sample.
* @param trackIndex The track index for this sample.
* @param bufferInfo The buffer information related to this sample.
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 8c98ac9..15b39f2 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -52,6 +52,12 @@
JavaThread(JavaThread &&) = delete; // uses "this" ptr, not moveable.
+ ~JavaThread() {
+ join(); // manually block until the future is ready as std::future
+ // destructor doesn't block unless it comes from std::async
+ // and it is the last reference to shared state.
+ }
+
void join() const {
mFuture.wait();
}
@@ -64,8 +70,9 @@
static int staticFunction(void *data) {
JavaThread *jt = static_cast<JavaThread *>(data);
jt->mF();
- jt->mIsClosed = true;
jt->mPromise.set_value();
+ jt->mIsClosed = true; // publicly inform that we are closed
+ // after we have accessed all variables.
return 0;
}
diff --git a/packages/SettingsProvider/res/values-as/strings.xml b/packages/SettingsProvider/res/values-as/strings.xml
index 5235e3c..89b7c1e 100644
--- a/packages/SettingsProvider/res/values-as/strings.xml
+++ b/packages/SettingsProvider/res/values-as/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"ছেটিংছসমূহৰ সঞ্চয়াগাৰ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"হটস্পটৰ ছেটিংসমূহ সলনি হৈছে"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"সবিশেষ চাবলৈ টিপক"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-bn/strings.xml b/packages/SettingsProvider/res/values-bn/strings.xml
index c785cd8..b2eaa2f 100644
--- a/packages/SettingsProvider/res/values-bn/strings.xml
+++ b/packages/SettingsProvider/res/values-bn/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"সেটিংস স্টোরেজ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"হটস্পট সেটিংসে পরিবর্তন করা হয়েছে"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"বিশদে জানতে ট্যাপ করুন"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml
index a469936..b006ac9 100644
--- a/packages/SettingsProvider/res/values-de/strings.xml
+++ b/packages/SettingsProvider/res/values-de/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"Einstellungsspeicher"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"Hotspot-Einstellungen wurden geändert"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Für Details tippen"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml
index 3f1fa61..a3d3469 100644
--- a/packages/SettingsProvider/res/values-es/strings.xml
+++ b/packages/SettingsProvider/res/values-es/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"Se han cambiado los ajustes del punto de acceso"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Toca para ver información detallada"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-gu/strings.xml b/packages/SettingsProvider/res/values-gu/strings.xml
index 074675f..1f91f71 100644
--- a/packages/SettingsProvider/res/values-gu/strings.xml
+++ b/packages/SettingsProvider/res/values-gu/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"સેટિંગ્સ સંગ્રહ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"હૉટસ્પૉટ સેટિંગ બદલાઈ ગઈ છે"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"વિગતો જોવા માટે ટૅપ કરો"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-kn/strings.xml b/packages/SettingsProvider/res/values-kn/strings.xml
index 0b0000d..400b358 100644
--- a/packages/SettingsProvider/res/values-kn/strings.xml
+++ b/packages/SettingsProvider/res/values-kn/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಸಂಗ್ರಹಣೆ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ಹಾಟ್ಸ್ಪಾಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳು ಬದಲಾಗಿವೆ"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ವಿವರಗಳನ್ನು ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-ml/strings.xml b/packages/SettingsProvider/res/values-ml/strings.xml
index 54a05fb..8df8ce4 100644
--- a/packages/SettingsProvider/res/values-ml/strings.xml
+++ b/packages/SettingsProvider/res/values-ml/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"സംഭരണ ക്രമീകരണം"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ഹോട്ട്സ്പോട്ട് ക്രമീകരണം മാറിയിരിക്കുന്നു"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"വിശദാംശങ്ങൾ കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-mr/strings.xml b/packages/SettingsProvider/res/values-mr/strings.xml
index 0e80f70..51b8b19 100644
--- a/packages/SettingsProvider/res/values-mr/strings.xml
+++ b/packages/SettingsProvider/res/values-mr/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"सेटिंग्ज संचयन"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"हॉटस्पॉट सेटिंग्ज बदलल्या आहेत"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"तपशील पाहण्यासाठी टॅप करा"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-ne/strings.xml b/packages/SettingsProvider/res/values-ne/strings.xml
index bb04b6ba..a0e3465 100644
--- a/packages/SettingsProvider/res/values-ne/strings.xml
+++ b/packages/SettingsProvider/res/values-ne/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"सेटिङहरू भण्डारण"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"हटस्पटका सेटिङ परिवर्तन गरिएका छन्"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"विवरणहरू हेर्न ट्याप गर्नुहोस्"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 4b73a55..486d8ff 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ହଟସ୍ପଟ୍ ସେଟିଂସ୍ ବଦଳାଯାଇଛି"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ବିବରଣୀ ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-pa/strings.xml b/packages/SettingsProvider/res/values-pa/strings.xml
index 5af8d6a..1c9a985 100644
--- a/packages/SettingsProvider/res/values-pa/strings.xml
+++ b/packages/SettingsProvider/res/values-pa/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"ਸੈਟਿੰਗਾਂ ਸਟੋਰੇਜ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ਹੌਟਸਪੌਟ ਸੈਟਿੰਗਾਂ ਬਦਲ ਗਈਆਂ ਹਨ"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ਵੇਰਵੇ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-te/strings.xml b/packages/SettingsProvider/res/values-te/strings.xml
index b1955ed..fa2191f 100644
--- a/packages/SettingsProvider/res/values-te/strings.xml
+++ b/packages/SettingsProvider/res/values-te/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"సెట్టింగ్ల నిల్వ"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"హాట్స్పాట్ సెట్టింగ్లు మార్చబడ్డాయి"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"వివరాలను చూడటానికి ట్యాప్ చేయండి"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values-ur/strings.xml b/packages/SettingsProvider/res/values-ur/strings.xml
index 2ce44b1..5a1b0f9 100644
--- a/packages/SettingsProvider/res/values-ur/strings.xml
+++ b/packages/SettingsProvider/res/values-ur/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"ترتیبات کا اسٹوریج"</string>
- <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
- <skip />
- <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
- <skip />
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"ہاٹ اسپاٹ کی ترتیبات تبدیل ہو گئیں"</string>
+ <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"تفصیلات دیکھنے کے لیے تھپتھپائیں"</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 44cec966..14903cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -63,7 +64,7 @@
* 6. Top-level entries are assigned sections by NotifSections ({@link #setSections})
* 7. Top-level entries within the same section are sorted by NotifComparators
* ({@link #setComparators})
- * 8. Pre-render filters are fired on each notification ({@link #addPreRenderFilter})
+ * 8. Finalize filters are fired on each notification ({@link #addFinalizeFilter})
* 9. OnBeforeRenderListListeners are fired ({@link #addOnBeforeRenderListListener})
* 9. The list is handed off to the view layer to be rendered
*/
@@ -169,14 +170,22 @@
}
/**
+ * Called after notifs have been filtered once, grouped, and sorted but before the final
+ * filtering.
+ */
+ public void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) {
+ mShadeListBuilder.addOnBeforeFinalizeFilterListener(listener);
+ }
+
+ /**
* Registers a filter with the pipeline to filter right before rendering the list (after
* pre-group filtering, grouping, promoting and sorting occurs). Filters are
* called on each notification in the order that they were registered. If any filter returns
* true, the notification is removed from the pipeline (and no other filters are called on that
* notif).
*/
- public void addPreRenderFilter(NotifFilter filter) {
- mShadeListBuilder.addPreRenderFilter(filter);
+ public void addFinalizeFilter(NotifFilter filter) {
+ mShadeListBuilder.addFinalizeFilter(filter);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 7631120..5b73b1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -18,11 +18,11 @@
import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZE_FILTERING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_GROUPING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_IDLE;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_GROUP_FILTERING;
-import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_RENDER_FILTERING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_RESETTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
@@ -36,6 +36,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -82,7 +83,7 @@
private final List<NotifFilter> mNotifPreGroupFilters = new ArrayList<>();
private final List<NotifPromoter> mNotifPromoters = new ArrayList<>();
- private final List<NotifFilter> mNotifPreRenderFilters = new ArrayList<>();
+ private final List<NotifFilter> mNotifFinalizeFilters = new ArrayList<>();
private final List<NotifComparator> mNotifComparators = new ArrayList<>();
private final List<NotifSection> mNotifSections = new ArrayList<>();
@@ -90,6 +91,8 @@
new ArrayList<>();
private final List<OnBeforeSortListener> mOnBeforeSortListeners =
new ArrayList<>();
+ private final List<OnBeforeFinalizeFilterListener> mOnBeforeFinalizeFilterListeners =
+ new ArrayList<>();
private final List<OnBeforeRenderListListener> mOnBeforeRenderListListeners =
new ArrayList<>();
@Nullable private OnRenderListListener mOnRenderListListener;
@@ -142,6 +145,13 @@
mOnBeforeSortListeners.add(listener);
}
+ void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) {
+ Assert.isMainThread();
+
+ mPipelineState.requireState(STATE_IDLE);
+ mOnBeforeFinalizeFilterListeners.add(listener);
+ }
+
void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
Assert.isMainThread();
@@ -157,12 +167,12 @@
filter.setInvalidationListener(this::onPreGroupFilterInvalidated);
}
- void addPreRenderFilter(NotifFilter filter) {
+ void addFinalizeFilter(NotifFilter filter) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
- mNotifPreRenderFilters.add(filter);
- filter.setInvalidationListener(this::onPreRenderFilterInvalidated);
+ mNotifFinalizeFilters.add(filter);
+ filter.setInvalidationListener(this::onFinalizeFilterInvalidated);
}
void addPromoter(NotifPromoter promoter) {
@@ -237,12 +247,12 @@
rebuildListIfBefore(STATE_SORTING);
}
- private void onPreRenderFilterInvalidated(NotifFilter filter) {
+ private void onFinalizeFilterInvalidated(NotifFilter filter) {
Assert.isMainThread();
- mLogger.logPreRenderFilterInvalidated(filter.getName(), mPipelineState.getState());
+ mLogger.logFinalizeFilterInvalidated(filter.getName(), mPipelineState.getState());
- rebuildListIfBefore(STATE_PRE_RENDER_FILTERING);
+ rebuildListIfBefore(STATE_FINALIZE_FILTERING);
}
private void onNotifComparatorInvalidated(NotifComparator comparator) {
@@ -298,8 +308,9 @@
// Step 6: Filter out entries after pre-group filtering, grouping, promoting and sorting
// Now filters can see grouping information to determine whether to filter or not.
- mPipelineState.incrementTo(STATE_PRE_RENDER_FILTERING);
- filterNotifs(mNotifList, mNewNotifList, mNotifPreRenderFilters);
+ dispatchOnBeforeFinalizeFilter(mReadOnlyNotifList);
+ mPipelineState.incrementTo(STATE_FINALIZE_FILTERING);
+ filterNotifs(mNotifList, mNewNotifList, mNotifFinalizeFilters);
applyNewNotifList();
pruneIncompleteGroups(mNotifList);
@@ -772,6 +783,12 @@
}
}
+ private void dispatchOnBeforeFinalizeFilter(List<ListEntry> entries) {
+ for (int i = 0; i < mOnBeforeFinalizeFilterListeners.size(); i++) {
+ mOnBeforeFinalizeFilterListeners.get(i).onBeforeFinalizeFilter(entries);
+ }
+ }
+
private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 8b2a07d..370de83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -77,7 +77,7 @@
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
- mNotifPipeline.addPreRenderFilter(mNotifFilter);
+ mNotifPipeline.addFinalizeFilter(mNotifFilter);
mBubbleController.addNotifCallback(mNotifCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index a26ee545..aaf71f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -87,7 +87,7 @@
@Override
public void attach(NotifPipeline pipeline) {
setupInvalidateNotifListCallbacks();
- pipeline.addPreRenderFilter(mNotifFilter);
+ pipeline.addFinalizeFilter(mNotifFilter);
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 1c8fdac..ebecf18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -16,31 +16,39 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
+import android.annotation.IntDef;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
-import java.util.ArrayList;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * Kicks off notification inflation and view rebinding when a notification is added or updated.
+ * Kicks off core notification inflation and view rebinding when a notification is added or updated.
* Aborts inflation when a notification is removed.
*
- * If a notification is not done inflating, this coordinator will filter the notification out
- * from the {@link ShadeListBuilder}.
+ * If a notification was uninflated, this coordinator will filter the notification out from the
+ * {@link ShadeListBuilder} until it is inflated.
*/
@Singleton
public class PreparationCoordinator implements Coordinator {
@@ -49,7 +57,7 @@
private final PreparationCoordinatorLogger mLogger;
private final NotifInflater mNotifInflater;
private final NotifInflationErrorManager mNotifErrorManager;
- private final List<NotificationEntry> mPendingNotifications = new ArrayList<>();
+ private final Map<NotificationEntry, Integer> mInflationStates = new ArrayMap<>();
private final IStatusBarService mStatusBarService;
@Inject
@@ -69,27 +77,44 @@
@Override
public void attach(NotifPipeline pipeline) {
pipeline.addCollectionListener(mNotifCollectionListener);
- pipeline.addPreRenderFilter(mNotifInflationErrorFilter);
- pipeline.addPreRenderFilter(mNotifInflatingFilter);
+ // Inflate after grouping/sorting since that affects what views to inflate.
+ pipeline.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
+ pipeline.addFinalizeFilter(mNotifInflationErrorFilter);
+ pipeline.addFinalizeFilter(mNotifInflatingFilter);
}
private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
+
@Override
- public void onEntryAdded(NotificationEntry entry) {
- inflateEntry(entry, "entryAdded");
+ public void onEntryInit(NotificationEntry entry) {
+ mInflationStates.put(entry, STATE_UNINFLATED);
}
@Override
public void onEntryUpdated(NotificationEntry entry) {
- rebind(entry, "entryUpdated");
+ @InflationState int state = getInflationState(entry);
+ if (state == STATE_INFLATED) {
+ mInflationStates.put(entry, STATE_INFLATED_INVALID);
+ } else if (state == STATE_ERROR) {
+ // Updated so maybe it won't error out now.
+ mInflationStates.put(entry, STATE_UNINFLATED);
+ }
}
@Override
public void onEntryRemoved(NotificationEntry entry, int reason) {
abortInflation(entry, "entryRemoved reason=" + reason);
}
+
+ @Override
+ public void onEntryCleanUp(NotificationEntry entry) {
+ mInflationStates.remove(entry);
+ }
};
+ private final OnBeforeFinalizeFilterListener mOnBeforeFinalizeFilterListener =
+ entries -> inflateAllRequiredViews(entries);
+
private final NotifFilter mNotifInflationErrorFilter = new NotifFilter(
TAG + "InflationError") {
/**
@@ -97,10 +122,7 @@
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- if (mNotifErrorManager.hasInflationError(entry)) {
- return true;
- }
- return false;
+ return getInflationState(entry) == STATE_ERROR;
}
};
@@ -110,7 +132,8 @@
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- return mPendingNotifications.contains(entry);
+ @InflationState int state = getInflationState(entry);
+ return (state != STATE_INFLATED) && (state != STATE_INFLATED_INVALID);
}
};
@@ -119,7 +142,7 @@
@Override
public void onInflationFinished(NotificationEntry entry) {
mLogger.logNotifInflated(entry.getKey());
- mPendingNotifications.remove(entry);
+ mInflationStates.put(entry, STATE_INFLATED);
mNotifInflatingFilter.invalidateList();
}
};
@@ -128,7 +151,7 @@
new NotifInflationErrorManager.NotifInflationErrorListener() {
@Override
public void onNotifInflationError(NotificationEntry entry, Exception e) {
- mPendingNotifications.remove(entry);
+ mInflationStates.put(entry, STATE_ERROR);
try {
final StatusBarNotification sbn = entry.getSbn();
// report notification inflation errors back up
@@ -152,9 +175,41 @@
}
};
+ private void inflateAllRequiredViews(List<ListEntry> entries) {
+ for (int i = 0, size = entries.size(); i < size; i++) {
+ ListEntry entry = entries.get(i);
+ if (entry instanceof GroupEntry) {
+ GroupEntry groupEntry = (GroupEntry) entry;
+ inflateNotifRequiredViews(groupEntry.getSummary());
+ List<NotificationEntry> children = groupEntry.getChildren();
+ for (int j = 0, groupSize = children.size(); j < groupSize; j++) {
+ inflateNotifRequiredViews(children.get(j));
+ }
+ } else {
+ NotificationEntry notifEntry = (NotificationEntry) entry;
+ inflateNotifRequiredViews(notifEntry);
+ }
+ }
+ }
+
+ private void inflateNotifRequiredViews(NotificationEntry entry) {
+ @InflationState int state = mInflationStates.get(entry);
+ switch (state) {
+ case STATE_UNINFLATED:
+ inflateEntry(entry, "entryAdded");
+ break;
+ case STATE_INFLATED_INVALID:
+ rebind(entry, "entryUpdated");
+ break;
+ case STATE_INFLATED:
+ case STATE_ERROR:
+ default:
+ // Nothing to do.
+ }
+ }
+
private void inflateEntry(NotificationEntry entry, String reason) {
abortInflation(entry, reason);
- mPendingNotifications.add(entry);
mNotifInflater.inflateViews(entry);
}
@@ -165,6 +220,32 @@
private void abortInflation(NotificationEntry entry, String reason) {
mLogger.logInflationAborted(entry.getKey(), reason);
entry.abortTask();
- mPendingNotifications.remove(entry);
}
+
+ private @InflationState int getInflationState(NotificationEntry entry) {
+ Integer stateObj = mInflationStates.get(entry);
+ Objects.requireNonNull(stateObj,
+ "Asking state of a notification preparation coordinator doesn't know about");
+ return stateObj;
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STATE_"},
+ value = {STATE_UNINFLATED, STATE_INFLATED_INVALID, STATE_INFLATED, STATE_ERROR})
+ @interface InflationState {}
+
+ /** The notification has never been inflated before. */
+ private static final int STATE_UNINFLATED = 0;
+
+ /** The notification is inflated. */
+ private static final int STATE_INFLATED = 1;
+
+ /**
+ * The notification is inflated, but its content may be out-of-date since the notification has
+ * been updated.
+ */
+ private static final int STATE_INFLATED_INVALID = 2;
+
+ /** The notification errored out while inflating */
+ private static final int STATE_ERROR = -1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeFinalizeFilterListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeFinalizeFilterListener.java
new file mode 100644
index 0000000..086661e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeFinalizeFilterListener.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+
+import java.util.List;
+
+/** See {@link NotifPipeline#addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener)} */
+public interface OnBeforeFinalizeFilterListener {
+ /**
+ * Called after the notif list has been filtered, grouped, and sorted but before they are
+ * filtered one last time before rendering.
+ *
+ * @param entries The current list of top-level entries. Note that this is a live view into the
+ * current list and will change whenever the pipeline is rerun.
+ */
+ void onBeforeFinalizeFilter(List<ListEntry> entries);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 1897ba2..f1f7d63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -82,7 +82,7 @@
public static final int STATE_GROUPING = 4;
public static final int STATE_TRANSFORMING = 5;
public static final int STATE_SORTING = 6;
- public static final int STATE_PRE_RENDER_FILTERING = 7;
+ public static final int STATE_FINALIZE_FILTERING = 7;
public static final int STATE_FINALIZING = 8;
@IntDef(prefix = { "STATE_" }, value = {
@@ -93,7 +93,7 @@
STATE_GROUPING,
STATE_TRANSFORMING,
STATE_SORTING,
- STATE_PRE_RENDER_FILTERING,
+ STATE_FINALIZE_FILTERING,
STATE_FINALIZING,
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index 6e15043..763547c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -87,12 +87,12 @@
})
}
- fun logPreRenderFilterInvalidated(name: String, pipelineState: Int) {
+ fun logFinalizeFilterInvalidated(name: String, pipelineState: Int) {
buffer.log(TAG, DEBUG, {
str1 = name
int1 = pipelineState
}, {
- """Pre-render NotifFilter "$str1" invalidated; pipeline state is $int1"""
+ """Finalize NotifFilter "$str1" invalidated; pipeline state is $int1"""
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
index 8f575cd..9edb5fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
@@ -21,7 +21,7 @@
/**
* Pluggable for participating in notif filtering.
- * See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addPreRenderFilter}.
+ * See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addFinalizeFilter}.
*/
public abstract class NotifFilter extends Pluggable<NotifFilter> {
protected NotifFilter(String name) {
@@ -37,7 +37,7 @@
* @param entry The entry in question.
* If this filter is registered via {@link NotifPipeline#addPreGroupFilter},
* this entry will not have any grouping nor sorting information.
- * If this filter is registered via {@link NotifPipeline#addPreRenderFilter},
+ * If this filter is registered via {@link NotifPipeline#addFinalizeFilter},
* this entry will have grouping and sorting information.
* @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of
* pipeline execution. This value will be the same for all pluggable calls made
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index a3e59e5..fd92ad0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -97,19 +97,25 @@
@Test
fun testBindService() {
manager.bindService()
+ executor.runAllReady()
assertTrue(mContext.isBound(componentName))
}
@Test
fun testUnbindService() {
manager.bindService()
+ executor.runAllReady()
+
manager.unbindService()
+ executor.runAllReady()
+
assertFalse(mContext.isBound(componentName))
}
@Test
fun testMaybeBindAndLoad() {
manager.maybeBindAndLoad(subscriberService)
+ executor.runAllReady()
verify(service).load(subscriberService)
@@ -119,14 +125,17 @@
@Test
fun testMaybeUnbind_bindingAndCallback() {
manager.maybeBindAndLoad(subscriberService)
+ executor.runAllReady()
manager.unbindService()
+ executor.runAllReady()
assertFalse(mContext.isBound(componentName))
}
@Test
fun testMaybeBindAndLoad_timeout() {
manager.maybeBindAndLoad(subscriberService)
+ executor.runAllReady()
executor.advanceClockToLast()
executor.runAllReady()
@@ -138,6 +147,7 @@
fun testMaybeBindAndSubscribe() {
val list = listOf("TEST_ID")
manager.maybeBindAndSubscribe(list)
+ executor.runAllReady()
assertTrue(mContext.isBound(componentName))
verify(service).subscribe(list, subscriberService)
@@ -148,6 +158,7 @@
val controlId = "TEST_ID"
val action = ControlAction.ERROR_ACTION
manager.maybeBindAndSendAction(controlId, action)
+ executor.runAllReady()
assertTrue(mContext.isBound(componentName))
verify(service).action(eq(controlId), capture(wrapperCaptor),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 546fce8..d7c7279 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -42,6 +42,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -84,6 +85,7 @@
@Mock private NotifCollection mNotifCollection;
@Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener;
@Spy private OnBeforeSortListener mOnBeforeSortListener;
+ @Spy private OnBeforeFinalizeFilterListener mOnBeforeFinalizeFilterListener;
@Spy private OnBeforeRenderListListener mOnBeforeRenderListListener;
@Spy private OnRenderListListener mOnRenderListListener = list -> mBuiltList = list;
@@ -387,7 +389,7 @@
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_2));
NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_2));
mListBuilder.addPreGroupFilter(preGroupFilter);
- mListBuilder.addPreRenderFilter(preRenderFilter);
+ mListBuilder.addFinalizeFilter(preRenderFilter);
// WHEN the pipeline is kicked off on a list of notifs
addNotif(0, PACKAGE_1);
@@ -423,7 +425,7 @@
public void testPreRenderNotifsAreFiltered() {
// GIVEN a NotifFilter that filters out a specific package
NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
- mListBuilder.addPreRenderFilter(filter1);
+ mListBuilder.addFinalizeFilter(filter1);
// WHEN the pipeline is kicked off on a list of notifs
addNotif(0, PACKAGE_1);
@@ -454,7 +456,7 @@
final String filterTag = "FILTER_ME";
// GIVEN a NotifFilter that filters out notifications with a tag
NotifFilter filter1 = spy(new NotifFilterWithTag(filterTag));
- mListBuilder.addPreRenderFilter(filter1);
+ mListBuilder.addFinalizeFilter(filter1);
// WHEN the pipeline is kicked off on a list of notifs
addGroupChildWithTag(0, PACKAGE_2, GROUP_1, filterTag);
@@ -742,8 +744,9 @@
mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
mListBuilder.setComparators(Collections.singletonList(comparator));
mListBuilder.setSections(Arrays.asList(section));
+ mListBuilder.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
+ mListBuilder.addFinalizeFilter(preRenderFilter);
mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
- mListBuilder.addPreRenderFilter(preRenderFilter);
// WHEN a few new notifs are added
addNotif(0, PACKAGE_1);
@@ -763,6 +766,7 @@
mOnBeforeSortListener,
section,
comparator,
+ mOnBeforeFinalizeFilterListener,
preRenderFilter,
mOnBeforeRenderListListener,
mOnRenderListListener);
@@ -777,6 +781,7 @@
inOrder.verify(section, atLeastOnce()).isInSection(any(ListEntry.class));
inOrder.verify(comparator, atLeastOnce())
.compare(any(ListEntry.class), any(ListEntry.class));
+ inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
inOrder.verify(preRenderFilter, atLeastOnce())
.shouldFilterOut(any(NotificationEntry.class), anyLong());
inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
@@ -1075,7 +1080,7 @@
// GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage
NotifFilter filter = new PackageFilter(PACKAGE_5);
OnBeforeRenderListListener listener = (list) -> filter.invalidateList();
- mListBuilder.addPreRenderFilter(filter);
+ mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated
@@ -1090,7 +1095,7 @@
// GIVEN a PreRenderFilter that gets invalidated during the grouping stage
NotifFilter filter = new PackageFilter(PACKAGE_5);
OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList();
- mListBuilder.addPreRenderFilter(filter);
+ mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
// WHEN we try to run the pipeline and the filter is invalidated
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index 5866d90..c4f3a16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -88,7 +88,7 @@
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
mKeyguardCoordinator.attach(mNotifPipeline);
- verify(mNotifPipeline, times(1)).addPreRenderFilter(filterCaptor.capture());
+ verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index 61a4fbe..792b4d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static junit.framework.Assert.assertTrue;
-
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -35,13 +35,16 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -54,14 +57,22 @@
private static final String TEST_MESSAGE = "TEST_MESSAGE";
private PreparationCoordinator mCoordinator;
+ private NotifCollectionListener mCollectionListener;
+ private OnBeforeFinalizeFilterListener mBeforeFilterListener;
+ private NotifFilter mUninflatedFilter;
private NotifFilter mInflationErrorFilter;
+ private NotifInflaterImpl.InflationCallback mCallback;
private NotifInflationErrorManager mErrorManager;
private NotificationEntry mEntry;
private Exception mInflationError;
- @Mock
- private NotifPipeline mNotifPipeline;
+ @Captor private ArgumentCaptor<NotifCollectionListener> mCollectionListenerCaptor;
+ @Captor private ArgumentCaptor<OnBeforeFinalizeFilterListener> mBeforeFilterListenerCaptor;
+ @Captor private ArgumentCaptor<NotifInflaterImpl.InflationCallback> mCallbackCaptor;
+
+ @Mock private NotifPipeline mNotifPipeline;
@Mock private IStatusBarService mService;
+ @Mock private NotifInflaterImpl mNotifInflater;
@Before
public void setUp() {
@@ -73,15 +84,28 @@
mCoordinator = new PreparationCoordinator(
mock(PreparationCoordinatorLogger.class),
- mock(NotifInflaterImpl.class),
+ mNotifInflater,
mErrorManager,
mService);
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
mCoordinator.attach(mNotifPipeline);
- verify(mNotifPipeline, times(2)).addPreRenderFilter(filterCaptor.capture());
+ verify(mNotifPipeline, times(2)).addFinalizeFilter(filterCaptor.capture());
List<NotifFilter> filters = filterCaptor.getAllValues();
mInflationErrorFilter = filters.get(0);
+ mUninflatedFilter = filters.get(1);
+
+ verify(mNotifPipeline).addCollectionListener(mCollectionListenerCaptor.capture());
+ mCollectionListener = mCollectionListenerCaptor.getValue();
+
+ verify(mNotifPipeline).addOnBeforeFinalizeFilterListener(
+ mBeforeFilterListenerCaptor.capture());
+ mBeforeFilterListener = mBeforeFilterListenerCaptor.getValue();
+
+ verify(mNotifInflater).setInflationCallback(mCallbackCaptor.capture());
+ mCallback = mCallbackCaptor.getValue();
+
+ mCollectionListener.onEntryInit(mEntry);
}
@Test
@@ -108,4 +132,42 @@
// THEN we filter it from the notification list.
assertTrue(mInflationErrorFilter.shouldFilterOut(mEntry, 0));
}
+
+ @Test
+ public void testInflatesNewNotification() {
+ // WHEN there is a new notification
+ mCollectionListener.onEntryAdded(mEntry);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
+
+ // THEN we inflate it
+ verify(mNotifInflater).inflateViews(mEntry);
+
+ // THEN we filter it out until it's done inflating.
+ assertTrue(mUninflatedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void testRebindsInflatedNotificationsOnUpdate() {
+ // GIVEN an inflated notification
+ mCallback.onInflationFinished(mEntry);
+
+ // WHEN notification is updated
+ mCollectionListener.onEntryUpdated(mEntry);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
+
+ // THEN we rebind it
+ verify(mNotifInflater).rebindViews(mEntry);
+
+ // THEN we do not filter it because it's not the first inflation.
+ assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
+ }
+
+ @Test
+ public void testDoesntFilterInflatedNotifs() {
+ // WHEN a notification is inflated
+ mCallback.onInflationFinished(mEntry);
+
+ // THEN it isn't filtered from shade list
+ assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7d970ed..f14a7e9 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2459,18 +2459,24 @@
return;
}
- if (!isSameViewEntered
- && (flags & FLAG_MANUAL_REQUEST) == 0
- && mAugmentedAutofillableIds != null
- && mAugmentedAutofillableIds.contains(id)) {
- // View was already reported when server could not handle a response, but it
- // triggered augmented autofill
-
- if (sDebug) Slog.d(TAG, "updateLocked(" + id + "): augmented-autofillable");
-
- // ...then trigger the augmented autofill UI
- triggerAugmentedAutofillLocked();
- return;
+ if ((flags & FLAG_MANUAL_REQUEST) == 0) {
+ // Not a manual request
+ if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(
+ id)) {
+ // Regular autofill handled the view and returned null response, but it
+ // triggered augmented autofill
+ if (!isSameViewEntered) {
+ if (sDebug) Slog.d(TAG, "trigger augmented autofill.");
+ triggerAugmentedAutofillLocked();
+ } else {
+ if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
+ }
+ return;
+ } else if (mForAugmentedAutofillOnly && isSameViewEntered) {
+ // Regular autofill is disabled.
+ if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
+ return;
+ }
}
if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..cea3251 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -103,7 +103,7 @@
private static boolean PROP_PIN_CAMERA =
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
"pin_camera",
- SystemProperties.getBoolean("pinner.pin_camera", false));
+ SystemProperties.getBoolean("pinner.pin_camera", true));
// Pin using pinlist.meta when pinning apps.
private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
"pinner.use_pinlist", true);
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 351dd6e..dabf886 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -181,15 +181,13 @@
}
private void onEscrowRestoreComplete(boolean success) {
- int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, 0, USER_SYSTEM);
+ int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
- if (bootCountDelta > BOOT_COUNT_TOLERANCE) {
- return;
+ if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
+ mInjector.reportMetric(success);
}
-
- mInjector.reportMetric(success);
}
private RebootEscrowKey getAndClearRebootEscrowKey() {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b693362..0b1c91f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -171,7 +171,6 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
-import android.os.IDeviceIdleController;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.MessageQueue.IdleHandler;
@@ -180,11 +179,11 @@
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
+import android.os.PowerWhitelistManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -411,7 +410,7 @@
private IConnectivityManager mConnManager;
private PowerManagerInternal mPowerManagerInternal;
- private IDeviceIdleController mDeviceIdleController;
+ private PowerWhitelistManager mPowerWhitelistManager;
/** Current cached value of the current Battery Saver mode's setting for restrict background. */
@GuardedBy("mUidRulesFirstLock")
@@ -618,8 +617,7 @@
mContext = Objects.requireNonNull(context, "missing context");
mActivityManager = Objects.requireNonNull(activityManager, "missing activityManager");
mNetworkManager = Objects.requireNonNull(networkManagement, "missing networkManagement");
- mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
- Context.DEVICE_IDLE_CONTROLLER));
+ mPowerWhitelistManager = mContext.getSystemService(PowerWhitelistManager.class);
mClock = Objects.requireNonNull(clock, "missing Clock");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
@@ -651,23 +649,17 @@
}
@GuardedBy("mUidRulesFirstLock")
- void updatePowerSaveWhitelistUL() {
- try {
- int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle();
- mPowerSaveWhitelistExceptIdleAppIds.clear();
- if (whitelist != null) {
- for (int uid : whitelist) {
- mPowerSaveWhitelistExceptIdleAppIds.put(uid, true);
- }
- }
- whitelist = mDeviceIdleController.getAppIdWhitelist();
- mPowerSaveWhitelistAppIds.clear();
- if (whitelist != null) {
- for (int uid : whitelist) {
- mPowerSaveWhitelistAppIds.put(uid, true);
- }
- }
- } catch (RemoteException e) {
+ private void updatePowerSaveWhitelistUL() {
+ int[] whitelist = mPowerWhitelistManager.getWhitelistedAppIds(/* includingIdle */ false);
+ mPowerSaveWhitelistExceptIdleAppIds.clear();
+ for (int uid : whitelist) {
+ mPowerSaveWhitelistExceptIdleAppIds.put(uid, true);
+ }
+
+ whitelist = mPowerWhitelistManager.getWhitelistedAppIds(/* includingIdle */ true);
+ mPowerSaveWhitelistAppIds.clear();
+ for (int uid : whitelist) {
+ mPowerSaveWhitelistAppIds.put(uid, true);
}
}
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index f445aa8..0487028 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -16,22 +16,17 @@
#define ATRACE_TAG ATRACE_TAG_ADB
#define LOG_TAG "PackageManagerShellCommandDataLoader-jni"
-#include <android-base/logging.h>
-
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <core_jni_helpers.h>
#include <cutils/trace.h>
+#include <endian.h>
+#include <nativehelper/JNIHelp.h>
#include <sys/eventfd.h>
#include <sys/poll.h>
-#include <nativehelper/JNIHelp.h>
-
-#include <core_jni_helpers.h>
-#include <endian.h>
-
-#include "dataloader.h"
-
#include <charconv>
#include <chrono>
#include <span>
@@ -40,6 +35,8 @@
#include <unordered_map>
#include <unordered_set>
+#include "dataloader.h"
+
namespace android {
namespace {
@@ -681,7 +678,7 @@
auto& writeFd = writeFds[fileIdx];
if (writeFd < 0) {
- writeFd = this->mIfs->openWrite(fileId);
+ writeFd.reset(this->mIfs->openWrite(fileId));
if (writeFd < 0) {
ALOGE("Failed to open file %d for writing (%d). Aboring.", header.fileIdx,
-writeFd);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 1cf8525..4127fec 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -293,9 +293,8 @@
verify(mRebootEscrow, never()).storeKey(any());
- ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
assertTrue(mService.armRebootEscrowIfNeeded());
- verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
+ verify(mRebootEscrow).storeKey(any());
assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID));
@@ -303,13 +302,72 @@
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(10);
- when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
+ when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
mService.loadRebootEscrowDataIfAvailable();
verify(mRebootEscrow).retrieveKey();
verify(mInjected, never()).reportMetric(anyBoolean());
}
+ @Test
+ public void loadRebootEscrowDataIfAvailable_ManualReboot_Failure_NoMetrics() throws Exception {
+ when(mInjected.getBootCount()).thenReturn(0);
+
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+
+ verify(mRebootEscrow, never()).storeKey(any());
+
+ assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID));
+
+ // pretend reboot happens here
+
+ when(mInjected.getBootCount()).thenReturn(10);
+ when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
+
+ mService.loadRebootEscrowDataIfAvailable();
+ verify(mInjected, never()).reportMetric(anyBoolean());
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_OTAFromBeforeArmedStatus_SuccessMetrics()
+ throws Exception {
+ when(mInjected.getBootCount()).thenReturn(0);
+
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mRebootEscrow);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+
+ verify(mRebootEscrow, never()).storeKey(any());
+
+ ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
+
+ assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID));
+
+ // Delete key to simulate old version that didn't have it.
+ mStorage.removeKey(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+
+ // pretend reboot happens here
+
+ when(mInjected.getBootCount()).thenReturn(10);
+ when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
+
+ mService.loadRebootEscrowDataIfAvailable();
+ verify(mInjected).reportMetric(eq(true));
+ }
@Test
public void loadRebootEscrowDataIfAvailable_RestoreUnsuccessful_Failure() throws Exception {
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index c8d1ce1..2482068 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -16,7 +16,7 @@
name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
target_required: [
"block_device_writer_module",
],
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index 78850c5..65cb364 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -47,6 +47,6 @@
},
},
- test_suites: ["general-tests", "pts"],
+ test_suites: ["general-tests", "pts", "vts-core"],
gtest: false,
}
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index 41cec46..ba86c3f 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -15,9 +15,6 @@
-->
<configuration description="Runs rollback tests for multiple users">
<option name="test-suite-tag" value="MultiUserRollbackTest" />
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
- </target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
</test>
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index e616ac4..4c29e72e 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -40,15 +40,20 @@
private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
+ private void cleanUp() throws Exception {
+ getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
+ getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
+ }
@After
public void tearDown() throws Exception {
- getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
+ cleanUp();
removeSecondaryUserIfNecessary();
}
@Before
public void setup() throws Exception {
+ cleanUp();
mOriginalUserId = getDevice().getCurrentUser();
createAndStartSecondaryUser();
// TODO(b/149733368): Remove the '-g' workaround when the bug is fixed.