summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java12
-rwxr-xr-xapi/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp13
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h3
-rw-r--r--config/hiddenapi-light-greylist.txt40
-rw-r--r--config/preloaded-classes2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java9
-rw-r--r--core/java/android/app/DexLoadReporter.java8
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/IUiAutomationConnection.aidl2
-rw-r--r--core/java/android/app/UiAutomation.java43
-rw-r--r--core/java/android/app/UiAutomationConnection.java7
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java8
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java29
-rw-r--r--core/java/android/service/notification/NotificationRankingUpdate.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/com/android/internal/util/function/HeptConsumer.java28
-rw-r--r--core/java/com/android/internal/util/function/HeptFunction.java28
-rw-r--r--core/java/com/android/internal/util/function/HeptPredicate.java28
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/OmniFunction.java62
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambda.java166
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java53
-rw-r--r--core/jni/Android.bp2
-rw-r--r--core/res/res/values-mcc302-mnc220/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc221/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc370/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc610/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc640/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc720/config.xml2
-rw-r--r--core/res/res/values/strings.xml12
-rw-r--r--keystore/java/android/security/KeyStore.java162
-rw-r--r--location/java/android/location/GnssMeasurement.java8
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml7
-rw-r--r--packages/SystemUI/res/values/strings.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java147
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java351
-rw-r--r--services/core/java/com/android/server/AppOpsService.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java98
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java9
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java14
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java14
-rw-r--r--services/core/java/com/android/server/pm/dex/DexoptUtils.java3
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java27
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobSetTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java8
-rw-r--r--startop/view_compiler/Android.bp19
-rw-r--r--startop/view_compiler/README.md28
-rw-r--r--startop/view_compiler/TEST_MAPPING7
-rw-r--r--startop/view_compiler/dex_builder_test/Android.bp29
-rw-r--r--startop/view_compiler/dex_builder_test/AndroidManifest.xml29
-rw-r--r--startop/view_compiler/dex_builder_test/AndroidTest.xml34
-rw-r--r--startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java68
-rw-r--r--startop/view_compiler/dex_testcase_generator.cc85
-rw-r--r--telecomm/java/android/telecom/Logging/EventManager.java36
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java39
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java19
76 files changed, 1699 insertions, 447 deletions
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
index 434b8e56dd36..bd9111228eac 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -343,13 +343,14 @@ public class TextViewPrecomputedTextPerfTest {
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.start(
+ final RecordingCanvas c = node.startRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
+ node.endRecording();
}
}
@@ -369,13 +370,14 @@ public class TextViewPrecomputedTextPerfTest {
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.start(
+ final RecordingCanvas c = node.startRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
+ node.endRecording();
}
}
@@ -397,13 +399,14 @@ public class TextViewPrecomputedTextPerfTest {
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.start(
+ final RecordingCanvas c = node.startRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
+ node.endRecording();
}
}
@@ -426,13 +429,14 @@ public class TextViewPrecomputedTextPerfTest {
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
- final RecordingCanvas c = node.start(
+ final RecordingCanvas c = node.startRecording(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
+ node.endRecording();
}
}
}
diff --git a/api/current.txt b/api/current.txt
index a5724fece528..fd09e6b00439 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -6184,6 +6184,7 @@ package android.app {
public final class UiAutomation {
method public void adoptShellPermissionIdentity();
+ method public void adoptShellPermissionIdentity(java.lang.String...);
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
method public void dropShellPermissionIdentity();
diff --git a/api/system-current.txt b/api/system-current.txt
index 237d4c427e90..4c975db6e971 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1088,6 +1088,7 @@ package android.content {
field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final java.lang.String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
field public static final java.lang.String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
+ field public static final java.lang.String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
}
public class IntentFilter implements android.os.Parcelable {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f0f599317352..eb498f596141 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -71,6 +71,9 @@ const int FIELD_ID_STRINGS = 9;
#define STATS_DATA_DIR "/data/misc/stats-data"
+// Cool down period for writing data to disk to avoid overwriting files.
+#define WRITE_DATA_COOL_DOWN_SEC 5
+
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -508,6 +511,16 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason) {
const int64_t timeNs = getElapsedRealtimeNs();
+ // Do not write to disk if we already have in the last few seconds.
+ // This is to avoid overwriting files that would have the same name if we
+ // write twice in the same second.
+ if (static_cast<unsigned long long> (timeNs) <
+ mLastWriteTimeNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
+ ALOGI("Statsd skipping writing data to disk. Already wrote data in last %d seconds",
+ WRITE_DATA_COOL_DOWN_SEC);
+ return;
+ }
+ mLastWriteTimeNs = timeNs;
for (auto& pair : mMetricsManagers) {
WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index ecfd819a3399..a5ce9b65f899 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -177,6 +177,9 @@ private:
long mLastPullerCacheClearTimeSec = 0;
+ // Last time we wrote data to disk.
+ int64_t mLastWriteTimeNs = 0;
+
#ifdef VERY_VERBOSE_PRINTING
bool mPrintAllLogs = false;
#endif
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0d9a3938738c..099756691c4e 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -441,42 +441,6 @@ Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
-Landroid/icu/impl/CurrencyData;-><init>()V
-Landroid/icu/impl/ICUResourceBundle;->getULocale()Landroid/icu/util/ULocale;
-Landroid/icu/impl/ICUResourceBundle;->getWithFallback(Ljava/lang/String;)Landroid/icu/impl/ICUResourceBundle;
-Landroid/icu/impl/IllegalIcuArgumentException;-><init>(Ljava/lang/String;)V
-Landroid/icu/text/ArabicShaping;-><init>(I)V
-Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
-Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
-Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
-Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
-Landroid/icu/text/ArabicShaping;->shape(Ljava/lang/String;)Ljava/lang/String;
-Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/DateIntervalFormat;-><init>()V
-Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;-><init>()V
-Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/SpoofChecker$ScriptSet;-><init>()V
-Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
-Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
-Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
-Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V
-Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
-Landroid/icu/text/Transliterator;->getInstance(Ljava/lang/String;)Landroid/icu/text/Transliterator;
-Landroid/icu/text/Transliterator;->getInstance(Ljava/lang/String;I)Landroid/icu/text/Transliterator;
-Landroid/icu/text/Transliterator;->transliterate(Landroid/icu/text/Replaceable;Landroid/icu/text/Transliterator$Position;Ljava/lang/String;)V
-Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
-Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/util/PersianCalendar;-><init>(Ljava/util/Locale;)V
-Landroid/icu/util/UResourceBundle;->getBundleInstance(Ljava/lang/String;Landroid/icu/util/ULocale;)Landroid/icu/util/UResourceBundle;
-Landroid/icu/util/UResourceBundle;->getKey()Ljava/lang/String;
-Landroid/icu/util/UResourceBundle;->getString()Ljava/lang/String;
-Landroid/icu/util/UResourceBundle;->getType()I
-Landroid/icu/util/UResourceBundleIterator;->hasNext()Z
-Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle;
-Landroid/inputmethodservice/IInputMethodSessionWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
-Landroid/inputmethodservice/IInputMethodWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
Landroid/location/ICountryListener$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;-><init>()V
@@ -1361,15 +1325,11 @@ Landroid/security/IKeystoreService;->exist(Ljava/lang/String;I)I
Landroid/security/IKeystoreService;->generateKey(Ljava/lang/String;Landroid/security/keymaster/KeymasterArguments;[BIILandroid/security/keymaster/KeyCharacteristics;)I
Landroid/security/IKeystoreService;->get(Ljava/lang/String;I)[B
Landroid/security/IKeystoreService;->getState(I)I
-Landroid/security/IKeystoreService;->get_pubkey(Ljava/lang/String;)[B
-Landroid/security/IKeystoreService;->import_key(Ljava/lang/String;[BII)I
Landroid/security/IKeystoreService;->insert(Ljava/lang/String;[BII)I
Landroid/security/IKeystoreService;->is_hardware_backed(Ljava/lang/String;)I
Landroid/security/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String;
Landroid/security/IKeystoreService;->reset()I
-Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B
Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I
-Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I
Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V
Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V
Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 22fc5e80787f..14597ee919bf 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -4117,6 +4117,8 @@ com.android.internal.util.StateMachine$SmHandler$StateInfo
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.XmlUtils
com.android.internal.util.XmlUtils$WriteMapCallback
+com.android.internal.util.function.HeptConsumer
+com.android.internal.util.function.HeptFunction
com.android.internal.util.function.HexConsumer
com.android.internal.util.function.HexFunction
com.android.internal.util.function.QuadConsumer
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 069effd3ef19..d4151322e219 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -277,7 +277,12 @@ public abstract class ActivityManagerInternal {
public abstract void startProcess(String processName, ApplicationInfo info,
boolean knownToBeDead, String hostingType, ComponentName hostingName);
- /** Starts up the starting activity process for debugging if needed. */
+ /** Starts up the starting activity process for debugging if needed.
+ * This function needs to be called synchronously from WindowManager context so the caller
+ * passes a lock {@code wmLock} and waits to be notified.
+ *
+ * @param wmLock calls {@code notify} on the object to wake up the caller.
+ */
public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
- ProfilerInfo profilerInfo);
+ ProfilerInfo profilerInfo, Object wmLock);
}
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index 0643414727cf..229bee55e911 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -87,7 +87,7 @@ import java.util.Set;
}
@Override
- public void report(List<BaseDexClassLoader> classLoadersChain, List<String> classPaths) {
+ public void report(List<ClassLoader> classLoadersChain, List<String> classPaths) {
if (classLoadersChain.size() != classPaths.size()) {
Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch");
return;
@@ -113,12 +113,12 @@ import java.util.Set;
registerSecondaryDexForProfiling(dexPathsForRegistration);
}
- private void notifyPackageManager(List<BaseDexClassLoader> classLoadersChain,
+ private void notifyPackageManager(List<ClassLoader> classLoadersChain,
List<String> classPaths) {
// Get the class loader names for the binder call.
List<String> classLoadersNames = new ArrayList<>(classPaths.size());
- for (BaseDexClassLoader bdc : classLoadersChain) {
- classLoadersNames.add(bdc.getClass().getName());
+ for (ClassLoader classLoader : classLoadersChain) {
+ classLoadersNames.add(classLoader.getClass().getName());
}
String packageName = ActivityThread.currentPackageName();
try {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e7597620e138..e2312a539ae4 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -475,7 +475,7 @@ interface IActivityManager {
* instrumentation at a time. An active instrumentation is one running and
* started from the shell.
*/
- void startDelegateShellPermissionIdentity(int uid);
+ void startDelegateShellPermissionIdentity(int uid, in String[] permissions);
/**
* Method for the shell UID to stop deletating its permission identity to an
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index ac4bf7d9c2c5..96da72a1b517 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -47,7 +47,7 @@ interface IUiAutomationConnection {
in ParcelFileDescriptor source);
void grantRuntimePermission(String packageName, String permission, int userId);
void revokeRuntimePermission(String packageName, String permission, int userId);
- void adoptShellPermissionIdentity(int uid);
+ void adoptShellPermissionIdentity(int uid, in String[] permissions);
void dropShellPermissionIdentity();
// Called from the system process.
oneway void shutdown();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 5a25f5aed161..3f9627ed807c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -354,12 +354,17 @@ public final class UiAutomation {
}
/**
- * Adopt the permission identity of the shell UID. This allows you to call APIs protected
- * permissions which normal apps cannot hold but are granted to the shell UID. If you
- * already adopted the shell permission identity this method would be a no-op.
- * Note that your permission state becomes that of the shell UID and it is not a
- * combination of your and the shell UID permissions.
+ * Adopt the permission identity of the shell UID for all permissions. This allows
+ * you to call APIs protected permissions which normal apps cannot hold but are
+ * granted to the shell UID. If you already adopted all shell permissions by calling
+ * this method or {@link #adoptShellPermissionIdentity(String...)} a subsequent call
+ * would be a no-op. Note that your permission state becomes that of the shell UID
+ * and it is not a combination of your and the shell UID permissions.
+ * <p>
+ * <strong>Note:<strong/> Calling this method adopts all shell permissions and overrides
+ * any subset of adopted permissions via {@link #adoptShellPermissionIdentity(String...)}.
*
+ * @see #adoptShellPermissionIdentity(String...)
* @see #dropShellPermissionIdentity()
*/
public void adoptShellPermissionIdentity() {
@@ -368,7 +373,33 @@ public final class UiAutomation {
}
try {
// Calling out without a lock held.
- mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid());
+ mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid(), null);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error executing adopting shell permission identity!", re);
+ }
+ }
+
+ /**
+ * Adopt the permission identity of the shell UID only for the provided permissions.
+ * This allows you to call APIs protected permissions which normal apps cannot hold
+ * but are granted to the shell UID. If you already adopted the specified shell
+ * permissions by calling this method or {@link #adoptShellPermissionIdentity()} a
+ * subsequent call would be a no-op. Note that your permission state becomes that of the
+ * shell UID and it is not a combination of your and the shell UID permissions.
+ * <p>
+ * <strong>Note:<strong/> Calling this method adopts only the specified shell permissions
+ * and overrides all adopted permissions via {@link #adoptShellPermissionIdentity()}.
+ *
+ * @see #adoptShellPermissionIdentity()
+ * @see #dropShellPermissionIdentity()
+ */
+ public void adoptShellPermissionIdentity(String... permissions) {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+ try {
+ // Calling out without a lock held.
+ mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid(), permissions);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error executing adopting shell permission identity!", re);
}
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index b406d9e30a53..dc2f9838785c 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -18,7 +18,7 @@ package android.app;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.graphics.Bitmap;
@@ -279,7 +279,8 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
@Override
- public void adoptShellPermissionIdentity(int uid) throws RemoteException {
+ public void adoptShellPermissionIdentity(int uid, @Nullable String[] permissions)
+ throws RemoteException {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
@@ -287,7 +288,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
}
final long identity = Binder.clearCallingIdentity();
try {
- mActivityManager.startDelegateShellPermissionIdentity(uid);
+ mActivityManager.startDelegateShellPermissionIdentity(uid, permissions);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index aa34da8e0159..02f38a790570 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1727,10 +1727,14 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.UNINSTALL_ALL_USERS";
/**
- * A string associated with a {@link #ACTION_UPGRADE_SETUP} activity
- * describing the last run version of the platform that was setup.
+ * A string that associates with a metadata entry, indicating the last run version of the
+ * platform that was setup.
+ *
+ * @see #ACTION_UPGRADE_SETUP
+ *
* @hide
*/
+ @SystemApi
public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4a4de5160e80..a87ee572b6d0 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -475,7 +475,7 @@ interface IPackageManager {
* @param classPaths the class paths corresponding to the class loaders names from
* {@param classLoadersNames}. The the first element corresponds to the first class loader
* and so on. A classpath is represented as a list of dex files separated by
- * {@code File.pathSeparator}.
+ * {@code File.pathSeparator}, or null if the class loader's classpath is not known.
* The dex files found in the first class path will be recorded in the usage file.
* @param loaderIsa the ISA of the loader process
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c1ac061e1f79..d3e40452d9fb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5825,16 +5825,16 @@ public abstract class PackageManager {
* {@code android.permission.SUSPEND_APPS} can put any app on the device into a suspended state.
*
* <p>While in this state, the application's notifications will be hidden, any of its started
- * activities will be stopped and it will not be able to show toasts or dialogs or ring the
- * device. When the user tries to launch a suspended app, the system will, instead, show a
+ * activities will be stopped and it will not be able to show toasts or dialogs or play audio.
+ * When the user tries to launch a suspended app, the system will, instead, show a
* dialog to the user informing them that they cannot use this app while it is suspended.
*
* <p>When an app is put into this state, the broadcast action
* {@link Intent#ACTION_MY_PACKAGE_SUSPENDED} will be delivered to any of its broadcast
* receivers that included this action in their intent-filters, <em>including manifest
* receivers.</em> Similarly, a broadcast action {@link Intent#ACTION_MY_PACKAGE_UNSUSPENDED}
- * is delivered when a previously suspended app is taken out of this state.
- * </p>
+ * is delivered when a previously suspended app is taken out of this state. Apps are expected to
+ * use these to gracefully deal with transitions to and from this state.
*
* @return {@code true} if the calling package has been suspended, {@code false} otherwise.
*
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 56e6aea815ec..64eae0cf4635 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1462,6 +1462,7 @@ public abstract class NotificationListenerService extends Service {
private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
private boolean mHidden;
private boolean mAudiblyAlerted;
+ private boolean mNoisy;
private ArrayList<Notification.Action> mSmartActions;
private ArrayList<CharSequence> mSmartReplies;
@@ -1636,6 +1637,11 @@ public abstract class NotificationListenerService extends Service {
return mAudiblyAlerted;
}
+ /** @hide */
+ public boolean isNoisy() {
+ return mNoisy;
+ }
+
/**
* @hide
*/
@@ -1646,7 +1652,8 @@ public abstract class NotificationListenerService extends Service {
NotificationChannel channel, ArrayList<String> overridePeople,
ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
int userSentiment, boolean hidden, boolean audiblyAlerted,
- ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies) {
+ boolean noisy, ArrayList<Notification.Action> smartActions,
+ ArrayList<CharSequence> smartReplies) {
mKey = key;
mRank = rank;
mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1663,6 +1670,7 @@ public abstract class NotificationListenerService extends Service {
mUserSentiment = userSentiment;
mHidden = hidden;
mAudiblyAlerted = audiblyAlerted;
+ mNoisy = noisy;
mSmartActions = smartActions;
mSmartReplies = smartReplies;
}
@@ -1715,6 +1723,7 @@ public abstract class NotificationListenerService extends Service {
private ArrayMap<String, Integer> mUserSentiment;
private ArrayMap<String, Boolean> mHidden;
private ArrayMap<String, Boolean> mAudiblyAlerted;
+ private ArrayMap<String, Boolean> mNoisy;
private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;
private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies;
@@ -1746,7 +1755,8 @@ public abstract class NotificationListenerService extends Service {
getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
getShowBadge(key), getUserSentiment(key), getHidden(key),
- getAudiblyAlerted(key), getSmartActions(key), getSmartReplies(key));
+ getAudiblyAlerted(key), getNoisy(key), getSmartActions(key),
+ getSmartReplies(key));
return rank >= 0;
}
@@ -1894,6 +1904,16 @@ public abstract class NotificationListenerService extends Service {
return audiblyAlerted == null ? false : audiblyAlerted.booleanValue();
}
+ private boolean getNoisy(String key) {
+ synchronized (this) {
+ if (mNoisy == null) {
+ buildNoisyLocked();
+ }
+ }
+ Boolean noisy = mNoisy.get(key);
+ return noisy == null ? false : noisy.booleanValue();
+ }
+
private ArrayList<Notification.Action> getSmartActions(String key) {
synchronized (this) {
if (mSmartActions == null) {
@@ -2034,6 +2054,11 @@ public abstract class NotificationListenerService extends Service {
}
// Locked by 'this'
+ private void buildNoisyLocked() {
+ mNoisy = buildBooleanMapFromBundle(mRankingUpdate.getNoisy());
+ }
+
+ // Locked by 'this'
private void buildSmartActions() {
Bundle smartActions = mRankingUpdate.getSmartActions();
mSmartActions = new ArrayMap<>(smartActions.size());
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index b561bfd98038..f80df93364f4 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -40,13 +40,14 @@ public class NotificationRankingUpdate implements Parcelable {
private final Bundle mSmartActions;
private final Bundle mSmartReplies;
private final Bundle mAudiblyAlerted;
+ private final Bundle mNoisy;
public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
Bundle visibilityOverrides, Bundle suppressedVisualEffects,
int[] importance, Bundle explanation, Bundle overrideGroupKeys,
Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions,
- Bundle smartReplies, Bundle audiblyAlerted) {
+ Bundle smartReplies, Bundle audiblyAlerted, Bundle noisy) {
mKeys = keys;
mInterceptedKeys = interceptedKeys;
mVisibilityOverrides = visibilityOverrides;
@@ -63,6 +64,7 @@ public class NotificationRankingUpdate implements Parcelable {
mSmartActions = smartActions;
mSmartReplies = smartReplies;
mAudiblyAlerted = audiblyAlerted;
+ mNoisy = noisy;
}
public NotificationRankingUpdate(Parcel in) {
@@ -83,6 +85,7 @@ public class NotificationRankingUpdate implements Parcelable {
mSmartActions = in.readBundle();
mSmartReplies = in.readBundle();
mAudiblyAlerted = in.readBundle();
+ mNoisy = in.readBundle();
}
@Override
@@ -108,6 +111,7 @@ public class NotificationRankingUpdate implements Parcelable {
out.writeBundle(mSmartActions);
out.writeBundle(mSmartReplies);
out.writeBundle(mAudiblyAlerted);
+ out.writeBundle(mNoisy);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -184,4 +188,8 @@ public class NotificationRankingUpdate implements Parcelable {
public Bundle getAudiblyAlerted() {
return mAudiblyAlerted;
}
+
+ public Bundle getNoisy() {
+ return mNoisy;
+ }
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b047ef7af032..67505e58cf17 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -45,7 +45,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
- DEFAULT_FLAGS.put("settings_mobile_network_v2", "false");
+ DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/com/android/internal/util/function/HeptConsumer.java b/core/java/com/android/internal/util/function/HeptConsumer.java
new file mode 100644
index 000000000000..171b0f24b5be
--- /dev/null
+++ b/core/java/com/android/internal/util/function/HeptConsumer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.internal.util.function;
+
+import java.util.function.Consumer;
+
+/**
+ * A 7-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface HeptConsumer<A, B, C, D, E, F, G> {
+ void accept(A a, B b, C c, D d, E e, F f, G g);
+}
diff --git a/core/java/com/android/internal/util/function/HeptFunction.java b/core/java/com/android/internal/util/function/HeptFunction.java
new file mode 100644
index 000000000000..7aa434575038
--- /dev/null
+++ b/core/java/com/android/internal/util/function/HeptFunction.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.internal.util.function;
+
+import java.util.function.Function;
+
+/**
+ * A 7-argument {@link Function}
+ *
+ * @hide
+ */
+public interface HeptFunction<A, B, C, D, E, F, G, R> {
+ R apply(A a, B b, C c, D d, E e, F f, G g);
+}
diff --git a/core/java/com/android/internal/util/function/HeptPredicate.java b/core/java/com/android/internal/util/function/HeptPredicate.java
new file mode 100644
index 000000000000..531e53a992bf
--- /dev/null
+++ b/core/java/com/android/internal/util/function/HeptPredicate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.internal.util.function;
+
+import java.util.function.Predicate;
+
+/**
+ * A 7-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface HeptPredicate<A, B, C, D, E, F, G> {
+ boolean test(A a, B b, C c, D d, E e, F f, G g);
+}
diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
index 9378869d6934..4ffe44194958 100755
--- a/core/java/com/android/internal/util/function/pooled/OmniFunction.java
+++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
@@ -18,6 +18,8 @@ package com.android.internal.util.function.pooled;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+import com.android.internal.util.function.HeptConsumer;
+import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadConsumer;
@@ -37,59 +39,61 @@ import java.util.function.Function;
*
* @hide
*/
-abstract class OmniFunction<A, B, C, D, E, F, R> implements
+abstract class OmniFunction<A, B, C, D, E, F, G, R> implements
PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>,
QuadFunction<A, B, C, D, R>, QuintFunction<A, B, C, D, E, R>,
- HexFunction<A, B, C, D, E, F, R>, PooledConsumer<A>, BiConsumer<A, B>,
- TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>, QuintConsumer<A, B, C, D, E>,
- HexConsumer<A, B, C, D, E, F>, PooledPredicate<A>, BiPredicate<A, B>,
+ HexFunction<A, B, C, D, E, F, R>, HeptFunction<A, B, C, D, E, F, G, R>,
+ PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>,
+ QuintConsumer<A, B, C, D, E>, HexConsumer<A, B, C, D, E, F>,
+ HeptConsumer<A, B, C, D, E, F, G>,
+ PooledPredicate<A>, BiPredicate<A, B>,
PooledSupplier<R>, PooledRunnable, ThrowingRunnable, ThrowingSupplier<R>,
PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble {
- abstract R invoke(A a, B b, C c, D d, E e, F f);
+ abstract R invoke(A a, B b, C c, D d, E e, F f, G g);
@Override
public R apply(A o, B o2) {
- return invoke(o, o2, null, null, null, null);
+ return invoke(o, o2, null, null, null, null, null);
}
@Override
public R apply(A o) {
- return invoke(o, null, null, null, null, null);
+ return invoke(o, null, null, null, null, null, null);
}
- abstract public <V> OmniFunction<A, B, C, D, E, F, V> andThen(
+ public abstract <V> OmniFunction<A, B, C, D, E, F, G, V> andThen(
Function<? super R, ? extends V> after);
- abstract public OmniFunction<A, B, C, D, E, F, R> negate();
+ public abstract OmniFunction<A, B, C, D, E, F, G, R> negate();
@Override
public void accept(A o, B o2) {
- invoke(o, o2, null, null, null, null);
+ invoke(o, o2, null, null, null, null, null);
}
@Override
public void accept(A o) {
- invoke(o, null, null, null, null, null);
+ invoke(o, null, null, null, null, null, null);
}
@Override
public void run() {
- invoke(null, null, null, null, null, null);
+ invoke(null, null, null, null, null, null, null);
}
@Override
public R get() {
- return invoke(null, null, null, null, null, null);
+ return invoke(null, null, null, null, null, null, null);
}
@Override
public boolean test(A o, B o2) {
- return (Boolean) invoke(o, o2, null, null, null, null);
+ return (Boolean) invoke(o, o2, null, null, null, null, null);
}
@Override
public boolean test(A o) {
- return (Boolean) invoke(o, null, null, null, null, null);
+ return (Boolean) invoke(o, null, null, null, null, null, null);
}
@Override
@@ -104,42 +108,52 @@ abstract class OmniFunction<A, B, C, D, E, F, R> implements
@Override
public R apply(A a, B b, C c) {
- return invoke(a, b, c, null, null, null);
+ return invoke(a, b, c, null, null, null, null);
}
@Override
public void accept(A a, B b, C c) {
- invoke(a, b, c, null, null, null);
+ invoke(a, b, c, null, null, null, null);
}
@Override
public R apply(A a, B b, C c, D d) {
- return invoke(a, b, c, d, null, null);
+ return invoke(a, b, c, d, null, null, null);
}
@Override
public R apply(A a, B b, C c, D d, E e) {
- return invoke(a, b, c, d, e, null);
+ return invoke(a, b, c, d, e, null, null);
}
@Override
public R apply(A a, B b, C c, D d, E e, F f) {
- return invoke(a, b, c, d, e, f);
+ return invoke(a, b, c, d, e, f, null);
+ }
+
+ @Override
+ public R apply(A a, B b, C c, D d, E e, F f, G g) {
+ return invoke(a, b, c, d, e, f, g);
}
@Override
public void accept(A a, B b, C c, D d) {
- invoke(a, b, c, d, null, null);
+ invoke(a, b, c, d, null, null, null);
}
@Override
public void accept(A a, B b, C c, D d, E e) {
- invoke(a, b, c, d, e, null);
+ invoke(a, b, c, d, e, null, null);
}
@Override
public void accept(A a, B b, C c, D d, E e, F f) {
- invoke(a, b, c, d, e, f);
+ invoke(a, b, c, d, e, f, null);
+ }
+
+ @Override
+ public void accept(A a, B b, C c, D d, E e, F f, G g) {
+ invoke(a, b, c, d, e, f, g);
}
@Override
@@ -153,5 +167,5 @@ abstract class OmniFunction<A, B, C, D, E, F, R> implements
}
@Override
- abstract public OmniFunction<A, B, C, D, E, F, R> recycleOnUse();
+ public abstract OmniFunction<A, B, C, D, E, F, G, R> recycleOnUse();
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
index 15698cc67e51..af3c7527c432 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -21,6 +21,8 @@ import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire
import android.os.Message;
+import com.android.internal.util.function.HeptConsumer;
+import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadConsumer;
@@ -174,7 +176,7 @@ public interface PooledLambda {
Consumer<? super A> function,
A arg1) {
return acquire(PooledLambdaImpl.sPool,
- function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null);
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null);
}
/**
@@ -190,7 +192,7 @@ public interface PooledLambda {
Predicate<? super A> function,
A arg1) {
return acquire(PooledLambdaImpl.sPool,
- function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null);
+ function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null);
}
/**
@@ -206,7 +208,7 @@ public interface PooledLambda {
Function<? super A, ? extends R> function,
A arg1) {
return acquire(PooledLambdaImpl.sPool,
- function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null);
+ function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null);
}
/**
@@ -236,7 +238,7 @@ public interface PooledLambda {
A arg1) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null);
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -255,7 +257,7 @@ public interface PooledLambda {
BiConsumer<? super A, ? super B> function,
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null);
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null);
}
/**
@@ -272,7 +274,7 @@ public interface PooledLambda {
BiPredicate<? super A, ? super B> function,
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null);
+ function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null);
}
/**
@@ -289,7 +291,7 @@ public interface PooledLambda {
BiFunction<? super A, ? super B, ? extends R> function,
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null);
+ function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null);
}
/**
@@ -306,7 +308,7 @@ public interface PooledLambda {
BiConsumer<? super A, ? super B> function,
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null);
}
/**
@@ -323,7 +325,7 @@ public interface PooledLambda {
BiPredicate<? super A, ? super B> function,
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null);
}
/**
@@ -340,7 +342,7 @@ public interface PooledLambda {
BiFunction<? super A, ? super B, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null);
}
/**
@@ -357,7 +359,7 @@ public interface PooledLambda {
BiConsumer<? super A, ? super B> function,
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null);
}
/**
@@ -374,7 +376,7 @@ public interface PooledLambda {
BiPredicate<? super A, ? super B> function,
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null);
}
/**
@@ -391,7 +393,7 @@ public interface PooledLambda {
BiFunction<? super A, ? super B, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
- function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null);
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null);
}
/**
@@ -422,7 +424,7 @@ public interface PooledLambda {
A arg1, B arg2) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null);
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -442,7 +444,7 @@ public interface PooledLambda {
TriConsumer<? super A, ? super B, ? super C> function,
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null);
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -460,7 +462,7 @@ public interface PooledLambda {
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null);
+ function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -478,7 +480,7 @@ public interface PooledLambda {
TriConsumer<? super A, ? super B, ? super C> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -496,7 +498,7 @@ public interface PooledLambda {
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -514,7 +516,7 @@ public interface PooledLambda {
TriConsumer<? super A, ? super B, ? super C> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -532,7 +534,7 @@ public interface PooledLambda {
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -550,7 +552,7 @@ public interface PooledLambda {
TriConsumer<? super A, ? super B, ? super C> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -568,7 +570,7 @@ public interface PooledLambda {
TriFunction<? super A, ? super B, ? super C, ? extends R> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
- function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null);
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null);
}
/**
@@ -600,7 +602,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null);
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -621,7 +623,7 @@ public interface PooledLambda {
QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -640,7 +642,7 @@ public interface PooledLambda {
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -659,7 +661,7 @@ public interface PooledLambda {
QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -678,7 +680,7 @@ public interface PooledLambda {
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -697,7 +699,7 @@ public interface PooledLambda {
QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -716,7 +718,7 @@ public interface PooledLambda {
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -735,7 +737,7 @@ public interface PooledLambda {
QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -754,7 +756,7 @@ public interface PooledLambda {
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -773,7 +775,7 @@ public interface PooledLambda {
QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -792,7 +794,7 @@ public interface PooledLambda {
QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
- function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null);
}
/**
@@ -825,7 +827,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null);
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -847,7 +849,7 @@ public interface PooledLambda {
QuintConsumer<? super A, ? super B, ? super C, ? super D, ? super E> function,
A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
- function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null);
+ function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null);
}
/**
@@ -867,7 +869,7 @@ public interface PooledLambda {
QuintFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? extends R>
function, A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
- function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null);
+ function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null);
}
/**
@@ -902,7 +904,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null);
+ function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -925,7 +927,7 @@ public interface PooledLambda {
HexConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F> function,
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
- function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6);
+ function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null);
}
/**
@@ -946,7 +948,7 @@ public interface PooledLambda {
HexFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
- function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6);
+ function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null);
}
/**
@@ -982,7 +984,91 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
- function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6);
+ function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7) }
+ */
+ static <A, B, C, D, E, F, G> PooledRunnable obtainRunnable(
+ HeptConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7) }
+ */
+ static <A, B, C, D, E, F, G, R> PooledSupplier<R> obtainSupplier(
+ HeptFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6,
+ * arg7) } when handled
+ */
+ static <A, B, C, D, E, F, G> Message obtainMessage(
+ HeptConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 565ae1129cb4..eea1e5f0ac5c 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -24,6 +24,9 @@ import android.util.Pools;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
+import com.android.internal.util.function.HeptConsumer;
+import com.android.internal.util.function.HeptFunction;
+import com.android.internal.util.function.HeptPredicate;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.HexPredicate;
@@ -51,12 +54,12 @@ import java.util.function.Supplier;
* @hide
*/
final class PooledLambdaImpl<R> extends OmniFunction<Object,
- Object, Object, Object, Object, Object, R> {
+ Object, Object, Object, Object, Object, Object, R> {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "PooledLambdaImpl";
- private static final int MAX_ARGS = 5;
+ private static final int MAX_ARGS = 7;
private static final int MAX_POOL_SIZE = 50;
@@ -122,7 +125,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
/**
* Bit schema:
- * AAAABCDEEEEEEFFFFFF
+ * AAAAAAABCDEEEEEEFFFFFF
*
* Where:
* A - whether {@link #mArgs arg} at corresponding index was specified at
@@ -158,17 +161,17 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
@Override
- R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
+ R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
checkNotRecycled();
if (DEBUG) {
Log.i(LOG_TAG, this + ".invoke("
+ commaSeparateFirstN(
- new Object[] { a1, a2, a3, a4, a5, a6 },
+ new Object[] { a1, a2, a3, a4, a5, a6, a7 },
LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS)))
+ ")");
}
final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3)
- && fillInArg(a4) && fillInArg(a5) && fillInArg(a6);
+ && fillInArg(a4) && fillInArg(a5) && fillInArg(a6) && fillInArg(a7);
int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE));
if (argCount != LambdaType.MASK_ARG_COUNT) {
for (int i = 0; i < argCount; i++) {
@@ -333,6 +336,27 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
}
}
+
+ case 7: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((HeptConsumer) mFunc).accept(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4),
+ popArg(5), popArg(6));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((HeptPredicate) mFunc).test(popArg(0),
+ popArg(1), popArg(2), popArg(3),
+ popArg(4), popArg(5), popArg(6));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((HeptFunction) mFunc).apply(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4),
+ popArg(5), popArg(6));
+ }
+ }
+ }
}
throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
}
@@ -396,7 +420,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
*/
static <E extends PooledLambda> E acquire(Pool pool, Object func,
int fNumArgs, int numPlaceholders, int fReturnType,
- Object a, Object b, Object c, Object d, Object e, Object f) {
+ Object a, Object b, Object c, Object d, Object e, Object f, Object g) {
PooledLambdaImpl r = acquire(pool);
if (DEBUG) {
Log.i(LOG_TAG,
@@ -411,6 +435,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
+ ", d = " + d
+ ", e = " + e
+ ", f = " + f
+ + ", g = " + g
+ ")");
}
r.mFunc = func;
@@ -423,6 +448,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
setIfInBounds(r.mArgs, 3, d);
setIfInBounds(r.mArgs, 4, e);
setIfInBounds(r.mArgs, 5, f);
+ setIfInBounds(r.mArgs, 6, g);
return (E) r;
}
@@ -448,12 +474,12 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
@Override
- public OmniFunction<Object, Object, Object, Object, Object, Object, R> negate() {
+ public OmniFunction<Object, Object, Object, Object, Object, Object, Object, R> negate() {
throw new UnsupportedOperationException();
}
@Override
- public <V> OmniFunction<Object, Object, Object, Object, Object, Object, V> andThen(
+ public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, V> andThen(
Function<? super R, ? extends V> after) {
throw new UnsupportedOperationException();
}
@@ -474,7 +500,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
@Override
- public OmniFunction<Object, Object, Object, Object, Object, Object, R> recycleOnUse() {
+ public OmniFunction<Object, Object, Object, Object, Object, Object, Object, R> recycleOnUse() {
if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()");
mFlags |= FLAG_RECYCLE_ON_USE;
return this;
@@ -519,10 +545,10 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
* Contract for encoding a supported lambda type in {@link #MASK_BIT_COUNT} bits
*/
static class LambdaType {
- public static final int MASK_ARG_COUNT = 0b111;
- public static final int MASK_RETURN_TYPE = 0b111000;
+ public static final int MASK_ARG_COUNT = 0b1111;
+ public static final int MASK_RETURN_TYPE = 0b1110000;
public static final int MASK = MASK_ARG_COUNT | MASK_RETURN_TYPE;
- public static final int MASK_BIT_COUNT = 6;
+ public static final int MASK_BIT_COUNT = 7;
static int encode(int argCount, int returnType) {
return mask(MASK_ARG_COUNT, argCount) | mask(MASK_RETURN_TYPE, returnType);
@@ -557,6 +583,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
case 4: return "Quad";
case 5: return "Quint";
case 6: return "Hex";
+ case 7: return "Hept";
default: throw new IllegalArgumentException("" + argCount);
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index c96aaba60775..bdd5f83aa4ea 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -240,7 +240,7 @@ cc_library_shared {
],
shared_libs: [
- "libbpf",
+ "libbpf_android",
"libnetdbpf",
"libnetdutils",
"libmemtrack",
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index 36efd0a28b91..c26bebe65a7a 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -33,7 +33,7 @@
<item>LPP_PROFILE=3</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index a11dd95174a2..96338b589cd2 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -30,7 +30,7 @@
<item>LPP_PROFILE=3</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 8d29ec15bf6b..79f4bb6fdd0b 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -34,7 +34,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 650aa62b4a4e..10b007e9850d 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -32,7 +32,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
index 4bb68dcf04be..657d1e77c4ab 100644
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -28,7 +28,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index 735a8c80e4e8..ba8c75a179e9 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -34,7 +34,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8d3992d20555..200c35d67b17 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -248,6 +248,10 @@
<item>@string/wfcSpnFormat_spn_wifi</item>
<item>@string/wfcSpnFormat_wifi_calling_bar_spn</item>
<item>@string/wfcSpnFormat_spn_vowifi</item>
+ <item>@string/wfcSpnFormat_wifi_calling</item>
+ <item>@string/wfcSpnFormat_wifi</item>
+ <item>@string/wfcSpnFormat_wifi_calling_wo_hyphen</item>
+ <item>@string/wfcSpnFormat_vowifi</item>
</string-array>
<!-- Spn during Wi-Fi Calling: "<operator>" -->
@@ -264,6 +268,14 @@
<string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string>
<!-- Spn during Wi-Fi Calling: "<operator> VoWifi" -->
<string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string>
+ <!-- Spn during Wi-Fi Calling: "Wi-Fi Calling" -->
+ <string name="wfcSpnFormat_wifi_calling">Wi-Fi Calling</string>
+ <!-- Spn during Wi-Fi Calling: "Wi-Fi" -->
+ <string name="wfcSpnFormat_wifi">Wi-Fi</string>
+ <!-- Spn during Wi-Fi Calling: "WiFi Calling" (without hyphen) -->
+ <string name="wfcSpnFormat_wifi_calling_wo_hyphen">WiFi Calling</string>
+ <!-- Spn during Wi-Fi Calling: "VoWifi" -->
+ <string name="wfcSpnFormat_vowifi">VoWifi</string>
<!-- WFC, summary for Disabled -->
<string name="wifi_calling_off_summary">Off</string>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 0a4ac8cc5fec..c10e482f1d33 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -30,6 +30,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.security.KeyStoreException;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -40,14 +41,21 @@ import android.security.keymaster.OperationResult;
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
-
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import java.math.BigInteger;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.security.InvalidKeyException;
import java.util.List;
import java.util.Locale;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
/**
* @hide This should not be made public in its present form because it
@@ -69,6 +77,7 @@ public class KeyStore {
public static final int VALUE_CORRUPTED = 8;
public static final int UNDEFINED_ACTION = 9;
public static final int WRONG_PASSWORD = 10;
+ public static final int KEY_ALREADY_EXISTS = 16;
public static final int CANNOT_ATTEST_IDS = -66;
public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
@@ -239,7 +248,12 @@ public class KeyStore {
if (value == null) {
value = new byte[0];
}
- return mBinder.insert(key, value, uid, flags);
+ int error = mBinder.insert(key, value, uid, flags);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(key, uid);
+ error = mBinder.insert(key, value, uid, flags);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -366,53 +380,6 @@ public class KeyStore {
return isEmpty(UserHandle.myUserId());
}
- public boolean generate(String key, int uid, int keyType, int keySize, int flags,
- byte[][] args) {
- try {
- return mBinder.generate(key, uid, keyType, keySize, flags,
- new KeystoreArguments(args)) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean importKey(String keyName, byte[] key, int uid, int flags) {
- try {
- return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public byte[] sign(String key, byte[] data) {
- try {
- return mBinder.sign(key, data);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
-
- }
-
- public boolean verify(String key, byte[] data, byte[] signature) {
- try {
- signature = signature != null ? signature : new byte[0];
- return mBinder.verify(key, data, signature) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return false;
- }
-
- }
-
public String grant(String key, int uid) {
try {
String grantAlias = mBinder.grant(key, uid);
@@ -496,7 +463,12 @@ public class KeyStore {
try {
entropy = entropy != null ? entropy : new byte[0];
args = args != null ? args : new KeymasterArguments();
- return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ int error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(alias, uid);
+ error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -528,8 +500,14 @@ public class KeyStore {
public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
int uid, int flags, KeyCharacteristics outCharacteristics) {
try {
- return mBinder.importKey(alias, args, format, keyData, uid, flags,
+ int error = mBinder.importKey(alias, args, format, keyData, uid, flags,
outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(alias, uid);
+ error = mBinder.importKey(alias, args, format, keyData, uid, flags,
+ outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -541,13 +519,78 @@ public class KeyStore {
return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
}
+ private String getAlgorithmFromPKCS8(byte[] keyData) {
+ try {
+ final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
+ final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
+ final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
+ return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
+ } catch (IOException e) {
+ Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
+ Log.e(TAG, Log.getStackTraceString(e));
+ return null;
+ }
+ }
+
+ private KeymasterArguments makeLegacyArguments(String algorithm) {
+ KeymasterArguments args = new KeymasterArguments();
+ args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
+ KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+ if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
+ }
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
+ args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ KeymasterArguments.UINT64_MAX_VALUE);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ KeymasterArguments.UINT64_MAX_VALUE);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, BigInteger.ZERO);
+ return args;
+ }
+
+ public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
+ String algorithm = getAlgorithmFromPKCS8(keyData);
+ if (algorithm == null) return false;
+ KeymasterArguments args = makeLegacyArguments(algorithm);
+ KeyCharacteristics out = new KeyCharacteristics();
+ int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
+ flags, out);
+ if (result != NO_ERROR) {
+ Log.e(TAG, Log.getStackTraceString(
+ new KeyStoreException(result, "legacy key import failed")));
+ return false;
+ }
+ return true;
+ }
+
public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
String wrappingKeyAlias,
byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
KeyCharacteristics outCharacteristics) {
try {
- return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
+ int error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(wrappedKeyAlias, -1);
+ error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
+ maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -627,21 +670,6 @@ public class KeyStore {
}
/**
- * Check if the operation referenced by {@code token} is currently authorized.
- *
- * @param token An operation token returned by a call to
- * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
- */
- public boolean isOperationAuthorized(IBinder token) {
- try {
- return mBinder.isOperationAuthorized(token);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
* Add an authentication record to the keystore authorization table.
*
* @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 2152e1edc6f5..f179bc3f9d3d 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,8 +16,8 @@
package android.location;
-import android.annotation.TestApi;
import android.annotation.IntDef;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -685,6 +685,12 @@ public final class GnssMeasurement implements Parcelable {
*
* <p>This includes ensuring that all half-cycle ambiguities are resolved before this value is
* reported as {@link #ADR_STATE_VALID}.
+ *
+ * <p>The alignment of the phase measurement will not be adjusted by the receiver so the
+ * in-phase and quadrature phase components will have a quarter cycle offset as they do when
+ * transmitted from the satellites. If the measurement is from a combination of the in-phase
+ * and quadrature phase components, then the alignment of the phase measurement will be aligned
+ * to the in-phase component.
*/
public double getAccumulatedDeltaRangeMeters() {
return mAccumulatedDeltaRangeMeters;
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index f138685e9810..c86ebe70db5c 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -152,6 +152,13 @@
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button" />
<TextView
+ android:id="@+id/toggle_silent"
+ android:text="@string/inline_silent_button_silent"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ style="@style/TextAppearance.NotificationInfo.Button" />
+ <TextView
android:id="@+id/keep"
android:minWidth="48dp"
android:text="@string/inline_keep_button"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6f5d6577f700..50454fc9bcf2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1540,6 +1540,12 @@
<!-- Notification inline controls: Shown when a channel's notifications are minimized -->
<string name="notification_channel_minimized">These notifications will be minimized</string>
+ <!-- Notification inline controls: Shown when a channel's notifications are silenced [CHAR_LIMIT=100] -->
+ <string name="notification_channel_silenced">These notifications will be shown silently</string>
+
+ <!-- Notification inline controls: Shown when a channel's notifications are set to alert [CHAR_LIMIT=100] -->
+ <string name="notification_channel_unsilenced">These notifications will alert you</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_blocking_helper">You usually dismiss these notifications.
\nKeep showing them?</string>
@@ -1556,6 +1562,12 @@
<!-- Notification inline controls: minimize notifications button -->
<string name="inline_minimize_button">Minimize</string>
+ <!-- Notification inline controls: show notifications silently button [CHAR_LIMIT=25] -->
+ <string name="inline_silent_button_silent">Show silently</string>
+
+ <!-- Notification inline controls: show and alert button [CHAR_LIMIT=25] -->
+ <string name="inline_silent_button_alert">Show and alert</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
index d6472b7ddbb9..d294012a7527 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -16,17 +16,17 @@
package com.android.systemui.analytics;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent;
+
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayList;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent;
-
/**
* Collects touch, sensor and phone events and converts the data to
* TouchAnalyticsProto.Session.
@@ -104,6 +104,7 @@ public class SensorLoggerSession {
proto.startTimestampMillis = mStartTimestampMillis;
proto.durationMillis = mEndTimestampMillis - mStartTimestampMillis;
proto.build = Build.FINGERPRINT;
+ proto.deviceId = Build.DEVICE;
proto.result = mResult;
proto.type = mType;
proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index b84b77c6d105..fb62baa5c63c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -102,6 +102,8 @@ public class NotificationData {
public StatusBarNotification notification;
public NotificationChannel channel;
public boolean audiblyAlerted;
+ public boolean noisy;
+ public int importance;
public StatusBarIconView icon;
public StatusBarIconView expandedIcon;
public ExpandableNotificationRow row; // the outer expanded view
@@ -140,6 +142,16 @@ public class NotificationData {
*/
private boolean hasSentReply;
+ /**
+ * Whether this notification should be displayed as a bubble.
+ */
+ private boolean mIsBubble;
+
+ /**
+ * Whether the user has dismissed this notification when it was in bubble form.
+ */
+ private boolean mUserDismissedBubble;
+
public Entry(StatusBarNotification n) {
this(n, null);
}
@@ -155,6 +167,8 @@ public class NotificationData {
public void populateFromRanking(@NonNull Ranking ranking) {
channel = ranking.getChannel();
audiblyAlerted = ranking.audiblyAlerted();
+ noisy = ranking.isNoisy();
+ importance = ranking.getImportance();
snoozeCriteria = ranking.getSnoozeCriteria();
userSentiment = ranking.getUserSentiment();
smartActions = ranking.getSmartActions() == null
@@ -172,6 +186,22 @@ public class NotificationData {
return interruption;
}
+ public void setIsBubble(boolean bubbleable) {
+ mIsBubble = bubbleable;
+ }
+
+ public boolean isBubble() {
+ return mIsBubble;
+ }
+
+ public void setBubbleDismissed(boolean userDismissed) {
+ mUserDismissedBubble = userDismissed;
+ }
+
+ public boolean isBubbleDismissed() {
+ return mUserDismissedBubble;
+ }
+
/**
* Resets the notification entry to be re-used.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
index 28c07a34beed..43b5503682cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
@@ -30,6 +30,9 @@ public class NotificationCounters {
/** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
"blocking_helper_stop_notifications";
+ /** Counter tag for when the user hits 'show silently' in the blocking helper. */
+ public static final String BLOCKING_HELPER_TOGGLE_SILENT =
+ "blocking_helper_toggle_silent";
/** Counter tag for when the user hits 'keep showing' in the blocking helper. */
public static final String BLOCKING_HELPER_KEEP_SHOWING =
"blocking_helper_keep_showing";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 0a197daf9186..fbe9c5d40beb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -23,7 +23,6 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -31,6 +30,8 @@ import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
@@ -98,6 +99,11 @@ public class NotificationGuts extends FrameLayout {
* Return whether something changed and needs to be saved, possibly requiring a bouncer.
*/
boolean shouldBeSaved();
+
+ /**
+ * Called when the guts view has finished its close animation.
+ */
+ default void onFinishedClosing() {}
}
public interface OnGutsClosedListener {
@@ -304,7 +310,7 @@ public class NotificationGuts extends FrameLayout {
x, y, r, 0);
a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- a.addListener(new AnimateCloseListener(this /* view */));
+ a.addListener(new AnimateCloseListener(this /* view */, mGutsContent));
a.start();
} else {
// Fade in the blocking helper.
@@ -312,11 +318,12 @@ public class NotificationGuts extends FrameLayout {
.alpha(0f)
.setDuration(StackStateAnimator.ANIMATION_DURATION_BLOCKING_HELPER_FADE)
.setInterpolator(Interpolators.ALPHA_OUT)
- .setListener(new AnimateCloseListener(this /* view */))
+ .setListener(new AnimateCloseListener(this, /* view */mGutsContent))
.start();
}
} else {
Log.w(TAG, "Failed to animate guts close");
+ mGutsContent.onFinishedClosing();
}
}
@@ -414,15 +421,18 @@ public class NotificationGuts extends FrameLayout {
/** Listener for animations executed in {@link #animateClose(int, int, boolean)}. */
private static class AnimateCloseListener extends AnimatorListenerAdapter {
final View mView;
+ private final GutsContent mGutsContent;
- private AnimateCloseListener(View view) {
+ private AnimateCloseListener(View view, GutsContent gutsContent) {
mView = view;
+ mGutsContent = gutsContent;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mView.setVisibility(View.GONE);
+ mGutsContent.onFinishedClosing();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 24999525ab72..b838c9b5482d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -28,7 +28,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -46,15 +45,13 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -298,7 +295,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
isForBlockingHelper,
- row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
+ row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE,
+ row.getEntry().noisy,
+ row.getEntry().importance);
}
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 903c27277b70..522da4d51470 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
@@ -16,13 +16,18 @@
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;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.Notification;
@@ -54,6 +59,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import java.util.List;
@@ -65,6 +71,17 @@ import java.util.List;
public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
private static final String TAG = "InfoGuts";
+ @IntDef(prefix = { "SWAP_CONTENT_" }, value = {
+ SWAP_CONTENT_UNDO,
+ SWAP_CONTENT_TOGGLE_SILENT,
+ SWAP_CONTENT_BLOCK,
+ })
+ @interface SwapContentAction {}
+
+ private static final int SWAP_CONTENT_UNDO = 0;
+ private static final int SWAP_CONTENT_TOGGLE_SILENT = 1;
+ private static final int SWAP_CONTENT_BLOCK = 2;
+
private INotificationManager mINotificationManager;
private PackageManager mPm;
private MetricsLogger mMetricsLogger;
@@ -74,7 +91,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private int mAppUid;
private int mNumUniqueChannelsInRow;
private NotificationChannel mSingleNotificationChannel;
- private int mStartingUserImportance;
+ private int mStartingChannelImportance;
+ private int mStartingChannelOrNotificationImportance;
private int mChosenImportance;
private boolean mIsSingleDefaultChannel;
private boolean mIsNonblockable;
@@ -82,6 +100,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private AnimatorSet mExpandAnimation;
private boolean mIsForeground;
private boolean mIsDeviceProvisioned;
+ private boolean mIsNoisy;
private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
@@ -102,10 +121,22 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
closeControls(v);
};
+ private OnClickListener mOnToggleSilent = v -> {
+ Runnable saveImportance = () -> {
+ mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
+ swapContent(SWAP_CONTENT_TOGGLE_SILENT);
+ };
+ if (mCheckSaveListener != null) {
+ mCheckSaveListener.checkSave(saveImportance, mSbn);
+ } else {
+ saveImportance.run();
+ }
+ };
+
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
Runnable saveImportance = () -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
- swapContent(false);
+ swapContent(SWAP_CONTENT_BLOCK);
};
if (mCheckSaveListener != null) {
mCheckSaveListener.checkSave(saveImportance, mSbn);
@@ -118,7 +149,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// Reset exit counter that we'll log and record an undo event separately (not an exit event)
mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
- swapContent(true);
+ swapContent(SWAP_CONTENT_UNDO);
};
public NotificationInfo(Context context, AttributeSet attrs) {
@@ -152,12 +183,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
final OnSettingsClickListener onSettingsClick,
final OnAppSettingsClickListener onAppSettingsClick,
boolean isDeviceProvisioned,
- boolean isNonblockable)
+ boolean isNonblockable,
+ boolean isNoisy,
+ int importance)
throws RemoteException {
bindNotification(pm, iNotificationManager, pkg, notificationChannel,
numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
onAppSettingsClick, isDeviceProvisioned, isNonblockable,
- false /* isBlockingHelper */, false /* isUserSentimentNegative */);
+ false /* isBlockingHelper */, false /* isUserSentimentNegative */, isNoisy,
+ importance);
}
public void bindNotification(
@@ -173,7 +207,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean isDeviceProvisioned,
boolean isNonblockable,
boolean isForBlockingHelper,
- boolean isUserSentimentNegative)
+ boolean isUserSentimentNegative,
+ boolean isNoisy,
+ int importance)
throws RemoteException {
mINotificationManager = iNotificationManager;
mMetricsLogger = Dependency.get(MetricsLogger.class);
@@ -186,7 +222,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mCheckSaveListener = checkSaveListener;
mOnSettingsClickListener = onSettingsClick;
mSingleNotificationChannel = notificationChannel;
- mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
+ int channelImportance = mSingleNotificationChannel.getImportance();
+ mStartingChannelImportance = mChosenImportance = channelImportance;
+ mStartingChannelOrNotificationImportance =
+ channelImportance == IMPORTANCE_UNSPECIFIED ? importance : channelImportance;
mNegativeUserSentiment = isUserSentimentNegative;
mIsNonblockable = isNonblockable;
mIsForeground =
@@ -194,6 +233,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mIsForBlockingHelper = isForBlockingHelper;
mAppUid = mSbn.getUid();
mIsDeviceProvisioned = isDeviceProvisioned;
+ mIsNoisy = isNoisy;
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
@@ -306,7 +346,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
private boolean hasImportanceChanged() {
- return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
+ return mSingleNotificationChannel != null
+ && mStartingChannelImportance != mChosenImportance;
}
private void saveImportance() {
@@ -320,34 +361,46 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
*/
private void updateImportance() {
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
- mChosenImportance - mStartingUserImportance);
+ mChosenImportance - mStartingChannelImportance);
Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
bgHandler.post(new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
- mStartingUserImportance, mChosenImportance));
+ mStartingChannelImportance, mChosenImportance));
}
private void bindButtons() {
// Set up stay-in-notification actions
View block = findViewById(R.id.block);
TextView keep = findViewById(R.id.keep);
+ TextView silent = findViewById(R.id.toggle_silent);
View minimize = findViewById(R.id.minimize);
findViewById(R.id.undo).setOnClickListener(mOnUndo);
block.setOnClickListener(mOnStopOrMinimizeNotifications);
keep.setOnClickListener(mOnKeepShowing);
+ silent.setOnClickListener(mOnToggleSilent);
minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
if (mIsNonblockable) {
keep.setText(android.R.string.ok);
block.setVisibility(GONE);
+ silent.setVisibility(GONE);
minimize.setVisibility(GONE);
} else if (mIsForeground) {
block.setVisibility(GONE);
+ silent.setVisibility(GONE);
minimize.setVisibility(VISIBLE);
- } else if (!mIsForeground) {
+ } else {
block.setVisibility(VISIBLE);
+ boolean showToggleSilent = mIsNoisy
+ && NotificationUtils.useNewInterruptionModel(mContext);
+ silent.setVisibility(showToggleSilent ? VISIBLE : GONE);
+ boolean isCurrentlyAlerting =
+ mStartingChannelOrNotificationImportance >= IMPORTANCE_DEFAULT;
+ silent.setText(isCurrentlyAlerting
+ ? R.string.inline_silent_button_silent
+ : R.string.inline_silent_button_alert);
minimize.setVisibility(GONE);
}
@@ -368,7 +421,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
- private void swapContent(boolean showPrompt) {
+ private void swapContent(@SwapContentAction int action) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
}
@@ -378,26 +431,43 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
TextView confirmationText = findViewById(R.id.confirmation_text);
View header = findViewById(R.id.header);
- if (showPrompt) {
- mChosenImportance = mStartingUserImportance;
- } else if (mIsForeground) {
- mChosenImportance = IMPORTANCE_MIN;
- confirmationText.setText(R.string.notification_channel_minimized);
- } else {
- mChosenImportance = IMPORTANCE_NONE;
- confirmationText.setText(R.string.notification_channel_disabled);
+ switch (action) {
+ case SWAP_CONTENT_UNDO:
+ mChosenImportance = mStartingChannelImportance;
+ break;
+ case SWAP_CONTENT_TOGGLE_SILENT:
+ if (mStartingChannelOrNotificationImportance >= IMPORTANCE_DEFAULT) {
+ mChosenImportance = IMPORTANCE_LOW;
+ confirmationText.setText(R.string.notification_channel_silenced);
+ } else {
+ mChosenImportance = IMPORTANCE_HIGH;
+ confirmationText.setText(R.string.notification_channel_unsilenced);
+ }
+ break;
+ case SWAP_CONTENT_BLOCK:
+ if (mIsForeground) {
+ mChosenImportance = IMPORTANCE_MIN;
+ confirmationText.setText(R.string.notification_channel_minimized);
+ } else {
+ mChosenImportance = IMPORTANCE_NONE;
+ confirmationText.setText(R.string.notification_channel_disabled);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException();
}
+ boolean isUndo = action == SWAP_CONTENT_UNDO;
ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
- prompt.getAlpha(), showPrompt ? 1f : 0f);
- promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+ prompt.getAlpha(), isUndo ? 1f : 0f);
+ promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
- confirmation.getAlpha(), showPrompt ? 0f : 1f);
- confirmAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
+ confirmation.getAlpha(), isUndo ? 0f : 1f);
+ confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
- prompt.setVisibility(showPrompt ? VISIBLE : GONE);
- confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
- header.setVisibility(showPrompt ? VISIBLE : GONE);
+ prompt.setVisibility(isUndo ? VISIBLE : GONE);
+ confirmation.setVisibility(isUndo ? GONE : VISIBLE);
+ header.setVisibility(isUndo ? VISIBLE : GONE);
mExpandAnimation = new AnimatorSet();
mExpandAnimation.playTogether(promptAnim, confirmAnim);
@@ -413,8 +483,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@Override
public void onAnimationEnd(Animator animation) {
if (!cancelled) {
- prompt.setVisibility(showPrompt ? VISIBLE : GONE);
- confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
+ prompt.setVisibility(isUndo ? VISIBLE : GONE);
+ confirmation.setVisibility(isUndo ? GONE : VISIBLE);
}
}
});
@@ -428,6 +498,25 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
@Override
+ public void onFinishedClosing() {
+ mStartingChannelImportance = mChosenImportance;
+ if (mChosenImportance != IMPORTANCE_UNSPECIFIED) {
+ mStartingChannelOrNotificationImportance = mChosenImportance;
+ }
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+
+ View prompt = findViewById(R.id.prompt);
+ ViewGroup confirmation = findViewById(R.id.confirmation);
+ View header = findViewById(R.id.header);
+ prompt.setVisibility(VISIBLE);
+ prompt.setAlpha(1f);
+ confirmation.setVisibility(GONE);
+ confirmation.setAlpha(1f);
+ header.setVisibility(VISIBLE);
+ header.setAlpha(1f);
+ }
+
+ @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
if (mGutsContainer != null &&
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index c3bf16e0f796..a315bf3c2d99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1124,7 +1124,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getExpandTranslationStart() {
- return -mTopPadding + getMinExpansionHeight();
+ return -mTopPadding + getMinExpansionHeight() - mShelf.getIntrinsicHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
index 50fd52ae0070..cfb633d61bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
@@ -134,4 +134,6 @@ message Session {
optional int32 touchAreaHeight = 10;
optional Type type = 11;
repeated PhoneEvent phoneEvents = 12;
+
+ optional string device_id = 13;
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index 0251f64fd6df..8e6bfe3a5f91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -437,15 +437,15 @@ public class NotificationDataTest extends SysuiTestCase {
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
- false, null, null);
+ false, false, null, null);
} else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
outRanking.getVisibilityOverride(), 255,
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), true, false, null,
- null);
+ outRanking.canShowBadge(), outRanking.getUserSentiment(), true, false,
+ false, null, null);
} else {
outRanking.populate(key, outRanking.getRank(),
outRanking.matchesInterruptionFilter(),
@@ -453,8 +453,7 @@ public class NotificationDataTest extends SysuiTestCase {
outRanking.getImportance(), outRanking.getImportanceExplanation(),
outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
outRanking.canShowBadge(), outRanking.getUserSentiment(), false, false,
- null,
- null);
+ false, null, null);
}
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 9c68e7d9ef3a..9f8a5cc0afdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -167,7 +167,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
0,
NotificationManager.IMPORTANCE_DEFAULT,
null, null,
- null, null, null, true, sentiment, false, false, null, null);
+ null, null, null, true, sentiment, false, false, false, null, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
}
@@ -186,7 +186,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
null, null,
null, null, null, true,
NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, false,
- smartActions, null);
+ false, smartActions, null);
return true;
}).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index ee35449e05da..626726d4aa4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -19,8 +19,10 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.Ranking
+ .USER_SENTIMENT_NEGATIVE;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
@@ -34,15 +36,14 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -57,11 +58,12 @@ import android.view.View;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager
+ .OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -71,8 +73,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.junit.MockitoRule;
import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
/**
* Tests for {@link NotificationGutsManager}.
@@ -84,7 +86,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
- TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
+ TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
private TestableLooper mTestableLooper;
private Handler mHandler;
private NotificationTestHelper mHelper;
@@ -297,7 +299,9 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */);
+ eq(true) /* isUserSentimentNegative */,
+ eq(false) /*isNoisy */,
+ eq(0));
}
@Test
@@ -324,7 +328,69 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(false) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */);
+ eq(true) /* isUserSentimentNegative */,
+ eq(false) /*isNoisy */,
+ eq(0));
+ }
+
+ @Test
+ public void testInitializeNotificationInfoView_noisy() throws Exception {
+ NotificationInfo notificationInfoView = mock(NotificationInfo.class);
+ ExpandableNotificationRow row = spy(mHelper.createRow());
+ row.setBlockingHelperShowing(true);
+ row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+ row.getEntry().noisy = true;
+ when(row.getIsNonblockable()).thenReturn(false);
+ StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+
+ mGutsManager.initializeNotificationInfo(row, notificationInfoView);
+
+ verify(notificationInfoView).bindNotification(
+ any(PackageManager.class),
+ any(INotificationManager.class),
+ eq(statusBarNotification.getPackageName()),
+ any(NotificationChannel.class),
+ anyInt(),
+ eq(statusBarNotification),
+ any(NotificationInfo.CheckSaveListener.class),
+ any(NotificationInfo.OnSettingsClickListener.class),
+ any(NotificationInfo.OnAppSettingsClickListener.class),
+ eq(false),
+ eq(false),
+ eq(true) /* isForBlockingHelper */,
+ eq(true) /* isUserSentimentNegative */,
+ eq(true) /*isNoisy */,
+ eq(0));
+ }
+
+ @Test
+ public void testInitializeNotificationInfoView_importance() throws Exception {
+ NotificationInfo notificationInfoView = mock(NotificationInfo.class);
+ ExpandableNotificationRow row = spy(mHelper.createRow());
+ row.setBlockingHelperShowing(true);
+ row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+ row.getEntry().importance = IMPORTANCE_DEFAULT;
+ when(row.getIsNonblockable()).thenReturn(false);
+ StatusBarNotification statusBarNotification = row.getStatusBarNotification();
+
+ mGutsManager.initializeNotificationInfo(row, notificationInfoView);
+
+ verify(notificationInfoView).bindNotification(
+ any(PackageManager.class),
+ any(INotificationManager.class),
+ eq(statusBarNotification.getPackageName()),
+ any(NotificationChannel.class),
+ anyInt(),
+ eq(statusBarNotification),
+ any(NotificationInfo.CheckSaveListener.class),
+ any(NotificationInfo.OnSettingsClickListener.class),
+ any(NotificationInfo.OnAppSettingsClickListener.class),
+ eq(false),
+ eq(false),
+ eq(true) /* isForBlockingHelper */,
+ eq(true) /* isUserSentimentNegative */,
+ eq(false) /*isNoisy */,
+ eq(IMPORTANCE_DEFAULT));
}
@Test
@@ -352,7 +418,9 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(true),
eq(false),
eq(false) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */);
+ eq(true) /* isUserSentimentNegative */,
+ eq(false) /*isNoisy */,
+ eq(0));
}
@Test
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 ca968a8af85b..37441963e32d 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
@@ -17,11 +17,14 @@
package com.android.systemui.statusbar.notification.row;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
+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;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -56,6 +59,7 @@ import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -72,6 +76,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -150,6 +155,15 @@ public class NotificationInfoTest extends SysuiTestCase {
IMPORTANCE_LOW);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
}
// TODO: if tests are taking too long replace this with something that makes the animation
@@ -172,7 +186,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -184,7 +199,8 @@ public class NotificationInfoTest extends SysuiTestCase {
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
assertEquals(iconDrawable, iconView.getDrawable());
}
@@ -192,7 +208,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
@@ -208,7 +225,8 @@ public class NotificationInfoTest extends SysuiTestCase {
eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(notificationChannelGroup);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
@@ -219,7 +237,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -228,7 +247,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
- false);
+ false, false, IMPORTANCE_DEFAULT);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
}
@@ -241,7 +260,7 @@ public class NotificationInfoTest extends SysuiTestCase {
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
- false);
+ false, false, IMPORTANCE_DEFAULT);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -249,7 +268,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -257,18 +277,71 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_BlockButton() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final View block = mNotificationInfo.findViewById(R.id.block);
+ final View toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent);
final View minimize = mNotificationInfo.findViewById(R.id.minimize);
assertEquals(VISIBLE, block.getVisibility());
+ assertEquals(GONE, toggleSilent.getVisibility());
assertEquals(GONE, minimize.getVisibility());
}
@Test
+ public void testBindNotification_SilenceButton() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_DEFAULT);
+ final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent);
+ assertEquals(VISIBLE, toggleSilent.getVisibility());
+ assertEquals(
+ mContext.getString(R.string.inline_silent_button_silent), toggleSilent.getText());
+ }
+
+ @Test
+ public void testBindNotification_UnSilenceButton() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_LOW);
+ final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent);
+ assertEquals(VISIBLE, toggleSilent.getVisibility());
+ assertEquals(
+ mContext.getString(R.string.inline_silent_button_alert), toggleSilent.getText());
+ }
+
+ @Test
+ public void testBindNotification_SilenceButton_ChannelImportanceUnspecified() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_DEFAULT);
+ final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent);
+ assertEquals(VISIBLE, toggleSilent.getVisibility());
+ assertEquals(
+ mContext.getString(R.string.inline_silent_button_silent), toggleSilent.getText());
+ }
+
+ @Test
+ public void testBindNotification_UnSilenceButton_ChannelImportanceUnspecified()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_LOW);
+ final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent);
+ assertEquals(VISIBLE, toggleSilent.getVisibility());
+ assertEquals(
+ mContext.getString(R.string.inline_silent_button_alert), toggleSilent.getText());
+ }
+
+ @Test
public void testBindNotification_MinButton() throws Exception {
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final View block = mNotificationInfo.findViewById(R.id.block);
final View minimize = mNotificationInfo.findViewById(R.id.minimize);
assertEquals(GONE, block.getVisibility());
@@ -283,7 +356,7 @@ public class NotificationInfoTest extends SysuiTestCase {
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
- }, null, true, false);
+ }, null, true, false, false, IMPORTANCE_DEFAULT);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -294,7 +367,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -306,7 +380,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
- }, null, false, false);
+ }, null, false, false, false, IMPORTANCE_DEFAULT);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -314,11 +388,12 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
- }, null, true, false);
+ }, null, true, false, false, IMPORTANCE_DEFAULT);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertEquals(View.VISIBLE, settingsButton.getVisibility());
}
@@ -326,7 +401,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
}
@@ -335,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
- true, true);
+ true, true, false, IMPORTANCE_DEFAULT);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
verify(mMetricsLogger, times(1)).count(anyString(), anyInt());
}
@@ -348,7 +424,7 @@ public class NotificationInfoTest extends SysuiTestCase {
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
latch.countDown();
- }, null, true, true);
+ }, null, true, true, false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.info).performClick();
// Verify that listener was triggered.
@@ -361,7 +437,7 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
- null, true, true);
+ null, true, true, false, IMPORTANCE_DEFAULT);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
@@ -372,7 +448,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
- null, true, true);
+ null, true, true, false, IMPORTANCE_DEFAULT);
final TextView blockView = mNotificationInfo.findViewById(R.id.block);
assertEquals(GONE, blockView.getVisibility());
}
@@ -381,7 +457,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testbindNotification_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false,
- true, true);
+ true, true, false, IMPORTANCE_DEFAULT);
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
@@ -390,7 +466,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
@@ -400,7 +477,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -410,7 +488,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
mTestableLooper.processAllMessages();
@@ -423,7 +502,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
mTestableLooper.processAllMessages();
@@ -432,11 +512,40 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
+ public void testDoesNotUpdateNotificationChannelAfterImportanceChangedSilenced()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ mTestableLooper.processAllMessages();
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
+ }
+
+ @Test
+ public void testDoesNotUpdateNotificationChannelAfterImportanceChangedUnSilenced()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ mTestableLooper.processAllMessages();
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
+ }
+
+ @Test
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
throws Exception {
int originalImportance = mNotificationChannel.getImportance();
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -450,7 +559,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.handleCloseControls(true, false);
@@ -468,7 +578,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */ ,
- true, false /* isNonblockable */);
+ true, false /* isNonblockable */, false, /* isNoisy */IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -489,7 +599,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */ ,
- true, false /* isNonblockable */);
+ true, false /* isNonblockable */, false, /* isNoisy */IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -510,7 +620,7 @@ public class NotificationInfoTest extends SysuiTestCase {
null /* onSettingsClick */, null /* onAppSettingsClick */ ,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */);
+ true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT);
NotificationGuts guts = spy(new NotificationGuts(mContext, null));
when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -538,7 +648,7 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */);
+ true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT);
NotificationGuts guts = spy(new NotificationGuts(mContext, null));
when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -566,7 +676,8 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */ ,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true, true /* isUserSentimentNegative */);
+ true, true /* isUserSentimentNegative */, false, /* isNoisy */
+ IMPORTANCE_DEFAULT);
mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
@@ -585,7 +696,7 @@ public class NotificationInfoTest extends SysuiTestCase {
null /* onSettingsClick */, null /* onAppSettingsClick */,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */);
+ true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
mTestableLooper.processAllMessages();
@@ -607,7 +718,8 @@ public class NotificationInfoTest extends SysuiTestCase {
false /* isNonblockable */,
true /* isForBlockingHelper */,
true,
- false /* isUserSentimentNegative */);
+ false /* isUserSentimentNegative */,
+ false, /* isNoisy */IMPORTANCE_DEFAULT);
NotificationGuts guts = mock(NotificationGuts.class);
doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
mNotificationInfo.setGutsParent(guts);
@@ -621,7 +733,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -634,7 +747,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBlockChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -666,7 +780,8 @@ public class NotificationInfoTest extends SysuiTestCase {
true /*provisioned */,
false /* isNonblockable */,
true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */);
+ true /* isUserSentimentNegative */,
+ false, /* isNoisy */IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -687,7 +802,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -701,7 +817,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -721,7 +838,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testKeepUpdatesNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.handleCloseControls(true, false);
@@ -738,7 +856,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBlockUndoDoesNotBlockNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -759,7 +878,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testMinUndoDoesNotMinNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -777,10 +897,97 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@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,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+ }
+
+ @Test
+ public void testUnSilenceCallsUpdateNotificationChannel() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance());
+ }
+
+ @Test
+ public void testSilenceCallsUpdateNotificationChannel_channelImportanceUnspecified()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+ }
+
+ @Test
+ public void testUnSilenceCallsUpdateNotificationChannel_channelImportanceUnspecified()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_LOW);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance());
+ }
+
+ @Test
public void testCloseControlsDoesNotUpdateiMinIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -795,7 +1002,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -812,7 +1020,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
- }, null, null, true, true);
+ }, null, null, true, true, false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
mTestableLooper.processAllMessages();
@@ -830,7 +1038,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
- }, null, null, true, false);
+ }, null, null, true, false, false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
mTestableLooper.processAllMessages();
@@ -866,7 +1074,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
- }, true, false);
+ }, true, false, false, IMPORTANCE_DEFAULT);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
settingsLink.performClick();
@@ -894,7 +1102,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
- }, true, false);
+ }, true, false, false, IMPORTANCE_DEFAULT);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
settingsLink.performClick();
@@ -913,7 +1121,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null,
- null, true, false);
+ null, true, false, false, IMPORTANCE_DEFAULT);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(GONE, settingsLink.getVisibility());
}
@@ -933,7 +1141,8 @@ public class NotificationInfoTest extends SysuiTestCase {
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, true, false);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(GONE, settingsLink.getVisibility());
}
@@ -956,7 +1165,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, false, true,
- true, true);
+ true, true, false, IMPORTANCE_DEFAULT);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(GONE, settingsLink.getVisibility());
}
@@ -972,7 +1181,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
@@ -984,7 +1194,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testUndoText_block() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -993,10 +1204,39 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@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, true,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_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, true,
+ true, IMPORTANCE_DEFAULT);
+
+ mNotificationInfo.findViewById(R.id.toggle_silent).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, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -1007,7 +1247,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testHeaderOnUndo() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
+ false, IMPORTANCE_DEFAULT);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 32667b850888..5814064e5fbd 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -36,8 +37,11 @@ import android.app.AppOpsManager.HistoricalOpEntry;
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -645,6 +649,26 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ final IntentFilter packageSuspendFilter = new IntentFilter();
+ packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ final String[] changedPkgs = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
+ for (int i = 0; i < changedUids.length; i++) {
+ final int changedUid = changedUids[i];
+ final String changedPkg = changedPkgs[i];
+ // We trust packagemanager to insert matching uid and packageNames in the extras
+ mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
+ AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
+ }
+ }
+ }, packageSuspendFilter);
+
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
packageManagerInternal.setExternalSourcesPolicy(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c52df2d5db82..c645e52a33fc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3046,35 +3046,18 @@ public class ActivityManagerService extends IActivityManager.Stub
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- synchronized (this) {
- /**
- * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
- * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
- * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
- * later to modify process settings due to the flags.
- * TODO(b/80414790): Investigate a better way of untangling this.
- */
+
return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
bOptions, userId);
- }
}
WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- synchronized (this) {
- /**
- * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
- * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
- * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
- * later to modify process settings due to the flags.
- * TODO(b/80414790): Investigate a better way of untangling this.
- */
return mActivityTaskManager.startActivityAndWait(caller, callingPackage, intent,
resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
bOptions, userId);
- }
}
@Override
@@ -19166,22 +19149,30 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
- ProfilerInfo profilerInfo) {
+ ProfilerInfo profilerInfo, Object wmLock) {
synchronized (ActivityManagerService.this) {
- if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
- setDebugApp(aInfo.processName, true, false);
- }
+ /**
+ * This function is called from the window manager context and needs to be executed
+ * synchronously. To avoid deadlock, we pass a message to AMS to execute the
+ * function and notify the passed in lock when it has been completed.
+ */
+ synchronized (wmLock) {
+ if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
+ setDebugApp(aInfo.processName, true, false);
+ }
- if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
- setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
- }
+ if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
+ setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
+ }
- if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
- setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
- }
+ if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
+ setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
+ }
- if (profilerInfo != null) {
- setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+ if (profilerInfo != null) {
+ setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+ }
+ wmLock.notify();
}
}
}
@@ -19473,7 +19464,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void startDelegateShellPermissionIdentity(int delegateUid) {
+ public void startDelegateShellPermissionIdentity(int delegateUid,
+ @Nullable String[] permissions) {
if (UserHandle.getCallingAppId() != Process.SHELL_UID
&& UserHandle.getCallingAppId() != Process.ROOT_UID) {
throw new SecurityException("Only the shell can delegate its permissions");
@@ -19492,11 +19484,13 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) {
throw new IllegalStateException("Bad shell delegate state");
}
- if (((ShellDelegate) mAppOpsService.getAppOpsServiceDelegate())
- .getDelegateUid() != delegateUid) {
+ final ShellDelegate delegate = (ShellDelegate) mAppOpsService
+ .getAppOpsServiceDelegate();
+ if (delegate.getDelegateUid() != delegateUid) {
throw new SecurityException("Shell can delegate permissions only "
+ "to one instrumentation at a time");
}
+ delegate.setPermissions(permissions);
return;
}
@@ -19514,7 +19508,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Hook them up...
final ShellDelegate shellDelegate = new ShellDelegate(
- instr.mTargetInfo.packageName, delegateUid);
+ instr.mTargetInfo.packageName, delegateUid, permissions);
mAppOpsService.setAppOpsServiceDelegate(shellDelegate);
getPackageManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
return;
@@ -19537,20 +19531,26 @@ public class ActivityManagerService extends IActivityManager.Stub
private class ShellDelegate implements CheckOpsDelegate, CheckPermissionDelegate {
private final String mTargetPackageName;
private final int mTargetUid;
+ private @Nullable String[] mPermissions;
- ShellDelegate(String targetPacakgeName, int targetUid) {
+ ShellDelegate(String targetPacakgeName, int targetUid, @Nullable String[] permissions) {
mTargetPackageName = targetPacakgeName;
mTargetUid = targetUid;
+ mPermissions = permissions;
}
int getDelegateUid() {
return mTargetUid;
}
+ void setPermissions(@Nullable String[] permissions) {
+ mPermissions = permissions;
+ }
+
@Override
public int checkOperation(int code, int uid, String packageName,
TriFunction<Integer, Integer, String, Integer> superImpl) {
- if (uid == mTargetUid) {
+ if (uid == mTargetUid && isTargetOp(code)) {
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(code, Process.SHELL_UID,
@@ -19565,7 +19565,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkAudioOperation(int code, int usage, int uid, String packageName,
QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) {
- if (uid == mTargetUid) {
+ if (uid == mTargetUid && isTargetOp(code)) {
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(code, usage, Process.SHELL_UID,
@@ -19580,7 +19580,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int noteOperation(int code, int uid, String packageName,
TriFunction<Integer, Integer, String, Integer> superImpl) {
- if (uid == mTargetUid) {
+ if (uid == mTargetUid && isTargetOp(code)) {
final long identity = Binder.clearCallingIdentity();
try {
return mAppOpsService.noteProxyOperation(code, Process.SHELL_UID,
@@ -19595,7 +19595,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkPermission(String permName, String pkgName, int userId,
TriFunction<String, String, Integer, Integer> superImpl) {
- if (mTargetPackageName.equals(pkgName)) {
+ if (mTargetPackageName.equals(pkgName) && isTargetPermission(permName)) {
return superImpl.apply(permName, "com.android.shell", userId);
}
return superImpl.apply(permName, pkgName, userId);
@@ -19604,11 +19604,29 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkUidPermission(String permName, int uid,
BiFunction<String, Integer, Integer> superImpl) {
- if (uid == mTargetUid) {
+ if (uid == mTargetUid && isTargetPermission(permName)) {
return superImpl.apply(permName, Process.SHELL_UID);
}
return superImpl.apply(permName, uid);
}
+
+ private boolean isTargetOp(int code) {
+ // null permissions means all ops are targeted
+ if (mPermissions == null) {
+ return true;
+ }
+ // no permission for the op means the op is targeted
+ final String permission = AppOpsManager.opToPermission(code);
+ if (permission == null) {
+ return true;
+ }
+ return isTargetPermission(permission);
+ }
+
+ private boolean isTargetPermission(@NonNull String permission) {
+ // null permissions means all permissions are targeted
+ return (mPermissions == null || ArrayUtils.contains(mPermissions, permission));
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index fe402eaa29b6..90180065461a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2105,8 +2105,13 @@ final class ActivityManagerShellCommand extends ShellCommand {
}
FeatureInfo[] features = pm.getSystemAvailableFeatures();
- Arrays.sort(features, (o1, o2) ->
- (o1.name == o2.name ? 0 : (o1.name == null ? -1 : o1.name.compareTo(o2.name))));
+ Arrays.sort(features, (o1, o2) -> {
+ if (o1.name == o2.name) return 0;
+ if (o1.name == null) return -1;
+ if (o2.name == null) return 1;
+ return o1.name.compareTo(o2.name);
+ });
+
for (int i = 0; i < features.length; i++) {
if (features[i].name != null) {
if (protoOutputStream != null) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 0ee55ed2e832..527539d8ce0d 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.media.AudioManager;
import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
@@ -393,6 +394,19 @@ public class CameraServiceProxy extends SystemService
boolean wasEmpty = mActiveCameraUsage.isEmpty();
switch (newCameraState) {
case ICameraServiceProxy.CAMERA_STATE_OPEN:
+ // Notify the audio subsystem about the facing of the most-recently opened
+ // camera This can be used to select the best audio tuning in case video
+ // recording with that camera will happen. Since only open events are used, if
+ // multiple cameras are opened at once, the one opened last will be used to
+ // select audio tuning.
+ AudioManager audioManager = getContext().getSystemService(AudioManager.class);
+ if (audioManager != null) {
+ // Map external to front for audio tuning purposes
+ String facingStr = (facing == ICameraServiceProxy.CAMERA_FACING_BACK) ?
+ "back" : "front";
+ String facingParameter = "cameraFacing=" + facingStr;
+ audioManager.setParameters(facingParameter);
+ }
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index deaa33485170..94c94a514dec 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -165,7 +165,7 @@ public class PermissionMonitor {
}
@VisibleForTesting
- int getDeviceFirstSdkInt() {
+ protected int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f87a5f7a1a52..b404c41c211d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6564,6 +6564,7 @@ public class NotificationManagerService extends SystemService {
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
Bundle audiblyAlerted = new Bundle();
+ Bundle noisy = new Bundle();
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
if (!isVisibleToListener(record.sbn, info)) {
@@ -6594,6 +6595,7 @@ public class NotificationManagerService extends SystemService {
smartActions.putParcelableArrayList(key, record.getSmartActions());
smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
audiblyAlerted.putBoolean(key, record.getAudiblyAlerted());
+ noisy.putBoolean(key, record.getSound() != null || record.getVibration() != null);
}
final int M = keys.size();
String[] keysAr = keys.toArray(new String[M]);
@@ -6605,7 +6607,7 @@ public class NotificationManagerService extends SystemService {
return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
- smartActions, smartReplies, audiblyAlerted);
+ smartActions, smartReplies, audiblyAlerted, noisy);
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 753c2833b056..580e4f481a27 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -35,6 +35,7 @@ import android.util.Slog;
import android.util.jar.StrictJarFile;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
@@ -153,7 +154,7 @@ public class DexManager {
* @param classPaths the class paths corresponding to the class loaders names from
* {@param classLoadersNames}. The the first element corresponds to the first class loader
* and so on. A classpath is represented as a list of dex files separated by
- * {@code File.pathSeparator}.
+ * {@code File.pathSeparator}, or null if the class loader's classpath is not known.
* The dex files found in the first class path will be recorded in the usage file.
* @param loaderIsa the ISA of the app loading the dex files
* @param loaderUserId the user id which runs the code loading the dex files
@@ -169,7 +170,8 @@ public class DexManager {
}
}
- private void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
+ @VisibleForTesting
+ /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
List<String> classLoaderNames, List<String> classPaths, String loaderIsa,
int loaderUserId) {
if (classLoaderNames.size() != classPaths.size()) {
@@ -186,8 +188,14 @@ public class DexManager {
return;
}
+ // The first classpath should never be null because the first classloader
+ // should always be an instance of BaseDexClassLoader.
+ String firstClassPath = classPaths.get(0);
+ if (firstClassPath == null) {
+ return;
+ }
// The classpath is represented as a list of dex files separated by File.pathSeparator.
- String[] dexPathsToRegister = classPaths.get(0).split(File.pathSeparator);
+ String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator);
// Encode the class loader contexts for the dexPathsToRegister.
String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index e1310a2f1ab3..d2600b5060b5 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -318,7 +318,8 @@ public final class DexoptUtils {
// is fine (they come over binder). Even if something changes we expect the sizes to be
// very small and it shouldn't matter much.
for (int i = 1; i < classLoadersNames.size(); i++) {
- if (!ClassLoaderFactory.isValidClassLoaderName(classLoadersNames.get(i))) {
+ if (!ClassLoaderFactory.isValidClassLoaderName(classLoadersNames.get(i))
+ || classPaths.get(i) == null) {
return null;
}
String classpath = encodeClasspath(classPaths.get(i).split(File.pathSeparator));
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2be55c02638d..70c86a1672fa 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1856,7 +1856,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public void notifyThrottling(Temperature temp) {
boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE;
StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
- isThrottling ? 1 : 0, temp.getValue());
+ isThrottling ?
+ StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__START :
+ StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__STOP,
+ temp.getValue());
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 6034f81f9cc8..7b7598e9b39d 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1280,15 +1280,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (!aInfo.processName.equals("system")) {
if ((startFlags & (START_FLAG_DEBUG | START_FLAG_NATIVE_DEBUGGING
| START_FLAG_TRACK_ALLOCATION)) != 0 || profilerInfo != null) {
- /**
- * Assume safe to call into AMS synchronously because the call that set these
- * flags should have originated from AMS which will already have its lock held.
- * @see ActivityManagerService#startActivityAndWait(IApplicationThread, String,
- * Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle, int)
- * TODO(b/80414790): Investigate a better way of untangling this.
- */
- mService.mAmInternal.setDebugFlagsForStartingActivity(
- aInfo, startFlags, profilerInfo);
+
+ // Mimic an AMS synchronous call by passing a message to AMS and wait for AMS
+ // to notify us that the task has completed.
+ // TODO(b/80414790) look into further untangling for the situation where the
+ // caller is on the same thread as the handler we are posting to.
+ synchronized (mService.mGlobalLock) {
+ // Post message to AMS.
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::setDebugFlagsForStartingActivity,
+ mService.mAmInternal, aInfo, startFlags, profilerInfo,
+ mService.mGlobalLock);
+ mService.mH.sendMessage(msg);
+ try {
+ mService.mGlobalLock.wait();
+ } catch (InterruptedException ignore) {
+
+ }
+ }
}
}
final String intentLaunchToken = intent.getLaunchToken();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 15a3a1a3c378..04a526fe4cf2 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -98,7 +98,7 @@ cc_defaults {
"libhwbinder",
"libutils",
"libhwui",
- "libbpf",
+ "libbpf_android",
"libnetdbpf",
"libnetdutils",
"android.hardware.audio.common@2.0",
diff --git a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
index e62e07d6858f..6b7634db8a60 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.os.Build;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -47,6 +48,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Presubmit
public class JobSetTest {
private static final String TAG = JobSetTest.class.getSimpleName();
private static final int SECONDARY_USER_ID_1 = 12;
@@ -64,6 +66,7 @@ public class JobSetTest {
final PackageManagerInternal pm = mock(PackageManagerInternal.class);
when(pm.getPackageTargetSdkVersion(anyString()))
.thenReturn(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, pm);
assumeFalse("Test cannot run in user " + mContext.getUserId(),
mContext.getUserId() == SECONDARY_USER_ID_1
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 553d234adfca..c6be1c022283 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -16,6 +16,10 @@
package com.android.server.pm;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -35,12 +39,14 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
import android.content.res.Resources;
+import android.media.AudioAttributes;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
@@ -54,6 +60,8 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
@@ -550,6 +558,32 @@ public class SuspendPackagesTest {
assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
}
+ @Test
+ public void testAudioOpBlockedOnSuspend() throws Exception {
+ final IAppOpsService iAppOps = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ final CountDownLatch latch = new CountDownLatch(1);
+ final IAppOpsCallback watcher = new IAppOpsCallback.Stub() {
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ if (op == OP_PLAY_AUDIO && packageName.equals(TEST_APP_PACKAGE_NAME)) {
+ latch.countDown();
+ }
+ }
+ };
+ iAppOps.startWatchingMode(OP_PLAY_AUDIO, TEST_APP_PACKAGE_NAME, watcher);
+ final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0);
+ int audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO,
+ AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME);
+ assertEquals("Audio muted for unsuspended package", MODE_ALLOWED, audioOpMode);
+ suspendTestPackage(null, null, null);
+ assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS));
+ audioOpMode = iAppOps.checkAudioOperation(OP_PLAY_AUDIO,
+ AudioAttributes.USAGE_UNKNOWN, testPackageUid, TEST_APP_PACKAGE_NAME);
+ assertEquals("Audio not muted for suspended package", MODE_IGNORED, audioOpMode);
+ iAppOps.stopWatchingMode(watcher);
+ }
+
@After
public void tearDown() throws IOException {
mAppCommsReceiver.unregister();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index bd42b7318158..dad7b93e822e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -68,6 +68,7 @@ public class DexManagerTests {
private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
DelegateLastClassLoader.class.getName();
+ private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader";
@Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Mock Installer mInstaller;
@@ -105,7 +106,7 @@ public class DexManagerTests {
mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0,
- "unsupported.class_loader");
+ UNSUPPORTED_CLASS_LOADER_NAME);
mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0,
DELEGATE_LAST_CLASS_LOADER_NAME);
@@ -405,6 +406,24 @@ public class DexManagerTests {
}
@Test
+ public void testNotifySupportedAndUnsupportedClassLoader() {
+ String classPath = String.join(File.pathSeparator, mBarUser0.getSecondaryDexPaths());
+ List<String> classLoaders =
+ Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
+ List<String> classPaths = Arrays.asList(classPath, classPath);
+ notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0);
+
+ assertNoUseInfo(mBarUser0);
+ }
+
+ @Test
+ public void testNotifyNullClassPath() {
+ notifyDexLoad(mBarUser0, null, mUser0);
+
+ assertNoUseInfo(mBarUser0);
+ }
+
+ @Test
public void testNotifyVariableClassLoader() {
// Record bar secondaries with the default PathClassLoader.
List<String> secondaries = mBarUser0.getSecondaryDexPaths();
@@ -499,14 +518,17 @@ public class DexManagerTests {
// By default, assume a single class loader in the chain.
// This makes writing tests much easier.
List<String> classLoaders = Arrays.asList(testData.mClassLoader);
- List<String> classPaths = Arrays.asList(String.join(File.pathSeparator, dexPaths));
+ List<String> classPaths = (dexPaths == null)
+ ? Arrays.asList((String) null)
+ : Arrays.asList(String.join(File.pathSeparator, dexPaths));
notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
}
- private void notifyDexLoad(TestData testData, List<String> classLoader, List<String> classPaths,
- int loaderUserId) {
- mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, classLoader, classPaths,
- testData.mLoaderIsa, loaderUserId);
+ private void notifyDexLoad(TestData testData, List<String> classLoaders,
+ List<String> classPaths, int loaderUserId) {
+ // We call the internal function so any exceptions thrown cause test failures.
+ mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders,
+ classPaths, testData.mLoaderIsa, loaderUserId);
}
private PackageUseInfo getPackageUseInfo(TestData testData) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 77f517b7c48b..cd15a57368e8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -353,6 +353,18 @@ public class DexoptUtilsTest {
}
@Test
+ public void testProcessContextForDexLoadNoClassPath() {
+ List<String> classLoaders = Arrays.asList(
+ DELEGATE_LAST_CLASS_LOADER_NAME,
+ PATH_CLASS_LOADER_NAME);
+ List<String> classPaths = Arrays.asList(
+ String.join(File.pathSeparator, "foo.dex", "bar.dex"),
+ null);
+ String[] context = DexoptUtils.processContextForDexLoad(classLoaders, classPaths);
+ assertNull(context);
+ }
+
+ @Test
public void testProcessContextForDexLoadIllegalCallEmptyList() {
boolean gotException = false;
try {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index 0d7b5843f47e..bcba15df8756 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -114,6 +114,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
Bundle smartActions = new Bundle();
Bundle smartReplies = new Bundle();
Bundle audiblyAlerted = new Bundle();
+ Bundle noisy = new Bundle();
for (int i = 0; i < mKeys.length; i++) {
String key = mKeys[i];
@@ -134,12 +135,13 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
smartActions.putParcelableArrayList(key, getSmartActions(key, i));
smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
audiblyAlerted.putBoolean(key, audiblyAlerted(i));
+ noisy.putBoolean(key, getNoisy(i));
}
NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
interceptedKeys.toArray(new String[0]), visibilityOverrides,
suppressedVisualEffects, importance, explanation, overrideGroupKeys,
channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
- smartActions, smartReplies, audiblyAlerted);
+ smartActions, smartReplies, audiblyAlerted, noisy);
return update;
}
@@ -195,6 +197,10 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
return index < 2;
}
+ private boolean getNoisy(int index) {
+ return index < 1;
+ }
+
private ArrayList<String> getPeople(String key, int index) {
ArrayList<String> people = new ArrayList<>();
for (int i = 0; i < index; i++) {
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index c39688cb8f2d..0c40a6b5fa84 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -62,3 +62,22 @@ cc_test_host {
],
test_suites: ["general-tests"],
}
+
+cc_binary_host {
+ name: "dex_testcase_generator",
+ defaults: ["viewcompiler_defaults"],
+ srcs: ["dex_testcase_generator.cc"],
+ static_libs: [
+ "libviewcompiler",
+ ],
+}
+
+genrule {
+ name: "generate_dex_testcases",
+ tools: [":dex_testcase_generator"],
+ cmd: "$(location :dex_testcase_generator) $(genDir)",
+ out: [
+ "simple.dex",
+ "trivial.dex",
+ ],
+}
diff --git a/startop/view_compiler/README.md b/startop/view_compiler/README.md
index 56595016cbb9..f8da02b53907 100644
--- a/startop/view_compiler/README.md
+++ b/startop/view_compiler/README.md
@@ -23,3 +23,31 @@ This tool is still in its early stages and has a number of limitations.
application.
* This only works for apps that do not use a custom layout inflater.
* Other limitations yet to be discovered.
+
+## DexBuilder Tests
+
+The DexBuilder has several low-level end to end tests to verify generated DEX
+code validates, runs, and has the correct behavior. There are, unfortunately, a
+number of pieces that must be added to generate new tests. Here are the
+components:
+
+* `dex_testcase_generator` - Written in C++ using `DexBuilder`. This runs as a
+ build step produce the DEX files that will be tested on device. See the
+ `genrule` named `generate_dex_testcases` in `Android.bp`. These files are then
+ copied over to the device by TradeFed when running tests.
+* `DexBuilderTest` - This is a Java Language test harness that loads the
+ generated DEX files and exercises methods in the file.
+
+To add a new DEX file test, follow these steps:
+1. Modify `dex_testcase_generator` to produce the DEX file.
+2. Add the filename to the `out` list of the `generate_dex_testcases` rule in
+ `Android.bp`.
+3. Add a new `push` option to `AndroidTest.xml` to copy the DEX file to the
+ device.
+4. Modify `DexBuilderTest.java` to load and exercise the new test.
+
+In each case, you should be able to cargo-cult the existing test cases.
+
+In general, you can probably get by without adding a new generated DEX file, and
+instead add more methods to the files that are already generated. In this case,
+you can skip all of steps 2 and 3 above, and simplify steps 1 and 4.
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
new file mode 100644
index 000000000000..5d675b76b395
--- /dev/null
+++ b/startop/view_compiler/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "dex-builder-test"
+ }
+ ]
+}
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
new file mode 100644
index 000000000000..4449ea0f707e
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2018 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.
+//
+
+android_test {
+ name: "dex-builder-test",
+ srcs: ["src/android/startop/test/DexBuilderTest.java"],
+ sdk_version: "current",
+ data: [":generate_dex_testcases"],
+ static_libs: [
+ "android-support-test",
+ "guava",
+ ],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ test_suites: ["general-tests"],
+}
diff --git a/startop/view_compiler/dex_builder_test/AndroidManifest.xml b/startop/view_compiler/dex_builder_test/AndroidManifest.xml
new file mode 100644
index 000000000000..6ac5fc5db345
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.startop.test" >
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.startop.test"
+ android:label="DexBuilder Tests"/>
+
+</manifest>
diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml
new file mode 100644
index 000000000000..6f90cf3b81a7
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Runs DexBuilder Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="dex-builder-test.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" />
+ <option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.startop.test" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
new file mode 100644
index 000000000000..87b25780aaa8
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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 android.startop.test;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import com.google.common.io.ByteStreams;
+import dalvik.system.InMemoryDexClassLoader;
+import dalvik.system.PathClassLoader;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import org.junit.Assert;
+import org.junit.Test;
+
+// Adding tests here requires changes in several other places. See README.md in
+// the view_compiler directory for more information.
+public class DexBuilderTest {
+ static ClassLoader loadDexFile(String filename) throws Exception {
+ return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename,
+ ClassLoader.getSystemClassLoader());
+ }
+
+ public void hello() {}
+
+ @Test
+ public void loadTrivialDex() throws Exception {
+ ClassLoader loader = loadDexFile("trivial.dex");
+ loader.loadClass("android.startop.test.testcases.Trivial");
+ }
+
+ @Test
+ public void return5() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("return5");
+ Assert.assertEquals(5, method.invoke(null));
+ }
+
+ @Test
+ public void returnParam() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("returnParam", int.class);
+ Assert.assertEquals(5, method.invoke(null, 5));
+ Assert.assertEquals(42, method.invoke(null, 42));
+ }
+
+ @Test
+ public void returnStringLength() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("returnStringLength", String.class);
+ Assert.assertEquals(13, method.invoke(null, "Hello, World!"));
+ }
+}
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
new file mode 100644
index 000000000000..898817b4768c
--- /dev/null
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "android-base/logging.h"
+#include "dex_builder.h"
+
+#include <fstream>
+#include <string>
+
+// Adding tests here requires changes in several other places. See README.md in
+// the view_compiler directory for more information.
+
+using namespace startop::dex;
+using namespace std;
+
+void GenerateTrivialDexFile(const string& outdir) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.Trivial")};
+ cbuilder.set_source_file("dex_testcase_generator.cc#GenerateTrivialDexFile");
+
+ slicer::MemView image{dex_file.CreateImage()};
+ std::ofstream out_file(outdir + "/trivial.dex");
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+// Generates test cases that test around 1 instruction.
+void GenerateSimpleTestCases(const string& outdir) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.SimpleTests")};
+ cbuilder.set_source_file("dex_testcase_generator.cc#GenerateSimpleTestCases");
+
+ // int return5() { return 5; }
+ auto return5{cbuilder.CreateMethod("return5", Prototype{TypeDescriptor::Int()})};
+ Value r{return5.MakeRegister()};
+ return5.BuildConst4(r, 5);
+ return5.BuildReturn(r);
+ return5.Encode();
+
+ // // int returnParam(int x) { return x; }
+ auto returnParam{cbuilder.CreateMethod("returnParam",
+ Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+ returnParam.BuildReturn(Value::Parameter(0));
+ returnParam.Encode();
+
+ // int returnStringLength(String x) { return x.length(); }
+ auto string_type{TypeDescriptor::FromClassname("java.lang.String")};
+ MethodDeclData string_length{
+ dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()})};
+
+ auto returnStringLength{
+ cbuilder.CreateMethod("returnStringLength", Prototype{TypeDescriptor::Int(), string_type})};
+ Value result = returnStringLength.MakeRegister();
+ returnStringLength.AddInstruction(
+ Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+ returnStringLength.BuildReturn(result);
+ returnStringLength.Encode();
+
+ slicer::MemView image{dex_file.CreateImage()};
+ std::ofstream out_file(outdir + "/simple.dex");
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+int main(int argc, char** argv) {
+ CHECK_EQ(argc, 2);
+
+ string outdir = argv[1];
+
+ GenerateTrivialDexFile(outdir);
+ GenerateSimpleTestCases(outdir);
+}
diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java
index 2bda6480b99e..1342038c6477 100644
--- a/telecomm/java/android/telecom/Logging/EventManager.java
+++ b/telecomm/java/android/telecom/Logging/EventManager.java
@@ -180,7 +180,7 @@ public class EventManager {
}
}
- private final List<Event> mEvents = new LinkedList<>();
+ private final List<Event> mEvents = Collections.synchronizedList(new LinkedList<>());
private final Loggable mRecordEntry;
public EventRecord(Loggable recordEntry) {
@@ -197,7 +197,7 @@ public class EventManager {
}
public List<Event> getEvents() {
- return mEvents;
+ return new LinkedList<>(mEvents);
}
public List<EventTiming> extractEventTimings() {
@@ -207,21 +207,24 @@ public class EventManager {
LinkedList<EventTiming> result = new LinkedList<>();
Map<String, PendingResponse> pendingResponses = new HashMap<>();
- for (Event event : mEvents) {
- if (requestResponsePairs.containsKey(event.eventId)) {
- // This event expects a response, so add that expected response to the maps
- // of pending events.
- for (EventManager.TimedEventPair p : requestResponsePairs.get(event.eventId)) {
- pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
- event.time, p.mTimeoutMillis, p.mName));
+ synchronized (mEvents) {
+ for (Event event : mEvents) {
+ if (requestResponsePairs.containsKey(event.eventId)) {
+ // This event expects a response, so add that expected response to the maps
+ // of pending events.
+ for (EventManager.TimedEventPair p : requestResponsePairs.get(
+ event.eventId)) {
+ pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
+ event.time, p.mTimeoutMillis, p.mName));
+ }
}
- }
- PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
- if (pendingResponse != null) {
- long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
- if (elapsedTime < pendingResponse.timeoutMillis) {
- result.add(new EventTiming(pendingResponse.name, elapsedTime));
+ PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
+ if (pendingResponse != null) {
+ long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
+ if (elapsedTime < pendingResponse.timeoutMillis) {
+ result.add(new EventTiming(pendingResponse.name, elapsedTime));
+ }
}
}
}
@@ -233,7 +236,8 @@ public class EventManager {
pw.print(mRecordEntry.getDescription());
pw.increaseIndent();
- for (Event event : mEvents) {
+ // Iterate over copy of events so that this doesn't hold the lock for too long.
+ for (Event event : getEvents()) {
pw.print(event.timestampString);
pw.print(" - ");
pw.print(event.eventId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3f9a5336e611..fbc54ae6a857 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1079,24 +1079,44 @@ public class CarrierConfigManager {
"wfc_operator_error_codes_string_array";
/**
- * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+ * Indexes of SPN format strings in wfcSpnFormats.
*
* <p>Available options are:
* <ul>
- * <li> 0: %s</li>
- * <li> 1: %s Wi-Fi Calling</li>
- * <li> 2: WLAN Call</li>
- * <li> 3: %s WLAN Call</li>
- * <li> 4: %s Wi-Fi</li>
- * <li> 5: WiFi Calling | %s</li>
- * <li> 6: %s VoWifi</li>
+ * <li> 0: %s</li>
+ * <li> 1: %s Wi-Fi Calling</li>
+ * <li> 2: WLAN Call</li>
+ * <li> 3: %s WLAN Call</li>
+ * <li> 4: %s Wi-Fi</li>
+ * <li> 5: WiFi Calling | %s</li>
+ * <li> 6: %s VoWifi</li>
+ * <li> 7: Wi-Fi Calling</li>
+ * <li> 8: Wi-Fi</li>
+ * <li> 9: WiFi Calling</li>
+ * <li> 10: VoWifi</li>
* @hide
*/
public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
- /** @hide */
+
+ /**
+ * Indexes of data SPN format strings in wfcSpnFormats.
+ *
+ * @see KEY_WFC_SPN_FORMAT_IDX_INT for available options.
+ * @hide
+ */
public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
/**
+ * Indexes of SPN format strings in wfcSpnFormats used during flight mode.
+ *
+ * Set to -1 to use the value from KEY_WFC_SPN_FORMAT_IDX_INT also in this case.
+ * @see KEY_WFC_SPN_FORMAT_IDX_INT for other available options.
+ * @hide
+ */
+ public static final String KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT =
+ "wfc_flight_mode_spn_format_idx_int";
+
+ /**
* Use root locale when reading wfcSpnFormats.
*
* If true, then the root locale will always be used when reading wfcSpnFormats. This means the
@@ -2456,6 +2476,7 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
+ sDefaults.putInt(KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT, -1);
sDefaults.putBoolean(KEY_WFC_SPN_USE_ROOT_LOCALE, false);
sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, "");
sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index f12756a8062f..af7123b84842 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -30,7 +30,9 @@ import static android.os.Process.SYSTEM_UID;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -63,24 +65,13 @@ public class PermissionMonitorTest {
@Mock private PackageManager mPackageManager;
private PermissionMonitor mPermissionMonitor;
- private int mMockFirstSdkInt;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES);
- // Try to use spy() here for stubbing getDeviceFirstSdkInt value but the spies are loaded
- // by a custom class loader that's different from the loader used for loading the real
- // thing. That means those two classes are not in the same package, so a package private
- // method is not accessible. Hence, using override method to control FIRST_SDK_INT value
- // instead of spy function for testing.
- mPermissionMonitor = new PermissionMonitor(mContext, null) {
- @Override
- int getDeviceFirstSdkInt() {
- return mMockFirstSdkInt;
- }
- };
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, null));
}
private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
@@ -166,13 +157,13 @@ public class PermissionMonitorTest {
@Test
public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
- mMockFirstSdkInt = VERSION_P;
+ doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- mMockFirstSdkInt = VERSION_Q;
+ doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,