summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt28
-rw-r--r--api/removed.txt1
-rw-r--r--cmds/statsd/Android.mk1
-rw-r--r--cmds/statsd/src/StatsService.cpp54
-rw-r--r--cmds/statsd/src/StatsService.h48
-rw-r--r--cmds/statsd/src/atoms.proto75
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp15
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp153
-rw-r--r--cmds/statsd/src/logd/LogEvent.h30
-rw-r--r--cmds/statsd/src/main.cpp12
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp2
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp157
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp36
-rw-r--r--core/java/android/app/Notification.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java2
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java9
-rw-r--r--core/java/android/hardware/face/FaceManager.java42
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl8
-rw-r--r--core/java/android/net/ConnectivityManager.java11
-rw-r--r--core/java/android/os/Build.java62
-rw-r--r--core/java/android/os/GraphicsEnvironment.java80
-rw-r--r--core/java/android/os/Process.java12
-rw-r--r--core/java/android/os/ZygoteProcess.java39
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java7
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/android/provider/Settings.java30
-rw-r--r--core/java/android/text/NativeLineBreaker.java145
-rw-r--r--core/java/android/text/SpannableStringBuilder.java9
-rw-r--r--core/java/android/text/SpannableStringInternal.java12
-rw-r--r--core/java/android/text/StaticLayout.java57
-rw-r--r--core/java/android/text/style/TextAppearanceSpan.java198
-rw-r--r--core/java/android/transition/ChangeImageTransform.java45
-rw-r--r--core/java/android/transition/TransitionManager.java21
-rw-r--r--core/java/android/util/ArrayMap.java41
-rw-r--r--core/java/android/util/ArraySet.java21
-rw-r--r--core/java/android/util/LongSparseLongArray.java6
-rw-r--r--core/java/android/util/SparseArray.java6
-rw-r--r--core/java/android/util/SparseBooleanArray.java10
-rw-r--r--core/java/android/util/SparseIntArray.java7
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java4
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java4
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java2
-rw-r--r--core/java/android/util/apk/VerityBuilder.java (renamed from core/java/android/util/apk/ApkVerityBuilder.java)40
-rw-r--r--core/java/android/view/ThreadedRenderer.java20
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java25
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java3
-rw-r--r--core/java/android/widget/ImageView.java4
-rw-r--r--core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java14
-rw-r--r--core/java/com/android/internal/os/Zygote.java15
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java13
-rw-r--r--core/jni/android/opengl/util.cpp6
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp9
-rw-r--r--core/jni/android_text_LineBreaker.cpp132
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp7
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp9
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp123
-rw-r--r--core/proto/android/providers/settings/global.proto3
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/values-hi/strings.xml2
-rw-r--r--core/res/res/values-tr/strings.xml2
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/coretests/src/android/provider/SettingsValidatorsTest.java8
-rw-r--r--data/etc/framework-sysconfig.xml2
-rw-r--r--graphics/java/android/graphics/Typeface.java8
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/DeviceInfo.cpp13
-rw-r--r--libs/hwui/DeviceInfo.h8
-rw-r--r--libs/hwui/Properties.cpp4
-rw-r--r--libs/hwui/Properties.h3
-rw-r--r--libs/hwui/TreeInfo.cpp29
-rw-r--r--libs/hwui/TreeInfo.h11
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp14
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp8
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp3
-rw-r--r--libs/hwui/renderthread/CanvasContext.h18
-rw-r--r--libs/hwui/renderthread/EglManager.cpp23
-rw-r--r--libs/hwui/renderthread/EglManager.h6
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h11
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp6
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/VulkanManager.h4
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp2
-rw-r--r--libs/hwui/utils/Color.cpp39
-rw-r--r--libs/hwui/utils/Color.h4
-rw-r--r--media/java/android/media/MediaPlayer.java2
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java5
-rw-r--r--packages/LocalTransport/Android.mk35
-rw-r--r--packages/LocalTransport/AndroidManifest.xml36
-rw-r--r--packages/LocalTransport/proguard.flags5
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransport.java (renamed from core/java/com/android/internal/backup/LocalTransport.java)18
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java (renamed from core/java/com/android/internal/backup/LocalTransportParameters.java)2
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java (renamed from core/java/com/android/internal/backup/LocalTransportService.java)2
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/Android.bp8
-rw-r--r--packages/SettingsLib/SearchWidget/AndroidManifest.xml23
-rw-r--r--packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml27
-rw-r--r--packages/SettingsLib/SearchWidget/res/values/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values/strings.xml4
-rw-r--r--packages/SettingsLib/search/Android.mk3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java63
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java19
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java56
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java106
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java51
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java65
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java102
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java106
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java90
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java33
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java66
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java66
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java66
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java74
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java822
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java424
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java511
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java108
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java72
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java86
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java12
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java25
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java62
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java4
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java3
-rw-r--r--services/core/java/com/android/server/content/ContentService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java8
-rw-r--r--services/core/java/com/android/server/security/VerityUtils.java164
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java106
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java37
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/jni/Android.bp3
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp32
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp50
-rw-r--r--services/core/jni/com_android_server_security_VerityUtils.cpp137
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/net/java/android/net/util/SharedLog.java14
-rw-r--r--services/robotests/src/com/android/server/backup/testing/TransportData.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java22
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java8
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java9
-rw-r--r--telephony/java/android/telephony/NeighboringCellInfo.java4
-rw-r--r--telephony/java/android/telephony/NetworkScan.java5
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java7
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java1
-rw-r--r--tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java9
-rw-r--r--tests/net/java/android/net/netlink/InetDiagSocketTest.java10
-rw-r--r--tests/net/java/android/net/util/SharedLogTest.java5
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java84
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java39
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java9
-rw-r--r--tools/apilint/apilint.py62
-rw-r--r--tools/stats_log_api_gen/main.cpp51
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java7
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java4
182 files changed, 4875 insertions, 1625 deletions
diff --git a/api/current.txt b/api/current.txt
index 1b0971000f3a..7d6c9397e940 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -7,6 +7,7 @@ package android {
public static final class Manifest.permission {
ctor public Manifest.permission();
field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
+ field public static final java.lang.String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -773,6 +774,7 @@ package android {
field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
+ field public static final int isLightTheme = 16844175; // 0x101058f
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
@@ -32520,6 +32522,7 @@ package android.os {
public class Build {
ctor public Build();
+ method public static java.util.List<android.os.Build.Partition> getPartitions();
method public static java.lang.String getRadioVersion();
method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
@@ -32548,6 +32551,14 @@ package android.os {
field public static final java.lang.String USER;
}
+ public static class Build.Partition {
+ ctor public Build.Partition();
+ method public java.lang.String getFingerprint();
+ method public java.lang.String getName();
+ method public long getTimeMillis();
+ field public static final java.lang.String PARTITION_NAME_SYSTEM = "system";
+ }
+
public static class Build.VERSION {
ctor public Build.VERSION();
field public static final java.lang.String BASE_OS;
@@ -42567,7 +42578,7 @@ package android.telephony {
method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
}
- public class NeighboringCellInfo implements android.os.Parcelable {
+ public deprecated class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
ctor public NeighboringCellInfo(int, java.lang.String, int);
@@ -43028,7 +43039,6 @@ package android.telephony {
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public java.lang.String getNai();
- method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public java.lang.String getNetworkCountryIso();
method public java.lang.String getNetworkOperator();
method public java.lang.String getNetworkOperatorName();
@@ -45039,11 +45049,20 @@ package android.text.style {
ctor public TextAppearanceSpan(android.os.Parcel);
method public int describeContents();
method public java.lang.String getFamily();
+ method public java.lang.String getFontFeatureSettings();
+ method public java.lang.String getFontVariationSettings();
method public android.content.res.ColorStateList getLinkTextColor();
+ method public int getShadowColor();
+ method public float getShadowDx();
+ method public float getShadowDy();
+ method public float getShadowRadius();
method public int getSpanTypeId();
method public android.content.res.ColorStateList getTextColor();
+ method public int getTextFontWeight();
method public int getTextSize();
method public int getTextStyle();
+ method public android.graphics.Typeface getTypeface();
+ method public boolean isElegantTextHeight();
method public void updateDrawState(android.text.TextPaint);
method public void updateMeasureState(android.text.TextPaint);
method public void writeToParcel(android.os.Parcel, int);
@@ -45686,6 +45705,7 @@ package android.util {
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public V get(java.lang.Object);
method public int indexOfKey(java.lang.Object);
+ method public int indexOfValue(java.lang.Object);
method public boolean isEmpty();
method public K keyAt(int);
method public java.util.Set<K> keySet();
@@ -45706,6 +45726,7 @@ package android.util {
ctor public ArraySet();
ctor public ArraySet(int);
ctor public ArraySet(android.util.ArraySet<E>);
+ ctor public ArraySet(java.util.Collection<? extends E>);
method public boolean add(E);
method public void addAll(android.util.ArraySet<? extends E>);
method public boolean addAll(java.util.Collection<? extends E>);
@@ -46277,6 +46298,7 @@ package android.util {
method public int keyAt(int);
method public void put(int, boolean);
method public void removeAt(int);
+ method public void setValueAt(int, boolean);
method public int size();
method public boolean valueAt(int);
}
@@ -46295,6 +46317,7 @@ package android.util {
method public int keyAt(int);
method public void put(int, int);
method public void removeAt(int);
+ method public void setValueAt(int, int);
method public int size();
method public int valueAt(int);
}
@@ -55244,6 +55267,7 @@ package dalvik.system {
public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader);
ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
+ ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader, boolean);
}
public class DexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/removed.txt b/api/removed.txt
index b6dabcd8614b..f7106d2207ec 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -545,6 +545,7 @@ package android.telephony {
}
public class TelephonyManager {
+ method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index d3496ed9798b..e090ed14320c 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -99,6 +99,7 @@ statsd_common_shared_libraries := \
libhidlbase \
libhidltransport \
libhwbinder \
+ android.frameworks.stats@1.0 \
android.hardware.health@2.0 \
android.hardware.power@1.0 \
android.hardware.power@1.1 \
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 2ef1169851ff..8da2d447a163 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -992,6 +992,60 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
return Status::ok();
}
+hardware::Return<void> StatsService::reportSpeakerImpedance(
+ const SpeakerImpedance& speakerImpedance) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportHardwareFailed(const HardwareFailed& hardwareFailed) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), hardwareFailed);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), physicalDropDetected);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportChargeCycles(const ChargeCycles& chargeCycles) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), chargeCycles);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(),
+ batteryHealthSnapshotArgs);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportSlowIo(const SlowIo& slowIo) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), slowIo);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) {
+ LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), batteryCausedShutdown);
+ mProcessor->OnLogEvent(&event);
+
+ return hardware::Void();
+}
+
void StatsService::binderDied(const wp <IBinder>& who) {
ALOGW("statscompanion service died");
StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 06189278abce..1f1d782af235 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -27,6 +27,8 @@
#include "shell/ShellSubscriber.h"
#include "statscompanion_util.h"
+#include <android/frameworks/stats/1.0/IStats.h>
+#include <android/frameworks/stats/1.0/types.h>
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
@@ -38,6 +40,7 @@
using namespace android;
using namespace android::base;
using namespace android::binder;
+using namespace android::frameworks::stats::V1_0;
using namespace android::os;
using namespace std;
@@ -45,7 +48,12 @@ namespace android {
namespace os {
namespace statsd {
-class StatsService : public BnStatsManager, public LogListener, public IBinder::DeathRecipient {
+using android::hardware::Return;
+
+class StatsService : public BnStatsManager,
+ public LogListener,
+ public IStats,
+ public IBinder::DeathRecipient {
public:
StatsService(const sp<Looper>& handlerLooper);
virtual ~StatsService();
@@ -146,6 +154,44 @@ public:
*/
virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override;
+ /**
+ * Binder call to get SpeakerImpedance atom.
+ */
+ virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
+
+ /**
+ * Binder call to get HardwareFailed atom.
+ */
+ virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override;
+
+ /**
+ * Binder call to get PhysicalDropDetected atom.
+ */
+ virtual Return<void> reportPhysicalDropDetected(
+ const PhysicalDropDetected& physicalDropDetected) override;
+
+ /**
+ * Binder call to get ChargeCyclesReported atom.
+ */
+ virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override;
+
+ /**
+ * Binder call to get BatteryHealthSnapshot atom.
+ */
+ virtual Return<void> reportBatteryHealthSnapshot(
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override;
+
+ /**
+ * Binder call to get SlowIo atom.
+ */
+ virtual Return<void> reportSlowIo(const SlowIo& slowIo) override;
+
+ /**
+ * Binder call to get BatteryCausedShutdown atom.
+ */
+ virtual Return<void> reportBatteryCausedShutdown(
+ const BatteryCausedShutdown& batteryCausedShutdown) override;
+
/** IBinder::DeathRecipient */
virtual void binderDied(const wp<IBinder>& who) override;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1e9c354d26bf..30d8bfce5d2a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -138,6 +138,9 @@ message Atom {
FingerprintAuthenticated fingerprint_authenticated = 88;
FingerprintErrorOccurred fingerprint_error_occurred = 89;
Notification notification = 90;
+ BatteryHealthSnapshot battery_health_snapshot = 91;
+ SlowIo slow_io = 92;
+ BatteryCausedShutdown battery_caused_shutdown = 93;
}
// Pulled events will start at field 10000.
@@ -200,9 +203,10 @@ message AttributionNode {
message KeyValuePair {
optional int32 key = 1;
oneof value {
- int64 value_int = 2;
- string value_str = 3;
- float value_float = 4;
+ int32 value_int = 2;
+ int64 value_long = 3;
+ string value_str = 4;
+ float value_float = 5;
}
}
@@ -769,6 +773,9 @@ message WakeupAlarmOccurred {
// Name of the wakeup alarm.
optional string tag = 2;
+
+ // Name of source package (for historical reasons, since BatteryStats tracked it).
+ optional string package_name = 3;
}
/**
@@ -1309,6 +1316,68 @@ message ChargeCyclesReported {
}
/**
+ * Log battery health snapshot.
+ *
+ * Resistance, Voltage, Open Circuit Voltage, Temperature, and Charge Level
+ * are snapshotted periodically over 24hrs.
+ */
+message BatteryHealthSnapshot {
+ enum BatterySnapshotType {
+ UNKNOWN = 0;
+ MIN_TEMP = 1; // Snapshot at min batt temp over 24hrs.
+ MAX_TEMP = 2; // Snapshot at max batt temp over 24hrs.
+ MIN_RESISTANCE = 3; // Snapshot at min batt resistance over 24hrs.
+ MAX_RESISTANCE = 4; // Snapshot at max batt resistance over 24hrs.
+ MIN_VOLTAGE = 5; // Snapshot at min batt voltage over 24hrs.
+ MAX_VOLTAGE = 6; // Snapshot at max batt voltage over 24hrs.
+ MIN_CURRENT = 7; // Snapshot at min batt current over 24hrs.
+ MAX_CURRENT = 8; // Snapshot at max batt current over 24hrs.
+ MIN_BATT_LEVEL = 9; // Snapshot at min battery level (SoC) over 24hrs.
+ MAX_BATT_LEVEL = 10; // Snapshot at max battery level (SoC) over 24hrs.
+ AVG_RESISTANCE = 11; // Snapshot at average battery resistance over 24hrs.
+ }
+ optional BatterySnapshotType type = 1;
+ // Temperature, in 1/10ths of degree C.
+ optional int32 temperature_deci_celcius = 2;
+ // Voltage Battery Voltage, in microVolts.
+ optional int32 voltage_micro_volt = 3;
+ // Current Battery current, in microAmps.
+ optional int32 current_micro_amps = 4;
+ // OpenCircuitVoltage Battery Open Circuit Voltage, in microVolts.
+ optional int32 open_circuit_micro_volt = 5;
+ // Resistance Battery Resistance, in microOhms.
+ optional int32 resistance_micro_ohm = 6;
+ // Level Battery Level, as % of full.
+ optional int32 level_percent = 7;
+}
+
+/**
+ * Log slow I/O operations on the primary storage.
+ */
+message SlowIo {
+ // Classifications of IO Operations.
+ enum IoOperation {
+ UNKNOWN = 0;
+ READ = 1;
+ WRITE = 2;
+ UNMAP = 3;
+ SYNC = 4;
+ }
+ optional IoOperation operation = 1;
+
+ // The number of slow IO operations of this type over 24 hours.
+ optional int32 count = 2;
+}
+
+/**
+ * Log battery caused shutdown with the last recorded voltage.
+ */
+message BatteryCausedShutdown {
+ // The last recorded battery voltage prior to shutdown.
+ optional int32 last_recorded_micro_volt = 1;
+}
+
+/**
* Logs the duration of a davey (jank of >=700ms) when it occurs
*
* Logged from:
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 66392f80f1fe..5fb196ff4884 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -163,10 +163,7 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
// battery_voltage
{android::util::BATTERY_VOLTAGE,
- {{},
- {},
- 1 * NS_PER_SEC,
- new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
+ {{}, {}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
{{4, 5, 6, 7, 8, 9},
@@ -204,17 +201,17 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},
// Size of specific categories of files. Eg. Music.
{android::util::CATEGORY_SIZE,
- {{},
- {},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
+ {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
// Number of fingerprints registered to each user.
{android::util::NUM_FINGERPRINTS,
{{},
{},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
- };
+ // ProcStats.
+ {android::util::PROC_STATS,
+ {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}},
+};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
}
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index f9f1b387279a..4bbcfd593366 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -92,7 +92,8 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
int32_t uid,
- const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map) {
mLogdTimestampNs = wallClockTimestampNs;
@@ -113,7 +114,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
pos[1]++;
}
- for (const auto&itr : string_map) {
+ for (const auto&itr : long_map) {
pos[2] = 1;
mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
pos[2] = 3;
@@ -122,7 +123,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
pos[1]++;
}
- for (const auto&itr : float_map) {
+ for (const auto&itr : string_map) {
pos[2] = 1;
mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
pos[2] = 4;
@@ -130,12 +131,142 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
mValues.back().mField.decorateLastPos(2);
pos[1]++;
}
+
+ for (const auto&itr : float_map) {
+ pos[2] = 1;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
+ pos[2] = 5;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second)));
+ mValues.back().mField.decorateLastPos(2);
+ pos[1]++;
+ }
if (!mValues.empty()) {
mValues.back().mField.decorateLastPos(1);
mValues.at(mValues.size() - 2).mField.decorateLastPos(1);
}
}
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const SpeakerImpedance& speakerImpedance) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::SPEAKER_IMPEDANCE_REPORTED;
+
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(1)), Value(speakerImpedance.speakerLocation)));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(2)), Value(speakerImpedance.milliOhms)));
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const HardwareFailed& hardwareFailed) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::HARDWARE_FAILED;
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+ Value(int32_t(hardwareFailed.hardwareType))));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(2)), Value(hardwareFailed.hardwareLocation)));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(3)), Value(int32_t(hardwareFailed.errorCode))));
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const PhysicalDropDetected& physicalDropDetected) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::PHYSICAL_DROP_DETECTED;
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+ Value(int32_t(physicalDropDetected.confidencePctg))));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(2)), Value(physicalDropDetected.accelPeak)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)),
+ Value(physicalDropDetected.freefallDuration)));
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const ChargeCycles& chargeCycles) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::CHARGE_CYCLES_REPORTED;
+
+ for (size_t i = 0; i < chargeCycles.cycleBucket.size(); i++) {
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 1)),
+ Value(chargeCycles.cycleBucket[i])));
+ }
+
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::BATTERY_HEALTH_SNAPSHOT;
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+ Value(int32_t(batteryHealthSnapshotArgs.type))));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)),
+ Value(batteryHealthSnapshotArgs.temperatureDeciC)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)),
+ Value(batteryHealthSnapshotArgs.voltageMicroV)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)),
+ Value(batteryHealthSnapshotArgs.currentMicroA)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(5)),
+ Value(batteryHealthSnapshotArgs.openCircuitVoltageMicroV)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)),
+ Value(batteryHealthSnapshotArgs.resistanceMicroOhm)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)),
+ Value(batteryHealthSnapshotArgs.levelPercent)));
+
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, const SlowIo& slowIo) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::SLOW_IO;
+
+ int pos[] = {1};
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(1)), Value(int32_t(slowIo.operation))));
+ pos[0]++;
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(slowIo.count)));
+
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const BatteryCausedShutdown& batteryCausedShutdown) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::BATTERY_CAUSED_SHUTDOWN;
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+ Value(batteryCausedShutdown.voltageMicroV)));
+
+ if (!mValues.empty()) {
+ mValues.back().mField.decorateLastPos(1);
+ }
+}
+
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {
mLogdTimestampNs = timestampNs;
mTagId = tagId;
@@ -213,9 +344,8 @@ bool LogEvent::write(float value) {
return false;
}
-
-
-bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map) {
if (mContext) {
@@ -233,6 +363,17 @@ bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
}
}
+ for (const auto& itr : long_map) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ write(itr.first);
+ write(itr.second);
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ }
+
for (const auto& itr : string_map) {
if (android_log_write_list_begin(mContext) < 0) {
return false;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 9ef0bf469c14..c7e2a8c5ca21 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -18,6 +18,7 @@
#include "FieldValue.h"
+#include <android/frameworks/stats/1.0/types.h>
#include <android/os/StatsLogEventWrapper.h>
#include <android/util/ProtoOutputStream.h>
#include <log/log_event_list.h>
@@ -28,6 +29,8 @@
#include <string>
#include <vector>
+using namespace android::frameworks::stats::V1_0;
+
namespace android {
namespace os {
namespace statsd {
@@ -77,10 +80,32 @@ public:
*/
explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
int32_t uid,
- const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const SpeakerImpedance& speakerImpedance);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const HardwareFailed& hardwareFailed);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const PhysicalDropDetected& physicalDropDetected);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const ChargeCycles& chargeCycles);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const SlowIo& slowIo);
+
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const BatteryCausedShutdown& batteryCausedShutdown);
+
~LogEvent();
/**
@@ -122,7 +147,8 @@ public:
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
- bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+ bool writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 9002f0773aaf..a5dac0836238 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -25,6 +25,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
+#include <hidl/HidlTransportSupport.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
@@ -56,12 +57,21 @@ int main(int /*argc*/, char** /*argv*/) {
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
+ ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
+
// Create the service
sp<StatsService> service = new StatsService(looper);
if (defaultServiceManager()->addService(String16("stats"), service) != 0) {
- ALOGE("Failed to add service");
+ ALOGE("Failed to add service as AIDL service");
return -1;
}
+
+ auto ret = service->registerAsService();
+ if (ret != ::android::OK) {
+ ALOGE("Failed to add service as HIDL service");
+ return 1; // or handle error
+ }
+
service->sayHiToStatsCompanion();
service->Startup();
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 9d9e5be9e165..dd3402dae2f8 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -781,7 +781,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
for (const auto& condIt : whatIt->second) {
const bool cond = dimensionKeysInCondition.find(condIt.first) !=
- dimensionKeysInCondition.end();
+ dimensionKeysInCondition.end() && condition;
handleStartEvent(MetricDimensionKey(dimensionInWhat, condIt.first),
conditionKey, cond, event);
dimensionKeysInCondition.erase(condIt.first);
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 6e3b04ce6b3b..d4907017dc6d 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -91,12 +91,16 @@ TEST(LogEventTest, TestLogParsing) {
TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
LogEvent event1(83, 2000);
- std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, int32_t> int_map;
+ std::map<int32_t, int64_t> long_map;
std::map<int32_t, std::string> string_map;
std::map<int32_t, float> float_map;
- int_map[11] = 123L;
- int_map[22] = 345L;
+ int_map[11] = 123;
+ int_map[22] = 345;
+
+ long_map[33] = 678L;
+ long_map[44] = 890L;
string_map[1] = "test2";
string_map[2] = "test1";
@@ -104,12 +108,15 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
float_map[111] = 2.2f;
float_map[222] = 1.1f;
- EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map));
+ EXPECT_TRUE(event1.writeKeyValuePairs(int_map,
+ long_map,
+ string_map,
+ float_map));
event1.init();
EXPECT_EQ(83, event1.GetTagId());
const auto& items = event1.getValues();
- EXPECT_EQ((size_t)12, items.size());
+ EXPECT_EQ((size_t)16, items.size());
const FieldValue& item0 = event1.getValues()[0];
EXPECT_EQ(0x2010101, item0.mField.getField());
@@ -118,8 +125,8 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
const FieldValue& item1 = event1.getValues()[1];
EXPECT_EQ(0x2010182, item1.mField.getField());
- EXPECT_EQ(Type::LONG, item1.mValue.getType());
- EXPECT_EQ(123L, item1.mValue.long_value);
+ EXPECT_EQ(Type::INT, item1.mValue.getType());
+ EXPECT_EQ(123, item1.mValue.int_value);
const FieldValue& item2 = event1.getValues()[2];
EXPECT_EQ(0x2010201, item2.mField.getField());
@@ -128,48 +135,68 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
const FieldValue& item3 = event1.getValues()[3];
EXPECT_EQ(0x2010282, item3.mField.getField());
- EXPECT_EQ(Type::LONG, item3.mValue.getType());
- EXPECT_EQ(345L, item3.mValue.long_value);
+ EXPECT_EQ(Type::INT, item3.mValue.getType());
+ EXPECT_EQ(345, item3.mValue.int_value);
const FieldValue& item4 = event1.getValues()[4];
EXPECT_EQ(0x2010301, item4.mField.getField());
EXPECT_EQ(Type::INT, item4.mValue.getType());
- EXPECT_EQ(1, item4.mValue.int_value);
+ EXPECT_EQ(33, item4.mValue.int_value);
const FieldValue& item5 = event1.getValues()[5];
- EXPECT_EQ(0x2010383, item5.mField.getField());
- EXPECT_EQ(Type::STRING, item5.mValue.getType());
- EXPECT_EQ("test2", item5.mValue.str_value);
+ EXPECT_EQ(0x2010382, item5.mField.getField());
+ EXPECT_EQ(Type::LONG, item5.mValue.getType());
+ EXPECT_EQ(678L, item5.mValue.int_value);
const FieldValue& item6 = event1.getValues()[6];
EXPECT_EQ(0x2010401, item6.mField.getField());
EXPECT_EQ(Type::INT, item6.mValue.getType());
- EXPECT_EQ(2, item6.mValue.int_value);
+ EXPECT_EQ(44, item6.mValue.int_value);
const FieldValue& item7 = event1.getValues()[7];
- EXPECT_EQ(0x2010483, item7.mField.getField());
- EXPECT_EQ(Type::STRING, item7.mValue.getType());
- EXPECT_EQ("test1", item7.mValue.str_value);
+ EXPECT_EQ(0x2010482, item7.mField.getField());
+ EXPECT_EQ(Type::LONG, item7.mValue.getType());
+ EXPECT_EQ(890L, item7.mValue.int_value);
const FieldValue& item8 = event1.getValues()[8];
EXPECT_EQ(0x2010501, item8.mField.getField());
EXPECT_EQ(Type::INT, item8.mValue.getType());
- EXPECT_EQ(111, item8.mValue.int_value);
+ EXPECT_EQ(1, item8.mValue.int_value);
const FieldValue& item9 = event1.getValues()[9];
- EXPECT_EQ(0x2010584, item9.mField.getField());
- EXPECT_EQ(Type::FLOAT, item9.mValue.getType());
- EXPECT_EQ(2.2f, item9.mValue.float_value);
+ EXPECT_EQ(0x2010583, item9.mField.getField());
+ EXPECT_EQ(Type::STRING, item9.mValue.getType());
+ EXPECT_EQ("test2", item9.mValue.str_value);
const FieldValue& item10 = event1.getValues()[10];
- EXPECT_EQ(0x2018601, item10.mField.getField());
+ EXPECT_EQ(0x2010601, item10.mField.getField());
EXPECT_EQ(Type::INT, item10.mValue.getType());
- EXPECT_EQ(222, item10.mValue.int_value);
+ EXPECT_EQ(2, item10.mValue.int_value);
const FieldValue& item11 = event1.getValues()[11];
- EXPECT_EQ(0x2018684, item11.mField.getField());
- EXPECT_EQ(Type::FLOAT, item11.mValue.getType());
- EXPECT_EQ(1.1f, item11.mValue.float_value);
+ EXPECT_EQ(0x2010683, item11.mField.getField());
+ EXPECT_EQ(Type::STRING, item11.mValue.getType());
+ EXPECT_EQ("test1", item11.mValue.str_value);
+
+ const FieldValue& item12 = event1.getValues()[12];
+ EXPECT_EQ(0x2010701, item12.mField.getField());
+ EXPECT_EQ(Type::INT, item12.mValue.getType());
+ EXPECT_EQ(111, item12.mValue.int_value);
+
+ const FieldValue& item13 = event1.getValues()[13];
+ EXPECT_EQ(0x2010784, item13.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item13.mValue.getType());
+ EXPECT_EQ(2.2f, item13.mValue.float_value);
+
+ const FieldValue& item14 = event1.getValues()[14];
+ EXPECT_EQ(0x2018801, item14.mField.getField());
+ EXPECT_EQ(Type::INT, item14.mValue.getType());
+ EXPECT_EQ(222, item14.mValue.int_value);
+
+ const FieldValue& item15 = event1.getValues()[15];
+ EXPECT_EQ(0x2018884, item15.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item15.mValue.getType());
+ EXPECT_EQ(1.1f, item15.mValue.float_value);
}
TEST(LogEventTest, TestLogParsing2) {
@@ -242,12 +269,16 @@ TEST(LogEventTest, TestLogParsing2) {
}
TEST(LogEventTest, TestKeyValuePairsEvent) {
- std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, int32_t> int_map;
+ std::map<int32_t, int64_t> long_map;
std::map<int32_t, std::string> string_map;
std::map<int32_t, float> float_map;
- int_map[11] = 123L;
- int_map[22] = 345L;
+ int_map[11] = 123;
+ int_map[22] = 345;
+
+ long_map[33] = 678L;
+ long_map[44] = 890L;
string_map[1] = "test2";
string_map[2] = "test1";
@@ -255,7 +286,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
float_map[111] = 2.2f;
float_map[222] = 1.1f;
- LogEvent event1(83, 2000, 2001, 10001, int_map, string_map, float_map);
+ LogEvent event1(83, 2000, 2001, 10001, int_map, long_map, string_map, float_map);
event1.init();
EXPECT_EQ(83, event1.GetTagId());
@@ -263,7 +294,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
EXPECT_EQ((int64_t)2001, event1.GetElapsedTimestampNs());
const auto& items = event1.getValues();
- EXPECT_EQ((size_t)13, items.size());
+ EXPECT_EQ((size_t)17, items.size());
const FieldValue& item0 = event1.getValues()[0];
EXPECT_EQ(0x00010000, item0.mField.getField());
@@ -277,8 +308,8 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
const FieldValue& item2 = event1.getValues()[2];
EXPECT_EQ(0x2020182, item2.mField.getField());
- EXPECT_EQ(Type::LONG, item2.mValue.getType());
- EXPECT_EQ(123L, item2.mValue.long_value);
+ EXPECT_EQ(Type::INT, item2.mValue.getType());
+ EXPECT_EQ(123, item2.mValue.int_value);
const FieldValue& item3 = event1.getValues()[3];
EXPECT_EQ(0x2020201, item3.mField.getField());
@@ -287,48 +318,68 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
const FieldValue& item4 = event1.getValues()[4];
EXPECT_EQ(0x2020282, item4.mField.getField());
- EXPECT_EQ(Type::LONG, item4.mValue.getType());
- EXPECT_EQ(345L, item4.mValue.long_value);
+ EXPECT_EQ(Type::INT, item4.mValue.getType());
+ EXPECT_EQ(345, item4.mValue.int_value);
const FieldValue& item5 = event1.getValues()[5];
EXPECT_EQ(0x2020301, item5.mField.getField());
EXPECT_EQ(Type::INT, item5.mValue.getType());
- EXPECT_EQ(1, item5.mValue.int_value);
+ EXPECT_EQ(33, item5.mValue.int_value);
const FieldValue& item6 = event1.getValues()[6];
- EXPECT_EQ(0x2020383, item6.mField.getField());
- EXPECT_EQ(Type::STRING, item6.mValue.getType());
- EXPECT_EQ("test2", item6.mValue.str_value);
+ EXPECT_EQ(0x2020382, item6.mField.getField());
+ EXPECT_EQ(Type::LONG, item6.mValue.getType());
+ EXPECT_EQ(678L, item6.mValue.long_value);
const FieldValue& item7 = event1.getValues()[7];
EXPECT_EQ(0x2020401, item7.mField.getField());
EXPECT_EQ(Type::INT, item7.mValue.getType());
- EXPECT_EQ(2, item7.mValue.int_value);
+ EXPECT_EQ(44, item7.mValue.int_value);
const FieldValue& item8 = event1.getValues()[8];
- EXPECT_EQ(0x2020483, item8.mField.getField());
- EXPECT_EQ(Type::STRING, item8.mValue.getType());
- EXPECT_EQ("test1", item8.mValue.str_value);
+ EXPECT_EQ(0x2020482, item8.mField.getField());
+ EXPECT_EQ(Type::LONG, item8.mValue.getType());
+ EXPECT_EQ(890L, item8.mValue.long_value);
const FieldValue& item9 = event1.getValues()[9];
EXPECT_EQ(0x2020501, item9.mField.getField());
EXPECT_EQ(Type::INT, item9.mValue.getType());
- EXPECT_EQ(111, item9.mValue.int_value);
+ EXPECT_EQ(1, item9.mValue.int_value);
const FieldValue& item10 = event1.getValues()[10];
- EXPECT_EQ(0x2020584, item10.mField.getField());
- EXPECT_EQ(Type::FLOAT, item10.mValue.getType());
- EXPECT_EQ(2.2f, item10.mValue.float_value);
+ EXPECT_EQ(0x2020583, item10.mField.getField());
+ EXPECT_EQ(Type::STRING, item10.mValue.getType());
+ EXPECT_EQ("test2", item10.mValue.str_value);
const FieldValue& item11 = event1.getValues()[11];
- EXPECT_EQ(0x2028601, item11.mField.getField());
+ EXPECT_EQ(0x2020601, item11.mField.getField());
EXPECT_EQ(Type::INT, item11.mValue.getType());
- EXPECT_EQ(222, item11.mValue.int_value);
+ EXPECT_EQ(2, item11.mValue.int_value);
const FieldValue& item12 = event1.getValues()[12];
- EXPECT_EQ(0x2028684, item12.mField.getField());
- EXPECT_EQ(Type::FLOAT, item12.mValue.getType());
- EXPECT_EQ(1.1f, item12.mValue.float_value);
+ EXPECT_EQ(0x2020683, item12.mField.getField());
+ EXPECT_EQ(Type::STRING, item12.mValue.getType());
+ EXPECT_EQ("test1", item12.mValue.str_value);
+
+ const FieldValue& item13 = event1.getValues()[13];
+ EXPECT_EQ(0x2020701, item13.mField.getField());
+ EXPECT_EQ(Type::INT, item13.mValue.getType());
+ EXPECT_EQ(111, item13.mValue.int_value);
+
+ const FieldValue& item14 = event1.getValues()[14];
+ EXPECT_EQ(0x2020784, item14.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item14.mValue.getType());
+ EXPECT_EQ(2.2f, item14.mValue.float_value);
+
+ const FieldValue& item15 = event1.getValues()[15];
+ EXPECT_EQ(0x2028801, item15.mField.getField());
+ EXPECT_EQ(Type::INT, item15.mValue.getType());
+ EXPECT_EQ(222, item15.mValue.int_value);
+
+ const FieldValue& item16 = event1.getValues()[16];
+ EXPECT_EQ(0x2028884, item16.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item16.mValue.getType());
+ EXPECT_EQ(1.1f, item16.mValue.float_value);
}
@@ -337,4 +388,4 @@ TEST(LogEventTest, TestKeyValuePairsEvent) {
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif \ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index f03821432cc1..75bd40f67946 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -81,6 +81,34 @@ StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
} // namespace
+/*
+ The following test has the following input.
+
+{ 10000000002 10000000002 (8)9999[I], [S], job0[S], 1[I], }
+{ 10000000010 10000000010 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
+{ 10000000011 10000000011 (29)1[I], }
+{ 10000000040 10000000040 (29)2[I], }
+{ 10000000050 10000000050 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
+{ 10000000101 10000000101 (8)9999[I], [S], job0[S], 0[I], }
+{ 10000000102 10000000102 (29)1[I], }
+{ 10000000200 10000000200 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
+{ 10000000201 10000000201 (8)9999[I], [S], job2[S], 1[I], }
+{ 10000000400 10000000400 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 1[I], }
+{ 10000000401 10000000401 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 1[I], }
+{ 10000000450 10000000450 (29)2[I], }
+{ 10000000500 10000000500 (8)9999[I], [S], job2[S], 0[I], }
+{ 10000000600 10000000600 (8)8888[I], [S], job2[S], 1[I], }
+{ 10000000650 10000000650 (29)1[I], }
+{ 309999999999 309999999999 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 0[I], }
+{ 310000000100 310000000100 (29)2[I], }
+{ 310000000300 310000000300 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
+{ 310000000600 310000000600 (8)8888[I], [S], job1[S], 1[I], }
+{ 310000000640 310000000640 (29)1[I], }
+{ 310000000650 310000000650 (29)2[I], }
+{ 310000000700 310000000700 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 0[I], }
+{ 310000000850 310000000850 (8)8888[I], [S], job2[S], 0[I], }
+{ 310000000900 310000000900 (8)8888[I], [S], job1[S], 0[I], }
+*/
TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
for (const bool hashStringInReport : { true, false }) {
for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
@@ -250,7 +278,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 650);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
@@ -269,7 +297,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi
data.dimensions_in_condition(),
android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
- EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 600);
+ EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 650);
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
@@ -331,7 +359,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 100);
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
@@ -353,7 +381,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi
EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 110);
+ EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 110);
EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3638bc48d2b5..81df447816d1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4440,7 +4440,7 @@ public class Notification implements Parcelable
}
private CharSequence processTextSpans(CharSequence text) {
- if (hasForegroundColor()) {
+ if (hasForegroundColor() || mInNightMode) {
return ContrastColorUtil.clearColorSpans(text);
}
return text;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 01557c59f8ac..eb5c720d6309 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -649,7 +649,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* successful so far. Do not call setTransactionSuccessful before calling this. When this
* returns a new transaction will have been created but not marked as successful.
* @return true if the transaction was yielded
- * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
+ * @deprecated if the db is locked more than once (because of nested transactions) then the lock
* will not be yielded. Use yieldIfContendedSafely instead.
*/
@Deprecated
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 92a814ca24c5..83998cc1c66a 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -348,7 +348,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* @hide
*/
public AuthenticationResult(CryptoObject crypto) {
- // For compatibility, this extends from common base class as FingerprintManager does.
// Identifier and userId is not used for BiometricPrompt.
super(crypto, null /* identifier */, 0 /* userId */);
}
@@ -410,8 +409,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
- * scanning for a fingerprint. It terminates when {@link
+ * This call warms up the biometric hardware, displays a system-provided dialog, and starts
+ * scanning for a biometric. It terminates when {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
* AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)}, or when the user
* dismisses the system-provided dialog, at which point the crypto object becomes invalid. This
@@ -453,8 +452,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
- * scanning for a fingerprint. It terminates when {@link
+ * This call warms up the biometric hardware, displays a system-provided dialog, and starts
+ * scanning for a biometric. It terminates when {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
* AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)} is called, or when
* the user dismisses the system-provided dialog. This operation can be canceled by using the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 66613ea50357..873a24a3b53b 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -244,17 +244,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
- * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
+ * Requests an auth token to tie sensitive operations to the confirmation of
* existing device credentials (e.g. pin/pattern/password).
*
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public long preEnroll() {
+ public long generateChallenge() {
long result = 0;
if (mService != null) {
try {
- result = mService.preEnroll(mToken);
+ result = mService.generateChallenge(mToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -263,16 +263,46 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
- * Finishes enrollment and cancels the current auth token.
+ * Invalidates the current auth token.
*
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public int postEnroll() {
+ public int revokeChallenge() {
int result = 0;
if (mService != null) {
try {
- result = mService.postEnroll(mToken);
+ result = mService.revokeChallenge(mToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public void setRequireAttention(boolean requireAttention, byte[] token) {
+ if (mService != null) {
+ try {
+ mService.setRequireAttention(requireAttention, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public boolean getRequireAttention(byte[] token) {
+ boolean result = true;
+ if (mService != null) {
+ try {
+ mService.getRequireAttention(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 50d07449493e..6681bd714779 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -66,10 +66,10 @@ interface IFaceService {
boolean isHardwareDetected(long deviceId, String opPackageName);
// Get a pre-enrollment authentication token
- long preEnroll(IBinder token);
+ long generateChallenge(IBinder token);
// Finish an enrollment sequence and invalidate the authentication token
- int postEnroll(IBinder token);
+ int revokeChallenge(IBinder token);
// Determine if a user has at least one enrolled face
boolean hasEnrolledFaces(int userId, String opPackageName);
@@ -94,4 +94,8 @@ interface IFaceService {
// Enumerate all faces
void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
+
+ int setRequireAttention(boolean requireAttention, in byte [] token);
+
+ boolean getRequireAttention(in byte [] token);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index f2e907833612..8333b817add0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -26,7 +26,6 @@ import android.annotation.UnsupportedAppUsage;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -3801,8 +3800,9 @@ public class ConnectivityManager {
private void unsupportedStartingFrom(int version) {
if (Process.myUid() == Process.SYSTEM_UID) {
- // The getApplicationInfo() call we make below is not supported in system context, and
- // we want to allow the system to use these APIs anyway.
+ // The getApplicationInfo() call we make below is not supported in system context. Let
+ // the call through here, and rely on the fact that ConnectivityService will refuse to
+ // allow the system to use these APIs anyway.
return;
}
@@ -3819,11 +3819,6 @@ public class ConnectivityManager {
// functions by accessing ConnectivityService directly. However, it should be clear that doing
// so is unsupported and may break in the future. http://b/22728205
private void checkLegacyRoutingApiAccess() {
- if (mContext.checkCallingOrSelfPermission("com.android.permission.INJECT_OMADM_SETTINGS")
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
-
unsupportedStartingFrom(VERSION_CODES.M);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6bd2e76cdf35..8681893702b4 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -30,6 +30,8 @@ import com.android.internal.telephony.TelephonyProperties;
import dalvik.system.VMRuntime;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -1083,7 +1085,67 @@ public class Build {
return true;
}
+ /** Build information for a particular device partition. */
+ public static class Partition {
+ /** The name identifying the system partition. */
+ public static final String PARTITION_NAME_SYSTEM = "system";
+
+ private String mName;
+ private String mFingerprint;
+ private long mTimeMs;
+
+ public Partition() {}
+
+ private Partition(String name, String fingerprint, long timeMs) {
+ mName = name;
+ mFingerprint = fingerprint;
+ mTimeMs = timeMs;
+ }
+
+ /** The name of this partition, e.g. "system", or "vendor" */
+ public String getName() {
+ return mName;
+ }
+
+ /** The build fingerprint of this partition, see {@link Build#FINGERPRINT}. */
+ public String getFingerprint() {
+ return mFingerprint;
+ }
+
+ /** The time (ms since epoch), at which this partition was built, see {@link Build#TIME}. */
+ public long getTimeMillis() {
+ return mTimeMs;
+ }
+ }
+
+ /**
+ * Get build information about partitions that have a separate fingerprint defined.
+ *
+ * The list includes partitions that are suitable candidates for over-the-air updates. This is
+ * not an exhaustive list of partitions on the device.
+ */
+ public static List<Partition> getPartitions() {
+ ArrayList<Partition> partitions = new ArrayList();
+
+ String[] names = new String[] {
+ "bootimage", "odm", "product", "product_services", Partition.PARTITION_NAME_SYSTEM,
+ "vendor"
+ };
+ for (String name : names) {
+ String fingerprint = SystemProperties.get("ro." + name + ".build.fingerprint");
+ if (TextUtils.isEmpty(fingerprint)) {
+ continue;
+ }
+ long time = getLong("ro." + name + ".build.date.utc") * 1000;
+ partitions.add(new Partition(name, fingerprint, time));
+ }
+
+ return partitions;
+ }
+
// The following properties only make sense for internal engineering builds.
+
+ /** The time at which the build was produced, given in milliseconds since the UNIX epoch. */
public static final long TIME = getLong("ro.build.date.utc") * 1000;
public static final String USER = getString("ro.build.user");
public static final String HOST = getString("ro.build.host");
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index f2e0bddb93aa..54be6393e651 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -44,6 +44,8 @@ public class GraphicsEnvironment {
private static final boolean DEBUG = false;
private static final String TAG = "GraphicsEnvironment";
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
+ private static final String ANGLE_PACKAGE_NAME = "com.android.angle";
+ private static final String GLES_MODE_METADATA_KEY = "com.android.angle.GLES_MODE";
private ClassLoader mClassLoader;
private String mLayerPath;
@@ -54,6 +56,7 @@ public class GraphicsEnvironment {
*/
public void setup(Context context) {
setupGpuLayers(context);
+ setupAngle(context);
chooseDriver(context);
}
@@ -121,7 +124,6 @@ public class GraphicsEnvironment {
}
}
}
-
}
// Include the app's lib directory in all cases
@@ -131,6 +133,80 @@ public class GraphicsEnvironment {
}
/**
+ * Pass ANGLE details down to trigger enable logic
+ */
+ private static void setupAngle(Context context) {
+
+ String angleEnabledApp =
+ Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.ANGLE_ENABLED_APP);
+
+ String packageName = context.getPackageName();
+
+ boolean devOptIn = false;
+ if ((angleEnabledApp != null && packageName != null)
+ && (!angleEnabledApp.isEmpty() && !packageName.isEmpty())
+ && angleEnabledApp.equals(packageName)) {
+
+ if (DEBUG) Log.v(TAG, packageName + " opted in for ANGLE via Developer Setting");
+
+ devOptIn = true;
+ }
+
+ ApplicationInfo appInfo;
+ try {
+ appInfo = context.getPackageManager().getApplicationInfo(packageName,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to get info about current application: " + packageName);
+ return;
+ }
+
+ String appPref = "dontcare";
+ final BaseBundle metadata = appInfo.metaData;
+ if (metadata != null) {
+ final String glesMode = metadata.getString(GLES_MODE_METADATA_KEY);
+ if (glesMode != null) {
+ if (glesMode.equals("angle")) {
+ appPref = "angle";
+ if (DEBUG) Log.v(TAG, packageName + " opted for ANGLE via AndroidManifest");
+ } else if (glesMode.equals("native")) {
+ appPref = "native";
+ if (DEBUG) Log.v(TAG, packageName + " opted for NATIVE via AndroidManifest");
+ } else {
+ Log.w(TAG, "Unrecognized GLES_MODE (\"" + glesMode + "\") for " + packageName
+ + ". Supported values are \"angle\" or \"native\"");
+ }
+ }
+ }
+
+ ApplicationInfo angleInfo;
+ try {
+ angleInfo = context.getPackageManager().getApplicationInfo(ANGLE_PACKAGE_NAME,
+ PackageManager.MATCH_SYSTEM_ONLY);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "ANGLE package '" + ANGLE_PACKAGE_NAME + "' not installed");
+ return;
+ }
+
+ String abi = chooseAbi(angleInfo);
+
+ // Build a path that includes installed native libs and APK
+ StringBuilder sb = new StringBuilder();
+ sb.append(angleInfo.nativeLibraryDir)
+ .append(File.pathSeparator)
+ .append(angleInfo.sourceDir)
+ .append("!/lib/")
+ .append(abi);
+ String paths = sb.toString();
+
+ if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
+
+ // Further opt-in logic is handled in native, so pass relevant info down
+ setAngleInfo(paths, packageName, appPref, devOptIn);
+ }
+
+ /**
* Choose whether the current process should use the builtin or an updated driver.
*/
private static void chooseDriver(Context context) {
@@ -218,4 +294,6 @@ public class GraphicsEnvironment {
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDriverPath(String path);
+ private static native void setAngleInfo(String path, String appPackage, String appPref,
+ boolean devOptIn);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6fab3c412ae5..0f64c4531bc3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -483,6 +483,8 @@ public class Process {
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
+ * @param packagesForUid null-ok all the packages with the same uid as this process.
+ * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -501,10 +503,13 @@ public class Process {
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
+ @Nullable String[] packagesForUid,
+ @Nullable String[] visibleVols,
@Nullable String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith, packageName,
+ packagesForUid, visibleVols, zygoteArgs);
}
/** @hide */
@@ -519,10 +524,13 @@ public class Process {
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
+ @Nullable String[] packagesForUid,
+ @Nullable String[] visibleVols,
@Nullable String[] zygoteArgs) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith, packageName,
+ packagesForUid, visibleVols, zygoteArgs);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 99181acb03c7..7fd0a4b66d66 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -215,6 +215,8 @@ public class ZygoteProcess {
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
+ * @param packagesForUid null-ok all the packages with the same uid as this process.
+ * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -231,12 +233,14 @@ public class ZygoteProcess {
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
+ @Nullable String[] packagesForUid,
+ @Nullable String[] visibleVols,
@Nullable String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
- packageName, zygoteArgs);
+ packageName, packagesForUid, visibleVols, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -355,6 +359,8 @@ public class ZygoteProcess {
* @param startChildZygote Start a sub-zygote. This creates a new zygote process
* that has its state cloned from this zygote process.
* @param packageName null-ok the name of the package this process belongs to.
+ * @param packagesForUid null-ok all the packages with the same uid as this process.
+ * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -372,6 +378,8 @@ public class ZygoteProcess {
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
+ @Nullable String[] packagesForUid,
+ @Nullable String[] visibleVols,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -439,6 +447,32 @@ public class ZygoteProcess {
argsForZygote.add("--package-name=" + packageName);
}
+ if (packagesForUid != null && packagesForUid.length > 0) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("--packages-for-uid=");
+
+ for (int i = 0; i < packagesForUid.length; ++i) {
+ if (i != 0) {
+ sb.append(',');
+ }
+ sb.append(packagesForUid[i]);
+ }
+ argsForZygote.add(sb.toString());
+ }
+
+ if (visibleVols != null && visibleVols.length > 0) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("--visible-vols=");
+
+ for (int i = 0; i < visibleVols.length; ++i) {
+ if (i != 0) {
+ sb.append(',');
+ }
+ sb.append(visibleVols[i]);
+ }
+ argsForZygote.add(sb.toString());
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
@@ -746,7 +780,8 @@ public class ZygoteProcess {
result = startViaZygote(processClass, niceName, uid, gid,
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
- true /* startChildZygote */, null /* packageName */, extraArgs);
+ true /* startChildZygote */, null /* packageName */,
+ null /* packagesForUid */, null /* visibleVolumes */, extraArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
}
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index d850e27e913f..1f54ea53facc 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -89,8 +89,13 @@ public abstract class StorageManagerInternal {
* @param appId The appId for the given package.
* @param sharedUserId The sharedUserId for given package if it specified
* {@code android:sharedUserId} in the manifest, otherwise {@code null}
- * @param userId
+ * @param userId The userId in which the storage needs to be mounted.
*/
public abstract void mountExternalStorageForApp(String packageName, int appId,
String sharedUserId, int userId);
+
+ /**
+ * @return Labels of storage volumes that are visible to the given userId.
+ */
+ public abstract String[] getVisibleVolumesForUser(int userId);
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index afd383691300..e55afb69bab9 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -157,7 +157,7 @@ public class VolumeInfo implements Parcelable {
public final DiskInfo disk;
public final String partGuid;
public int mountFlags = 0;
- public int mountUserId = -1;
+ public int mountUserId = UserHandle.USER_NULL;
@UnsupportedAppUsage
public int state = STATE_UNMOUNTED;
public String fsType;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index aa178fb9ff36..1d3cf19e18f0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7267,12 +7267,12 @@ public final class Settings {
private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
- * Whether the device should pulse on reach gesture.
+ * Gesture that wakes up the lock screen.
* @hide
*/
- public static final String DOZE_REACH_GESTURE = "doze_reach_gesture";
+ public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_lock_screen_gesture";
- private static final Validator DOZE_REACH_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+ private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Gesture that wakes up the display, showing the ambient version of the status bar.
@@ -7689,6 +7689,15 @@ public final class Settings {
BOOLEAN_VALIDATOR;
/**
+ * Whether or not face unlock is allowed for apps (through BiometricPrompt).
+ * @hide
+ */
+ public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled";
+
+ private static final Validator FACE_UNLOCK_APP_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
@@ -8184,11 +8193,12 @@ public final class Settings {
DOZE_ALWAYS_ON,
DOZE_PICK_UP_GESTURE,
DOZE_DOUBLE_TAP_GESTURE,
- DOZE_REACH_GESTURE,
+ DOZE_WAKE_LOCK_SCREEN_GESTURE,
DOZE_WAKE_SCREEN_GESTURE,
NFC_PAYMENT_DEFAULT_COMPONENT,
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
FACE_UNLOCK_KEYGUARD_ENABLED,
+ FACE_UNLOCK_APP_ENABLED,
ASSIST_GESTURE_ENABLED,
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_WAKE_ENABLED,
@@ -8331,12 +8341,13 @@ public final class Settings {
VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
- VALIDATORS.put(DOZE_REACH_GESTURE, DOZE_REACH_GESTURE_VALIDATOR);
+ VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);
VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
+ VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -9593,8 +9604,7 @@ public final class Settings {
* Use the old dnsmasq DHCP server for tethering instead of the framework implementation.
*
* Integer values are interpreted as boolean, and the absence of an explicit setting
- * is interpreted as |true|.
- * TODO: make the default |false|
+ * is interpreted as |false|.
* @hide
*/
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
@@ -11570,6 +11580,12 @@ public final class Settings {
public static final String GPU_DEBUG_APP = "gpu_debug_app";
/**
+ * App should try to use ANGLE
+ * @hide
+ */
+ public static final String ANGLE_ENABLED_APP = "angle_enabled_app";
+
+ /**
* Ordered GPU debug layer list
* i.e. <layer1>:<layer2>:...:<layerN>
* @hide
diff --git a/core/java/android/text/NativeLineBreaker.java b/core/java/android/text/NativeLineBreaker.java
index 2bcfa5fe0857..94e10e89acbd 100644
--- a/core/java/android/text/NativeLineBreaker.java
+++ b/core/java/android/text/NativeLineBreaker.java
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -258,16 +259,91 @@ public class NativeLineBreaker {
/**
* A result object of a line breaking
*/
- public static class LineBreaks {
- public int breakCount;
- private static final int INITIAL_SIZE = 16;
- public int[] breaks = new int[INITIAL_SIZE];
- public float[] widths = new float[INITIAL_SIZE];
- public float[] ascents = new float[INITIAL_SIZE];
- public float[] descents = new float[INITIAL_SIZE];
- // TODO: Introduce Hyphenator for explaining the meaning of flags.
- public int[] flags = new int[INITIAL_SIZE];
- // breaks, widths, and flags should all have the same length
+ public static class Result {
+ // Following two contstant must be synced with minikin's line breaker.
+ private static final int TAB_MASK = 0x20000000;
+ private static final int HYPHEN_MASK = 0xFF;
+
+ private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ Result.class.getClassLoader(), nGetReleaseResultFunc(), 32);
+ private final long mPtr;
+
+ private Result(long ptr) {
+ mPtr = ptr;
+ sRegistry.registerNativeAllocation(this, mPtr);
+ }
+
+ /**
+ * Returns a number of line count.
+ *
+ * @return number of lines
+ */
+ public @IntRange(from = 0) int getLineCount() {
+ return nGetLineCount(mPtr);
+ }
+
+ /**
+ * Returns a break offset of the line.
+ *
+ * @param lineIndex an index of the line.
+ * @return the break offset.
+ */
+ public @IntRange(from = 0) int getLineBreakOffset(@IntRange(from = 0) int lineIndex) {
+ return nGetLineBreakOffset(mPtr, lineIndex);
+ }
+
+ /**
+ * Returns a width of the line in pixels.
+ *
+ * @param lineIndex an index of the line.
+ * @return a width of the line in pixexls
+ */
+ public @Px float getLineWidth(@IntRange(from = 0) int lineIndex) {
+ return nGetLineWidth(mPtr, lineIndex);
+ }
+
+ /**
+ * Returns an entier font ascent of the line in pixels.
+ *
+ * @param lineIndex an index of the line.
+ * @return an entier font ascent of the line in pixels.
+ */
+ public @Px float getLineAscent(@IntRange(from = 0) int lineIndex) {
+ return nGetLineAscent(mPtr, lineIndex);
+ }
+
+ /**
+ * Returns an entier font descent of the line in pixels.
+ *
+ * @param lineIndex an index of the line.
+ * @return an entier font descent of the line in pixels.
+ */
+ public @Px float getLineDescent(@IntRange(from = 0) int lineIndex) {
+ return nGetLineDescent(mPtr, lineIndex);
+ }
+
+ /**
+ * Returns true if the line has a TAB character.
+ *
+ * @param lineIndex an index of the line.
+ * @return true if the line has a TAB character
+ */
+ public boolean hasLineTab(int lineIndex) {
+ return (nGetLineFlag(mPtr, lineIndex) & TAB_MASK) != 0;
+ }
+
+ /**
+ * Returns a packed packed hyphen edit for the line.
+ *
+ * @param lineIndex an index of the line.
+ * @return a packed hyphen edit for the line.
+ * @see android.text.Hyphenator#unpackStartHyphenEdit(int)
+ * @see android.text.Hyphenator#unpackEndHyphenEdit(int)
+ * @see android.text.Hyphenator#packHyphenEdit(int,int)
+ */
+ public int getLineHyphenEdit(int lineIndex) {
+ return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK);
+ }
}
private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
@@ -294,14 +370,12 @@ public class NativeLineBreaker {
* @param measuredPara a result of the text measurement
* @param constraints for a single paragraph
* @param lineNumber a line number of this paragraph
- * @param out object to set line break information for the given paragraph
*/
- public void computeLineBreaks(
+ public Result computeLineBreaks(
@NonNull NativeMeasuredParagraph measuredPara,
@NonNull ParagraphConstraints constraints,
- @IntRange(from = 0) int lineNumber,
- @NonNull LineBreaks out) {
- out.breakCount = nComputeLineBreaks(
+ @IntRange(from = 0) int lineNumber) {
+ return new Result(nComputeLineBreaks(
mNativePtr,
// Inputs
@@ -313,17 +387,7 @@ public class NativeLineBreaker {
constraints.mWidth,
constraints.mVariableTabStops,
constraints.mDefaultTabStop,
- lineNumber,
-
- // Outputs
- out,
- out.breaks.length,
- out.breaks,
- out.widths,
- out.ascents,
- out.descents,
- out.flags);
-
+ lineNumber));
}
@FastNative
@@ -341,7 +405,7 @@ public class NativeLineBreaker {
// arrays do not have to be resized
// The individual character widths will be returned in charWidths. The length of
// charWidths must be at least the length of the text.
- private static native int nComputeLineBreaks(
+ private static native long nComputeLineBreaks(
/* non zero */ long nativePtr,
// Inputs
@@ -353,14 +417,21 @@ public class NativeLineBreaker {
@FloatRange(from = 0.0f) float restWidth,
@Nullable int[] variableTabStops,
int defaultTabStop,
- @IntRange(from = 0) int indentsOffset,
-
- // Outputs
- @NonNull LineBreaks recycle,
- @IntRange(from = 0) int recycleLength,
- @NonNull int[] recycleBreaks,
- @NonNull float[] recycleWidths,
- @NonNull float[] recycleAscents,
- @NonNull float[] recycleDescents,
- @NonNull int[] recycleFlags);
+ @IntRange(from = 0) int indentsOffset);
+
+ // Result accessors
+ @CriticalNative
+ private static native int nGetLineCount(long ptr);
+ @CriticalNative
+ private static native int nGetLineBreakOffset(long ptr, int idx);
+ @CriticalNative
+ private static native float nGetLineWidth(long ptr, int idx);
+ @CriticalNative
+ private static native float nGetLineAscent(long ptr, int idx);
+ @CriticalNative
+ private static native float nGetLineDescent(long ptr, int idx);
+ @CriticalNative
+ private static native int nGetLineFlag(long ptr, int idx);
+ @CriticalNative
+ private static native long nGetReleaseResultFunc();
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index c5fabaf2d840..0d29da00f7c9 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1610,13 +1610,14 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
public boolean equals(Object o) {
if (o instanceof Spanned &&
toString().equals(o.toString())) {
- Spanned other = (Spanned) o;
+ final Spanned other = (Spanned) o;
// Check span data
- Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] thisSpans = getSpans(0, length(), Object.class);
if (mSpanCount == otherSpans.length) {
for (int i = 0; i < mSpanCount; ++i) {
- Object thisSpan = mSpans[i];
- Object otherSpan = otherSpans[i];
+ final Object thisSpan = thisSpans[i];
+ final Object otherSpan = otherSpans[i];
if (thisSpan == this) {
if (other != otherSpan ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 7acd5399792c..a9866335f271 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -16,12 +16,13 @@
package android.text;
+import android.annotation.UnsupportedAppUsage;
+
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import libcore.util.EmptyArray;
-import android.annotation.UnsupportedAppUsage;
import java.lang.reflect.Array;
/* package */ abstract class SpannableStringInternal
@@ -502,13 +503,14 @@ import java.lang.reflect.Array;
public boolean equals(Object o) {
if (o instanceof Spanned &&
toString().equals(o.toString())) {
- Spanned other = (Spanned) o;
+ final Spanned other = (Spanned) o;
// Check span data
- Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] thisSpans = getSpans(0, length(), Object.class);
if (mSpanCount == otherSpans.length) {
for (int i = 0; i < mSpanCount; ++i) {
- Object thisSpan = mSpans[i];
- Object otherSpan = otherSpans[i];
+ final Object thisSpan = thisSpans[i];
+ final Object otherSpan = otherSpans[i];
if (thisSpan == this) {
if (other != otherSpan ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e1ffef01feae..d2f085369448 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -599,7 +599,14 @@ public class StaticLayout extends Layout {
float ellipsizedWidth = b.mEllipsizedWidth;
TextUtils.TruncateAt ellipsize = b.mEllipsize;
final boolean addLastLineSpacing = b.mAddLastLineLineSpacing;
- NativeLineBreaker.LineBreaks lineBreaks = new NativeLineBreaker.LineBreaks();
+
+ int lineBreakCapacity = 0;
+ int[] breaks = null;
+ float[] lineWidths = null;
+ float[] ascents = null;
+ float[] descents = null;
+ boolean[] hasTabs = null;
+ int[] hyphenEdits = null;
mLineCount = 0;
mEllipsized = false;
@@ -732,14 +739,27 @@ public class StaticLayout extends Layout {
constraints.setIndent(firstWidth, firstWidthLineCount);
constraints.setTabStops(variableTabStops, TAB_INCREMENT);
- lineBreaker.computeLineBreaks(measuredPara.getNativeMeasuredParagraph(),
- constraints, mLineCount, lineBreaks);
- int breakCount = lineBreaks.breakCount;
- final int[] breaks = lineBreaks.breaks;
- final float[] lineWidths = lineBreaks.widths;
- final float[] ascents = lineBreaks.ascents;
- final float[] descents = lineBreaks.descents;
- final int[] flags = lineBreaks.flags;
+ NativeLineBreaker.Result res = lineBreaker.computeLineBreaks(
+ measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount);
+ int breakCount = res.getLineCount();
+ if (lineBreakCapacity < breakCount) {
+ lineBreakCapacity = breakCount;
+ breaks = new int[lineBreakCapacity];
+ lineWidths = new float[lineBreakCapacity];
+ ascents = new float[lineBreakCapacity];
+ descents = new float[lineBreakCapacity];
+ hasTabs = new boolean[lineBreakCapacity];
+ hyphenEdits = new int[lineBreakCapacity];
+ }
+
+ for (int i = 0; i < breakCount; ++i) {
+ breaks[i] = res.getLineBreakOffset(i);
+ lineWidths[i] = res.getLineWidth(i);
+ ascents[i] = res.getLineAscent(i);
+ descents[i] = res.getLineDescent(i);
+ hasTabs[i] = res.hasLineTab(i);
+ hyphenEdits[i] = res.getLineHyphenEdit(i);
+ }
final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
final boolean ellipsisMayBeApplied = ellipsize != null
@@ -750,7 +770,7 @@ public class StaticLayout extends Layout {
&& ellipsisMayBeApplied) {
// Calculate width
float width = 0;
- int flag = 0; // XXX May need to also have starting hyphen edit
+ boolean hasTab = false; // XXX May need to also have starting hyphen edit
for (int i = remainingLineCount - 1; i < breakCount; i++) {
if (i == breakCount - 1) {
width += lineWidths[i];
@@ -759,12 +779,12 @@ public class StaticLayout extends Layout {
width += measuredPara.getCharWidthAt(j - paraStart);
}
}
- flag |= flags[i] & TAB_MASK;
+ hasTab |= hasTabs[i];
}
// Treat the last line and overflowed lines as a single line.
breaks[remainingLineCount - 1] = breaks[breakCount - 1];
lineWidths[remainingLineCount - 1] = width;
- flags[remainingLineCount - 1] = flag;
+ hasTabs[remainingLineCount - 1] = hasTab;
breakCount = remainingLineCount;
}
@@ -821,8 +841,8 @@ public class StaticLayout extends Layout {
v = out(source, here, endPos,
ascent, descent, fmTop, fmBottom,
v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
- flags[breakIndex], needMultiply, measuredPara, bufEnd,
- includepad, trackpad, addLastLineSpacing, chs,
+ hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply,
+ measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,
paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
paint, moreChars);
@@ -860,7 +880,7 @@ public class StaticLayout extends Layout {
fm.top, fm.bottom,
v,
spacingmult, spacingadd, null,
- null, fm, 0,
+ null, fm, false, 0,
needMultiply, measuredPara, bufEnd,
includepad, trackpad, addLastLineSpacing, null,
bufStart, ellipsize,
@@ -871,7 +891,8 @@ public class StaticLayout extends Layout {
private int out(final CharSequence text, final int start, final int end, int above, int below,
int top, int bottom, int v, final float spacingmult, final float spacingadd,
final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
- final int flags, final boolean needMultiply, @NonNull final MeasuredParagraph measured,
+ final boolean hasTab, final int hyphenEdit, final boolean needMultiply,
+ @NonNull final MeasuredParagraph measured,
final int bufEnd, final boolean includePad, final boolean trackPad,
final boolean addLastLineLineSpacing, final char[] chs,
final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth,
@@ -1005,8 +1026,8 @@ public class StaticLayout extends Layout {
// TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
// one bit for start field
- lines[off + TAB] |= flags & TAB_MASK;
- lines[off + HYPHEN] = flags;
+ lines[off + TAB] |= hasTab ? TAB_MASK : 0;
+ lines[off + HYPHEN] = hyphenEdit;
lines[off + DIR] |= dir << DIR_SHIFT;
mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index c17cfd500827..2dc4f6001a06 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -16,11 +16,13 @@
package android.text.style;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.LeakyTypefaceStorage;
import android.graphics.Typeface;
+import android.graphics.fonts.Font;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
@@ -38,6 +40,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
private final ColorStateList mTextColorLink;
private final Typeface mTypeface;
+ private final int mTextFontWeight;
+
+ private final float mShadowRadius;
+ private final float mShadowDx;
+ private final float mShadowDy;
+ private final int mShadowColor;
+
+ private final boolean mHasElegantTextHeight;
+ private final boolean mElegantTextHeight;
+ private final boolean mHasLetterSpacing;
+ private final float mLetterSpacing;
+
+ private final String mFontFeatureSettings;
+ private final String mFontVariationSettings;
+
/**
* Uses the specified TextAppearance resource to determine the
* text appearance. The <code>appearance</code> should be, for example,
@@ -104,6 +121,34 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
}
}
+ mTextFontWeight = a.getInt(com.android.internal.R.styleable
+ .TextAppearance_textFontWeight, -1);
+
+ mShadowRadius = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowRadius, 0.0f);
+ mShadowDx = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowDx, 0.0f);
+ mShadowDy = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowDy, 0.0f);
+ mShadowColor = a.getInt(com.android.internal.R.styleable
+ .TextAppearance_shadowColor, 0);
+
+ mHasElegantTextHeight = a.hasValue(com.android.internal.R.styleable
+ .TextAppearance_elegantTextHeight);
+ mElegantTextHeight = a.getBoolean(com.android.internal.R.styleable
+ .TextAppearance_elegantTextHeight, false);
+
+ mHasLetterSpacing = a.hasValue(com.android.internal.R.styleable
+ .TextAppearance_letterSpacing);
+ mLetterSpacing = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_letterSpacing, 0.0f);
+
+ mFontFeatureSettings = a.getString(com.android.internal.R.styleable
+ .TextAppearance_fontFeatureSettings);
+
+ mFontVariationSettings = a.getString(com.android.internal.R.styleable
+ .TextAppearance_fontVariationSettings);
+
a.recycle();
if (colorList >= 0) {
@@ -129,6 +174,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
mTextColor = color;
mTextColorLink = linkColor;
mTypeface = null;
+
+ mTextFontWeight = -1;
+
+ mShadowRadius = 0.0f;
+ mShadowDx = 0.0f;
+ mShadowDy = 0.0f;
+ mShadowColor = 0;
+
+ mHasElegantTextHeight = false;
+ mElegantTextHeight = false;
+ mHasLetterSpacing = false;
+ mLetterSpacing = 0.0f;
+
+ mFontFeatureSettings = null;
+ mFontVariationSettings = null;
}
public TextAppearanceSpan(Parcel src) {
@@ -146,6 +206,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
mTextColorLink = null;
}
mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+
+ mTextFontWeight = src.readInt();
+
+ mShadowRadius = src.readFloat();
+ mShadowDx = src.readFloat();
+ mShadowDy = src.readFloat();
+ mShadowColor = src.readInt();
+
+ mHasElegantTextHeight = src.readBoolean();
+ mElegantTextHeight = src.readBoolean();
+ mHasLetterSpacing = src.readBoolean();
+ mLetterSpacing = src.readFloat();
+
+ mFontFeatureSettings = src.readString();
+ mFontVariationSettings = src.readString();
}
public int getSpanTypeId() {
@@ -183,6 +258,21 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
dest.writeInt(0);
}
LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
+
+ dest.writeInt(mTextFontWeight);
+
+ dest.writeFloat(mShadowRadius);
+ dest.writeFloat(mShadowDx);
+ dest.writeFloat(mShadowDy);
+ dest.writeInt(mShadowColor);
+
+ dest.writeBoolean(mHasElegantTextHeight);
+ dest.writeBoolean(mElegantTextHeight);
+ dest.writeBoolean(mHasLetterSpacing);
+ dest.writeFloat(mLetterSpacing);
+
+ dest.writeString(mFontFeatureSettings);
+ dest.writeString(mFontVariationSettings);
}
/**
@@ -225,6 +315,81 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
return mStyle;
}
+ /**
+ * Returns the text font weight specified by this span, or <code>-1</code>
+ * if it does not specify one.
+ */
+ public int getTextFontWeight() {
+ return mTextFontWeight;
+ }
+
+ /**
+ * Returns the typeface specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public Typeface getTypeface() {
+ return mTypeface;
+ }
+
+ /**
+ * Returns the color of the text shadow specified by this span, or <code>0</code>
+ * if it does not specify one.
+ */
+ public int getShadowColor() {
+ return mShadowColor;
+ }
+
+ /**
+ * Returns the horizontal offset of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowDx() {
+ return mShadowDx;
+ }
+
+ /**
+ * Returns the vertical offset of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowDy() {
+ return mShadowDy;
+ }
+
+ /**
+ * Returns the blur radius of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowRadius() {
+ return mShadowRadius;
+ }
+
+ /**
+ * Returns the font feature settings specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public String getFontFeatureSettings() {
+ return mFontFeatureSettings;
+ }
+
+ /**
+ * Returns the font variation settings specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public String getFontVariationSettings() {
+ return mFontVariationSettings;
+ }
+
+ /**
+ * Returns the value of elegant height metrics flag specified by this span,
+ * or <code>false</code> if it does not specify one.
+ */
+ public boolean isElegantTextHeight() {
+ return mElegantTextHeight;
+ }
+
@Override
public void updateDrawState(TextPaint ds) {
updateMeasureState(ds);
@@ -236,6 +401,10 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
if (mTextColorLink != null) {
ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0);
}
+
+ if (mShadowColor != 0) {
+ ds.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
+ }
}
@Override
@@ -267,7 +436,16 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
}
if (styledTypeface != null) {
- int fake = style & ~styledTypeface.getStyle();
+ final Typeface readyTypeface;
+ if (mTextFontWeight >= 0) {
+ final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight);
+ final boolean italic = (style & Typeface.ITALIC) != 0;
+ readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic));
+ } else {
+ readyTypeface = styledTypeface;
+ }
+
+ int fake = style & ~readyTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
ds.setFakeBoldText(true);
@@ -277,11 +455,27 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
ds.setTextSkewX(-0.25f);
}
- ds.setTypeface(styledTypeface);
+ ds.setTypeface(readyTypeface);
}
if (mTextSize > 0) {
ds.setTextSize(mTextSize);
}
+
+ if (mHasElegantTextHeight) {
+ ds.setElegantTextHeight(mElegantTextHeight);
+ }
+
+ if (mHasLetterSpacing) {
+ ds.setLetterSpacing(mLetterSpacing);
+ }
+
+ if (mFontFeatureSettings != null) {
+ ds.setFontFeatureSettings(mFontFeatureSettings);
+ }
+
+ if (mFontVariationSettings != null) {
+ ds.setFontVariationSettings(mFontVariationSettings);
+ }
}
}
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
index d7a912057858..9fa9961d21bc 100644
--- a/core/java/android/transition/ChangeImageTransform.java
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -97,22 +97,13 @@ public class ChangeImageTransform extends Transition {
values.put(PROPNAME_BOUNDS, bounds);
Matrix matrix;
ImageView.ScaleType scaleType = imageView.getScaleType();
- if (scaleType == ImageView.ScaleType.FIT_XY) {
- matrix = imageView.getImageMatrix();
- if (!matrix.isIdentity()) {
- matrix = new Matrix(matrix);
- } else {
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
- if (drawableWidth > 0 && drawableHeight > 0) {
- float scaleX = ((float) bounds.width()) / drawableWidth;
- float scaleY = ((float) bounds.height()) / drawableHeight;
- matrix = new Matrix();
- matrix.setScale(scaleX, scaleY);
- } else {
- matrix = null;
- }
- }
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+ if (scaleType == ImageView.ScaleType.FIT_XY && drawableWidth > 0 && drawableHeight > 0) {
+ float scaleX = ((float) bounds.width()) / drawableWidth;
+ float scaleY = ((float) bounds.height()) / drawableHeight;
+ matrix = new Matrix();
+ matrix.setScale(scaleX, scaleY);
} else {
matrix = new Matrix(imageView.getImageMatrix());
}
@@ -152,17 +143,13 @@ public class ChangeImageTransform extends Transition {
}
Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
- if (startBounds == null || endBounds == null) {
- return null;
- }
-
Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
+ if (startBounds == null || endBounds == null || startMatrix == null || endMatrix == null) {
+ return null;
+ }
- boolean matricesEqual = (startMatrix == null && endMatrix == null) ||
- (startMatrix != null && startMatrix.equals(endMatrix));
-
- if (startBounds.equals(endBounds) && matricesEqual) {
+ if (startBounds.equals(endBounds) && startMatrix.equals(endMatrix)) {
return null;
}
@@ -172,15 +159,9 @@ public class ChangeImageTransform extends Transition {
int drawableHeight = drawable.getIntrinsicHeight();
ObjectAnimator animator;
- if (drawableWidth == 0 || drawableHeight == 0) {
+ if (drawableWidth <= 0 || drawableHeight <= 0) {
animator = createNullAnimator(imageView);
} else {
- if (startMatrix == null) {
- startMatrix = Matrix.IDENTITY_MATRIX;
- }
- if (endMatrix == null) {
- endMatrix = Matrix.IDENTITY_MATRIX;
- }
ANIMATED_TRANSFORM_PROPERTY.set(imageView, startMatrix);
animator = createMatrixAnimator(imageView, startMatrix, endMatrix);
}
@@ -189,7 +170,7 @@ public class ChangeImageTransform extends Transition {
private ObjectAnimator createNullAnimator(ImageView imageView) {
return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
- NULL_MATRIX_EVALUATOR, null, null);
+ NULL_MATRIX_EVALUATOR, Matrix.IDENTITY_MATRIX, Matrix.IDENTITY_MATRIX);
}
private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix,
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index c4ef77a3e7ae..4608e205ec7c 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -188,8 +188,12 @@ public class TransitionManager {
final ViewGroup sceneRoot = scene.getSceneRoot();
if (!sPendingTransitions.contains(sceneRoot)) {
+ Scene oldScene = Scene.getCurrentScene(sceneRoot);
if (transition == null) {
- exitPreviousScene(sceneRoot);
+ // Notify old scene that it is being exited
+ if (oldScene != null) {
+ oldScene.exit();
+ }
scene.enter();
} else {
@@ -198,7 +202,6 @@ public class TransitionManager {
Transition transitionClone = transition.clone();
transitionClone.setSceneRoot(sceneRoot);
- Scene oldScene = Scene.getCurrentScene(sceneRoot);
if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
transitionClone.setCanRemoveViews(true);
}
@@ -212,14 +215,6 @@ public class TransitionManager {
}
}
- private static void exitPreviousScene(final ViewGroup sceneRoot) {
- // Notify previous scene that it is being exited
- final Scene previousScene = Scene.getCurrentScene(sceneRoot);
- if (previousScene != null) {
- previousScene.exit();
- }
- }
-
@UnsupportedAppUsage
private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
@@ -349,7 +344,11 @@ public class TransitionManager {
transition.captureValues(sceneRoot, true);
}
- exitPreviousScene(sceneRoot);
+ // Notify previous scene that it is being exited
+ Scene previousScene = Scene.getCurrentScene(sceneRoot);
+ if (previousScene != null) {
+ previousScene.exit();
+ }
}
/**
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 5108a796a036..294a1799a2d3 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -71,19 +71,19 @@ public final class ArrayMap<K, V> implements Map<K, V> {
/**
* Maximum number of entries to have in array caches.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
private static final int CACHE_SIZE = 10;
/**
* Special hash array value that indicates the container is immutable.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
static final int[] EMPTY_IMMUTABLE_INTS = new int[0];
/**
* @hide Special immutable empty ArrayMap.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use your own singleton empty map.
public static final ArrayMap EMPTY = new ArrayMap<>(-1);
/**
@@ -92,21 +92,21 @@ public final class ArrayMap<K, V> implements Map<K, V> {
* The first entry in the array is a pointer to the next array in the
* list; the second entry is a pointer to the int[] hash code array for it.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
static Object[] mBaseCache;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
static int mBaseCacheSize;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
static Object[] mTwiceBaseCache;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
static int mTwiceBaseCacheSize;
final boolean mIdentityHashCode;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use public key/value API.
int[] mHashes;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use public key/value API.
Object[] mArray;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
int mSize;
MapCollections<K, V> mCollections;
@@ -122,7 +122,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use indexOfKey(Object).
int indexOf(Object key, int hash) {
final int N = mSize;
@@ -161,7 +161,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
return ~end;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use indexOf(null)
int indexOfNull() {
final int N = mSize;
@@ -200,7 +200,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
return ~end;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
private void allocArrays(final int size) {
if (mHashes == EMPTY_IMMUTABLE_INTS) {
throw new UnsupportedOperationException("ArrayMap is immutable");
@@ -239,7 +239,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
mArray = new Object[size<<1];
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
if (hashes.length == (BASE_SIZE*2)) {
synchronized (ArrayMap.class) {
@@ -393,8 +393,15 @@ public final class ArrayMap<K, V> implements Map<K, V> {
: indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
}
- @UnsupportedAppUsage
- int indexOfValue(Object value) {
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(Object value) {
final int N = mSize*2;
final Object[] array = mArray;
if (value == null) {
@@ -551,7 +558,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
* The array must already be large enough to contain the item.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use put(K, V).
public void append(K key, V value) {
int index = mSize;
final int hash = key == null ? 0
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 526a950b4820..d74a0fe8d2c1 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -71,15 +71,15 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
static int sTwiceBaseCacheSize;
final boolean mIdentityHashCode;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use public API.
int[] mHashes;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Storage is an implementation detail. Use public API.
Object[] mArray;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
int mSize;
MapCollections<E, E> mCollections;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Hashes are an implementation detail. Use indexOfKey(Object).
private int indexOf(Object key, int hash) {
final int N = mSize;
@@ -118,7 +118,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
return ~end;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use indexOf(null)
private int indexOfNull() {
final int N = mSize;
@@ -157,7 +157,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
return ~end;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
private void allocArrays(final int size) {
if (size == (BASE_SIZE * 2)) {
synchronized (ArraySet.class) {
@@ -215,7 +215,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
mArray = new Object[size];
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Allocations are an implementation detail.
private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
if (hashes.length == (BASE_SIZE * 2)) {
synchronized (ArraySet.class) {
@@ -289,9 +289,10 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
}
}
- /** {@hide} */
- @UnsupportedAppUsage
- public ArraySet(Collection<E> set) {
+ /**
+ * Create a new ArraySet with items from the given collection.
+ */
+ public ArraySet(Collection<? extends E> set) {
this();
if (set != null) {
addAll(set);
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index d5af92234b31..af163ac8f246 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -46,11 +46,11 @@ import libcore.util.EmptyArray;
* @hide
*/
public class LongSparseLongArray implements Cloneable {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.
private long[] mKeys;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.
private long[] mValues;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // The type isn't even public.
private int mSize;
/**
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index aa5ca3530621..89ea2d35fc2f 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -56,11 +56,11 @@ public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)
private int[] mKeys;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, E)
private Object[] mValues;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
private int mSize;
/**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 9c6b9698d1ae..d4c40954bdd1 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -185,7 +185,9 @@ public class SparseBooleanArray implements Cloneable {
return mValues[index];
}
- /** @hide */
+ /**
+ * Directly set the value at a particular index.
+ */
public void setValueAt(int index, boolean value) {
mValues[index] = value;
}
@@ -304,10 +306,10 @@ public class SparseBooleanArray implements Cloneable {
return buffer.toString();
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)
private int[] mKeys;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, boolean)
private boolean[] mValues;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
private int mSize;
}
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 19547534aef5..9e6bad1d9ae0 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -46,11 +46,11 @@ import libcore.util.EmptyArray;
* order in the case of <code>valueAt(int)</code>.</p>
*/
public class SparseIntArray implements Cloneable {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)
private int[] mKeys;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, int)
private int[] mValues;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
private int mSize;
/**
@@ -191,7 +191,6 @@ public class SparseIntArray implements Cloneable {
/**
* Directly set the value at a particular index.
- * @hide
*/
public void setValueAt(int index, int value) {
mValues[index] = value;
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 1203541756e8..1bbef8e9cfff 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -410,7 +410,7 @@ public class ApkSignatureSchemeV2Verifier {
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
- return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
}
}
@@ -423,7 +423,7 @@ public class ApkSignatureSchemeV2Verifier {
if (vSigner.verityRootHash == null) {
return null;
}
- return ApkVerityBuilder.generateApkVerityRootHash(
+ return VerityBuilder.generateApkVerityRootHash(
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
}
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 939522dcd57f..1471870bd7d2 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -534,7 +534,7 @@ public class ApkSignatureSchemeV3Verifier {
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
SignatureInfo signatureInfo = findSignature(apk);
- return ApkVerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
+ return VerityBuilder.generateApkVerity(apkPath, bufferFactory, signatureInfo);
}
}
@@ -547,7 +547,7 @@ public class ApkSignatureSchemeV3Verifier {
if (vSigner.verityRootHash == null) {
return null;
}
- return ApkVerityBuilder.generateApkVerityRootHash(
+ return VerityBuilder.generateApkVerityRootHash(
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
}
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 081033ae84e9..87af5364c945 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -332,7 +332,7 @@ final class ApkSigningBlockUtils {
try {
byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
apk.length(), signatureInfo);
- ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerityTree(apk,
+ VerityBuilder.VerityResult verity = VerityBuilder.generateApkVerityTree(apk,
signatureInfo, new ByteBufferFactory() {
@Override
public ByteBuffer create(int capacity) {
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index edd09f8f73c4..443bbd8597af 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -29,19 +29,18 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
/**
- * ApkVerityBuilder builds the APK verity tree and the verity header. The generated tree format can
- * be stored on disk for apk-verity setup and used by kernel. Note that since the current
- * implementation is different from the upstream, we call this implementation apk-verity instead of
- * fs-verity.
+ * VerityBuilder builds the verity Merkle tree and other metadata. The generated tree format can
+ * be stored on disk for fs-verity setup and used by kernel. The builder support standard
+ * fs-verity, and Android specific apk-verity that requires additional kernel patches.
*
- * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
- * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
- * the "Central Directory offset" field of ZIP End of Central Directory.
+ * <p>Unlike a regular Merkle tree of fs-verity, the apk-verity tree does not cover the file content
+ * fully, and has to skip APK Signing Block with some special treatment for the "Central Directory
+ * offset" field of ZIP End of Central Directory.
*
* @hide
*/
-public abstract class ApkVerityBuilder {
- private ApkVerityBuilder() {}
+public abstract class VerityBuilder {
+ private VerityBuilder() {}
private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size
private static final int DIGEST_SIZE_BYTES = 32; // SHA-256 size
@@ -52,7 +51,7 @@ public abstract class ApkVerityBuilder {
private static final byte[] DEFAULT_SALT = new byte[8];
/** Result generated by the builder. */
- public static class ApkVerityResult {
+ public static class VerityResult {
/** Raw fs-verity metadata and Merkle tree ready to be deployed on disk. */
public final ByteBuffer verityData;
@@ -62,7 +61,7 @@ public abstract class ApkVerityBuilder {
/** Root hash of the Merkle tree. */
public final byte[] rootHash;
- private ApkVerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
+ private VerityResult(ByteBuffer verityData, int merkleTreeSize, byte[] rootHash) {
this.verityData = verityData;
this.merkleTreeSize = merkleTreeSize;
this.rootHash = rootHash;
@@ -74,14 +73,14 @@ public abstract class ApkVerityBuilder {
* ByteBuffer} created by the {@link ByteBufferFactory}. The output is suitable to be used as
* the on-disk format for fs-verity to use.
*
- * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+ * @return VerityResult containing a buffer with the generated Merkle tree stored at the
* front, the tree size, and the calculated root hash.
*/
@NonNull
- public static ApkVerityResult generateFsVerityTree(@NonNull RandomAccessFile apk,
+ public static VerityResult generateFsVerityTree(@NonNull RandomAccessFile apk,
@NonNull ByteBufferFactory bufferFactory)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- return generateVerityTree(apk, bufferFactory, null /* signatureInfo */,
+ return generateVerityTreeInternal(apk, bufferFactory, null /* signatureInfo */,
false /* skipSigningBlock */);
}
@@ -91,18 +90,19 @@ public abstract class ApkVerityBuilder {
* Block specificed in {@code signatureInfo}. The output is suitable to be used as the on-disk
* format for fs-verity to use (with elide and patch extensions).
*
- * @return ApkVerityResult containing a buffer with the generated Merkle tree stored at the
+ * @return VerityResult containing a buffer with the generated Merkle tree stored at the
* front, the tree size, and the calculated root hash.
*/
@NonNull
- public static ApkVerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
+ public static VerityResult generateApkVerityTree(@NonNull RandomAccessFile apk,
@Nullable SignatureInfo signatureInfo, @NonNull ByteBufferFactory bufferFactory)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
- return generateVerityTree(apk, bufferFactory, signatureInfo, true /* skipSigningBlock */);
+ return generateVerityTreeInternal(apk, bufferFactory, signatureInfo,
+ true /* skipSigningBlock */);
}
@NonNull
- private static ApkVerityResult generateVerityTree(@NonNull RandomAccessFile apk,
+ private static VerityResult generateVerityTreeInternal(@NonNull RandomAccessFile apk,
@NonNull ByteBufferFactory bufferFactory, @Nullable SignatureInfo signatureInfo,
boolean skipSigningBlock)
throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
@@ -124,7 +124,7 @@ public abstract class ApkVerityBuilder {
byte[] salt = skipSigningBlock ? DEFAULT_SALT : null;
byte[] apkRootHash = generateVerityTreeInternal(apk, signatureInfo, salt, levelOffset,
tree, skipSigningBlock);
- return new ApkVerityResult(output, merkleTreeSize, apkRootHash);
+ return new VerityResult(output, merkleTreeSize, apkRootHash);
}
static void generateApkVerityFooter(@NonNull RandomAccessFile apk,
@@ -173,7 +173,7 @@ public abstract class ApkVerityBuilder {
throws IOException, SignatureNotFoundException, SecurityException, DigestException,
NoSuchAlgorithmException {
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
- ApkVerityResult result = generateVerityTree(apk, bufferFactory, signatureInfo,
+ VerityResult result = generateVerityTreeInternal(apk, bufferFactory, signatureInfo,
true /* skipSigningBlock */);
ByteBuffer footer = slice(result.verityData, result.merkleTreeSize,
result.verityData.limit());
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0986b89849cf..42690cef9da3 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -974,6 +974,25 @@ public final class ThreadedRenderer {
}
}
+ /** The root of everything */
+ public @NonNull RenderNode getRootNode() {
+ return mRootNode;
+ }
+
+ private boolean mForceDark = false;
+
+ /**
+ * Whether or not the force-dark feature should be used for this renderer.
+ */
+ public boolean setForceDark(boolean enable) {
+ if (mForceDark != enable) {
+ mForceDark = enable;
+ nSetForceDark(mNativeProxy, enable);
+ return true;
+ }
+ return false;
+ }
+
/**
* Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
* TODO: deduplicate against ThreadedRenderer.
@@ -1253,4 +1272,5 @@ public final class ThreadedRenderer {
private static native void nSetIsolatedProcess(boolean enabled);
private static native void nSetContextPriority(int priority);
private static native void nAllocateBuffers(long nativeProxy, Surface window);
+ private static native void nSetForceDark(long nativeProxy, boolean enabled);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1eb35c546c99..78e6dd8fb139 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15255,6 +15255,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* a value of 'true' will not override any 'false' value in its parent chain nor will
* it prevent any 'false' in any of its children.
*
+ * The default behavior of force dark is also influenced by the Theme's
+ * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute.
+ * If a theme is isLightTheme="false", then force dark is globally disabled for that theme.
+ *
* @param allow Whether or not to allow force dark.
*
* @hide
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5bc44ce2bd49..bef8e8fedfdf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -43,6 +43,7 @@ import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -1077,6 +1078,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+ updateForceDarkMode();
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
@@ -1085,6 +1087,27 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private int getNightMode() {
+ return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ }
+
+ private void updateForceDarkMode() {
+ if (mAttachInfo.mThreadedRenderer == null) return;
+
+ boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+ TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+ boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false);
+ a.recycle();
+
+ boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode);
+ changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme);
+
+ if (changed) {
+ // TODO: Don't require regenerating all display lists to apply this setting
+ invalidateWorld(mView);
+ }
+ }
+
@UnsupportedAppUsage
public View getView() {
return mView;
@@ -4077,6 +4100,8 @@ public final class ViewRootImpl implements ViewParent,
mForceNextWindowRelayout = true;
requestLayout();
}
+
+ updateForceDarkMode();
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index e1600c4a92c8..d09323d3f8ad 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -124,7 +124,8 @@ public interface InputMethod {
* @hide
*/
@MainThread
- public void updateInputMethodDisplay(int displayId);
+ default void updateInputMethodDisplay(int displayId) {
+ }
/**
* Bind a new application environment in to the input method, so that it
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0fef9a54a2ff..12cc54d7241e 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1338,7 +1338,9 @@ public class ImageView extends View {
return;
}
if (matrix == null) {
- mDrawable.setBounds(0, 0, getWidth(), getHeight());
+ final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
+ final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
+ mDrawable.setBounds(0, 0, vwidth, vheight);
} else {
mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);
if (mDrawMatrix == null) {
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index cb282b69845c..0080ace230a2 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -66,13 +66,13 @@ public class AmbientDisplayConfiguration {
return !TextUtils.isEmpty(doubleTapSensorType());
}
- public boolean reachGestureEnabled(int user) {
- return boolSettingDefaultOn(Settings.Secure.DOZE_REACH_GESTURE, user)
- && reachGestureAvailable();
+ public boolean wakeLockScreenGestureEnabled(int user) {
+ return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user)
+ && wakeLockScreenGestureAvailable();
}
- public boolean reachGestureAvailable() {
- return !TextUtils.isEmpty(reachSensorType());
+ public boolean wakeLockScreenGestureAvailable() {
+ return !TextUtils.isEmpty(wakeLockScreenSensorType());
}
public boolean wakeScreenGestureEnabled(int user) {
@@ -92,8 +92,8 @@ public class AmbientDisplayConfiguration {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
- public String reachSensorType() {
- return mContext.getResources().getString(R.string.config_dozeReachSensorType);
+ public String wakeLockScreenSensorType() {
+ return mContext.getResources().getString(R.string.config_dozeWakeLockScreenSensorType);
}
public String wakeScreenSensorType() {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 927322e97e28..98b7b5d28779 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -133,15 +133,16 @@ public final class Zygote {
* if this is the parent, or -1 on error.
*/
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
- int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- String packageName) {
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
+ String packageName, String[] packagesForUid, String[] visibleVolIds) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
- fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName);
+ fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName,
+ packagesForUid, visibleVolIds);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
@@ -154,9 +155,9 @@ public final class Zygote {
}
native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
- int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- String packageName);
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
+ String packageName, String[] packagesForUid, String[] visibleVolIds);
/**
* Called to do any initialization before starting an application.
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 06c41d858f7c..4a94ec4a4071 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -241,7 +241,8 @@ class ZygoteConnection {
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
- parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName);
+ parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName,
+ parsedArgs.packagesForUid, parsedArgs.visibleVolIds);
try {
if (pid == 0) {
@@ -432,6 +433,12 @@ class ZygoteConnection {
/** from --package-name */
String packageName;
+ /** from --packages-for-uid */
+ String[] packagesForUid;
+
+ /** from --visible-vols */
+ String[] visibleVolIds;
+
/**
* Any args after and including the first non-option arg
* (or after a '--')
@@ -687,6 +694,10 @@ class ZygoteConnection {
throw new IllegalArgumentException("Duplicate arg specified");
}
packageName = arg.substring(arg.indexOf('=') + 1);
+ } else if (arg.startsWith("--packages-for-uid=")) {
+ packagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
+ } else if (arg.startsWith("--visible-vols=")) {
+ visibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");
} else {
break;
}
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index b16359727e40..a45b4933a900 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -622,13 +622,17 @@ void util_multiplyMV(JNIEnv *env, jclass clazz,
// ---------------------------------------------------------------------------
+// The internal format is no longer the same as pixel format, per Table 2 in
+// https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml
static int checkInternalFormat(SkColorType colorType, int internalformat,
int type)
{
switch(colorType) {
case kN32_SkColorType:
return (type == GL_UNSIGNED_BYTE &&
- internalformat == GL_RGBA) ? 0 : -1;
+ internalformat == GL_RGBA) ||
+ (type == GL_UNSIGNED_BYTE &&
+ internalformat == GL_SRGB8_ALPHA8) ? 0 : -1;
case kAlpha_8_SkColorType:
return (type == GL_UNSIGNED_BYTE &&
internalformat == GL_ALPHA) ? 0 : -1;
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index dfa5de6b65c6..b70485d9a0ea 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -28,6 +28,14 @@ void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
}
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn) {
+ ScopedUtfChars pathChars(env, path);
+ ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars appPrefChars(env, appPref);
+ android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
+ appPrefChars.c_str(), devOptIn);
+}
+
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader(
env, classLoader);
@@ -44,6 +52,7 @@ void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) {
const JNINativeMethod g_methods[] = {
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
};
diff --git a/core/jni/android_text_LineBreaker.cpp b/core/jni/android_text_LineBreaker.cpp
index dac108ef5497..543910727ffd 100644
--- a/core/jni/android_text_LineBreaker.cpp
+++ b/core/jni/android_text_LineBreaker.cpp
@@ -41,17 +41,6 @@
namespace android {
-struct JLineBreaksID {
- jfieldID breaks;
- jfieldID widths;
- jfieldID ascents;
- jfieldID descents;
- jfieldID flags;
-};
-
-static jclass gLineBreaks_class;
-static JLineBreaksID gLineBreaks_fieldID;
-
static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray javaArray) {
if (javaArray == nullptr) {
return std::vector<float>();
@@ -85,34 +74,7 @@ static jlong nGetReleaseFunc() {
return reinterpret_cast<jlong>(nFinish);
}
-static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
- jfloatArray recycleWidths, jfloatArray recycleAscents,
- jfloatArray recycleDescents, jintArray recycleFlags,
- jint recycleLength, const minikin::LineBreakResult& result) {
- const size_t nBreaks = result.breakPoints.size();
- if ((size_t)recycleLength < nBreaks) {
- // have to reallocate buffers
- recycleBreaks = env->NewIntArray(nBreaks);
- recycleWidths = env->NewFloatArray(nBreaks);
- recycleAscents = env->NewFloatArray(nBreaks);
- recycleDescents = env->NewFloatArray(nBreaks);
- recycleFlags = env->NewIntArray(nBreaks);
-
- env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
- env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
- env->SetObjectField(recycle, gLineBreaks_fieldID.ascents, recycleAscents);
- env->SetObjectField(recycle, gLineBreaks_fieldID.descents, recycleDescents);
- env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
- }
- // copy data
- env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data());
- env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data());
- env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data());
- env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data());
- env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data());
-}
-
-static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
+static jlong nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
// Inputs
jcharArray javaText,
jlong measuredTextPtr,
@@ -122,18 +84,7 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
jfloat restWidth,
jintArray variableTabStops,
jint defaultTabStop,
- jint indentsOffset,
-
- // Outputs
- jobject recycle,
- jint recycleLength,
- jintArray recycleBreaks,
- jfloatArray recycleWidths,
- jfloatArray recycleAscents,
- jfloatArray recycleDescents,
- jintArray recycleFlags,
- jfloatArray charWidths) {
-
+ jint indentsOffset) {
minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
ScopedCharArrayRO text(env, javaText);
@@ -141,14 +92,44 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
minikin::U16StringPiece u16Text(text.get(), length);
minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr);
- minikin::LineBreakResult result = builder->computeBreaks(
- u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
- tabStops.get(), tabStops.size(), defaultTabStop);
- recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
- recycleFlags, recycleLength, result);
+ std::unique_ptr<minikin::LineBreakResult> result =
+ std::make_unique<minikin::LineBreakResult>(builder->computeBreaks(
+ u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
+ tabStops.get(), tabStops.size(), defaultTabStop));
+ return reinterpret_cast<jlong>(result.release());
+}
+
+static jint nGetLineCount(jlong ptr) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints.size();
+}
+
+static jint nGetLineBreakOffset(jlong ptr, jint i) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints[i];
+}
+
+static jfloat nGetLineWidth(jlong ptr, jint i) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->widths[i];
+}
- return static_cast<jint>(result.breakPoints.size());
+static jfloat nGetLineAscent(jlong ptr, jint i) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->ascents[i];
+}
+
+static jfloat nGetLineDescent(jlong ptr, jint i) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->descents[i];
+}
+
+static jint nGetLineFlag(jlong ptr, jint i) {
+ return reinterpret_cast<minikin::LineBreakResult*>(ptr)->flags[i];
+}
+
+static void nReleaseResult(jlong ptr) {
+ delete reinterpret_cast<minikin::LineBreakResult*>(ptr);
+}
+
+static jlong nGetReleaseResultFunc() {
+ return reinterpret_cast<jlong>(nReleaseResult);
}
static const JNINativeMethod gMethods[] = {
@@ -166,8 +147,6 @@ static const JNINativeMethod gMethods[] = {
// Regular JNI
{"nComputeLineBreaks", "("
"J" // nativePtr
-
- // Inputs
"[C" // text
"J" // MeasuredParagraph ptr.
"I" // length
@@ -177,31 +156,20 @@ static const JNINativeMethod gMethods[] = {
"[I" // variableTabStops
"I" // defaultTabStop
"I" // indentsOffset
-
- // Outputs
- "Landroid/text/NativeLineBreaker$LineBreaks;" // recycle
- "I" // recycleLength
- "[I" // recycleBreaks
- "[F" // recycleWidths
- "[F" // recycleAscents
- "[F" // recycleDescents
- "[I" // recycleFlags
- ")I", (void*) nComputeLineBreaks}
+ ")J", (void*) nComputeLineBreaks},
+
+ // Result accessors, CriticalNatives
+ {"nGetLineCount", "(J)I", (void*)nGetLineCount},
+ {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset},
+ {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth},
+ {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent},
+ {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent},
+ {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag},
+ {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},
};
-int register_android_text_LineBreaker(JNIEnv* env)
-{
- gLineBreaks_class = MakeGlobalRefOrDie(env,
- FindClassOrDie(env, "android/text/NativeLineBreaker$LineBreaks"));
-
- gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I");
- gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F");
- gLineBreaks_fieldID.ascents = GetFieldIDOrDie(env, gLineBreaks_class, "ascents", "[F");
- gLineBreaks_fieldID.descents = GetFieldIDOrDie(env, gLineBreaks_class, "descents", "[F");
- gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[I");
-
- return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker",
- gMethods, NELEM(gMethods));
+int register_android_text_LineBreaker(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", gMethods, NELEM(gMethods));
}
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 3c59bd1e3856..7a5b60493dcd 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1064,6 +1064,12 @@ static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject c
proxy->allocateBuffers(surface);
}
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean enable) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setForceDark(enable);
+}
+
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -1177,6 +1183,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
{ "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
{ "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
+ { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
};
static JavaVM* mJvm = nullptr;
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index c15b7ee4fe04..109e65c4a1d0 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -285,10 +285,6 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
jboolean useBpfStats) {
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- return -1;
- }
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
@@ -308,6 +304,11 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr
if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
return -1;
} else {
+ ScopedUtfChars path8(env, path);
+ if (path8.c_str() == NULL) {
+ ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
+ return -1;
+ }
if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
limitUid, path8.c_str()) < 0)
return -1;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 364393e1c649..1f958628374d 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -382,11 +382,10 @@ static int UnmountTree(const char* path) {
return 0;
}
-static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& pkg_sandbox_dir,
- std::string* error_msg) {
+static bool createPkgSandbox(uid_t uid, const std::string& package_name, std::string* error_msg) {
// Create /mnt/user/0/package/<package-name>
userid_t user_id = multiuser_get_user_id(uid);
- StringAppendF(&pkg_sandbox_dir, "/%d", user_id);
+ std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
*error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
return false;
@@ -396,7 +395,7 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p
*error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
return false;
}
- StringAppendF(&pkg_sandbox_dir, "/%s", package_name);
+ StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) {
*error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
return false;
@@ -404,10 +403,51 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p
return true;
}
+static bool mountPkgSpecificDir(const std::string& mntSourceRoot,
+ const std::string& mntTargetRoot, const std::string& packageName,
+ const char* dirName, std::string* error_msg) {
+ std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
+ mntSourceRoot.c_str(), dirName, packageName.c_str());
+ std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
+ mntTargetRoot.c_str(), dirName, packageName.c_str());
+ if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(),
+ nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
+ *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s",
+ mntSourceDir.c_str(), mntTargetDir.c_str(), strerror(errno));
+ return false;
+ }
+ if (TEMP_FAILURE_RETRY(mount(nullptr, mntTargetDir.c_str(),
+ nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) {
+ *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", mntTargetDir.c_str());
+ return false;
+ }
+ return true;
+}
+
+static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& volumeLabels, userid_t userId, std::string* error_msg) {
+ for (auto& label : volumeLabels) {
+ std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
+ std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
+ if (label == "emulated") {
+ StringAppendF(&mntSource, "/%d", userId);
+ StringAppendF(&mntTarget, "/%d", userId);
+ }
+ for (auto& package : packageNames) {
+ mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg);
+ mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg);
+ mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+ }
+ }
+ return true;
+}
+
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
- bool force_mount_namespace, std::string* error_msg, const char* package_name) {
+ bool force_mount_namespace, std::string* error_msg, const std::string& package_name,
+ const std::vector<std::string>& packages_for_uid,
+ const std::vector<std::string>& visible_vol_ids) {
// See storage config details at http://source.android.com/tech/storage/
String8 storageSource;
@@ -459,12 +499,25 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
return false;
}
} else {
- if (package_name == nullptr) {
+ if (package_name.empty()) {
return true;
}
- std::string pkgSandboxDir("/mnt/user");
- if (!createPkgSandbox(uid, package_name, pkgSandboxDir, error_msg)) {
- return false;
+ userid_t user_id = multiuser_get_user_id(uid);
+ std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s",
+ user_id, package_name.c_str());
+ struct stat sb;
+ bool sandboxAlreadyCreated = true;
+ if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) {
+ if (errno == ENOENT) {
+ ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str());
+ sandboxAlreadyCreated = false;
+ if (!createPkgSandbox(uid, package_name, error_msg)) {
+ return false;
+ }
+ } else {
+ ALOGE("Failed to lstat %s", pkgSandboxDir.c_str());
+ return false;
+ }
}
if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",
nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
@@ -472,6 +525,15 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
pkgSandboxDir.c_str(), strerror(errno));
return false;
}
+ // If the sandbox was already created by vold, only then set up the bind mounts for
+ // pkg specific directories. Otherwise, leave as is and bind mounts will be taken
+ // care of by vold later.
+ if (sandboxAlreadyCreated) {
+ if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
+ user_id, error_msg)) {
+ return false;
+ }
+ }
}
} else {
if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
@@ -611,7 +673,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
jlong permittedCapabilities, jlong effectiveCapabilities,
jint mount_external, jstring java_se_info, jstring java_se_name,
bool is_system_server, bool is_child_zygote, jstring instructionSet,
- jstring dataDir, jstring packageName) {
+ jstring dataDir, jstring packageName, jobjectArray packagesForUid,
+ jobjectArray visibleVolIds) {
std::string error_msg;
auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
@@ -661,17 +724,33 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
ALOGW("Native bridge will not be used because dataDir == NULL.");
}
- ScopedUtfChars* package_name = nullptr;
- const char* package_name_c_str = nullptr;
+ std::string package_name_str("");
if (packageName != nullptr) {
- package_name = new ScopedUtfChars(env, packageName);
- package_name_c_str = package_name->c_str();
+ ScopedUtfChars package(env, packageName);
+ package_name_str = package.c_str();
} else if (is_system_server) {
- package_name_c_str = "android";
+ package_name_str = "android";
+ }
+ std::vector<std::string> packages_for_uid;
+ if (packagesForUid != nullptr) {
+ jsize count = env->GetArrayLength(packagesForUid);
+ for (jsize i = 0; i < count; ++i) {
+ jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i);
+ ScopedUtfChars package(env, package_for_uid);
+ packages_for_uid.push_back(package.c_str());
+ }
+ }
+ std::vector<std::string> visible_vol_ids;
+ if (visibleVolIds != nullptr) {
+ jsize count = env->GetArrayLength(visibleVolIds);
+ for (jsize i = 0; i < count; ++i) {
+ jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i);
+ ScopedUtfChars vol(env, visible_vol_id);
+ visible_vol_ids.push_back(vol.c_str());
+ }
}
bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
- package_name_c_str);
- delete package_name;
+ package_name_str, packages_for_uid, visible_vol_ids);
if (!success) {
ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
if (errno == ENOTCONN || errno == EROFS) {
@@ -936,7 +1015,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
- jstring instructionSet, jstring appDataDir, jstring packageName) {
+ jstring instructionSet, jstring appDataDir, jstring packageName,
+ jobjectArray packagesForUid, jobjectArray visibleVolIds) {
jlong capabilities = 0;
// Grant CAP_WAKE_ALARM to the Bluetooth process.
@@ -989,7 +1069,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
mount_external, se_info, se_name, false,
- is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName);
+ is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName,
+ packagesForUid, visibleVolIds);
}
return pid;
}
@@ -1003,7 +1084,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
- false, NULL, NULL, nullptr);
+ false, NULL, NULL, nullptr, nullptr, nullptr);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -1084,7 +1165,7 @@ static const JNINativeMethod gMethods[] = {
{ "nativeSecurityInit", "()V",
(void *) com_android_internal_os_Zygote_nativeSecurityInit },
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index f9f725a130ed..14ed9e6eeadb 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -397,6 +397,9 @@ message GlobalSettingsProto {
// Ordered GPU debug layer list
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // App will load ANGLE instead of native GLES drivers.
+ optional SettingProto angle_enabled_app = 3;
}
optional Gpu gpu = 59;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ade0b111111d..9acb08b25db2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -941,7 +941,6 @@
Requesting this by itself is not sufficient to give you
location access.
<p>Protection level: dangerous
- @hide
-->
<permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
android:permissionGroup="android.permission-group.LOCATION"
@@ -4463,14 +4462,6 @@
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
- <service android:name="com.android.internal.backup.LocalTransportService"
- android:permission="android.permission.CONFIRM_FULL_BACKUP"
- android:exported="false">
- <intent-filter>
- <action android:name="android.backup.TRANSPORT_HOST" />
- </intent-filter>
- </service>
-
<service android:name="com.android.server.MountServiceIdler"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6ae25417e386..bebd4896e89b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -531,7 +531,7 @@
<skip />
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
<string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"चेहरे की पहचान की गई"</string>
- <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरा की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
+ <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"चेहरे की पहचान की गई, कृपया पुष्टि बटन दबाएं"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 41616df4209d..912db2001851 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -529,7 +529,7 @@
<string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Parmak izi kimlik doğrulaması yapıldı"</string>
<string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Yüz kimliği doğrulandı"</string>
- <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yüz kimliği doğrulandı, lütfen doğrula\'ya basın"</string>
+ <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Yüz kimliği doğrulandı, lütfen onayla\'ya basın"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Parmak izi donanımı kullanılamıyor."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Parmak izi depolanamıyor. Lütfen mevcut parmak izlerinden birini kaldırın."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Parmak izi için zaman aşımı oluştu. Tekrar deneyin."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9aebf6c4597f..0daf5a76562d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2113,8 +2113,8 @@
<!-- Type of the long press sensor. Empty if long press is not supported. -->
<string name="config_dozeLongPressSensorType" translatable="false"></string>
- <!-- Type of the reach sensor. Empty if reach is not supported. -->
- <string name="config_dozeReachSensorType" translatable="false"></string>
+ <!-- Type of sensor that wakes up the lock screen. Empty if not supported. -->
+ <string name="config_dozeWakeLockScreenSensorType" translatable="false"></string>
<!-- Type of the wake up sensor. Empty if not supported. -->
<string name="config_dozeWakeScreenSensorType" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cc99a4e4e640..cdaff18cf38a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,6 +2912,7 @@
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />
<public name="minimumUiTimeout" />
+ <public name="isLightTheme" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9f2256a6461a..72ae0d61654a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3279,7 +3279,7 @@
<java-symbol type="array" name="config_hideWhenDisabled_packageNames" />
<java-symbol type="string" name="config_dozeLongPressSensorType" />
- <java-symbol type="string" name="config_dozeReachSensorType" />
+ <java-symbol type="string" name="config_dozeWakeLockScreenSensorType" />
<java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
<java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index fee470dce24d..8f0e76bdc0c9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -447,6 +447,7 @@ public class SettingsBackupTest {
Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
+ Settings.Global.ANGLE_ENABLED_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index 890929374159..b0d29bd1d8f0 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -73,7 +73,7 @@ public class SettingsValidatorsTest {
@Test
public void testComponentNameValidator() {
assertTrue(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate(
- "android/com.android.internal.backup.LocalTransport"));
+ "com.android.localtransport/.LocalTransport"));
assertFalse(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate("rectangle"));
}
@@ -90,7 +90,7 @@ public class SettingsValidatorsTest {
@Test
public void testNullableComponentNameValidator_onValidComponentName_returnsTrue() {
assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
- "android/com.android.internal.backup.LocalTransport"));
+ "com.android.localtransport/.LocalTransport"));
}
@Test
@@ -185,7 +185,7 @@ public class SettingsValidatorsTest {
@Test
public void testComponentNameListValidator() {
Validator v = new SettingsValidators.ComponentNameListValidator(",");
- assertTrue(v.validate("android/com.android.internal.backup.LocalTransport,"
+ assertTrue(v.validate("com.android.localtransport/.LocalTransport,"
+ "com.google.android.gms/.backup.migrate.service.D2dTransport"));
assertFalse(v.validate("com.google.5android,android"));
}
@@ -200,7 +200,7 @@ public class SettingsValidatorsTest {
@Test
public void testPackageNameListValidator() {
Validator v = new SettingsValidators.PackageNameListValidator(",");
- assertTrue(v.validate("com.android.internal.backup.LocalTransport,com.google.android.gms"));
+ assertTrue(v.validate("com.android.localtransport.LocalTransport,com.google.android.gms"));
assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android"));
}
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index ae6a7f6d6808..b0d2de17527d 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -28,7 +28,7 @@
<!-- Whitelist of what components are permitted as backup data transports. The
'service' attribute here is a flattened ComponentName string. -->
<backup-transport-whitelisted-service
- service="android/com.android.internal.backup.LocalTransportService" />
+ service="com.android.localtransport/.LocalTransportService" />
<!-- Whitelist of bundled applications which all handle URLs to their websites by default -->
<app-link package="com.android.carrierdefaultapp" />
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 492c236c014e..e6ac06011e23 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -34,7 +34,6 @@ import android.os.Build;
import android.provider.FontRequest;
import android.provider.FontsContract;
import android.text.FontConfig;
-import android.util.ArrayMap;
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.LruCache;
@@ -1112,13 +1111,6 @@ public class Typeface {
}
}
- // Following methods are left for layoutlib
- // TODO: Remove once layoutlib stop calling buildSystemFallback
- /** @hide */
- public static void buildSystemFallback(String xmlPath, String fontDir,
- ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
- }
-
static {
final HashMap<String, Typeface> systemFontMap = new HashMap<>();
initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 11dad2e0d731..494e5135d5bb 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -229,6 +229,7 @@ cc_defaults {
"ResourceCache.cpp",
"SkiaCanvas.cpp",
"Snapshot.cpp",
+ "TreeInfo.cpp",
"VectorDrawable.cpp",
"protos/graphicsstats.proto",
],
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 21fbbdca7ad0..0b9d82b105a3 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -61,18 +61,6 @@ DisplayInfo QueryDisplayInfo() {
return displayInfo;
}
-void QueryCompositionPreference(ui::Dataspace* dataSpace,
- ui::PixelFormat* pixelFormat) {
- if (Properties::isolatedProcess) {
- *dataSpace = ui::Dataspace::V0_SRGB;
- *pixelFormat = ui::PixelFormat::RGBA_8888;
- }
-
- status_t status =
- SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat);
- LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
-}
-
DeviceInfo::DeviceInfo() {
#if HWUI_NULL_GPU
mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
@@ -80,7 +68,6 @@ DeviceInfo::DeviceInfo() {
mMaxTextureSize = -1;
#endif
mDisplayInfo = QueryDisplayInfo();
- QueryCompositionPreference(&mTargetDataSpace, &mTargetPixelFormat);
}
int DeviceInfo::maxTextureSize() const {
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 1d7477416077..595621573e6e 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -17,7 +17,6 @@
#define DEVICEINFO_H
#include <ui/DisplayInfo.h>
-#include <ui/GraphicTypes.h>
#include "utils/Macros.h"
@@ -37,9 +36,6 @@ public:
// this value is only valid after the GPU has been initialized and there is a valid graphics
// context or if you are using the HWUI_NULL_GPU
int maxTextureSize() const;
-
- ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; }
- ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; }
const DisplayInfo& displayInfo() const { return mDisplayInfo; }
private:
@@ -50,10 +46,6 @@ private:
int mMaxTextureSize;
DisplayInfo mDisplayInfo;
-
- // TODO(lpy) Replace below with android_ prefix types.
- ui::Dataspace mTargetDataSpace;
- ui::PixelFormat mTargetPixelFormat;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 17bec1934490..a699e2f7195b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,6 +61,7 @@ bool Properties::filterOutTestOverhead = false;
bool Properties::disableVsync = false;
bool Properties::skpCaptureEnabled = false;
bool Properties::forceDarkMode = false;
+bool Properties::enableForceDarkSupport = false;
bool Properties::enableRTAnimations = true;
bool Properties::runningInEmulator = false;
@@ -149,6 +150,9 @@ bool Properties::load() {
forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false);
+ // TODO: make this on by default
+ enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, false);
+
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
(prevDebugStencilClip != debugStencilClip);
}
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index ea017a72cd74..542bc71f7c72 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -192,6 +192,8 @@ enum DebugLevel {
#define PROPERTY_FORCE_DARK "debug.hwui.force_dark"
+#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
+
///////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////
@@ -266,6 +268,7 @@ public:
static bool skpCaptureEnabled;
static bool forceDarkMode;
+ static bool enableForceDarkSupport;
// For experimentation b/68769804
ANDROID_API static bool enableRTAnimations;
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
new file mode 100644
index 000000000000..808a12a311e2
--- /dev/null
+++ b/libs/hwui/TreeInfo.cpp
@@ -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.
+ */
+
+#include "TreeInfo.h"
+
+#include "renderthread/CanvasContext.h"
+
+namespace android::uirenderer {
+
+TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
+ : mode(mode)
+ , prepareTextures(mode == MODE_FULL)
+ , canvasContext(canvasContext)
+ , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index caa5762d174a..a0d960527ca6 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,8 +16,8 @@
#pragma once
-#include "utils/Macros.h"
#include "Properties.h"
+#include "utils/Macros.h"
#include <utils/Timers.h>
@@ -40,7 +40,7 @@ public:
virtual void onError(const std::string& message) = 0;
protected:
- virtual ~ErrorHandler() {}
+ virtual ~ErrorHandler() = default;
};
class TreeObserver {
@@ -52,7 +52,7 @@ public:
virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
protected:
- virtual ~TreeObserver() {}
+ virtual ~TreeObserver() = default;
};
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
@@ -71,8 +71,7 @@ public:
MODE_RT_ONLY,
};
- TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
- : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
+ TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext);
TraversalMode mode;
// TODO: Remove this? Currently this is used to signal to stop preparing
@@ -94,7 +93,7 @@ public:
bool updateWindowPositions = false;
- int disableForceDark = Properties::forceDarkMode ? 0 : 1;
+ int disableForceDark;
struct Out {
bool hasFunctors = false;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index e8bf4922cd46..d401b385075e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -167,6 +167,12 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
mEglSurface = mEglManager.createSurface(surface, colorMode);
}
+ if (colorMode == ColorMode::SRGB) {
+ mSurfaceColorType = SkColorType::kN32_SkColorType;
+ } else if (colorMode == ColorMode::WideColorGamut) {
+ mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
+ }
+
if (mEglSurface != EGL_NO_SURFACE) {
const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
@@ -184,14 +190,6 @@ bool SkiaOpenGLPipeline::isContextReady() {
return CC_LIKELY(mEglManager.hasEglContext());
}
-SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const {
- return mEglManager.getSurfaceColorType();
-}
-
-sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() {
- return mEglManager.getSurfaceColorSpace();
-}
-
void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
if (thread.eglManager().hasEglContext()) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 086a76088a75..4ab3541d447b 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -47,8 +47,6 @@ public:
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
- SkColorType getSurfaceColorType() const override;
- sk_sp<SkColorSpace> getSurfaceColorSpace() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index ee9158c5ffc1..42a411a6808c 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -48,6 +48,9 @@ public:
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
+ SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+ sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
+
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
@@ -106,6 +109,8 @@ protected:
void dumpResourceCacheUsage() const;
renderthread::RenderThread& mRenderThread;
+ SkColorType mSurfaceColorType;
+ sk_sp<SkColorSpace> mSurfaceColorSpace;
private:
void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 4ef30fc6bebc..a2d811993f2f 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -137,14 +137,6 @@ bool SkiaVulkanPipeline::isContextReady() {
return CC_LIKELY(mVkManager.hasVkContext());
}
-SkColorType SkiaVulkanPipeline::getSurfaceColorType() const {
- return mVkManager.getSurfaceColorType();
-}
-
-sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() {
- return mVkManager.getSurfaceColorSpace();
-}
-
void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
VkFunctorDrawable::vkInvokeFunctor(functor);
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 6e723a8373e1..14c0d69dba33 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -43,8 +43,6 @@ public:
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
- SkColorType getSurfaceColorType() const override;
- sk_sp<SkColorSpace> getSurfaceColorSpace() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c8c394a72541..92a749f3da33 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -144,8 +144,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
mNativeSurface = std::move(surface);
- // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode.
- ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy;
+ ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
mFrameNumber = -1;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2315cb9c73f9..2307ee4801d3 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -182,6 +182,23 @@ public:
mFrameCompleteCallbacks.push_back(std::move(func));
}
+ void setForceDark(bool enable) {
+ mUseForceDark = enable;
+ }
+
+ bool useForceDark() {
+ // The force-dark override has the highest priority, followed by the disable setting
+ // for the feature as a whole, followed last by whether or not this context has had
+ // force dark set (typically automatically done via UIMode)
+ if (Properties::forceDarkMode) {
+ return true;
+ }
+ if (!Properties::enableForceDarkSupport) {
+ return false;
+ }
+ return mUseForceDark;
+ }
+
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -228,6 +245,7 @@ private:
bool mOpaque;
bool mWideColorGamut = false;
+ bool mUseForceDark = false;
LightInfo mLightInfo;
LightGeometry mLightGeometry = {{0, 0, 0}, 0};
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 0cb23e532064..d4ffddde8def 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -126,17 +126,6 @@ void EglManager::initialize() {
createContext();
createPBufferSurface();
makeCurrent(mPBufferSurface, nullptr, /* force */ true);
-
- mSurfaceColorGamut = DataSpaceToColorGamut(
- static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
-
- LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut &&
- !EglExtensions.displayP3, "EGL doesn't support Display P3.");
-
- mSurfaceColorType = PixelFormatToColorType(
- static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat()));
- mSurfaceColorSpace = DataSpaceToColorSpace(
- static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
}
void EglManager::initExtensions() {
@@ -309,21 +298,13 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode color
if (wideColorGamut) {
attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
} else {
- if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
- attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
- } else {
- attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
- }
+ attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
}
#else
if (wideColorGamut) {
attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
} else {
- if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
- attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
- } else {
- attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
- }
+ attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
}
#endif
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index e97228cd0a39..55c81d42d8a0 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -78,9 +78,6 @@ public:
// Depending on installed extensions, the result is either Android native fence or EGL fence.
status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
- SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
- sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; }
-
private:
void initExtensions();
@@ -95,9 +92,6 @@ private:
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;
- SkColorSpace::Gamut mSurfaceColorGamut;
- SkColorType mSurfaceColorType;
- sk_sp<SkColorSpace> mSurfaceColorSpace;
enum class SwapBehavior {
Discard,
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 0297c9c141ff..4972554c65cc 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -43,15 +43,8 @@ namespace renderthread {
enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
enum class ColorMode {
- // Legacy means HWUI will produce buffer with whatever platform prefers
- // HWUI to produce, however, HWUI doesn't accurately convert color from
- // source color space to destination color space, instead HWUI will take
- // the pixel value directly and interpret it destination color space.
- Legacy,
- // DisplayColorGamut means HWUI will produce buffer with whatever platform
- // prefers HWUI to produce and accurately convert color from source color
- // space to destination color space.
- DisplayColorGamut,
+ // SRGB means HWUI will produce buffer in SRGB color space.
+ SRGB,
// WideColorGamut means HWUI would support rendering scRGB non-linear into
// a signed buffer with enough range to support the wide color gamut of the
// display.
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6106e24c093b..54219b5a1489 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -298,6 +298,12 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr)
});
}
+void RenderProxy::setForceDark(bool enable) {
+ mRenderThread.queue().post([this, enable]() {
+ mContext->setForceDark(enable);
+ });
+}
+
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d22f56ef38fd..d29fcc49d7a6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -119,7 +119,7 @@ public:
ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
- ANDROID_API long getDroppedFrameReportCount();
+ ANDROID_API void setForceDark(bool enable);
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
int bottom, SkBitmap* bitmap);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index e54eb6a0c5f1..7c59b6d340d2 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -120,10 +120,6 @@ public:
// Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
status_t createReleaseFence(sp<Fence>& nativeFence);
- // TODO(b/115636873): Handle composition preference.
- SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; }
- sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); }
-
private:
friend class RenderThread;
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 680fcb3a732b..cdf31da37074 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -386,7 +386,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
EXPECT_FALSE(pipeline->isSurfaceReady());
- EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy));
+ EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB));
EXPECT_TRUE(pipeline->isSurfaceReady());
renderThread.destroyGlContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 9f71e91629fb..3fb6a31a7d97 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -57,21 +57,6 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
return false;
}
-SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) {
- switch (pixelFormat) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- return SkColorType::kN32_SkColorType;
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- return SkColorType::kRGBA_F16_SkColorType;
- case HAL_PIXEL_FORMAT_RGBA_1010102:
- return SkColorType::kRGBA_1010102_SkColorType;
- default:
- ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat);
- return SkColorType::kN32_SkColorType;
- }
-}
-
android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
switch (colorType) {
case kRGBA_8888_SkColorType:
@@ -92,30 +77,6 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
}
}
-SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) {
- switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- return SkColorSpace::kSRGB_Gamut;
- case HAL_DATASPACE_STANDARD_BT2020:
- return SkColorSpace::kRec2020_Gamut;
- case HAL_DATASPACE_STANDARD_DCI_P3:
- return SkColorSpace::kDCIP3_D65_Gamut;
- case HAL_DATASPACE_STANDARD_ADOBE_RGB:
- return SkColorSpace::kAdobeRGB_Gamut;
- case HAL_DATASPACE_STANDARD_UNSPECIFIED:
- case HAL_DATASPACE_STANDARD_BT601_625:
- case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
- case HAL_DATASPACE_STANDARD_BT601_525:
- case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
- case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
- case HAL_DATASPACE_STANDARD_BT470M:
- case HAL_DATASPACE_STANDARD_FILM:
- default:
- ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace);
- return SkColorSpace::kSRGB_Gamut;
- }
-}
-
sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
SkColorSpace::Gamut gamut;
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index e935a0d5ec8b..4daccda78e23 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -115,12 +115,8 @@ static constexpr float EOCF(float srgb) {
// returns true for sRGB, gamma 2.2 and Display P3 for instance
bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
-SkColorType PixelFormatToColorType(android_pixel_format pixelFormat);
-
android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
-SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace);
-
sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
struct Lab {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ed4da22f69e7..340f27950638 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -336,7 +336,7 @@ import java.util.Vector;
*
* <table border="0" cellspacing="0" cellpadding="0">
* <tr><td>Method Name </p></td>
- * <td>Valid Sates </p></td>
+ * <td>Valid States </p></td>
* <td>Invalid States </p></td>
* <td>Comments </p></td></tr>
* <tr><td>attachAuxEffect </p></td>
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 7b7b800155cd..84d246f50ee3 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -271,7 +271,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
@Override
void process() {
- // TODO: switch to next data source and play
+ if (getState() == PLAYER_STATE_PLAYING) {
+ pause();
+ }
+ playNextDataSource();
}
});
}
diff --git a/packages/LocalTransport/Android.mk b/packages/LocalTransport/Android.mk
new file mode 100644
index 000000000000..3484b0f7a537
--- /dev/null
+++ b/packages/LocalTransport/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := LocalTransport
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/LocalTransport/AndroidManifest.xml b/packages/LocalTransport/AndroidManifest.xml
new file mode 100644
index 000000000000..196be1e998f3
--- /dev/null
+++ b/packages/LocalTransport/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2018 Google Inc.
+ *
+ * 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="com.android.localtransport"
+ android:sharedUserId="android.uid.system" >
+
+
+ <application android:allowBackup="false" >
+ <!-- This service does not need to be exported because it shares uid with the system server
+ which is the only client. -->
+ <service android:name=".LocalTransportService"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.backup.TRANSPORT_HOST" />
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/packages/LocalTransport/proguard.flags b/packages/LocalTransport/proguard.flags
new file mode 100644
index 000000000000..c1f51b892d40
--- /dev/null
+++ b/packages/LocalTransport/proguard.flags
@@ -0,0 +1,5 @@
+-keep class com.android.localTransport.LocalTransport
+-keep class com.android.localTransport.LocalTransportParameters
+-keep class com.android.localTransport.LocalTransportService
+
+
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index d0f02725b1a0..0bf8bc1051c2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -26,7 +26,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
@@ -56,7 +55,7 @@ public class LocalTransport extends BackupTransport {
private static final boolean DEBUG = false;
private static final String TRANSPORT_DIR_NAME
- = "com.android.internal.backup.LocalTransport";
+ = "com.android.localtransport.LocalTransport";
private static final String TRANSPORT_DESTINATION_STRING
= "Backing up to debug-only private cache";
@@ -75,10 +74,10 @@ public class LocalTransport extends BackupTransport {
private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
private Context mContext;
- private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
- private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
- private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
- private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
+ private File mDataDir;
+ private File mCurrentSetDir;
+ private File mCurrentSetIncrementalDir;
+ private File mCurrentSetFullDir;
private PackageInfo[] mRestorePackages = null;
private int mRestorePackage = -1; // Index into mRestorePackages
@@ -101,6 +100,11 @@ public class LocalTransport extends BackupTransport {
private final LocalTransportParameters mParameters;
private void makeDataDirs() {
+ mDataDir = mContext.getFilesDir();
+ mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
+ mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
+ mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
+
mCurrentSetDir.mkdirs();
mCurrentSetFullDir.mkdir();
mCurrentSetIncrementalDir.mkdir();
diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 2427d39fd65e..784be224f367 100644
--- a/core/java/com/android/internal/backup/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.util.KeyValueSettingObserver;
import android.content.ContentResolver;
diff --git a/core/java/com/android/internal/backup/LocalTransportService.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
index 69c48e2a48cf..ac4f418b68f6 100644
--- a/core/java/com/android/internal/backup/LocalTransportService.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.app.Service;
import android.content.Intent;
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index ee4c95445bff..89438e555b0d 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -15,6 +15,7 @@ android_library {
"SettingsLibHelpUtils",
"SettingsLibRestrictedLockUtils",
"SettingsLibAppPreference",
+ "SettingsLibSearchWidget",
],
// ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml
index a034d297bac8..2f576e62202e 100644
--- a/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="help_feedback_label" msgid="4550436169116444686">"Help en feedback"</string>
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hulp en feedback"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp
new file mode 100644
index 000000000000..7541ca456138
--- /dev/null
+++ b/packages/SettingsLib/SearchWidget/Android.bp
@@ -0,0 +1,8 @@
+android_library {
+ name: "SettingsLibSearchWidget",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SearchWidget/AndroidManifest.xml b/packages/SettingsLib/SearchWidget/AndroidManifest.xml
new file mode 100644
index 000000000000..b86544ec68c1
--- /dev/null
+++ b/packages/SettingsLib/SearchWidget/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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="com.android.settingslib.search">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
new file mode 100644
index 000000000000..7e65848de189
--- /dev/null
+++ b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.49,19l-5.73,-5.73C15.53,12.2 16,10.91 16,9.5C16,5.91 13.09,3 9.5,3S3,5.91 3,9.5C3,13.09 5.91,16 9.5,16c1.41,0 2.7,-0.47 3.77,-1.24L19,20.49L20.49,19zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/>
+</vector>
diff --git a/packages/SettingsLib/SearchWidget/res/values/strings.xml b/packages/SettingsLib/SearchWidget/res/values/strings.xml
new file mode 100644
index 000000000000..0b12810ffc38
--- /dev/null
+++ b/packages/SettingsLib/SearchWidget/res/values/strings.xml
@@ -0,0 +1,20 @@
+<!--
+ 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.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Text used as a search hint into the search box [CHAR_LIMIT=60]-->
+ <string name="search_menu">Search settings</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3859092ebfa8..bd9a6ec335b7 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -446,7 +446,6 @@
<string name="alarm_template_far" msgid="3779172822607461675">"अलार्म <xliff:g id="WHEN">%1$s</xliff:g> को बजेगा"</string>
<string name="zen_mode_duration_settings_title" msgid="229547412251222757">"अवधि"</string>
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
- <!-- no translation found for zen_mode_forever (2704305038191592967) -->
- <skip />
+ <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 332ced66ef77..508adbd2a121 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1116,4 +1116,6 @@
<!-- time label for event have that happened very recently [CHAR LIMIT=60] -->
<string name="time_unit_just_now">Just now</string>
- </resources>
+ <!-- The notice header of Third-party licenses. not translatable -->
+ <string name="notice_header" translatable="false"></string>
+</resources>
diff --git a/packages/SettingsLib/search/Android.mk b/packages/SettingsLib/search/Android.mk
index cb1989157db8..14f96269c54e 100644
--- a/packages/SettingsLib/search/Android.mk
+++ b/packages/SettingsLib/search/Android.mk
@@ -5,6 +5,9 @@ LOCAL_MODULE = SettingsLib-search
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/main/res
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 0c29f431ef3f..9653972414ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -30,6 +30,7 @@ import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -98,6 +99,7 @@ public class LocalBluetoothProfileManager {
private PbapClientProfile mPbapClientProfile;
private PbapServerProfile mPbapProfile;
private HearingAidProfile mHearingAidProfile;
+ private SapProfile mSapProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -210,6 +212,13 @@ public class LocalBluetoothProfileManager {
addProfile(mPbapClientProfile, PbapClientProfile.NAME,
BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
}
+ if (mSapProfile == null && supportedList.contains(BluetoothProfile.SAP)) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local SAP profile");
+ }
+ mSapProfile = new SapProfile(mContext, mDeviceManager, this);
+ addProfile(mSapProfile, SapProfile.NAME, BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
+ }
mEventManager.registerProfileIntentReceiver();
}
@@ -550,6 +559,11 @@ public class LocalBluetoothProfileManager {
removedProfiles.remove(mHearingAidProfile);
}
+ if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) {
+ profiles.add(mSapProfile);
+ removedProfiles.remove(mSapProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 9a6f104fadd5..b4acc4810faf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -36,12 +36,10 @@ import java.util.List;
*/
final class SapProfile implements LocalBluetoothProfile {
private static final String TAG = "SapProfile";
- private static boolean V = true;
private BluetoothSap mService;
private boolean mIsProfileReady;
- private final LocalBluetoothAdapter mLocalAdapter;
private final CachedBluetoothDeviceManager mDeviceManager;
private final LocalBluetoothProfileManager mProfileManager;
@@ -59,7 +57,7 @@ final class SapProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothSap) proxy;
// We just bound to the service, so refresh the UI for any connected SAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,7 +79,7 @@ final class SapProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
@@ -96,13 +94,11 @@ final class SapProfile implements LocalBluetoothProfile {
return BluetoothProfile.SAP;
}
- SapProfile(Context context, LocalBluetoothAdapter adapter,
- CachedBluetoothDeviceManager deviceManager,
+ SapProfile(Context context, CachedBluetoothDeviceManager deviceManager,
LocalBluetoothProfileManager profileManager) {
- mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- mLocalAdapter.getProfileProxy(context, new SapServiceListener(),
+ BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new SapServiceListener(),
BluetoothProfile.SAP);
}
@@ -115,50 +111,47 @@ final class SapProfile implements LocalBluetoothProfile {
}
public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> sinks = mService.getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
+ if (mService == null) {
+ return false;
}
return mService.connect(device);
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- return mService.disconnect(device);
- } else {
+ if (mService == null) {
return false;
}
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
}
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
-
- return !deviceList.isEmpty() && deviceList.get(0).equals(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -169,7 +162,9 @@ final class SapProfile implements LocalBluetoothProfile {
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -207,11 +202,11 @@ final class SapProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP,
- mService);
+ mService);
mService = null;
}catch (Throwable t) {
Log.w(TAG, "Error cleaning up SAP proxy", t);
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
index 42306f6d46d0..9db4a35c1d78 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
@@ -46,7 +46,7 @@ import java.util.zip.GZIPInputStream;
* TODO: Remove duplicate codes once backward support ends.
*/
class LicenseHtmlGeneratorFromXml {
- private static final String TAG = "LicenseHtmlGeneratorFromXml";
+ private static final String TAG = "LicenseGeneratorFromXml";
private static final String TAG_ROOT = "licenses";
private static final String TAG_FILE_NAME = "file-name";
@@ -107,12 +107,13 @@ class LicenseHtmlGeneratorFromXml {
mXmlFiles = xmlFiles;
}
- public static boolean generateHtml(List<File> xmlFiles, File outputFile) {
+ public static boolean generateHtml(List<File> xmlFiles, File outputFile,
+ String noticeHeader) {
LicenseHtmlGeneratorFromXml genertor = new LicenseHtmlGeneratorFromXml(xmlFiles);
- return genertor.generateHtml(outputFile);
+ return genertor.generateHtml(outputFile, noticeHeader);
}
- private boolean generateHtml(File outputFile) {
+ private boolean generateHtml(File outputFile, String noticeHeader) {
for (File xmlFile : mXmlFiles) {
parse(xmlFile);
}
@@ -125,7 +126,8 @@ class LicenseHtmlGeneratorFromXml {
try {
writer = new PrintWriter(outputFile);
- generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer);
+ generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer,
+ noticeHeader);
writer.flush();
writer.close();
@@ -239,13 +241,18 @@ class LicenseHtmlGeneratorFromXml {
@VisibleForTesting
static void generateHtml(Map<String, String> fileNameToContentIdMap,
- Map<String, String> contentIdToFileContentMap, PrintWriter writer) {
+ Map<String, String> contentIdToFileContentMap, PrintWriter writer,
+ String noticeHeader) {
List<String> fileNameList = new ArrayList();
fileNameList.addAll(fileNameToContentIdMap.keySet());
Collections.sort(fileNameList);
writer.println(HTML_HEAD_STRING);
+ if (!TextUtils.isEmpty(noticeHeader)) {
+ writer.println(noticeHeader);
+ }
+
int count = 0;
Map<String, Integer> contentIdToOrderMap = new HashMap();
List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList();
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
index 393006940740..78e807cf1a1c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java
@@ -60,7 +60,7 @@ public class LicenseHtmlLoader extends AsyncLoader<File> {
File cachedHtmlFile = getCachedHtmlFile(mContext);
if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile)
- || generateHtmlFile(xmlFiles, cachedHtmlFile)) {
+ || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) {
return cachedHtmlFile;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
index 360c19c2b795..ca6248505dc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
@@ -19,6 +19,7 @@ package com.android.settingslib.license;
import android.content.Context;
import android.util.Log;
+import com.android.settingslib.R;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.io.File;
@@ -65,7 +66,7 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> {
File cachedHtmlFile = getCachedHtmlFile(mContext);
if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile)
- || generateHtmlFile(xmlFiles, cachedHtmlFile)) {
+ || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) {
return cachedHtmlFile;
}
@@ -101,7 +102,8 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> {
return outdated;
}
- static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) {
- return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile);
+ static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) {
+ return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile,
+ context.getString(R.string.notice_header));
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
index 74bd97f40ff7..e9c523881373 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java
@@ -37,7 +37,8 @@ import com.android.settingslib.AppItem;
/**
* Loader for historical chart data for both network and UID details.
*
- * Deprecated in favor of {@link NetworkCycleDataLoader}
+ * Deprecated in favor of {@link NetworkCycleChartDataLoader} and
+ * {@link NetworkCycleDataForUidLoader}
*
* @deprecated
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java
new file mode 100644
index 000000000000..9b3ff8b2e165
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartData.java
@@ -0,0 +1,56 @@
+/*
+ * 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.settingslib.net;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Usage data in a billing cycle with bucketized data for plotting the usage chart.
+ */
+public class NetworkCycleChartData extends NetworkCycleData {
+ public static final long BUCKET_DURATION_MS = TimeUnit.DAYS.toMillis(1);
+
+ private List<NetworkCycleData> mUsageBuckets;
+
+ private NetworkCycleChartData() {
+ }
+
+ public List<NetworkCycleData> getUsageBuckets() {
+ return mUsageBuckets;
+ }
+
+ public static class Builder extends NetworkCycleData.Builder {
+ private NetworkCycleChartData mObject = new NetworkCycleChartData();
+
+ public Builder setUsageBuckets(List<NetworkCycleData> buckets) {
+ getObject().mUsageBuckets = buckets;
+ return this;
+ }
+
+ @Override
+ protected NetworkCycleChartData getObject() {
+ return mObject;
+ }
+
+ @Override
+ public NetworkCycleChartData build() {
+ return getObject();
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
new file mode 100644
index 000000000000..7ae3398d42ea
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
@@ -0,0 +1,106 @@
+/*
+ * 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.settingslib.net;
+
+import android.app.usage.NetworkStats;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Loader for network data usage history. It returns a list of usage data per billing cycle with
+ * bucketized usages.
+ */
+public class NetworkCycleChartDataLoader
+ extends NetworkCycleDataLoader<List<NetworkCycleChartData>> {
+
+ private static final String TAG = "NetworkCycleChartLoader";
+
+ private final List<NetworkCycleChartData> mData;
+
+ private NetworkCycleChartDataLoader(Builder builder) {
+ super(builder);
+ mData = new ArrayList<NetworkCycleChartData>();
+ }
+
+ @Override
+ void recordUsage(long start, long end) {
+ try {
+ final NetworkStats stats = mNetworkStatsManager.querySummary(
+ mNetworkType, mSubId, start, end);
+ final long total = getTotalUsage(stats);
+ if (total > 0L) {
+ final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
+ builder.setUsageBuckets(getUsageBuckets(start, end))
+ .setStartTime(start)
+ .setEndTime(end)
+ .setTotalUsage(total);
+ mData.add(builder.build());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ }
+ }
+
+ @Override
+ List<NetworkCycleChartData> getCycleUsage() {
+ return mData;
+ }
+
+ public static Builder<?> builder(Context context) {
+ return new Builder<NetworkCycleChartDataLoader>(context) {
+ @Override
+ public NetworkCycleChartDataLoader build() {
+ return new NetworkCycleChartDataLoader(this);
+ }
+ };
+ }
+
+ private List<NetworkCycleData> getUsageBuckets(long start, long end) {
+ final List<NetworkCycleData> data = new ArrayList<>();
+ long bucketStart = start;
+ long bucketEnd = start + NetworkCycleChartData.BUCKET_DURATION_MS;
+ while (bucketEnd <= end) {
+ long usage = 0L;
+ try {
+ final NetworkStats stats = mNetworkStatsManager.querySummary(
+ mNetworkType, mSubId, bucketStart, bucketEnd);
+ usage = getTotalUsage(stats);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ }
+ data.add(new NetworkCycleData.Builder()
+ .setStartTime(bucketStart).setEndTime(bucketEnd).setTotalUsage(usage).build());
+ bucketStart = bucketEnd;
+ bucketEnd += NetworkCycleChartData.BUCKET_DURATION_MS;
+ }
+ return data;
+ }
+
+ public static abstract class Builder<T extends NetworkCycleChartDataLoader>
+ extends NetworkCycleDataLoader.Builder<T> {
+
+ public Builder(Context context) {
+ super(context);
+ }
+
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
index 2d8c0de42ba4..26c65a2c4a48 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleData.java
@@ -16,54 +16,55 @@
package com.android.settingslib.net;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
/**
- * Data structure representing usage data in a billing cycle.
+ * Base data structure representing usage data in a billing cycle.
*/
public class NetworkCycleData {
- public static final long BUCKET_DURATION_MS = TimeUnit.DAYS.toMillis(1);
- public long startTime;
- public long endTime;
- public long totalUsage;
- public List<NetworkCycleData> usageBuckets;
- private NetworkCycleData(Builder builder) {
- startTime = builder.mStart;
- endTime = builder.mEnd;
- totalUsage = builder.mTotalUsage;
- usageBuckets = builder.mUsageBuckets;
+ private long mStartTime;
+ private long mEndTime;
+ private long mTotalUsage;
+
+ protected NetworkCycleData() {
+ }
+
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ public long getEndTime() {
+ return mEndTime;
+ }
+
+ public long getTotalUsage() {
+ return mTotalUsage;
}
public static class Builder {
- private long mStart;
- private long mEnd;
- private long mTotalUsage;
- private List<NetworkCycleData> mUsageBuckets;
+
+ private NetworkCycleData mObject = new NetworkCycleData();
public Builder setStartTime(long start) {
- mStart = start;
+ getObject().mStartTime = start;
return this;
}
public Builder setEndTime(long end) {
- mEnd = end;
+ getObject().mEndTime = end;
return this;
}
public Builder setTotalUsage(long total) {
- mTotalUsage = total;
+ getObject().mTotalUsage = total;
return this;
}
- public Builder setUsageBuckets(List<NetworkCycleData> buckets) {
- mUsageBuckets = buckets;
- return this;
+ protected NetworkCycleData getObject() {
+ return mObject;
}
public NetworkCycleData build() {
- return new NetworkCycleData(this);
+ return getObject();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java
new file mode 100644
index 000000000000..9d13717bbbcc
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUid.java
@@ -0,0 +1,65 @@
+/*
+ * 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.settingslib.net;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Usage data in a billing cycle for a specific Uid.
+ */
+public class NetworkCycleDataForUid extends NetworkCycleData {
+
+ private long mBackgroudUsage;
+ private long mForegroudUsage;
+
+ private NetworkCycleDataForUid() {
+ }
+
+ public long getBackgroudUsage() {
+ return mBackgroudUsage;
+ }
+
+ public long getForegroudUsage() {
+ return mForegroudUsage;
+ }
+
+ public static class Builder extends NetworkCycleData.Builder {
+
+ private NetworkCycleDataForUid mObject = new NetworkCycleDataForUid();
+
+ public Builder setBackgroundUsage(long backgroundUsage) {
+ getObject().mBackgroudUsage = backgroundUsage;
+ return this;
+ }
+
+ public Builder setForegroundUsage(long foregroundUsage) {
+ getObject().mForegroudUsage = foregroundUsage;
+ return this;
+ }
+
+ @Override
+ public NetworkCycleDataForUid getObject() {
+ return mObject;
+ }
+
+ @Override
+ public NetworkCycleDataForUid build() {
+ return getObject();
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java
new file mode 100644
index 000000000000..95efb4cea491
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java
@@ -0,0 +1,102 @@
+/*
+ * 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.settingslib.net;
+
+import static android.app.usage.NetworkStats.Bucket.STATE_FOREGROUND;
+import static android.net.NetworkStats.TAG_NONE;
+
+import android.app.usage.NetworkStats;
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Loader for network data usage history. It returns a list of usage data per billing cycle for a
+ * specific Uid.
+ */
+public class NetworkCycleDataForUidLoader extends
+ NetworkCycleDataLoader<List<NetworkCycleDataForUid>> {
+ private static final String TAG = "NetworkDataForUidLoader";
+
+ private final List<NetworkCycleDataForUid> mData;
+ private final int mUid;
+
+ private NetworkCycleDataForUidLoader(Builder builder) {
+ super(builder);
+ mUid = builder.mUid;
+ mData = new ArrayList<NetworkCycleDataForUid>();
+ }
+
+ @Override
+ void recordUsage(long start, long end) {
+ try {
+ final NetworkStats stats = mNetworkStatsManager.queryDetailsForUid(
+ mNetworkType, mSubId, start, end, mUid);
+ final long total = getTotalUsage(stats);
+ if (total > 0L) {
+ final long foreground = getForegroundUsage(start, end);
+ final NetworkCycleDataForUid.Builder builder = new NetworkCycleDataForUid.Builder();
+ builder.setBackgroundUsage(total - foreground)
+ .setForegroundUsage(foreground)
+ .setStartTime(start)
+ .setEndTime(end)
+ .setTotalUsage(total);
+ mData.add(builder.build());
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception querying network detail.", e);
+ }
+ }
+
+ @Override
+ List<NetworkCycleDataForUid> getCycleUsage() {
+ return mData;
+ }
+
+ public static Builder<?> builder(Context context) {
+ return new Builder<NetworkCycleDataForUidLoader>(context) {
+ @Override
+ public NetworkCycleDataForUidLoader build() {
+ return new NetworkCycleDataForUidLoader(this);
+ }
+ };
+ }
+
+ private long getForegroundUsage(long start, long end) {
+ final NetworkStats stats = mNetworkStatsManager.queryDetailsForUidTagState(
+ mNetworkType, mSubId, start, end, mUid, TAG_NONE, STATE_FOREGROUND);
+ return getTotalUsage(stats);
+ }
+
+ public static abstract class Builder<T extends NetworkCycleDataForUidLoader>
+ extends NetworkCycleDataLoader.Builder<T> {
+
+ private int mUid;
+
+ public Builder(Context context) {
+ super(context);
+ }
+
+ public Builder<T> setUid(int uid) {
+ mUid = uid;
+ return this;
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
index 80e13563d74b..cc936d2485c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -32,32 +32,28 @@ import android.net.TrafficStats;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.format.DateUtils;
-import android.util.Log;
import android.util.Pair;
import java.time.ZonedDateTime;
-import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
-import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.loader.content.AsyncTaskLoader;
/**
* Loader for network data usage history. It returns a list of usage data per billing cycle.
*/
-public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleData>> {
- private static final String TAG = "CycleDataSummaryLoader";
- private final NetworkStatsManager mNetworkStatsManager;
- private final String mSubId;
- private final int mNetworkType;
+public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
+ private static final String TAG = "NetworkCycleDataLoader";
+ protected final NetworkStatsManager mNetworkStatsManager;
+ protected final String mSubId;
+ protected final int mNetworkType;
private final NetworkPolicy mPolicy;
private final NetworkTemplate mNetworkTemplate;
@VisibleForTesting
final INetworkStatsService mNetworkStatsService;
- private NetworkCycleDataLoader(Builder builder) {
+ protected NetworkCycleDataLoader(Builder<?> builder) {
super(builder.mContext);
mPolicy = builder.mPolicy;
mSubId = builder.mSubId;
@@ -75,21 +71,25 @@ public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleDat
forceLoad();
}
- @Override
- public List<NetworkCycleData> loadInBackground() {
+ public D loadInBackground() {
if (mPolicy == null) {
- return loadFourWeeksData();
+ loadFourWeeksData();
+ } else {
+ loadPolicyData();
}
- final List<NetworkCycleData> data = new ArrayList<>();
- final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator = NetworkPolicyManager
- .cycleIterator(mPolicy);
+ return getCycleUsage();
+ }
+
+ @VisibleForTesting
+ void loadPolicyData() {
+ final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator =
+ NetworkPolicyManager.cycleIterator(mPolicy);
while (iterator.hasNext()) {
final Pair<ZonedDateTime, ZonedDateTime> cycle = iterator.next();
final long cycleStart = cycle.first.toInstant().toEpochMilli();
final long cycleEnd = cycle.second.toInstant().toEpochMilli();
- getUsage(cycleStart, cycleEnd, data);
+ recordUsage(cycleStart, cycleEnd);
}
- return data;
}
@Override
@@ -105,8 +105,7 @@ public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleDat
}
@VisibleForTesting
- List<NetworkCycleData> loadFourWeeksData() {
- final List<NetworkCycleData> data = new ArrayList<>();
+ void loadFourWeeksData() {
try {
final INetworkStatsSession networkSession = mNetworkStatsService.openSession();
final NetworkStatsHistory networkHistory = networkSession.getHistoryForNetwork(
@@ -117,7 +116,7 @@ public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleDat
long cycleEnd = historyEnd;
while (cycleEnd > historyStart) {
final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4);
- getUsage(cycleStart, cycleEnd, data);
+ recordUsage(cycleStart, cycleEnd);
cycleEnd = cycleStart;
}
@@ -125,29 +124,23 @@ public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleDat
} catch (RemoteException e) {
throw new RuntimeException(e);
}
- return data;
}
@VisibleForTesting
- void getUsage(long start, long end, @NonNull List<NetworkCycleData> data) {
- try {
- final NetworkStats stats = mNetworkStatsManager.querySummary(
- mNetworkType, mSubId, start, end);
- final long total = getTotalUsage(stats);
- if (total > 0L) {
- data.add(new NetworkCycleData.Builder()
- .setStartTime(start)
- .setEndTime(end)
- .setTotalUsage(total)
- .setUsageBuckets(getUsageBuckets(start, end))
- .build());
+ abstract void recordUsage(long start, long end);
+
+ abstract D getCycleUsage();
+
+ public static Builder<?> builder(Context context) {
+ return new Builder<NetworkCycleDataLoader>(context) {
+ @Override
+ public NetworkCycleDataLoader build() {
+ return null;
}
- } catch (RemoteException e) {
- Log.e(TAG, "Exception querying network detail.", e);
- }
+ };
}
- private long getTotalUsage(NetworkStats stats) {
+ protected long getTotalUsage(NetworkStats stats) {
long bytes = 0L;
if (stats != null) {
final NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -159,61 +152,38 @@ public class NetworkCycleDataLoader extends AsyncTaskLoader<List<NetworkCycleDat
return bytes;
}
- private List<NetworkCycleData> getUsageBuckets(long start, long end) {
- final List<NetworkCycleData> data = new ArrayList<>();
- long bucketStart = start;
- long bucketEnd = start + NetworkCycleData.BUCKET_DURATION_MS;
- while (bucketEnd <= end) {
- long usage = 0L;
- try {
- final NetworkStats stats = mNetworkStatsManager.querySummary(
- mNetworkType, mSubId, bucketStart, bucketEnd);
- usage = getTotalUsage(stats);
- } catch (RemoteException e) {
- Log.e(TAG, "Exception querying network detail.", e);
- }
- data.add(new NetworkCycleData.Builder()
- .setStartTime(bucketStart).setEndTime(bucketEnd).setTotalUsage(usage).build());
- bucketStart = bucketEnd;
- bucketEnd += NetworkCycleData.BUCKET_DURATION_MS;
- }
- return data;
- }
-
- public static class Builder {
+ public static abstract class Builder<T extends NetworkCycleDataLoader> {
private final Context mContext;
private NetworkPolicy mPolicy;
private String mSubId;
private int mNetworkType;
private NetworkTemplate mNetworkTemplate;
- public Builder(Context context) {
+ public Builder (Context context) {
mContext = context;
}
- public Builder setNetworkPolicy(NetworkPolicy policy) {
+ public Builder<T> setNetworkPolicy(NetworkPolicy policy) {
mPolicy = policy;
return this;
}
- public Builder setSubscriberId(String subId) {
+ public Builder<T> setSubscriberId(String subId) {
mSubId = subId;
return this;
}
- public Builder setNetworkType(int networkType) {
+ public Builder<T> setNetworkType(int networkType) {
mNetworkType = networkType;
return this;
}
- public Builder setNetworkTemplate(NetworkTemplate template) {
+ public Builder<T> setNetworkTemplate(NetworkTemplate template) {
mNetworkTemplate = template;
return this;
}
- public NetworkCycleDataLoader build() {
- return new NetworkCycleDataLoader(this);
- }
+ public abstract T build();
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
new file mode 100644
index 000000000000..9bb53ee6a343
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/SapProfileTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSap;
+import android.bluetooth.BluetoothProfile;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
+public class SapProfileTest {
+
+ @Mock
+ private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock
+ private LocalBluetoothProfileManager mProfileManager;
+ @Mock
+ private BluetoothSap mService;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ private BluetoothProfile.ServiceListener mServiceListener;
+ private SapProfile mProfile;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+ mProfile = new SapProfile(RuntimeEnvironment.application, mDeviceManager, mProfileManager);
+ mServiceListener = mShadowBluetoothAdapter.getServiceListener();
+ mServiceListener.onServiceConnected(BluetoothProfile.SAP, mService);
+ }
+
+ @Test
+ public void connect_shouldConnectBluetoothSap() {
+ mProfile.connect(mBluetoothDevice);
+ verify(mService).connect(mBluetoothDevice);
+ }
+
+ @Test
+ public void disconnect_shouldDisconnectBluetoothSap() {
+ mProfile.disconnect(mBluetoothDevice);
+ verify(mService).disconnect(mBluetoothDevice);
+ }
+
+ @Test
+ public void getConnectionStatus_shouldReturnConnectionState() {
+ when(mService.getConnectionState(mBluetoothDevice)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ assertThat(mProfile.getConnectionStatus(mBluetoothDevice)).
+ isEqualTo(BluetoothProfile.STATE_CONNECTED);
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 96b2a1433f53..b00476b24921 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -50,7 +50,7 @@ public class LicenseHtmlGeneratorFromXmlTest {
+ "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n"
+ "</licenses2>";
- private static final String EXPECTED_HTML_STRING =
+ private static final String HTML_HEAD_STRING =
"<html><head>\n"
+ "<style type=\"text/css\">\n"
+ "body { padding: 0; font-family: sans-serif; }\n"
@@ -63,8 +63,12 @@ public class LicenseHtmlGeneratorFromXmlTest {
+ "</head>"
+ "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n"
+ "<div class=\"toc\">\n"
- + "<ul>\n"
- + "<li><a href=\"#id0\">/file0</a></li>\n"
+ + "<ul>\n";
+
+ private static final String HTML_CUSTOM_HEADING = "Custom heading";
+
+ private static final String HTML_BODY_STRING =
+ "<li><a href=\"#id0\">/file0</a></li>\n"
+ "<li><a href=\"#id0\">/file1</a></li>\n"
+ "</ul>\n"
+ "</div><!-- table of contents -->\n"
@@ -81,6 +85,11 @@ public class LicenseHtmlGeneratorFromXmlTest {
+ "</td></tr><!-- same-license -->\n"
+ "</table></body></html>\n";
+ private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING;
+
+ private static final String EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING =
+ HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING;
+
@Test
public void testParseValidXmlStream() throws XmlPullParserException, IOException {
Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
@@ -117,7 +126,23 @@ public class LicenseHtmlGeneratorFromXmlTest {
StringWriter output = new StringWriter();
LicenseHtmlGeneratorFromXml.generateHtml(
- fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output));
+ fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), "");
assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING);
}
+
+ @Test
+ public void testGenerateHtmlWithCustomHeading() {
+ Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
+
+ fileNameToContentIdMap.put("/file0", "0");
+ fileNameToContentIdMap.put("/file1", "0");
+ contentIdToFileContentMap.put("0", "license content #0");
+
+ StringWriter output = new StringWriter();
+ LicenseHtmlGeneratorFromXml.generateHtml(
+ fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output),
+ HTML_CUSTOM_HEADING);
+ assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java
index 12a4e699fb76..c32cc99daf96 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java
@@ -142,7 +142,7 @@ public class LicenseHtmlLoaderCompatTest {
}
@Implementation
- static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) {
+ static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) {
return sGenerateHtmlFileSucceeded;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java
new file mode 100644
index 000000000000..3dc110d30e1e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleChartDataLoaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.settingslib.net;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.os.RemoteException;
+import android.text.format.DateUtils;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class NetworkCycleChartDataLoaderTest {
+
+ @Mock
+ private NetworkStatsManager mNetworkStatsManager;
+ @Mock
+ private Context mContext;
+
+ private NetworkCycleChartDataLoader mLoader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE))
+ .thenReturn(mNetworkStatsManager);
+ }
+
+ @Test
+ public void recordUsage_shouldQueryNetworkSummary() throws RemoteException {
+ final long end = System.currentTimeMillis();
+ final long start = end - (DateUtils.WEEK_IN_MILLIS * 4);
+ final int networkType = ConnectivityManager.TYPE_MOBILE;
+ final String subId = "TestSubscriber";
+ mLoader = NetworkCycleChartDataLoader.builder(mContext)
+ .setNetworkType(networkType).setSubscriberId(subId).build();
+
+ mLoader.recordUsage(start, end);
+
+ verify(mNetworkStatsManager).querySummary(networkType, subId, start, end);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java
new file mode 100644
index 000000000000..53fe45197236
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.settingslib.net;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.text.format.DateUtils;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class NetworkCycleDataForUidLoaderTest {
+
+ @Mock
+ private NetworkStatsManager mNetworkStatsManager;
+ @Mock
+ private Context mContext;
+
+ private NetworkCycleDataForUidLoader mLoader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NETWORK_STATS_SERVICE))
+ .thenReturn(mNetworkStatsManager);
+ }
+
+ @Test
+ public void recordUsage_shouldQueryNetworkDetailsForUid() {
+ final long end = System.currentTimeMillis();
+ final long start = end - (DateUtils.WEEK_IN_MILLIS * 4);
+ final int networkType = ConnectivityManager.TYPE_MOBILE;
+ final String subId = "TestSubscriber";
+ final int uid = 1;
+ mLoader = NetworkCycleDataForUidLoader.builder(mContext)
+ .setUid(uid).setNetworkType(networkType).setSubscriberId(subId).build();
+
+ mLoader.recordUsage(start, end);
+
+ verify(mNetworkStatsManager).queryDetailsForUid(networkType, subId, start, end, uid);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
index 4c4207b23cab..be7f1bbb280f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -16,13 +16,10 @@
package com.android.settingslib.net;
-import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -50,6 +47,7 @@ import org.robolectric.util.ReflectionHelpers;
import java.time.ZonedDateTime;
import java.util.Iterator;
+import java.util.List;
@RunWith(SettingsLibRobolectricTestRunner.class)
public class NetworkCycleDataLoaderTest {
@@ -64,8 +62,11 @@ public class NetworkCycleDataLoaderTest {
private Iterator<Range<ZonedDateTime>> mIterator;
@Mock
private INetworkStatsService mNetworkStatsService;
+ @Mock
+ private NetworkCycleDataLoader.Builder mBuilder;
+
- private NetworkCycleDataLoader mLoader;
+ private NetworkCycleDataTestLoader mLoader;
@Before
public void setUp() {
@@ -77,8 +78,8 @@ public class NetworkCycleDataLoaderTest {
@Test
public void loadInBackground_noNetworkPolicy_shouldLoad4WeeksData() {
- mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
- doReturn(null).when(mLoader).loadFourWeeksData();
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+ doNothing().when(mLoader).loadFourWeeksData();
mLoader.loadInBackground();
@@ -86,31 +87,45 @@ public class NetworkCycleDataLoaderTest {
}
@Test
- public void loadInBackground_shouldQueryNetworkSummary() throws RemoteException {
+ public void loadInBackground_hasNetworkPolicy_shouldLoadPolicyData() {
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+ ReflectionHelpers.setField(mLoader, "mPolicy", mPolicy);
+
+ mLoader.loadInBackground();
+
+ verify(mLoader).loadPolicyData();
+ }
+
+ @Test
+ public void loadPolicyData_shouldRecordUsageFromPolicyCycle() {
final int networkType = ConnectivityManager.TYPE_MOBILE;
final String subId = "TestSubscriber";
final ZonedDateTime now = ZonedDateTime.now();
final Range<ZonedDateTime> cycle = new Range<>(now, now);
+ final long nowInMs = now.toInstant().toEpochMilli();
// mock 1 cycle data.
// hasNext() will be called internally in next(), hence setting it to return true twice.
when(mIterator.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
when(mIterator.next()).thenReturn(cycle);
- mLoader = new NetworkCycleDataLoader.Builder(mContext)
- .setNetworkPolicy(mPolicy).setNetworkType(networkType).setSubscriberId(subId).build();
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+ ReflectionHelpers.setField(mLoader, "mPolicy", mPolicy);
+ ReflectionHelpers.setField(mLoader, "mNetworkType", networkType);
+ ReflectionHelpers.setField(mLoader, "mSubId", subId);
- mLoader.loadInBackground();
+ mLoader.loadPolicyData();
- verify(mNetworkStatsManager).querySummary(eq(networkType), eq(subId), anyLong(), anyLong());
+ verify(mLoader).recordUsage(nowInMs, nowInMs);
}
@Test
- public void loadFourWeeksData_shouldGetUsageForLast4Weeks() throws RemoteException {
- mLoader = spy(new NetworkCycleDataLoader.Builder(mContext).build());
+ public void loadFourWeeksData_shouldRecordUsageForLast4Weeks() throws RemoteException {
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
ReflectionHelpers.setField(mLoader, "mNetworkStatsService", mNetworkStatsService);
final INetworkStatsSession networkSession = mock(INetworkStatsSession.class);
when(mNetworkStatsService.openSession()).thenReturn(networkSession);
final NetworkStatsHistory networkHistory = mock(NetworkStatsHistory.class);
- when(networkSession.getHistoryForNetwork(nullable(NetworkTemplate.class), anyInt())).thenReturn(networkHistory);
+ when(networkSession.getHistoryForNetwork(nullable(NetworkTemplate.class), anyInt()))
+ .thenReturn(networkHistory);
final long now = System.currentTimeMillis();
final long fourWeeksAgo = now - (DateUtils.WEEK_IN_MILLIS * 4);
when(networkHistory.getStart()).thenReturn(fourWeeksAgo);
@@ -118,6 +133,23 @@ public class NetworkCycleDataLoaderTest {
mLoader.loadFourWeeksData();
- verify(mLoader).getUsage(eq(fourWeeksAgo), eq(now), any());
+ verify(mLoader).recordUsage(fourWeeksAgo, now);
+ }
+
+ public class NetworkCycleDataTestLoader extends NetworkCycleDataLoader<List<NetworkCycleData>> {
+
+ private NetworkCycleDataTestLoader(Context context) {
+ super(NetworkCycleDataLoader.builder(mContext));
+ mContext = context;
+ }
+
+ @Override
+ void recordUsage(long start, long end) {
+ }
+
+ @Override
+ List<NetworkCycleData> getCycleUsage() {
+ return null;
+ }
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java
deleted file mode 100644
index d8e73b7db322..000000000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.settingslib.testutils;
-
-import android.os.Bundle;
-import android.widget.LinearLayout;
-
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.fragment.app.FragmentManager;
-
-import org.robolectric.Robolectric;
-
-/**
- * Utilities for creating Fragments for testing.
- * <p>
- * TODO(b/111195449) - Duplicated from org.robolectric.shadows.support.v4.SupportFragmentTestUtil
- */
-@Deprecated
-public class FragmentTestUtils {
-
- public static void startFragment(Fragment fragment) {
- buildFragmentManager(FragmentUtilActivity.class)
- .beginTransaction().add(fragment, null).commit();
- }
-
- public static void startFragment(Fragment fragment,
- Class<? extends FragmentActivity> activityClass) {
- buildFragmentManager(activityClass)
- .beginTransaction().add(fragment, null).commit();
- }
-
- public static void startVisibleFragment(Fragment fragment) {
- buildFragmentManager(FragmentUtilActivity.class)
- .beginTransaction().add(1, fragment, null).commit();
- }
-
- public static void startVisibleFragment(Fragment fragment,
- Class<? extends FragmentActivity> activityClass, int containerViewId) {
- buildFragmentManager(activityClass)
- .beginTransaction().add(containerViewId, fragment, null).commit();
- }
-
- private static FragmentManager buildFragmentManager(
- Class<? extends FragmentActivity> activityClass) {
- FragmentActivity activity = Robolectric.setupActivity(activityClass);
- return activity.getSupportFragmentManager();
- }
-
- private static class FragmentUtilActivity extends FragmentActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- LinearLayout view = new LinearLayout(this);
- view.setId(1);
-
- setContentView(view);
- }
- }
-}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c53417b4e0f5..de86789053e9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -55,7 +55,7 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string>
+ <string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string>
<!-- Default value for whether or not to pulse the notification LED when there is a
pending notification -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bd21b8353136..c09b76394340 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -659,6 +659,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.GPU_DEBUG_LAYERS,
GlobalSettingsProto.Gpu.DEBUG_LAYERS);
+ dumpSetting(s, p,
+ Settings.Global.ANGLE_ENABLED_APP,
+ GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 63978ba60171..3d193db392a4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3285,8 +3285,8 @@ public class SettingsProvider extends ContentProvider {
if (currentVersion == 133) {
// Version 133: Add default end button behavior
final SettingsState systemSettings = getSystemSettingsLocked(userId);
- if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR) ==
- null) {
+ if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR)
+ .isNull()) {
String defaultEndButtonBehavior = Integer.toString(getContext()
.getResources().getInteger(R.integer.def_end_button_behavior));
systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index 36fb3a7b4307..7154f5396fbd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -21,6 +21,8 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.app.ActivityOptions;
+import android.content.Context;
+import android.os.Handler;
/**
* Wrapper around internal ActivityOptions creation.
@@ -43,4 +45,17 @@ public abstract class ActivityOptionsCompat {
RemoteAnimationAdapterCompat remoteAnimationAdapter) {
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());
}
+
+ public static ActivityOptions makeCustomAnimation(Context context, int enterResId,
+ int exitResId, final Runnable callback, final Handler callbackHandler) {
+ return ActivityOptions.makeCustomAnimation(context, enterResId, exitResId, callbackHandler,
+ new ActivityOptions.OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ if (callback != null) {
+ callbackHandler.post(callback);
+ }
+ }
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index a3b539588d9b..0215fda81485 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -61,13 +61,14 @@ public class SwipeHelper implements Gefingerpoken {
public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
+ protected final Handler mHandler;
+
private float mMinSwipeProgress = 0f;
private float mMaxSwipeProgress = 1f;
private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
private final Callback mCallback;
- private final Handler mHandler;
private final int mSwipeDirection;
private final VelocityTracker mVelocityTracker;
private final FalsingManager mFalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index e6026c14cd28..21b21d9f5527 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -44,7 +44,7 @@ public class DozeLog {
public static final int PULSE_REASON_SENSOR_PICKUP = 3;
public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
- public static final int PULSE_REASON_SENSOR_REACH = 6;
+ public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 6;
public static final int REASON_SENSOR_WAKE_UP = 7;
private static boolean sRegisterKeyguardCallback = true;
@@ -177,9 +177,9 @@ public class DozeLog {
log("state " + state);
}
- public static void traceReachWakeUp() {
+ public static void traceWakeLockScreenWakeUp() {
if (!ENABLED) return;
- log("reachWakeUp");
+ log("wakeLockScreenWakeUp");
}
public static void traceProximityResult(Context context, boolean near, long millis,
@@ -199,7 +199,7 @@ public class DozeLog {
case PULSE_REASON_SENSOR_PICKUP: return "pickup";
case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
- case PULSE_REASON_SENSOR_REACH: return "reach";
+ case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakeLockScreen";
case REASON_SENSOR_WAKE_UP: return "wakeup";
default: throw new IllegalArgumentException("bad reason: " + pulseReason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f9dfb5d10403..701394763fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -113,10 +113,10 @@ public class DozeSensors {
true /* reports touch coordinates */,
true /* touchscreen */),
new TriggerSensor(
- findSensorWithType(config.reachSensorType()),
- Settings.Secure.DOZE_REACH_GESTURE,
+ findSensorWithType(config.wakeLockScreenSensorType()),
+ Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
true /* configured */,
- DozeLog.PULSE_REASON_SENSOR_REACH,
+ DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
false /* reports touch coordinates */,
false /* touchscreen */),
new WakeScreenSensor(),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 31548b93ea60..cb91d7815be5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -128,7 +128,7 @@ public class DozeTriggers implements DozeMachine.Part {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
- boolean isReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_REACH;
+ boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
if (isLongPress) {
requestPulse(pulseReason, sensorPerformedProxCheck);
@@ -141,7 +141,7 @@ public class DozeTriggers implements DozeMachine.Part {
if (isDoubleTap) {
mDozeHost.onDoubleTap(screenX, screenY);
mMachine.wakeUp();
- } else if (isPickup || isReach) {
+ } else if (isPickup || isWakeLockScreen) {
mMachine.wakeUp();
} else {
mDozeHost.extendPulse();
@@ -156,8 +156,8 @@ public class DozeTriggers implements DozeMachine.Part {
final boolean withinVibrationThreshold =
timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold);
- } else if (isReach) {
- DozeLog.traceReachWakeUp();
+ } else if (isWakeLockScreen) {
+ DozeLog.traceWakeLockScreenWakeUp();
}
}
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 72c2c0bec31f..9978ec364cdb 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
@@ -87,7 +87,6 @@ import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -109,6 +108,7 @@ import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarStateController;
@@ -146,11 +146,9 @@ import java.util.function.BiConsumer;
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
public class NotificationStackScrollLayout extends ViewGroup
- implements Callback, ExpandHelper.Callback, ScrollAdapter,
- OnHeightChangedListener, OnGroupChangeListener,
- OnMenuEventListener, VisibilityLocationProvider,
- NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler,
- Dumpable {
+ implements ExpandHelper.Callback, ScrollAdapter, OnHeightChangedListener,
+ OnGroupChangeListener, VisibilityLocationProvider, NotificationListContainer,
+ ConfigurationListener, DragDownCallback, AnimationStateHandler, Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -164,7 +162,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private static final int INVALID_POINTER = -1;
private ExpandHelper mExpandHelper;
- private NotificationSwipeHelper mSwipeHelper;
+ private final NotificationSwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
@@ -291,10 +289,6 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
private int mMaxScrollAfterExpand;
private ExpandableNotificationRow.LongPressListener mLongPressListener;
-
- private NotificationMenuRowPlugin mCurrMenuRow;
- private View mTranslatingParentView;
- private View mMenuExposedView;
boolean mCheckForLeavebehind;
/**
@@ -466,6 +460,9 @@ public class NotificationStackScrollLayout extends ViewGroup
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelView mNotificationPanel;
+ private final NotificationGutsManager
+ mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -495,7 +492,8 @@ public class NotificationStackScrollLayout extends ViewGroup
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
+ mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, new SwipeHelperCallback(),
+ getContext(), new NotificationMenuListener());
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
initView(context);
mFalsingManager = FalsingManager.getInstance(context);
@@ -639,41 +637,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuClicked(View view, int x, int y, MenuItem item) {
- if (mLongPressListener == null) {
- return;
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
- row.getStatusBarNotification().getPackageName());
- }
- mLongPressListener.onLongPress(view, x, y, item);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuReset(View row) {
- if (mTranslatingParentView != null && row == mTranslatingParentView) {
- mMenuExposedView = null;
- mTranslatingParentView = null;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuShown(View row) {
- mMenuExposedView = mTranslatingParentView;
- if (row instanceof ExpandableNotificationRow) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
- ((ExpandableNotificationRow) row).getStatusBarNotification()
- .getPackageName());
- }
- mSwipeHelper.onMenuShown(row);
- }
-
- @Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
@@ -1295,111 +1258,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mQsContainer = qsContainer;
}
- /**
- * Handles cleanup after the given {@code view} has been fully swiped out (including
- * re-invoking dismiss logic in case the notification has not made its way out yet).
- */
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onChildDismissed(View view) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (!row.isDismissed()) {
- handleChildViewDismissed(view);
- }
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
- }
-
- /**
- * Starts up notification dismiss and tells the notification, if any, to remove itself from
- * layout.
- *
- * @param view view (e.g. notification) to dismiss from the layout
- */
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void handleChildViewDismissed(View view) {
- if (mDismissAllInProgress) {
- return;
- }
-
- boolean isBlockingHelperShown = false;
-
- setSwipingInProgress(false);
- if (mDragAnimPendingChildren.contains(view)) {
- // We start the swipe and finish it in the same frame; we don't want a drag animation.
- mDragAnimPendingChildren.remove(view);
- }
- mAmbientState.onDragFinished(view);
- updateContinuousShadowDrawing();
-
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
- }
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
- }
-
- if (!isBlockingHelperShown) {
- mSwipedOutViews.add(view);
- }
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
- null,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- false /* deferred */);
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onChildSnappedBack(View animView, float targetLeft) {
- mAmbientState.onDragFinished(animView);
- updateContinuousShadowDrawing();
- if (!mDragAnimPendingChildren.contains(animView)) {
- if (mAnimationsEnabled) {
- mSnappedBackChildren.add(animView);
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- } else {
- // We start the swipe and snap back in the same frame, we don't want any animation
- mDragAnimPendingChildren.remove(animView);
- }
- if (mCurrMenuRow != null && targetLeft == 0) {
- mCurrMenuRow.resetMenu();
- mCurrMenuRow = null;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
- // Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onBeginDrag(View v) {
- mFalsingManager.onNotificatonStartDismissing();
- setSwipingInProgress(true);
- mAmbientState.onBeginDrag(v);
- updateContinuousShadowDrawing();
- if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
- mDragAnimPendingChildren.add(v);
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- }
-
@ShadeViewRefactor(RefactorComponent.ADAPTER)
public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
@@ -1418,41 +1276,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onDragCancelled(View v) {
- mFalsingManager.onNotificatonStopDismissing();
- setSwipingInProgress(false);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public View getChildAtPosition(MotionEvent ev) {
- View child = getChildAtPosition(ev.getX(), ev.getY());
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- ExpandableNotificationRow parent = row.getNotificationParent();
- if (parent != null && parent.areChildrenExpanded()
- && (parent.areGutsExposed()
- || mMenuExposedView == parent
- || (parent.getNotificationChildren().size() == 1
- && parent.isClearable()))) {
- // In this case the group is expanded and showing the menu for the
- // group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child. We also do the same
- // if we only have a single child.
- child = parent;
- }
- }
- return child;
- }
-
@ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
@@ -1696,18 +1519,11 @@ public class NotificationStackScrollLayout extends ViewGroup
return mScrollingEnabled;
}
- @Override
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public boolean canChildBeDismissed(View v) {
+ private boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean isAntiFalsingNeeded() {
- return onKeyguard();
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
@@ -1787,8 +1603,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
// Check if we need to clear any snooze leavebehinds
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- if (guts != null && !isTouchInView(ev, guts)
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
&& guts.getGutsContent() instanceof NotificationSnooze) {
NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
if ((ns.isExpanded() && isCancelOrUp)
@@ -3013,11 +2829,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
// Check if we need to clear any snooze leavebehinds
boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt
- && !scrollWantsIt) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+ !expandWantsIt && !scrollWantsIt) {
mCheckForLeavebehind = false;
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
}
@@ -3077,8 +2893,8 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
public void cleanUpViewState(View child) {
- if (child == mTranslatingParentView) {
- mTranslatingParentView = null;
+ if (child == mSwipeHelper.getTranslatingParentView()) {
+ mSwipeHelper.clearTranslatingParentView();
}
mCurrentStackScrollState.removeViewStateForView(child);
}
@@ -3986,7 +3802,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void checkSnoozeLeavebehind() {
if (mCheckForLeavebehind) {
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
mCheckForLeavebehind = false;
@@ -4068,7 +3884,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- private void setIsExpanded(boolean isExpanded) {
+ public void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
mStackScrollAlgorithm.setIsExpanded(isExpanded);
@@ -5242,8 +5058,8 @@ public class NotificationStackScrollLayout extends ViewGroup
setFooterView(footerView);
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void inflateEmptyShadeView() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private void inflateEmptyShadeView() {
EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
@@ -5274,8 +5090,8 @@ public class NotificationStackScrollLayout extends ViewGroup
mScrimController.setNotificationCount(getNotGoneChildCount());
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setNotificationPanel(NotificationPanelView notificationPanelView) {
mNotificationPanel = notificationPanelView;
}
@@ -5293,306 +5109,29 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnOverscrollTopChangedListener {
- /**
- * Notifies a listener that the overscroll has changed.
- *
- * @param amount the amount of overscroll, in pixels
- * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
- * unrubberbanded motion to directly expand overscroll view (e.g
- * expand
- * QS)
- */
- void onOverscrollTopChanged(float amount, boolean isRubberbanded);
-
- /**
- * Notify a listener that the scroller wants to escape from the scrolling motion and
- * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
- *
- * @param velocity The velocity that the Scroller had when over flinging
- * @param open Should the fling open or close the overscroll view.
- */
- void flingTopOverscroll(float velocity, boolean open);
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private class NotificationSwipeHelper extends SwipeHelper
- implements NotificationSwipeActionHelper {
- private static final long COVER_MENU_DELAY = 4000;
- private Runnable mFalsingCheck;
- private Handler mHandler;
-
- private static final long SWIPE_MENU_TIMING = 200;
-
- public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
- super(swipeDirection, callback, context);
- mHandler = new Handler();
- mFalsingCheck = new Runnable() {
- @Override
- public void run() {
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- };
- }
-
- @Override
- public void onDownUpdate(View currView, MotionEvent ev) {
- mTranslatingParentView = currView;
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchStart();
- }
- mCurrMenuRow = null;
- mHandler.removeCallbacks(mFalsingCheck);
-
- // Slide back any notifications that might be showing a menu
- resetExposedMenuView(true /* animate */, false /* force */);
-
- if (currView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) currView;
-
- if (row.getEntry().hasFinishedInitialization()) {
- mCurrMenuRow = row.createMenu();
- mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this);
- mCurrMenuRow.onTouchStart();
- }
- }
- }
-
- private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
- return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
- }
-
- @Override
- public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
- mHandler.removeCallbacks(mFalsingCheck);
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchMove(delta);
- }
- }
-
- @Override
- public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
- float translation) {
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchEnd();
- handleMenuRowSwipe(ev, animView, velocity, mCurrMenuRow);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean swipedFarEnough(float translation, float viewSize) {
- return swipedFarEnough();
- }
-
- private void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- if (!menuRow.shouldShowMenu()) {
- // If the menu should not be shown, then there is no need to check if the a swipe
- // should result in a snapping to the menu. As a result, just check if the swipe
- // was enough to dismiss the notification.
- if (isDismissGesture(ev)) {
- dismiss(animView, velocity);
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- return;
- }
-
- if (menuRow.isSnappedAndOnSameSide()) {
- // Menu was snapped to previously and we're on the same side
- handleSwipeFromSnap(ev, animView, velocity, menuRow);
- } else {
- // Menu has not been snapped, or was snapped previously but is now on
- // the opposite side.
- handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
- }
- }
-
- private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- boolean isDismissGesture = isDismissGesture(ev);
- final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
- final boolean gestureFastEnough =
- mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity);
-
- final double timeForGesture = ev.getEventTime() - ev.getDownTime();
- final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
- && timeForGesture >= SWIPE_MENU_TIMING;
-
- if (!isFalseGesture(ev)
- && (swipedEnoughToShowMenu(menuRow)
- && (!gestureFastEnough || showMenuForSlowOnGoing))
- || (gestureTowardsMenu && !isDismissGesture)) {
- // Menu has not been snapped to previously and this is menu revealing gesture
- snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
- menuRow.onSnapOpen();
- } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
- dismiss(animView, velocity);
- menuRow.onDismiss();
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- }
-
- private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- boolean isDismissGesture = isDismissGesture(ev);
-
- final boolean withinSnapMenuThreshold =
- menuRow.isWithinSnapMenuThreshold();
-
- if (withinSnapMenuThreshold && !isDismissGesture) {
- // Haven't moved enough to unsnap from the menu
- menuRow.onSnapOpen();
- snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
- } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
- // Only dismiss if we're not moving towards the menu
- dismiss(animView, velocity);
- menuRow.onDismiss();
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- }
-
- @Override
- public void dismissChild(final View view, float velocity,
- boolean useAccelerateInterpolator) {
- super.dismissChild(view, velocity, useAccelerateInterpolator);
- if (mIsExpanded) {
- // We don't want to quick-dismiss when it's a heads up as this might lead to closing
- // of the panel early.
- handleChildViewDismissed(view);
- }
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- handleMenuCoveredOrDismissed();
- }
-
- @Override
- public void snapChild(final View animView, final float targetLeft, float velocity) {
- super.snapChild(animView, targetLeft, velocity);
- onDragCancelled(animView);
- if (targetLeft == 0) {
- handleMenuCoveredOrDismissed();
- }
- }
-
- @Override
- public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
- }
-
- private void handleMenuCoveredOrDismissed() {
- if (mMenuExposedView != null && mMenuExposedView == mTranslatingParentView) {
- mMenuExposedView = null;
- }
- }
-
- @Override
- public Animator getViewTranslationAnimator(View v, float target,
- AnimatorUpdateListener listener) {
- if (v instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
- } else {
- return super.getViewTranslationAnimator(v, target, listener);
- }
- }
-
- @Override
- public void setTranslation(View v, float translate) {
- ((ExpandableView) v).setTranslation(translate);
- }
-
- @Override
- public float getTranslation(View v) {
- return ((ExpandableView) v).getTranslation();
- }
-
- @Override
- public void dismiss(View animView, float velocity) {
- dismissChild(animView, velocity,
- !swipedFastEnough(0, 0) /* useAccelerateInterpolator */);
- }
-
- @Override
- public void snapOpen(View animView, int targetLeft, float velocity) {
- snapChild(animView, targetLeft, velocity);
- }
-
- private void snapBack(View animView, float velocity) {
- snapChild(animView, 0, velocity);
- }
-
- @Override
- public boolean swipedFastEnough(float translation, float velocity) {
- return swipedFastEnough();
- }
-
- @Override
- public float getMinDismissVelocity() {
- return getEscapeVelocity();
- }
-
- public void onMenuShown(View animView) {
- onDragCancelled(animView);
-
- // If we're on the lockscreen we want to false this.
- if (isAntiFalsingNeeded()) {
- mHandler.removeCallbacks(mFalsingCheck);
- mHandler.postDelayed(mFalsingCheck, COVER_MENU_DELAY);
- }
- }
-
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- View view = null;
- if (guts != null && !guts.getGutsContent().isLeavebehind()) {
- // Only close visible guts if they're not a leavebehind.
- view = guts;
- } else if (mCurrMenuRow != null && mCurrMenuRow.isMenuVisible()
- && mTranslatingParentView != null) {
- // Checking menu
- view = mTranslatingParentView;
- }
- if (view != null && !isTouchInView(ev, view)) {
- // Touch was outside visible guts / menu notification, close what's visible
- mStatusBar.getGutsManager().closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- }
+ /**
+ * Notifies a listener that the overscroll has changed.
+ *
+ * @param amount the amount of overscroll, in pixels
+ * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
+ * unrubberbanded motion to directly expand overscroll view (e.g
+ * expand
+ * QS)
+ */
+ void onOverscrollTopChanged(float amount, boolean isRubberbanded);
- public void resetExposedMenuView(boolean animate, boolean force) {
- if (mMenuExposedView == null
- || (!force && mMenuExposedView == mTranslatingParentView)) {
- // If no menu is showing or it's showing for this view we do nothing.
- return;
- }
- final View prevMenuExposedView = mMenuExposedView;
- if (animate) {
- Animator anim = getViewTranslationAnimator(prevMenuExposedView,
- 0 /* leftTarget */, null /* updateListener */);
- if (anim != null) {
- anim.start();
- }
- } else if (mMenuExposedView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) mMenuExposedView;
- if (!row.isRemoved()) {
- row.resetTranslation();
- }
- }
- mMenuExposedView = null;
- }
- }
+ /**
+ * Notify a listener that the scroller wants to escape from the scrolling motion and
+ * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
+ *
+ * @param velocity The velocity that the Scroller had when over flinging
+ * @param open Should the fling open or close the overscroll view.
+ */
+ void flingTopOverscroll(float velocity, boolean open);
+ }
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public boolean hasActiveNotifications() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public boolean hasActiveNotifications() {
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
@@ -5656,8 +5195,8 @@ public class NotificationStackScrollLayout extends ViewGroup
return mStatusBarState == StatusBarState.KEYGUARD;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void updateSpeedBumpIndex() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5677,24 +5216,6 @@ public class NotificationStackScrollLayout extends ViewGroup
updateSpeedBumpIndex(speedBumpIndex, noAmbient);
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean isTouchInView(MotionEvent ev, View view) {
- if (view == null) {
- return false;
- }
- final int height = (view instanceof ExpandableView)
- ? ((ExpandableView) view).getActualHeight()
- : view.getHeight();
- final int rx = (int) ev.getRawX();
- final int ry = (int) ev.getRawY();
- view.getLocationOnScreen(mTempInt2);
- final int x = mTempInt2[0];
- final int y = mTempInt2[1];
- Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
- boolean ret = rect.contains(rx, ry);
- return ret;
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
@@ -5718,11 +5239,29 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.INPUT)
public void closeControlsIfOutsideTouch(MotionEvent ev) {
- mSwipeHelper.closeControlsIfOutsideTouch(ev);
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ View view = null;
+ if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+ // Only close visible guts if they're not a leavebehind.
+ view = guts;
+ } else if (menuRow != null && menuRow.isMenuVisible()
+ && translatingParentView != null) {
+ // Checking menu
+ view = translatingParentView;
+ }
+ if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+ // Touch was outside visible guts / menu notification, close what's visible
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ resetExposedMenuView(true /* animate */, true /* force */);
+ }
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- static class AnimationEvent {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[]{
@@ -6022,8 +5561,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private final StateListener mStateListener = new StateListener() {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ private final StateListener mStateListener = new StateListener() {
@Override
public void onStatePreChange(int oldState, int newState) {
if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
@@ -6036,9 +5575,222 @@ public class NotificationStackScrollLayout extends ViewGroup
setStatusBarState(newState);
}
- @Override
- public void onStatePostChange() {
+ @Override
+ public void onStatePostChange() {
NotificationStackScrollLayout.this.onStatePostChange();
}
- };
+ };
+
+ class NotificationMenuListener implements NotificationMenuRowPlugin.OnMenuEventListener {
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuClicked(View view, int x, int y, MenuItem item) {
+ if (mLongPressListener == null) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+ row.getStatusBarNotification().getPackageName());
+ }
+ mLongPressListener.onLongPress(view, x, y, item);
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuReset(View row) {
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuShown(View row) {
+ if (row instanceof ExpandableNotificationRow) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+ ((ExpandableNotificationRow) row).getStatusBarNotification()
+ .getPackageName());
+ }
+ mSwipeHelper.onMenuShown(row);
+ }
+ }
+
+ class SwipeHelperCallback implements NotificationSwipeHelper.NotificationCallback {
+ @Override
+ public void onDismiss() {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn,
+ NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+ mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ @Override
+ public boolean isExpanded() {
+ return NotificationStackScrollLayout.this.isExpanded();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onDragCancelled(View v) {
+ mFalsingManager.onNotificatonStopDismissing();
+ setSwipingInProgress(false);
+ }
+
+ /**
+ * Handles cleanup after the given {@code view} has been fully swiped out (including
+ * re-invoking dismiss logic in case the notification has not made its way out yet).
+ */
+ @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void onChildDismissed(View view) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (!row.isDismissed()) {
+ handleChildViewDismissed(view);
+ }
+ ViewGroup transientContainer = row.getTransientContainer();
+ if (transientContainer != null) {
+ transientContainer.removeTransientView(view);
+ }
+ }
+
+ /**
+ * Starts up notification dismiss and tells the notification, if any, to remove itself from
+ * layout.
+ *
+ * @param view view (e.g. notification) to dismiss from the layout
+ */
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void handleChildViewDismissed(View view) {
+ if (mDismissAllInProgress) {
+ return;
+ }
+
+ boolean isBlockingHelperShown = false;
+
+ setSwipingInProgress(false);
+ if (mDragAnimPendingChildren.contains(view)) {
+ // We start the swipe and finish it in the same frame; we don't want a drag
+ // animation.
+ mDragAnimPendingChildren.remove(view);
+ }
+ mAmbientState.onDragFinished(view);
+ updateContinuousShadowDrawing();
+
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUp()) {
+ mHeadsUpManager.addSwipedOutNotification(
+ row.getStatusBarNotification().getKey());
+ }
+ isBlockingHelperShown =
+ row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ }
+
+ if (!isBlockingHelperShown) {
+ mSwipedOutViews.add(view);
+ }
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(
+ null,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ false /* deferred */);
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean isAntiFalsingNeeded() {
+ return onKeyguard();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public View getChildAtPosition(MotionEvent ev) {
+ View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
+ ev.getY());
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (parent != null && parent.areChildrenExpanded()
+ && (parent.areGutsExposed()
+ || mSwipeHelper.getExposedMenuView() == parent
+ || (parent.getNotificationChildren().size() == 1
+ && parent.isClearable()))) {
+ // In this case the group is expanded and showing the menu for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child. We also do the same
+ // if we only have a single child.
+ child = parent;
+ }
+ }
+ return child;
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onBeginDrag(View v) {
+ mFalsingManager.onNotificatonStartDismissing();
+ setSwipingInProgress(true);
+ mAmbientState.onBeginDrag(v);
+ updateContinuousShadowDrawing();
+ if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
+ mDragAnimPendingChildren.add(v);
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void onChildSnappedBack(View animView, float targetLeft) {
+ mAmbientState.onDragFinished(animView);
+ updateContinuousShadowDrawing();
+ if (!mDragAnimPendingChildren.contains(animView)) {
+ if (mAnimationsEnabled) {
+ mSnappedBackChildren.add(animView);
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ } else {
+ // We start the swipe and snap back in the same frame, we don't want any animation
+ mDragAnimPendingChildren.remove(animView);
+ }
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ if (menuRow != null && targetLeft == 0) {
+ menuRow.resetMenu();
+ mSwipeHelper.clearCurrentMenuRow();
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean updateSwipeProgress(View animView, boolean dismissable,
+ float swipeProgress) {
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public float getFalsingThresholdFactor() {
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return NotificationStackScrollLayout.this.canChildBeDismissed(v);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
new file mode 100644
index 000000000000..028957d233ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -0,0 +1,424 @@
+/*
+ * 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 Licen
+ */
+
+
+package com.android.systemui.statusbar.notification.stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+
+@ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.INPUT)
+class NotificationSwipeHelper extends SwipeHelper
+ implements NotificationSwipeActionHelper {
+ @VisibleForTesting
+ protected static final long COVER_MENU_DELAY = 4000;
+ private static final String TAG = "NotificationSwipeHelper";
+ private final Runnable mFalsingCheck;
+ private View mTranslatingParentView;
+ private View mMenuExposedView;
+ private final NotificationCallback mCallback;
+ private final NotificationMenuRowPlugin.OnMenuEventListener mMenuListener;
+
+ private static final long SWIPE_MENU_TIMING = 200;
+
+ private NotificationMenuRowPlugin mCurrMenuRow;
+
+ public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
+ Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+ super(swipeDirection, callback, context);
+ mMenuListener = menuListener;
+ mCallback = callback;
+ mFalsingCheck = new Runnable() {
+ @Override
+ public void run() {
+ resetExposedMenuView(true /* animate */, true /* force */);
+ }
+ };
+ }
+
+ public View getTranslatingParentView() {
+ return mTranslatingParentView;
+ }
+
+ public void clearTranslatingParentView() { setTranslatingParentView(null); }
+
+ @VisibleForTesting
+ protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+
+ public void setExposedMenuView(View view) {
+ mMenuExposedView = view;
+ }
+
+ public void clearExposedMenuView() { setExposedMenuView(null); }
+
+ public void clearCurrentMenuRow() { setCurrentMenuRow(null); }
+
+ public View getExposedMenuView() {
+ return mMenuExposedView;
+ }
+
+ public void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
+ mCurrMenuRow = menuRow;
+ }
+
+ public NotificationMenuRowPlugin getCurrentMenuRow() { return mCurrMenuRow; }
+
+ @VisibleForTesting
+ protected Handler getHandler() { return mHandler; }
+
+ @VisibleForTesting
+ protected Runnable getFalsingCheck() { return mFalsingCheck; };
+
+ @Override
+ public void onDownUpdate(View currView, MotionEvent ev) {
+ mTranslatingParentView = currView;
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchStart();
+ }
+ clearCurrentMenuRow();
+ getHandler().removeCallbacks(getFalsingCheck());
+
+ // Slide back any notifications that might be showing a menu
+ resetExposedMenuView(true /* animate */, false /* force */);
+
+ if (currView instanceof ExpandableNotificationRow) {
+ initializeRow((ExpandableNotificationRow) currView);
+ }
+ }
+
+ @VisibleForTesting
+ protected void initializeRow(ExpandableNotificationRow row) {
+ if (row.getEntry().hasFinishedInitialization()) {
+ mCurrMenuRow = row.createMenu();
+ mCurrMenuRow.setMenuClickListener(mMenuListener);
+ mCurrMenuRow.onTouchStart();
+ }
+ }
+
+ private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
+ return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
+ }
+
+ @Override
+ public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
+ getHandler().removeCallbacks(getFalsingCheck());
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchMove(delta);
+ }
+ }
+
+ @Override
+ public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
+ float translation) {
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchEnd();
+ handleMenuRowSwipe(ev, animView, velocity, menuRow);
+ return true;
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ protected void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ if (!menuRow.shouldShowMenu()) {
+ // If the menu should not be shown, then there is no need to check if the a swipe
+ // should result in a snapping to the menu. As a result, just check if the swipe
+ // was enough to dismiss the notification.
+ if (isDismissGesture(ev)) {
+ dismiss(animView, velocity);
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ return;
+ }
+
+ if (menuRow.isSnappedAndOnSameSide()) {
+ // Menu was snapped to previously and we're on the same side
+ handleSwipeFromSnap(ev, animView, velocity, menuRow);
+ } else {
+ // Menu has not been snapped, or was snapped previously but is now on
+ // the opposite side.
+ handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
+ }
+ }
+
+ private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+ final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
+ final boolean gestureFastEnough = getEscapeVelocity() <= Math.abs(velocity);
+
+ final double timeForGesture = ev.getEventTime() - ev.getDownTime();
+ final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
+ && timeForGesture >= SWIPE_MENU_TIMING;
+
+ if (!isFalseGesture(ev)
+ && (swipedEnoughToShowMenu(menuRow)
+ && (!gestureFastEnough || showMenuForSlowOnGoing))
+ || (gestureTowardsMenu && !isDismissGesture)) {
+ // Menu has not been snapped to previously and this is menu revealing gesture
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ menuRow.onSnapOpen();
+ } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+
+ final boolean withinSnapMenuThreshold =
+ menuRow.isWithinSnapMenuThreshold();
+
+ if (withinSnapMenuThreshold && !isDismissGesture) {
+ // Haven't moved enough to unsnap from the menu
+ menuRow.onSnapOpen();
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
+ // Only dismiss if we're not moving towards the menu
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ @Override
+ public void dismissChild(final View view, float velocity,
+ boolean useAccelerateInterpolator) {
+ superDismissChild(view, velocity, useAccelerateInterpolator);
+ if (mCallback.isExpanded()) {
+ // We don't want to quick-dismiss when it's a heads up as this might lead to closing
+ // of the panel early.
+ mCallback.handleChildViewDismissed(view);
+ }
+ mCallback.onDismiss();
+ handleMenuCoveredOrDismissed();
+ }
+
+ @VisibleForTesting
+ protected void superDismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
+ super.dismissChild(view, velocity, useAccelerateInterpolator);
+ }
+
+ @VisibleForTesting
+ protected void superSnapChild(final View animView, final float targetLeft, float velocity) {
+ super.snapChild(animView, targetLeft, velocity);
+ }
+
+ @Override
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ superSnapChild(animView, targetLeft, velocity);
+ mCallback.onDragCancelled(animView);
+ if (targetLeft == 0) {
+ handleMenuCoveredOrDismissed();
+ }
+ }
+
+ @Override
+ public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
+ mCallback.onSnooze(sbn, snoozeOption);
+ }
+
+ @VisibleForTesting
+ protected void handleMenuCoveredOrDismissed() {
+ View exposedMenuView = getExposedMenuView();
+ if (exposedMenuView != null && exposedMenuView == mTranslatingParentView) {
+ clearExposedMenuView();
+ }
+ }
+
+ @VisibleForTesting
+ protected Animator superGetViewTranslationAnimator(View v, float target,
+ ValueAnimator.AnimatorUpdateListener listener) {
+ return super.getViewTranslationAnimator(v, target, listener);
+ }
+
+ @Override
+ public Animator getViewTranslationAnimator(View v, float target,
+ ValueAnimator.AnimatorUpdateListener listener) {
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+ } else {
+ return superGetViewTranslationAnimator(v, target, listener);
+ }
+ }
+
+ @Override
+ public void setTranslation(View v, float translate) {
+ if (v instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) v).setTranslation(translate);
+ } else {
+ Log.wtf(TAG, "setTranslation should only be called on an ExpandableNotificationRow.");
+ }
+ }
+
+ @Override
+ public float getTranslation(View v) {
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslation();
+ }
+ else {
+ Log.wtf(TAG, "getTranslation should only be called on an ExpandableNotificationRow.");
+ return 0f;
+ }
+ }
+
+ @Override
+ public boolean swipedFastEnough(float translation, float viewSize) {
+ return swipedFastEnough();
+ }
+
+ @Override
+ @VisibleForTesting
+ protected boolean swipedFastEnough() {
+ return super.swipedFastEnough();
+ }
+
+ @Override
+ public boolean swipedFarEnough(float translation, float viewSize) {
+ return swipedFarEnough();
+ }
+
+ @Override
+ @VisibleForTesting
+ protected boolean swipedFarEnough() {
+ return super.swipedFarEnough();
+ }
+
+ @Override
+ public void dismiss(View animView, float velocity) {
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
+ }
+
+ @Override
+ public void snapOpen(View animView, int targetLeft, float velocity) {
+ snapChild(animView, targetLeft, velocity);
+ }
+
+ @VisibleForTesting
+ protected void snapClosed(View animView, float velocity) {
+ snapChild(animView, 0, velocity);
+ }
+
+ @Override
+ @VisibleForTesting
+ protected float getEscapeVelocity() {
+ return super.getEscapeVelocity();
+ }
+
+ @Override
+ public float getMinDismissVelocity() {
+ return getEscapeVelocity();
+ }
+
+ public void onMenuShown(View animView) {
+ setExposedMenuView(getTranslatingParentView());
+ mCallback.onDragCancelled(animView);
+ Handler handler = getHandler();
+
+ // If we're on the lockscreen we want to false this.
+ if (mCallback.isAntiFalsingNeeded()) {
+ handler.removeCallbacks(getFalsingCheck());
+ handler.postDelayed(getFalsingCheck(), COVER_MENU_DELAY);
+ }
+ }
+
+ @VisibleForTesting
+ protected boolean shouldResetMenu(boolean force) {
+ if (mMenuExposedView == null
+ || (!force && mMenuExposedView == mTranslatingParentView)) {
+ // If no menu is showing or it's showing for this view we do nothing.
+ return false;
+ }
+ return true;
+ }
+
+ public void resetExposedMenuView(boolean animate, boolean force) {
+ if (!shouldResetMenu(force)) {
+ return;
+ }
+ final View prevMenuExposedView = getExposedMenuView();
+ if (animate) {
+ Animator anim = getViewTranslationAnimator(prevMenuExposedView,
+ 0 /* leftTarget */, null /* updateListener */);
+ if (anim != null) {
+ anim.start();
+ }
+ } else if (prevMenuExposedView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView;
+ if (!row.isRemoved()) {
+ row.resetTranslation();
+ }
+ }
+ clearExposedMenuView();
+ }
+
+ public static boolean isTouchInView(MotionEvent ev, View view) {
+ if (view == null) {
+ return false;
+ }
+ final int height = (view instanceof ExpandableView)
+ ? ((ExpandableView) view).getActualHeight()
+ : view.getHeight();
+ final int rx = (int) ev.getRawX();
+ final int ry = (int) ev.getRawY();
+ int[] temp = new int[2];
+ view.getLocationOnScreen(temp);
+ final int x = temp[0];
+ final int y = temp[1];
+ Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+ boolean ret = rect.contains(rx, ry);
+ return ret;
+ }
+
+ public interface NotificationCallback extends SwipeHelper.Callback{
+ boolean isExpanded();
+
+ void handleChildViewDismissed(View view);
+
+ void onSnooze(StatusBarNotification sbn, SnoozeOption snoozeOption);
+
+ void onDismiss();
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 09c19319429b..da59450af4df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -79,13 +79,14 @@ public class NonPhoneDependencyTest extends SysuiTestCase {
Dependency.get(NotificationLockscreenUserManager.class);
NotificationViewHierarchyManager viewHierarchyManager =
Dependency.get(NotificationViewHierarchyManager.class);
+ NotificationGroupManager groupManager = Dependency.get(NotificationGroupManager.class);
when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(lockscreenUserManager);
- when(mPresenter.getGroupManager()).thenReturn(
- Dependency.get(NotificationGroupManager.class));
+ when(mPresenter.getGroupManager()).thenReturn(groupManager);
entryManager.setUpWithPresenter(mPresenter, mListContainer, mEntryManagerCallback,
mHeadsUpManager);
+ groupManager.setHeadsUpManager(mHeadsUpManager);
gutsManager.setUpWithPresenter(mPresenter, mListContainer, mCheckSaveListener,
mOnClickListener);
notificationLogger.setUpWithEntryManager(entryManager, mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
new file mode 100644
index 000000000000..b5f67c06b2d1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -0,0 +1,511 @@
+/*
+ * 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.systemui.statusbar.notification.stack;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.service.notification.StatusBarNotification;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.MotionEvent;
+
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationMenuRow;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link NotificationSwipeHelper}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationSwipeHelperTest extends SysuiTestCase {
+
+ private NotificationSwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper.NotificationCallback mCallback;
+ private NotificationMenuRowPlugin.OnMenuEventListener mListener;
+ private View mView;
+ private MotionEvent mEvent;
+ private NotificationMenuRowPlugin mMenuRow;
+ private Handler mHandler;
+ private ExpandableNotificationRow mNotificationRow;
+ private Runnable mFalsingCheck;
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ @Before
+ @UiThreadTest
+ public void setUp() throws Exception {
+ mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
+ mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
+ mSwipeHelper = spy(new NotificationSwipeHelper(SwipeHelper.X, mCallback, mContext, mListener));
+ mView = mock(View.class);
+ mEvent = mock(MotionEvent.class);
+ mMenuRow = mock(NotificationMenuRowPlugin.class);
+ mNotificationRow = mock(ExpandableNotificationRow.class);
+ mHandler = mock(Handler.class);
+ mFalsingCheck = mock(Runnable.class);
+ }
+
+ @Test
+ public void testSetExposedMenuView() {
+ assertEquals("intialized with null exposed menu view", null,
+ mSwipeHelper.getExposedMenuView());
+ mSwipeHelper.setExposedMenuView(mView);
+ assertEquals("swipe helper has correct exposedMenuView after setExposedMenuView to a view",
+ mView, mSwipeHelper.getExposedMenuView());
+ mSwipeHelper.setExposedMenuView(null);
+ assertEquals("swipe helper has null exposedMenuView after setExposedMenuView to null",
+ null, mSwipeHelper.getExposedMenuView());
+ }
+
+ @Test
+ public void testClearExposedMenuView() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ mSwipeHelper.clearExposedMenuView();
+ verify(mSwipeHelper, times(1)).setExposedMenuView(null);
+ }
+
+ @Test
+ public void testGetTranslatingParentView() {
+ assertEquals("intialized with null translating parent view", null,
+ mSwipeHelper.getTranslatingParentView());
+ mSwipeHelper.setTranslatingParentView(mView);
+ assertEquals("has translating parent view after setTranslatingParentView with a view",
+ mView, mSwipeHelper.getTranslatingParentView());
+ }
+
+ @Test
+ public void testClearTranslatingParentView() {
+ doNothing().when(mSwipeHelper).setTranslatingParentView(null);
+ mSwipeHelper.clearTranslatingParentView();
+ verify(mSwipeHelper, times(1)).setTranslatingParentView(null);
+ }
+
+ @Test
+ public void testSetCurrentMenuRow() {
+ assertEquals("currentMenuRow initializes to null", null,
+ mSwipeHelper.getCurrentMenuRow());
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+ assertEquals("currentMenuRow set correctly after setCurrentMenuRow", mMenuRow,
+ mSwipeHelper.getCurrentMenuRow());
+ mSwipeHelper.setCurrentMenuRow(null);
+ assertEquals("currentMenuRow set to null after setCurrentMenuRow to null",
+ null, mSwipeHelper.getCurrentMenuRow());
+ }
+
+ @Test
+ public void testClearCurrentMenuRow() {
+ doNothing().when(mSwipeHelper).setCurrentMenuRow(null);
+ mSwipeHelper.clearCurrentMenuRow();
+ verify(mSwipeHelper, times(1)).setCurrentMenuRow(null);
+ }
+
+ @Test
+ public void testOnDownUpdate_ExpandableNotificationRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+ doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+ doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+ doNothing().when(mSwipeHelper).initializeRow(any());
+
+ mSwipeHelper.onDownUpdate(mNotificationRow, mEvent);
+
+ verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+ verify(mSwipeHelper, times(1)).initializeRow(mNotificationRow);
+ }
+
+ @Test
+ public void testOnDownUpdate_notExpandableNotificationRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+ doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+ doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+ doNothing().when(mSwipeHelper).initializeRow(any());
+
+ mSwipeHelper.onDownUpdate(mView, mEvent);
+
+ verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+ verify(mSwipeHelper, times(0)).initializeRow(any());
+ }
+
+ @Test
+ public void testOnMoveUpdate_menuRow() {
+ when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+ mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mMenuRow, times(1)).onTouchMove(10);
+ }
+
+ @Test
+ public void testOnMoveUpdate_noMenuRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+ mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ }
+
+ @Test
+ public void testHandleUpEvent_noMenuRow() {
+ assertFalse("Menu row does not exist",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRow() {
+ when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+ doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+ }
+
+ @Test
+ public void testDismissChild_notExpanded() {
+ when(mCallback.isExpanded()).thenReturn(false);
+ doNothing().when(mSwipeHelper).superDismissChild(mView, 0, false);
+ doNothing().when(mSwipeHelper).handleMenuCoveredOrDismissed();
+
+ mSwipeHelper.dismissChild(mView, 0, false);
+
+ verify(mSwipeHelper, times(1)).superDismissChild(mView, 0, false);
+ verify(mCallback, times(0)).handleChildViewDismissed(mView);
+ verify(mCallback, times(1)).onDismiss();
+ verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+ }
+
+ @Test
+ public void testSnapchild_targetIsZero() {
+ doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0);
+ mSwipeHelper.snapChild(mView, 0, 0);
+
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0);
+ verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+ }
+
+
+ @Test
+ public void testSnapchild_targetNotZero() {
+ doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
+ mSwipeHelper.snapChild(mView, 10, 0);
+
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0);
+ verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
+ }
+
+ @Test
+ public void testSnooze() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ SnoozeOption snoozeOption = mock(SnoozeOption.class);
+ mSwipeHelper.snooze(sbn, snoozeOption);
+ verify(mCallback, times(1)).onSnooze(sbn, snoozeOption);
+ }
+
+ @Test
+ public void testGetViewTranslationAnimator_notExpandableNotificationRow() {
+ Animator animator = mock(Animator.class);
+ AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+ doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener);
+
+ assertEquals("returns the correct animator from super", animator,
+ mSwipeHelper.getViewTranslationAnimator(mView, 0, listener));
+
+ verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener);
+ }
+
+ @Test
+ public void testGetViewTranslationAnimator_expandableNotificationRow() {
+ Animator animator = mock(Animator.class);
+ AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+ doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener);
+
+ assertEquals("returns the correct animator from super when view is an ENR", animator,
+ mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener));
+
+ verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener);
+ }
+
+ @Test
+ public void testSetTranslation() {
+ mSwipeHelper.setTranslation(mNotificationRow, 0);
+ verify(mNotificationRow, times(1)).setTranslation(0);
+ }
+
+ @Test
+ public void testGetTranslation() {
+ doReturn(30f).when(mNotificationRow).getTranslation();
+
+ assertEquals("Returns getTranslation for the ENR",
+ mSwipeHelper.getTranslation(mNotificationRow), 30f);
+
+ verify(mNotificationRow, times(1)).getTranslation();
+ }
+
+ @Test
+ public void testDismiss() {
+ doNothing().when(mSwipeHelper).dismissChild(mView, 0, true);
+ doReturn(false).when(mSwipeHelper).swipedFastEnough();
+
+ mSwipeHelper.dismiss(mView, 0);
+
+ verify(mSwipeHelper, times(1)).swipedFastEnough();
+ verify(mSwipeHelper, times(1)).dismissChild(mView, 0, true);
+ }
+
+ @Test
+ public void testSnapOpen() {
+ doNothing().when(mSwipeHelper).snapChild(mView, 30, 0);
+
+ mSwipeHelper.snapOpen(mView, 30, 0);
+
+ verify(mSwipeHelper, times(1)).snapChild(mView, 30, 0);
+ }
+
+ @Test
+ public void testSnapClosed() {
+ doNothing().when(mSwipeHelper).snapChild(mView, 0, 0);
+
+ mSwipeHelper.snapClosed(mView, 0);
+
+ verify(mSwipeHelper, times(1)).snapChild(mView, 0, 0);
+ }
+
+ @Test
+ public void testGetMinDismissVelocity() {
+ doReturn(30f).when(mSwipeHelper).getEscapeVelocity();
+
+ assertEquals("Returns getEscapeVelocity", 30f, mSwipeHelper.getMinDismissVelocity());
+ }
+
+ @Test
+ public void onMenuShown_noAntiFalsing() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+ doReturn(mHandler).when(mSwipeHelper).getHandler();
+ doReturn(false).when(mCallback).isAntiFalsingNeeded();
+ doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+ mSwipeHelper.onMenuShown(mView);
+
+ verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+ verify(mHandler, times(0)).removeCallbacks(mFalsingCheck);
+ verify(mHandler, times(0)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+ }
+
+ @Test
+ public void onMenuShown_antiFalsing() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+ doReturn(mHandler).when(mSwipeHelper).getHandler();
+ doReturn(true).when(mCallback).isAntiFalsingNeeded();
+ doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+ mSwipeHelper.onMenuShown(mView);
+
+ verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mHandler, times(1)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+ }
+
+ @Test
+ public void testResetExposedMenuView_noReset() {
+ doReturn(false).when(mSwipeHelper).shouldResetMenu(false);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(false, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should not clear exposed menu row
+ verify(mSwipeHelper, times(0)).clearExposedMenuView();
+ }
+
+ @Test
+ public void testResetExposedMenuView_animate() {
+ Animator animator = mock(Animator.class);
+
+ doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+ doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+ doReturn(false).when(mNotificationRow).isRemoved();
+ doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(true, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should retrieve and start animator
+ verify(mSwipeHelper, times(1)).getViewTranslationAnimator(mNotificationRow, 0, null);
+ verify(animator, times(1)).start();
+
+ // should not reset translation on row directly
+ verify(mNotificationRow, times(0)).resetTranslation();
+
+ // should clear exposed menu row
+ verify(mSwipeHelper, times(1)).clearExposedMenuView();
+ }
+
+
+ @Test
+ public void testResetExposedMenuView_noAnimate() {
+ Animator animator = mock(Animator.class);
+
+ doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+ doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+ doReturn(false).when(mNotificationRow).isRemoved();
+ doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(false, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should not retrieve and start animator
+ verify(mSwipeHelper, times(0)).getViewTranslationAnimator(mNotificationRow, 0, null);
+ verify(animator, times(0)).start();
+
+ // should reset translation on row directly
+ verify(mNotificationRow, times(1)).resetTranslation();
+
+ // should clear exposed menu row
+ verify(mSwipeHelper, times(1)).clearExposedMenuView();
+ }
+
+ @Test
+ public void testIsTouchInView() {
+ assertEquals("returns false when view is null", false,
+ NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+
+ doReturn(20).when(mView).getWidth();
+ doReturn(20).when(mView).getHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+ doAnswer(answer).when(mView).getLocationOnScreen(any());
+
+ assertTrue("Touch is within the view",
+ mSwipeHelper.isTouchInView(mEvent, mView));
+
+ doReturn(50f).when(mEvent).getRawX();
+
+ assertFalse("Touch is not within the view",
+ mSwipeHelper.isTouchInView(mEvent, mView));
+ }
+
+ @Test
+ public void testIsTouchInView_expandable() {
+ assertEquals("returns false when view is null", false,
+ NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+
+ doReturn(20).when(mNotificationRow).getWidth();
+ doReturn(20).when(mNotificationRow).getActualHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+ doAnswer(answer).when(mNotificationRow).getLocationOnScreen(any());
+
+ assertTrue("Touch is within the view",
+ mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+
+ doReturn(50f).when(mEvent).getRawX();
+
+ assertFalse("Touch is not within the view",
+ mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+ }
+}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 90c10fdcbfde..39472955dfa8 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6447,7 +6447,7 @@ message MetricsEvent {
// OPEN: Settings > System > Input & Gesture > Reach up gesture
// OS: Q
- SETTINGS_GESTURE_REACH = 1557;
+ SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557;
// OPEN: Emergency dialer opened
// CLOSE: Emergency dialer closed
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e41a09ef672e..a1989e51ee51 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -57,6 +57,7 @@ import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
import android.net.IIpConnectivityMetrics;
+import android.net.INetd;
import android.net.INetdEventCallback;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
@@ -88,6 +89,7 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.NetdService;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -259,7 +261,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
- private INetworkManagementService mNetd;
+ private INetworkManagementService mNMS;
+ private INetd mNetd;
private INetworkStatsService mStatsService;
private INetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
@@ -759,7 +762,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
mContext = checkNotNull(context, "missing Context");
- mNetd = checkNotNull(netManager, "missing INetworkManagementService");
+ mNMS = checkNotNull(netManager, "missing INetworkManagementService");
mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
mPolicyManagerInternal = checkNotNull(
@@ -767,6 +770,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
"missing NetworkPolicyManagerInternal");
mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
+ mNetd = NetdService.getInstance();
mKeyStore = KeyStore.getInstance();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -849,7 +853,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTethering = makeTethering();
- mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+ mPermissionMonitor = new PermissionMonitor(mContext, mNMS);
//set up the listener for user state for creating user VPNs
IntentFilter intentFilter = new IntentFilter();
@@ -864,8 +868,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
try {
- mNetd.registerObserver(mTethering);
- mNetd.registerObserver(mDataActivityObserver);
+ mNMS.registerObserver(mTethering);
+ mNMS.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
}
@@ -896,7 +900,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
- mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
+ mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
registerPrivateDnsSettingsCallbacks();
}
@@ -912,7 +916,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mDefaultRequest;
}
};
- return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
+ return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
}
@@ -1476,6 +1480,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
};
/**
+ * Ensures that the system cannot call a particular method.
+ */
+ private boolean disallowedBecauseSystemCaller() {
+ // TODO: start throwing a SecurityException when GnssLocationProvider stops calling
+ // requestRouteToHost.
+ if (isSystem(Binder.getCallingUid())) {
+ log("This method exists only for app backwards compatibility"
+ + " and must not be called by system services.");
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface.
* @param networkType the type of the network over which traffic to the
@@ -1486,6 +1504,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
@Override
public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
+ if (disallowedBecauseSystemCaller()) {
+ return false;
+ }
enforceChangePermission();
if (mProtectedNetworks.contains(networkType)) {
enforceConnectivityInternalPermission();
@@ -1563,7 +1584,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("Adding legacy route " + bestRoute +
" for UID/PID " + uid + "/" + Binder.getCallingPid());
try {
- mNetd.addLegacyRouteForNetId(netId, bestRoute, uid);
+ mNMS.addLegacyRouteForNetId(netId, bestRoute, uid);
} catch (Exception e) {
// never crash - catch them all
if (DBG) loge("Exception trying to add a route: " + e);
@@ -1853,7 +1874,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
try {
- mNetd.addIdleTimer(iface, timeout, type);
+ mNMS.addIdleTimer(iface, timeout, type);
} catch (Exception e) {
// You shall not crash!
loge("Exception in setupDataActivityTracking " + e);
@@ -1872,7 +1893,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
try {
// the call fails silently if no idle timer setup for this interface
- mNetd.removeIdleTimer(iface);
+ mNMS.removeIdleTimer(iface);
} catch (Exception e) {
loge("Exception in removeDataActivityTracking " + e);
}
@@ -1880,6 +1901,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
+ * Update data activity tracking when network state is updated.
+ */
+ private void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+ NetworkAgentInfo oldNetwork) {
+ if (newNetwork != null) {
+ setupDataActivityTracking(newNetwork);
+ }
+ if (oldNetwork != null) {
+ removeDataActivityTracking(oldNetwork);
+ }
+ }
+ /**
* Reads the network specific MTU size from resources.
* and set it on it's iface.
*/
@@ -1907,7 +1940,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
try {
if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
- mNetd.setMtu(iface, mtu);
+ mNMS.setMtu(iface, mtu);
} catch (Exception e) {
Slog.e(TAG, "exception in setMtu()" + e);
}
@@ -2561,7 +2594,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
nai.clearLingerState();
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
- removeDataActivityTracking(nai);
+ updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.name());
}
@@ -2581,7 +2614,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// NetworkFactories, so network traffic isn't interrupted for an unnecessarily
// long time.
try {
- mNetd.removeNetwork(nai.network.netId);
+ mNMS.removeNetwork(nai.network.netId);
} catch (Exception e) {
loge("Exception removing network: " + e);
}
@@ -2779,20 +2812,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // TODO: remove this code once we know that the Slog.wtf is never hit.
- //
- // Find all networks that are satisfying this request and remove the request
- // from their request lists.
- // TODO - it's my understanding that for a request there is only a single
- // network satisfying it, so this loop is wasteful
- for (NetworkAgentInfo otherNai : mNetworkAgentInfos.values()) {
- if (otherNai.isSatisfyingRequest(nri.request.requestId) && otherNai != nai) {
- Slog.wtf(TAG, "Request " + nri.request + " satisfied by " +
- otherNai.name() + ", but mNetworkAgentInfos says " +
- (nai != null ? nai.name() : "null"));
- }
- }
-
// Maintain the illusion. When this request arrived, we might have pretended
// that a network connected to serve it, even though the network was already
// connected. Now that this request has gone away, we might have to pretend
@@ -3760,7 +3779,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
}
- setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, vpn, profile));
+ setLockdownTracker(new LockdownVpnTracker(mContext, mNMS, this, vpn, profile));
} else {
setLockdownTracker(null);
}
@@ -4015,7 +4034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
loge("Starting user already has a VPN");
return;
}
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
+ userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId);
mVpns.put(userId, userVpn);
if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
updateLockdownVpn();
@@ -4632,7 +4651,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDnsManager.updatePrivateDnsStatus(netId, newLp);
// Start or stop clat accordingly to network state.
- networkAgent.updateClat(mNetd);
+ networkAgent.updateClat(mNMS);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
@@ -4671,9 +4690,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
final String prefix = "iface:" + iface;
try {
if (add) {
- mNetd.getNetdService().wakeupAddInterface(iface, prefix, mark, mask);
+ mNetd.wakeupAddInterface(iface, prefix, mark, mask);
} else {
- mNetd.getNetdService().wakeupDelInterface(iface, prefix, mark, mask);
+ mNetd.wakeupDelInterface(iface, prefix, mark, mask);
}
} catch (Exception e) {
loge("Exception modifying wakeup packet monitoring: " + e);
@@ -4689,7 +4708,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (String iface : interfaceDiff.added) {
try {
if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNetd.addInterfaceToNetwork(iface, netId);
+ mNMS.addInterfaceToNetwork(iface, netId);
wakeupModifyInterface(iface, caps, true);
} catch (Exception e) {
loge("Exception adding interface: " + e);
@@ -4699,7 +4718,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, caps, false);
- mNetd.removeInterfaceFromNetwork(iface, netId);
+ mNMS.removeInterfaceFromNetwork(iface, netId);
} catch (Exception e) {
loge("Exception removing interface: " + e);
}
@@ -4723,7 +4742,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (route.hasGateway()) continue;
if (VDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNetd.addRoute(netId, route);
+ mNMS.addRoute(netId, route);
} catch (Exception e) {
if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
loge("Exception in addRoute for non-gateway: " + e);
@@ -4734,7 +4753,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (route.hasGateway() == false) continue;
if (VDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNetd.addRoute(netId, route);
+ mNMS.addRoute(netId, route);
} catch (Exception e) {
if ((route.getGateway() instanceof Inet4Address) || VDBG) {
loge("Exception in addRoute for gateway: " + e);
@@ -4745,7 +4764,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (RouteInfo route : routeDiff.removed) {
if (VDBG) log("Removing Route [" + route + "] from network " + netId);
try {
- mNetd.removeRoute(netId, route);
+ mNMS.removeRoute(netId, route);
} catch (Exception e) {
loge("Exception in removeRoute: " + e);
}
@@ -4857,7 +4876,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final String newPermission = getNetworkPermission(newNc);
if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
try {
- mNetd.setNetworkPermission(nai.network.netId, newPermission);
+ mNMS.setNetworkPermission(nai.network.netId, newPermission);
} catch (RemoteException e) {
loge("Exception in setNetworkPermission: " + e);
}
@@ -4917,12 +4936,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!newRanges.isEmpty()) {
final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
newRanges.toArray(addedRangesArray);
- mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray);
+ mNMS.addVpnUidRanges(nai.network.netId, addedRangesArray);
}
if (!prevRanges.isEmpty()) {
final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
prevRanges.toArray(removedRangesArray);
- mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+ mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);
}
} catch (Exception e) {
// Never crash!
@@ -5091,9 +5110,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void makeDefault(NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
- setupDataActivityTracking(newNetwork);
+
try {
- mNetd.setDefaultNetId(newNetwork.network.netId);
+ mNMS.setDefaultNetId(newNetwork.network.netId);
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
@@ -5266,6 +5285,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
if (isNewDefault) {
+ updateDataActivityTracking(newNetwork, oldDefaultNetwork);
// Notify system services that this network is up.
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
@@ -5488,12 +5508,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
try {
// This should never fail. Specifying an already in use NetID will cause failure.
if (networkAgent.isVPN()) {
- mNetd.createVirtualNetwork(networkAgent.network.netId,
+ mNMS.createVirtualNetwork(networkAgent.network.netId,
!networkAgent.linkProperties.getDnsServers().isEmpty(),
(networkAgent.networkMisc == null ||
!networkAgent.networkMisc.allowBypass));
} else {
- mNetd.createPhysicalNetwork(networkAgent.network.netId,
+ mNMS.createPhysicalNetwork(networkAgent.network.netId,
getNetworkPermission(networkAgent.networkCapabilities));
}
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1d163eed00a4..de930f794e50 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -161,6 +161,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private static final int MAX_UID_RANGES_PER_COMMAND = 10;
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
/**
* Name representing {@link #setGlobalAlert(long)} limit when delivered to
* {@link INetworkManagementEventObserver#limitReached(String, String)}.
@@ -1234,18 +1236,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void startTethering(String[] dhcpRange) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // cmd is "tether start first_start first_stop second_start second_stop ..."
// an odd number of addrs will fail
- final Command cmd = new Command("tether", "start");
- for (String d : dhcpRange) {
- cmd.appendArg(d);
- }
-
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherStart(dhcpRange);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1253,9 +1249,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void stopTethering() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "stop");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherStop();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1263,25 +1259,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public boolean isTetheringStarted() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final NativeDaemonEvent event;
try {
- event = mConnector.execute("tether", "status");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final boolean isEnabled = mNetdService.tetherIsEnabled();
+ return isEnabled;
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
-
- // 210 Tethering services started
- event.checkCode(TetherStatusResult);
- return event.getMessage().endsWith("started");
}
@Override
public void tetherInterface(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "interface", "add", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherInterfaceAdd(iface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
List<RouteInfo> routes = new ArrayList<>();
// The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
@@ -1294,9 +1286,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void untetherInterface(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("tether", "interface", "remove", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherInterfaceRemove(iface);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
} finally {
removeInterfaceFromLocalNetwork(iface);
}
@@ -1306,11 +1298,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public String[] listTetheredInterfaces() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("tether", "interface", "list"),
- TetherInterfaceListResult);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final List<String> result = mNetdService.tetherInterfaceList();
+ return result.toArray(EMPTY_STRING_ARRAY);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1319,16 +1310,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
- final Command cmd = new Command("tether", "dns", "set", netId);
-
- for (String s : dns) {
- cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
- }
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.tetherDnsSet(netId, dns);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1336,10 +1322,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public String[] getDnsForwarders() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ final List<String> result = mNetdService.tetherDnsList();
+ return result.toArray(EMPTY_STRING_ARRAY);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d505a77c9192..21f54dd33d3e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -329,6 +329,12 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mPackagesLock")
private final SparseArray<String> mSandboxIds = new SparseArray<>();
+ /**
+ * List of volumes visible to any user.
+ * TODO: may be have a map of userId -> volumes?
+ */
+ private final CopyOnWriteArrayList<VolumeInfo> mVisibleVols = new CopyOnWriteArrayList<>();
+
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
/** Holding lock for AppFuse business */
@@ -623,16 +629,12 @@ class StorageManagerService extends IStorageManager.Stub
Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
break;
}
- try {
- mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- }
+ mount(vol);
break;
}
case H_VOLUME_UNMOUNT: {
final VolumeInfo vol = (VolumeInfo) msg.obj;
- unmount(vol.getId());
+ unmount(vol);
break;
}
case H_VOLUME_BROADCAST: {
@@ -869,6 +871,8 @@ class StorageManagerService extends IStorageManager.Stub
addInternalVolumeLocked();
}
+ mVisibleVols.clear();
+
try {
mVold.reset();
@@ -1466,7 +1470,7 @@ class StorageManagerService extends IStorageManager.Stub
= mContext.getPackageManager().getInstalledApplicationsAsUser(
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
synchronized (mPackagesLock) {
- final ArraySet<String> userPackages = getPackagesForUserPL(userId);
+ final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
for (int i = appInfos.size() - 1; i >= 0; --i) {
if (appInfos.get(i).isInstantApp()) {
continue;
@@ -1523,7 +1527,7 @@ class StorageManagerService extends IStorageManager.Stub
}
@GuardedBy("mPackagesLock")
- private ArraySet<String> getPackagesForUserPL(int userId) {
+ private ArraySet<String> getAvailablePackagesForUserPL(int userId) {
ArraySet<String> userPackages = mPackages.get(userId);
if (userPackages == null) {
userPackages = new ArraySet<>();
@@ -1535,8 +1539,24 @@ class StorageManagerService extends IStorageManager.Stub
private String[] getPackagesArrayForUser(int userId) {
if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING;
+ final ArraySet<String> userPackages;
synchronized (mPackagesLock) {
- return getPackagesForUserPL(userId).toArray(new String[0]);
+ userPackages = getAvailablePackagesForUserPL(userId);
+ if (!userPackages.isEmpty()) {
+ return userPackages.toArray(new String[0]);
+ }
+ }
+ final List<ApplicationInfo> appInfos =
+ mContext.getPackageManager().getInstalledApplicationsAsUser(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ synchronized (mPackagesLock) {
+ for (int i = appInfos.size() - 1; i >= 0; --i) {
+ if (appInfos.get(i).isInstantApp()) {
+ continue;
+ }
+ userPackages.add(appInfos.get(i).packageName);
+ }
+ return userPackages.toArray(new String[0]);
}
}
@@ -1747,8 +1767,15 @@ class StorageManagerService extends IStorageManager.Stub
if (isMountDisallowed(vol)) {
throw new SecurityException("Mounting " + volId + " restricted by policy");
}
+ mount(vol);
+ }
+
+ private void mount(VolumeInfo vol) {
try {
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
+ if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) {
+ mVisibleVols.add(vol);
+ }
} catch (Exception e) {
Slog.wtf(TAG, e);
}
@@ -1759,8 +1786,15 @@ class StorageManagerService extends IStorageManager.Stub
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
final VolumeInfo vol = findVolumeByIdOrThrow(volId);
+ unmount(vol);
+ }
+
+ private void unmount(VolumeInfo vol) {
try {
mVold.unmount(vol.id);
+ if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) {
+ mVisibleVols.remove(vol);
+ }
} catch (Exception e) {
Slog.wtf(TAG, e);
}
@@ -3596,6 +3630,14 @@ class StorageManagerService extends IStorageManager.Stub
pw.decreaseIndent();
pw.println();
+ pw.println("mVisibleVols:");
+ pw.increaseIndent();
+ for (int i = 0; i < mVisibleVols.size(); i++) {
+ mVisibleVols.get(i).dump(pw);
+ }
+ pw.decreaseIndent();
+
+ pw.println();
pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
if (pair == null) {
@@ -3716,7 +3758,7 @@ class StorageManagerService extends IStorageManager.Stub
int userId) {
final String sandboxId;
synchronized (mPackagesLock) {
- final ArraySet<String> userPackages = getPackagesForUserPL(userId);
+ final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
// If userPackages is empty, it means the user is not started yet, so no need to
// do anything now.
if (userPackages.isEmpty() || userPackages.contains(packageName)) {
@@ -3734,5 +3776,29 @@ class StorageManagerService extends IStorageManager.Stub
Slog.wtf(TAG, e);
}
}
+
+ @Override
+ public String[] getVisibleVolumesForUser(int userId) {
+ final ArrayList<String> visibleVolsForUser = new ArrayList<>();
+ for (int i = mVisibleVols.size() - 1; i >= 0; --i) {
+ final VolumeInfo vol = mVisibleVols.get(i);
+ if (vol.isVisibleForUser(userId)) {
+ visibleVolsForUser.add(getVolumeLabel(vol));
+ }
+ }
+ return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]);
+ }
+
+ private String getVolumeLabel(VolumeInfo vol) {
+ // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold
+ switch (vol.getType()) {
+ case VolumeInfo.TYPE_EMULATED:
+ return "emulated";
+ case VolumeInfo.TYPE_PUBLIC:
+ return vol.fsUuid == null ? vol.id : vol.fsUuid;
+ default:
+ return null;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 692f9cfaa833..a3a5ac8b5999 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -368,7 +368,6 @@ import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
-import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -2398,6 +2397,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mUserController = new UserController(this);
+ mPendingIntentController = new PendingIntentController(
+ mHandlerThread.getLooper(), mUserController);
+
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -2413,9 +2415,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mStackSupervisor = mActivityTaskManager.mStackSupervisor;
- mPendingIntentController = new PendingIntentController(
- mHandlerThread.getLooper(), mUserController);
-
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
@@ -3538,6 +3537,9 @@ public class ActivityManagerService extends IActivityManager.Stub
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
try {
+ final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+ final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class)
+ .getVisibleVolumesForUser(UserHandle.getUserId(uid));
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
@@ -3547,12 +3549,14 @@ public class ActivityManagerService extends IActivityManager.Stub
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
+ packageNames, visibleVolIds,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
+ packageNames, visibleVolIds,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkTime(startTime, "startProcess: returned from zygote!");
@@ -9431,9 +9435,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
if (workSource != null) {
- StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag);
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag, sourcePkg);
} else {
- StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag);
+ StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag,
+ sourcePkg);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index add9f2a7e9d8..36261b505a94 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -1960,10 +1960,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
if (task == null) {
Slog.d(TAG, "Could not find task for id: "+ taskId);
+ SafeActivityOptions.abort(options);
return;
}
if (getLockTaskController().isLockTaskModeViolation(task)) {
Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode");
+ SafeActivityOptions.abort(options);
return;
}
ActivityOptions realOptions = options != null
@@ -1983,7 +1985,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} finally {
Binder.restoreCallingIdentity(origId);
}
- SafeActivityOptions.abort(options);
}
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 66c7c437284b..f0ff570e385b 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4685,7 +4685,9 @@ public class AudioService extends IAudioService.Stub
@Override
public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
{
- Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setHearingAidDeviceConnectionState state=" + state
+ + " addr=" + device.getAddress())).printLog(TAG));
setBluetoothHearingAidDeviceConnectionState(
device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
@@ -4723,12 +4725,12 @@ public class AudioService extends IAudioService.Stub
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
{
- mDeviceLogger.log(new AudioEventLogger.StringEvent(
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
"setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
// only querying address as this is the only readily available field on the device
+ " addr=" + device.getAddress()
+ " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
- + " vol=" + a2dpVolume));
+ + " vol=" + a2dpVolume)).printLog(TAG));
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored"));
return 0;
@@ -5888,6 +5890,8 @@ public class AudioService extends IAudioService.Stub
}
private void onSendBecomingNoisyIntent() {
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
}
@@ -7253,7 +7257,7 @@ public class AudioService extends IAudioService.Stub
// - wired: logged before onSetWiredDeviceConnectionState() is executed
// - A2DP: logged at reception of method call
final private AudioEventLogger mDeviceLogger = new AudioEventLogger(
- LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection");
+ LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP/hearing aid device connection");
final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
LOG_NB_EVENTS_FORCE_USE,
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0f68c6889680..87cf9c434fc0 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -39,6 +39,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -156,9 +157,18 @@ public class BiometricService extends SystemService {
} else if (mCurrentModality == BIOMETRIC_IRIS) {
Slog.w(TAG, "Unsupported modality");
} else if (mCurrentModality == BIOMETRIC_FACE) {
- mFaceService.authenticateFromService(true /* requireConfirmation */, token,
- sessionId, userId, receiver, flags, opPackageName, bundle,
- dialogReceiver, callingUid, callingPid, callingUserId);
+ // If the user disabled face for apps, return ERROR_HW_UNAVAILABLE
+ if (isFaceEnabledForApps()) {
+ receiver.onError(0 /* deviceId */,
+ BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ FaceManager.getErrorString(getContext(),
+ BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
+ } else {
+ mFaceService.authenticateFromService(true /* requireConfirmation */,
+ token, sessionId, userId, receiver, flags, opPackageName,
+ bundle, dialogReceiver, callingUid, callingPid, callingUserId);
+ }
} else {
Slog.w(TAG, "Unsupported modality");
}
@@ -168,6 +178,15 @@ public class BiometricService extends SystemService {
});
}
+ private boolean isFaceEnabledForApps() {
+ // TODO: maybe cache this and eliminate duplicated code with KeyguardUpdateMonitor
+ return Settings.Secure.getIntForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_APP_ENABLED,
+ 1 /* default */,
+ UserHandle.USER_CURRENT) == 0;
+ }
+
@Override // Binder call
public void cancelAuthentication(IBinder token, String opPackageName)
throws RemoteException {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 98c38dd41bfc..f6af52ae00a3 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -28,10 +28,11 @@ import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.hardware.face.IFaceService;
@@ -121,15 +122,15 @@ public class FaceService extends BiometricServiceBase {
* The following methods contain common code which is shared in biometrics/common.
*/
@Override // Binder call
- public long preEnroll(IBinder token) {
+ public long generateChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- return startPreEnroll(token);
+ return startGenerateChallenge(token);
}
@Override // Binder call
- public int postEnroll(IBinder token) {
+ public int revokeChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- return startPostEnroll(token);
+ return startRevokeChallenge(token);
}
@Override // Binder call
@@ -346,6 +347,45 @@ public class FaceService extends BiometricServiceBase {
// TODO: confirm security token when we move timeout management into the HAL layer.
mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
}
+
+ @Override
+ public int setRequireAttention(boolean requireAttention, final byte[] token) {
+ checkPermission(MANAGE_BIOMETRIC);
+
+ final ArrayList<Byte> byteToken = new ArrayList<>();
+ for (int i = 0; i < token.length; i++) {
+ byteToken.add(token[i]);
+ }
+
+ int result;
+ try {
+ result = mDaemon != null ? mDaemon.setRequireAttention(requireAttention, byteToken)
+ : Status.INTERNAL_ERROR;
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to setRequireAttention to " + requireAttention);
+ result = Status.INTERNAL_ERROR;
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean getRequireAttention(final byte[] token) {
+ checkPermission(MANAGE_BIOMETRIC);
+
+ final ArrayList<Byte> byteToken = new ArrayList<>();
+ for (int i = 0; i < token.length; i++) {
+ byteToken.add(token[i]);
+ }
+
+ boolean result = true;
+ try {
+ result = mDaemon != null ? mDaemon.getRequireAttention(byteToken).value : true;
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to getRequireAttention");
+ }
+ return result;
+ }
}
/**
@@ -779,30 +819,30 @@ public class FaceService extends BiometricServiceBase {
return mDaemon;
}
- private long startPreEnroll(IBinder token) {
+ private long startGenerateChallenge(IBinder token) {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
- Slog.w(TAG, "startPreEnroll: no face HAL!");
+ Slog.w(TAG, "startGenerateChallenge: no face HAL!");
return 0;
}
try {
return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
} catch (RemoteException e) {
- Slog.e(TAG, "startPreEnroll failed", e);
+ Slog.e(TAG, "startGenerateChallenge failed", e);
}
return 0;
}
- private int startPostEnroll(IBinder token) {
+ private int startRevokeChallenge(IBinder token) {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
- Slog.w(TAG, "startPostEnroll: no face HAL!");
+ Slog.w(TAG, "startRevokeChallenge: no face HAL!");
return 0;
}
try {
return daemon.revokeChallenge();
} catch (RemoteException e) {
- Slog.e(TAG, "startPostEnroll failed", e);
+ Slog.e(TAG, "startRevokeChallenge failed", e);
}
return 0;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2a80f0e7c291..48082b64ddfc 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -163,8 +163,8 @@ public class Vpn {
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
- private Context mContext;
- private NetworkInfo mNetworkInfo;
+ private final Context mContext;
+ private final NetworkInfo mNetworkInfo;
private String mPackage;
private int mOwnerUID;
private String mInterface;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 2b1d9196fe18..1e6bb04858a1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -320,9 +320,8 @@ public class TetheringConfiguration {
}
private static boolean getEnableLegacyDhcpServer(Context ctx) {
- // TODO: make the default false (0) and update javadoc in Settings.java
final ContentResolver cr = ctx.getContentResolver();
- final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
+ final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
return intVal != 0;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d8d650b28dee..5698fdf439a8 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1226,7 +1226,7 @@ public final class ContentService extends IContentService.Stub {
if (userId == UserHandle.USER_ALL) {
mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);
} else if (userId < 0) {
throw new IllegalArgumentException("Invalid user: " + userId);
} else if (userId != UserHandle.getCallingUserId()) {
@@ -1247,7 +1247,7 @@ public final class ContentService extends IContentService.Stub {
? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
Manifest.permission.INTERACT_ACROSS_USERS)
: Manifest.permission.INTERACT_ACROSS_USERS_FULL;
- throw new SecurityException(TAG + "Neither user " + uid
+ throw new SecurityException("No access to " + uri + ": neither user " + uid
+ " nor current process has " + permissions);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e10827bc6101..296d7ae349bc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8474,7 +8474,7 @@ public class PackageManagerService extends IPackageManager.Stub
private boolean canSkipFullApkVerification(String apkPath) {
final byte[] rootHashObserved;
try {
- rootHashObserved = VerityUtils.generateFsverityRootHash(apkPath);
+ rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
if (rootHashObserved == null) {
return false; // APK does not contain Merkle tree root hash.
}
@@ -16004,12 +16004,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (apkPath != null) {
final VerityUtils.SetupResult result =
- VerityUtils.generateApkVeritySetupData(apkPath);
+ VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */,
+ true /* skipSigningBlock */);
if (result.isOk()) {
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
FileDescriptor fd = result.getUnownedFileDescriptor();
try {
- final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
+ final byte[] signedRootHash =
+ VerityUtils.generateApkVerityRootHash(apkPath);
mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
} catch (InstallerException | IOException | DigestException |
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 9f69702911c9..8070f3add5c6 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -28,40 +28,74 @@ import android.util.Slog;
import android.util.apk.ApkSignatureVerifier;
import android.util.apk.ByteBufferFactory;
import android.util.apk.SignatureNotFoundException;
+import android.util.apk.VerityBuilder;
+
+import libcore.util.HexEncoding;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.DigestException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
+import sun.security.pkcs.PKCS7;
+
/** Provides fsverity related operations. */
abstract public class VerityUtils {
private static final String TAG = "VerityUtils";
+ /** The maximum size of signature file. This is just to avoid potential abuse. */
+ private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+
private static final boolean DEBUG = false;
/**
- * Generates Merkle tree and fsverity metadata.
+ * Generates Merkle tree and fs-verity metadata.
*
- * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the
+ * @return {@code SetupResult} that contains the result code, and when success, the
* {@code FileDescriptor} to read all the data from.
*/
- public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
- if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath);
+ public static SetupResult generateApkVeritySetupData(@NonNull String apkPath,
+ String signaturePath, boolean skipSigningBlock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file "
+ + signaturePath);
+ }
SharedMemory shm = null;
try {
- byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
- if (signedRootHash == null) {
+ byte[] signedVerityHash;
+ if (skipSigningBlock) {
+ signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
+ } else {
+ Path path = Paths.get(signaturePath);
+ if (Files.exists(path)) {
+ // TODO(112037636): fail early if the signing key is not in .fs-verity keyring.
+ PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path));
+ signedVerityHash = pkcs7.getContentInfo().getContentBytes();
+ if (DEBUG) {
+ Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash));
+ }
+ } else {
+ signedVerityHash = null;
+ }
+ }
+
+ if (signedVerityHash == null) {
if (DEBUG) {
- Slog.d(TAG, "Skip verity tree generation since there is no root hash");
+ Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
}
return SetupResult.skipped();
}
- Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath,
- signedRootHash);
+ Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath,
+ signaturePath, signedVerityHash, skipSigningBlock);
shm = result.first;
int contentSize = result.second;
FileDescriptor rfd = shm.getFileDescriptor();
@@ -81,9 +115,9 @@ abstract public class VerityUtils {
}
/**
- * {@see ApkSignatureVerifier#generateFsverityRootHash(String)}.
+ * {@see ApkSignatureVerifier#generateApkVerityRootHash(String)}.
*/
- public static byte[] generateFsverityRootHash(@NonNull String apkPath)
+ public static byte[] generateApkVerityRootHash(@NonNull String apkPath)
throws NoSuchAlgorithmException, DigestException, IOException {
return ApkSignatureVerifier.generateApkVerityRootHash(apkPath);
}
@@ -97,22 +131,114 @@ abstract public class VerityUtils {
}
/**
+ * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code
+ * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and
+ * extensions, including a PKCS#7 signature provided in {@code signaturePath}.
+ *
+ * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code
+ * ByteBuffer}. The data will be used outside this method via the factory itself.
+ *
+ * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor
+ * and authenticated extensions.
+ */
+ private static byte[] generateFsverityMetadata(String filePath, String signaturePath,
+ @NonNull TrackedShmBufferFactory trackedBufferFactory)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
+ VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree(
+ file, trackedBufferFactory);
+
+ ByteBuffer buffer = result.verityData;
+ buffer.position(result.merkleTreeSize);
+ return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath,
+ buffer);
+ }
+ }
+
+ /**
+ * Generates fs-verity descriptor including the extensions to the {@code output} and returns the
+ * fs-verity measurement.
+ *
+ * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated
+ * extensions.
+ */
+ private static byte[] generateFsverityDescriptorAndMeasurement(
+ @NonNull RandomAccessFile file, @NonNull byte[] rootHash,
+ @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ final short kRootHashExtensionId = 1;
+ final short kPkcs7SignatureExtensionId = 3;
+ final int origPosition = output.position();
+
+ // For generating fs-verity file measurement, which consists of the descriptor and
+ // authenticated extensions (but not unauthenticated extensions and the footer).
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ // 1. Generate fs-verity descriptor.
+ final byte[] desc = constructFsverityDescriptorNative(file.length());
+ output.put(desc);
+ md.update(desc);
+
+ // 2. Generate authenticated extensions.
+ final byte[] authExt =
+ constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length);
+ output.put(authExt);
+ output.put(rootHash);
+ md.update(authExt);
+ md.update(rootHash);
+
+ // 3. Generate unauthenticated extensions.
+ ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
+ output.putShort((short) 1); // number of unauthenticated extensions below
+ output.position(output.position() + 6);
+
+ // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be
+ // done by the caller if needed).
+ Path path = Paths.get(pkcs7SignaturePath);
+ if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) {
+ throw new IllegalArgumentException("Signature size is unexpectedly large: "
+ + pkcs7SignaturePath);
+ }
+ final byte[] pkcs7Signature = Files.readAllBytes(path);
+ output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId,
+ pkcs7Signature.length));
+ output.put(pkcs7Signature);
+
+ // 4. Generate the footer.
+ output.put(constructFsverityFooterNative(output.position() - origPosition));
+
+ return md.digest();
+ }
+
+ private static native byte[] constructFsverityDescriptorNative(long fileSize);
+ private static native byte[] constructFsverityExtensionNative(short extensionId,
+ int extensionDataSize);
+ private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead);
+
+ /**
* Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains
* Merkle tree and fsverity headers for the given apk, in the form that can immediately be used
* for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
* length equals to the returned {@code Integer}.
*/
- private static Pair<SharedMemory, Integer> generateApkVerityIntoSharedMemory(
- String apkPath, byte[] expectedRootHash)
+ private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(
+ String apkPath, String signaturePath, @NonNull byte[] expectedRootHash,
+ boolean skipSigningBlock)
throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
SignatureNotFoundException {
TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
- byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath,
- shmBufferFactory);
+ byte[] generatedRootHash;
+ if (skipSigningBlock) {
+ generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
+ } else {
+ generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory);
+ }
// We only generate Merkle tree once here, so it's important to make sure the root hash
// matches the signed one in the apk.
if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
- throw new SecurityException("Locally generated verity root hash does not match");
+ throw new SecurityException("verity hash mismatch: "
+ + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash));
}
int contentSize = shmBufferFactory.getBufferLimit();
@@ -126,11 +252,15 @@ abstract public class VerityUtils {
return Pair.create(shm, contentSize);
}
+ private static String bytesToString(byte[] bytes) {
+ return HexEncoding.encodeToString(bytes);
+ }
+
public static class SetupResult {
/** Result code if verity is set up correctly. */
private static final int RESULT_OK = 1;
- /** Result code if the apk does not contain a verity root hash. */
+ /** Result code if signature is not provided. */
private static final int RESULT_SKIPPED = 2;
/** Result code if the setup failed. */
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index c6e6449313c0..3c64dd278f78 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -47,6 +47,7 @@ import android.os.IStatsManager;
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
@@ -63,10 +64,13 @@ import android.os.storage.StorageManager;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.procstats.IProcessStats;
+import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
import com.android.internal.os.KernelCpuSpeedReader;
@@ -82,6 +86,7 @@ import com.android.internal.util.DumpUtils;
import com.android.server.BinderCallsStatsService;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
@@ -95,6 +100,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -123,7 +129,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public static final String CONFIG_DIR = "/data/misc/stats-service";
static final String TAG = "StatsCompanionService";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
public static final int CODE_DATA_BROADCAST = 1;
public static final int CODE_SUBSCRIBER_BROADCAST = 1;
@@ -174,12 +180,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
new KernelUidCpuClusterTimeReader();
private static IThermalService sThermalService;
+ private File mBaseDir =
+ new File(SystemServiceManager.ensureSystemDir(), "stats_companion");
public StatsCompanionService(Context context) {
super();
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-
+ mBaseDir.mkdirs();
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@Override
@@ -1245,6 +1253,86 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
Binder.restoreCallingIdentity(token);
}
+ long mLastProcStatsHighWaterMark = readProcStatsHighWaterMark();
+
+ private long readProcStatsHighWaterMark() {
+ try {
+ File[] files = mBaseDir.listFiles();
+ if (files == null || files.length == 0) {
+ return 0;
+ }
+ if (files.length > 1) {
+ Log.e(TAG, "Only 1 file expected for high water mark. Found " + files.length);
+ }
+ return Long.valueOf(files[0].getName());
+ } catch (SecurityException e) {
+ Log.e(TAG, "Failed to get procstats high watermark file.", e);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Failed to parse file name.", e);
+ }
+ return 0;
+ }
+
+ private IProcessStats mProcessStats =
+ IProcessStats.Stub.asInterface(ServiceManager.getService(ProcessStats.SERVICE_NAME));
+
+ private void pullProcessStats(
+ int tagId, long elapsedNanos, long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ try {
+ List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+ long highWaterMark = mProcessStats.getCommittedStats(
+ mLastProcStatsHighWaterMark, ProcessStats.REPORT_ALL, true, statsFiles);
+ if (statsFiles.size() != 1) {
+ return;
+ }
+ InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
+ int[] len = new int[1];
+ byte[] stats = readFully(stream, len);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeStorage(Arrays.copyOf(stats, len[0]));
+ pulledData.add(e);
+ new File(mBaseDir.getAbsolutePath() + "/" + mLastProcStatsHighWaterMark).delete();
+ mLastProcStatsHighWaterMark = highWaterMark;
+ new File(
+ mBaseDir.getAbsolutePath() + "/" + mLastProcStatsHighWaterMark).createNewFile();
+ } catch (IOException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
+ }
+ }
+
+ static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
+ int pos = 0;
+ final int initialAvail = stream.available();
+ byte[] data = new byte[initialAvail > 0 ? (initialAvail + 1) : 16384];
+ while (true) {
+ int amt = stream.read(data, pos, data.length - pos);
+ if (DEBUG) {
+ Slog.i(TAG, "Read " + amt + " bytes at " + pos + " of avail " + data.length);
+ }
+ if (amt < 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "**** FINISHED READING: pos=" + pos + " len=" + data.length);
+ }
+ outLen[0] = pos;
+ return data;
+ }
+ pos += amt;
+ if (pos >= data.length) {
+ byte[] newData = new byte[pos + 16384];
+ if (DEBUG) {
+ Slog.i(TAG, "Copying " + pos + " bytes to new array len " + newData.length);
+ }
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
/**
* Pulls various data.
*/
@@ -1358,6 +1446,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.PROC_STATS: {
+ pullProcessStats(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
@@ -1368,13 +1460,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void statsdReady() {
enforceCallingPermission();
- if (DEBUG) Slog.d(TAG, "learned that statsdReady");
+ if (DEBUG) {
+ Slog.d(TAG, "learned that statsdReady");
+ }
sayHiToStatsd(); // tell statsd that we're ready too and link to it
- mContext.sendBroadcastAsUser(
- new Intent(StatsManager.ACTION_STATSD_STARTED)
+ mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)
.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
- UserHandle.SYSTEM,
- android.Manifest.permission.DUMP);
+ UserHandle.SYSTEM, android.Manifest.permission.DUMP);
}
@Override
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 1eae56745a75..e718c7b2a36e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -20,8 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -48,16 +48,13 @@ import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.input.InputWindowHandle;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.InsetUtils;
-
import com.google.android.collect.Sets;
-
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -93,6 +90,7 @@ public class RecentsAnimationController implements DeathRecipient {
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
+ private int mTargetActivityType;
private Rect mMinimizedHomeBounds = new Rect();
// We start the RecentsAnimationController in a pending-start state since we need to wait for
@@ -259,23 +257,37 @@ public class RecentsAnimationController implements DeathRecipient {
mDisplayId = displayId;
}
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
+ initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+ }
+
/**
* Initializes the recents animation controller. This is a separate call from the constructor
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
- // Make leashes for each of the visible tasks and add it to the recents animation to be
- // started
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+ @VisibleForTesting
+ void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+ mTargetActivityType = targetActivityType;
+
+ // Make leashes for each of the visible/target tasks and add it to the recents animation to
+ // be started
final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
+ final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ if (targetStack != null) {
+ for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
+ final Task t = targetStack.getChildAt(i);
+ if (!visibleTasks.contains(t)) {
+ visibleTasks.add(t);
+ }
+ }
+ }
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
final WindowConfiguration config = task.getWindowConfiguration();
if (config.tasksAreFloating()
- || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || config.getActivityType() == targetActivityType) {
+ || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
continue;
}
addAnimation(task, !recentTaskIds.get(task.mTaskId));
@@ -586,7 +598,10 @@ public class RecentsAnimationController implements DeathRecipient {
final Rect insets = new Rect();
mainWindow.getContentInsets(insets);
InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
- mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
+ final int mode = topApp.getActivityType() == mTargetActivityType
+ ? MODE_OPENING
+ : MODE_CLOSING;
+ mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cc23ab6f77d9..6aa0e0144c40 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -561,9 +561,10 @@ class Task extends WindowContainer<AppWindowToken> {
@Override
public SurfaceControl getAnimationLeashParent() {
- // Reparent to the animation layer so that we aren't clipped by the non-minimized
- // stack bounds, currently we only animate the task for the recents animation
- return getAppAnimationLayer(ANIMATION_LAYER_STANDARD);
+ // Currently, only the recents animation will create animation leashes for tasks. In this
+ // case, reparent the task to the home animation layer while it is being animated to allow
+ // the home activity to reorder the app windows relative to its own.
+ return getAppAnimationLayer(ANIMATION_LAYER_HOME);
}
boolean isTaskAnimating() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e86093952474..4883f972f1e5 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -42,10 +42,8 @@ import android.view.MagnificationSpec;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
-
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
-
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
@@ -71,7 +69,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
/**
* Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
- * activities that happens below all {@link TaskStack}s.
+ * activities and all activities that are being controlled by the recents animation. This
+ * layer is generally below all {@link TaskStack}s.
*/
static final int ANIMATION_LAYER_HOME = 2;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7caa7aedb873..b627df4a3313 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -227,6 +227,7 @@ import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -2714,6 +2715,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @VisibleForTesting
+ void setRecentsAnimationController(RecentsAnimationController controller) {
+ mRecentsAnimationController = controller;
+ }
+
public RecentsAnimationController getRecentsAnimationController() {
return mRecentsAnimationController;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index becde7311607..157b6349f4ee 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -37,6 +37,7 @@ cc_library_static {
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
+ "com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
@@ -89,7 +90,6 @@ cc_defaults {
"libsensorservicehidl",
"libgui",
"libusbhost",
- "libsuspend",
"libtinyalsa",
"libEGL",
"libGLESv2",
@@ -121,6 +121,7 @@ cc_defaults {
"android.hardware.vr@1.0",
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
+ "android.system.suspend@1.0",
],
static_libs: [
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 02ad6c71b586..0ff60e44b0ce 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -30,6 +30,8 @@
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/system/suspend/1.0/ISystemSuspend.h>
+#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -39,7 +41,6 @@
#include <log/log.h>
#include <utils/misc.h>
#include <utils/Log.h>
-#include <suspend/autosuspend.h>
using android::hardware::Return;
using android::hardware::Void;
@@ -49,6 +50,8 @@ using android::hardware::power::V1_0::Status;
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
+using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::ISystemSuspendCallback;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -63,6 +66,7 @@ static sem_t wakeup_sem;
extern sp<IPowerV1_0> getPowerHalV1_0();
extern sp<IPowerV1_1> getPowerHalV1_1();
extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
+extern sp<ISystemSuspend> getSuspendHal();
// Java methods used in getLowPowerStats
static jmethodID jgetAndUpdatePlatformState = NULL;
@@ -70,16 +74,19 @@ static jmethodID jgetSubsystem = NULL;
static jmethodID jputVoter = NULL;
static jmethodID jputState = NULL;
-static void wakeup_callback(bool success)
-{
- ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
- int ret = sem_post(&wakeup_sem);
- if (ret < 0) {
- char buf[80];
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error posting wakeup sem: %s\n", buf);
+class WakeupCallback : public ISystemSuspendCallback {
+public:
+ Return<void> notifyWakeup(bool success) override {
+ ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
+ int ret = sem_post(&wakeup_sem);
+ if (ret < 0) {
+ char buf[80];
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error posting wakeup sem: %s\n", buf);
+ }
+ return Void();
}
-}
+};
static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
{
@@ -101,11 +108,14 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
return -1;
}
ALOGV("Registering callback...");
- autosuspend_set_wakeup_callback(&wakeup_callback);
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ suspendHal->registerCallback(new WakeupCallback());
}
// Wait for wakeup.
ALOGV("Waiting for wakeup...");
+ // TODO(b/116747600): device can suspend and wakeup after sem_wait() finishes and before wakeup
+ // reason is recorded, i.e. BatteryStats might occasionally miss wakeup events.
int ret = sem_wait(&wakeup_sem);
if (ret < 0) {
char buf[80];
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index b2d35d4153a0..0c9b5f4999a0 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -19,6 +19,7 @@
//#define LOG_NDEBUG 0
#include <android/hardware/power/1.1/IPower.h>
+#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
@@ -35,7 +36,7 @@
#include <utils/Log.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
-#include <suspend/autosuspend.h>
+#include <hidl/ServiceManagement.h>
#include "com_android_server_power_PowerManagerService.h"
@@ -44,6 +45,9 @@ using android::hardware::Void;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
+using android::system::suspend::V1_0::ISystemSuspend;
+using android::system::suspend::V1_0::IWakeLock;
+using android::system::suspend::V1_0::WakeLockType;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -171,6 +175,46 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t
}
}
+static sp<ISystemSuspend> gSuspendHal = nullptr;
+static sp<IWakeLock> gSuspendBlocker = nullptr;
+static std::mutex gSuspendMutex;
+
+// Assume SystemSuspend HAL is always alive.
+// TODO: Force device to restart if SystemSuspend HAL dies.
+sp<ISystemSuspend> getSuspendHal() {
+ static std::once_flag suspendHalFlag;
+ std::call_once(suspendHalFlag, [](){
+ ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, "default");
+ gSuspendHal = ISystemSuspend::getService();
+ assert(gSuspendHal != nullptr);
+ });
+ return gSuspendHal;
+}
+
+void enableAutoSuspend() {
+ static bool enabled = false;
+
+ std::lock_guard<std::mutex> lock(gSuspendMutex);
+ if (!enabled) {
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ suspendHal->enableAutosuspend();
+ enabled = true;
+ }
+ if (gSuspendBlocker) {
+ gSuspendBlocker->release();
+ gSuspendBlocker.clear();
+ }
+}
+
+void disableAutoSuspend() {
+ std::lock_guard<std::mutex> lock(gSuspendMutex);
+ if (!gSuspendBlocker) {
+ sp<ISystemSuspend> suspendHal = getSuspendHal();
+ gSuspendBlocker = suspendHal->acquireWakeLock(WakeLockType::PARTIAL,
+ "PowerManager.SuspendLockout");
+ }
+}
+
// ----------------------------------------------------------------------------
static void nativeInit(JNIEnv* env, jobject obj) {
@@ -207,13 +251,13 @@ static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean
static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
if (enable) {
android::base::Timer t;
- autosuspend_enable();
+ enableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD("Excessive delay in autosuspend_enable() while turning screen off");
}
} else {
android::base::Timer t;
- autosuspend_disable();
+ disableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD("Excessive delay in autosuspend_disable() while turning screen on");
}
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
new file mode 100644
index 000000000000..d0f173b572c8
--- /dev/null
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VerityUtils"
+
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include <utils/Log.h>
+
+#include <string.h>
+
+// TODO(112037636): Always include once fsverity.h is upstreamed and backported.
+#define HAS_FSVERITY 0
+
+#if HAS_FSVERITY
+#include <linux/fsverity.h>
+#endif
+
+namespace android {
+
+namespace {
+
+class JavaByteArrayHolder {
+ public:
+ static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) {
+ return new JavaByteArrayHolder(env, size);
+ }
+
+ jbyte* getRaw() {
+ return mElements;
+ }
+
+ jbyteArray release() {
+ mEnv->ReleaseByteArrayElements(mBytes, mElements, 0);
+ mElements = nullptr;
+ return mBytes;
+ }
+
+ private:
+ JavaByteArrayHolder(JNIEnv* env, jsize size) {
+ mEnv = env;
+ mBytes = mEnv->NewByteArray(size);
+ mElements = mEnv->GetByteArrayElements(mBytes, nullptr);
+ memset(mElements, 0, size);
+ }
+
+ virtual ~JavaByteArrayHolder() {
+ LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released");
+ }
+
+ JNIEnv* mEnv;
+ jbyteArray mBytes;
+ jbyte* mElements;
+};
+
+jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
+ fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw());
+
+ memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic));
+ desc->major_version = 1;
+ desc->minor_version = 0;
+ desc->log_data_blocksize = 12;
+ desc->log_tree_blocksize = 12;
+ desc->data_algorithm = FS_VERITY_ALG_SHA256;
+ desc->tree_algorithm = FS_VERITY_ALG_SHA256;
+ desc->flags = 0;
+ desc->orig_file_size = fileSize;
+ desc->auth_ext_count = 1;
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
+ jint extensionDataSize) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
+ fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw());
+
+ ext->length = sizeof(fsverity_extension) + extensionDataSize;
+ ext->type = extensionId;
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
+ jint offsetToDescriptorHead) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
+ fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw());
+
+ footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer);
+ memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic));
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+const JNINativeMethod sMethods[] = {
+ { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
+ { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },
+ { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter },
+};
+
+} // namespace
+
+int register_android_server_security_VerityUtils(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bb6e6840f3b4..918f57e2945e 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -54,6 +54,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
+int register_android_server_security_VerityUtils(JNIEnv* env);
};
using namespace android;
@@ -101,5 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsService(env);
+ register_android_server_security_VerityUtils(env);
return JNI_VERSION_1_4;
}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index f7bf393f367b..5a73a4e492ee 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -17,6 +17,7 @@
package android.net.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -92,10 +93,17 @@ public class SharedLog {
}
/**
- * Log an error due to an exception, with the exception stacktrace.
+ * Log an error due to an exception, with the exception stacktrace if provided.
+ *
+ * <p>The error and exception message appear in the shared log, but the stacktrace is only
+ * logged in general log output (logcat).
*/
- public void e(@NonNull String msg, @NonNull Throwable e) {
- Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e);
+ public void e(@NonNull String msg, @Nullable Throwable exception) {
+ if (exception == null) {
+ e(msg);
+ return;
+ }
+ Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
}
public void i(String msg) {
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportData.java b/services/robotests/src/com/android/server/backup/testing/TransportData.java
index 4c67180050e2..77f5d9a48c18 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportData.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportData.java
@@ -48,9 +48,9 @@ public class TransportData {
public static TransportData localTransport() {
return new TransportData(
- "android/com.android.internal.backup.LocalTransport",
- "android/com.android.internal.backup.LocalTransportService",
- "com.android.internal.backup.LocalTransport",
+ "com.android.localtransport/.LocalTransport",
+ "com.android.localtransport/.LocalTransportService",
+ "com.android.localtransport.LocalTransport",
null,
"Backing up to debug-only private cache",
null,
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index e7c45d59078c..aaa00452204b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,6 +25,8 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
@@ -33,6 +36,7 @@ import static org.mockito.Mockito.when;
import android.os.Binder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
+import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;
@@ -109,6 +113,24 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
}
+ @Test
+ public void testIncludedApps_expectTargetAndVisible() throws Exception {
+ sWm.setRecentsAnimationController(mController);
+ final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ hiddenAppWindow.setHidden(true);
+ mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+
+ // Ensure that we are animating the target activity as well
+ assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+ assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 702161e48b75..13f3e5e7a3ad 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1030,6 +1030,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertEquals(1, mZenModeHelperSpy.mConditions.mSubscriptions.size());
}
+ @Test
+ public void testEmptyDefaultRulesMap() {
+ ZenModeConfig config = new ZenModeConfig();
+ config.automaticRules = new ArrayMap<>();
+ mZenModeHelperSpy.mConfig = config;
+ mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer
+ }
+
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 995418ee706c..57b652e4cc59 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -271,6 +271,14 @@ public class CarrierConfigManager {
KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
/**
+ * Do only allow auto selection in Advanced Network Settings when in home network.
+ * Manual selection is allowed when in roaming network.
+ * @hide
+ */
+ public static final String
+ KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
+
+ /**
* Control whether users receive a simplified network settings UI and improved network
* selection.
*/
@@ -2181,6 +2189,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ sDefaults.putBoolean(KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false);
sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 8e99518d78b8..5e4518f67538 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -32,7 +32,11 @@ import android.os.Parcelable;
/**
* Represents the neighboring cell information, including
* Received Signal Strength and Cell ID location.
+ *
+ * @deprecated This class should not be used by anyone targeting SDK level 29 (Q) or higher.
+ * Instead callers should use {@Link android.telephony.CellInfo}.
*/
+@Deprecated
public class NeighboringCellInfo implements Parcelable
{
/**
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 7c7d7a0397ad..202da6817cb5 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -16,11 +16,10 @@
package android.telephony;
+import android.annotation.IntDef;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.annotation.IntDef;
-import android.util.Log;
import com.android.internal.telephony.ITelephony;
@@ -113,6 +112,8 @@ public class NetworkScan {
}
try {
telephony.stopNetworkScan(mSubId, mScanId);
+ } catch (IllegalArgumentException ex) {
+ Rlog.d(TAG, "stopNetworkScan - no active scan for ScanID=" + mScanId);
} catch (RemoteException ex) {
Rlog.e(TAG, "stopNetworkScan RemoteException", ex);
} catch (RuntimeException ex) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 38ee79f06690..d1091f489f14 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2153,7 +2153,12 @@ public class SubscriptionManager {
/**
* Set preferred default data.
- * Set on which slot default data will be on.
+ * Set on which slot most cellular data will be on.
+ * It's also usually what we set up internet connection on.
+ *
+ * PreferredData overwrites user setting of default data subscription. And it's used
+ * by ANAS or carrier apps to switch primary and CBRS subscription dynamically in multi-SIM
+ * devices.
*
* @param slotId which slot is preferred to for cellular data.
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 824533d59bf5..ea9ac39c8111 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1590,6 +1590,7 @@ public class TelephonyManager {
*
* @return List of NeighboringCellInfo or null if info unavailable.
*
+ * @removed
* @deprecated Use {@link #getAllCellInfo} which returns a superset of the information
* from NeighboringCellInfo, including LTE cell information.
*/
diff --git a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
index ae011a0316aa..c86f06eb88e4 100644
--- a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
+++ b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
@@ -21,6 +21,7 @@ import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ByteArrayInputStreamSource;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestDescription;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
@@ -84,7 +85,10 @@ public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {
// showmap requires root, we enable it here for the rest of the test
mTestDevice.enableAdbRoot();
- listener.testRunStarted(RUN_NAME, 0 /* testCount */);
+ listener.testRunStarted(RUN_NAME, 1 /* testCount */);
+
+ TestDescription testDescription = new TestDescription(getClass().getName(), "run");
+ listener.testStarted(testDescription);
// process name -> list of pids with that name
Map<String, List<String>> nativeProcesses = collectNativeProcesses();
@@ -94,7 +98,8 @@ public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {
mNativeProcessToMemory.put(
NUM_NATIVE_PROCESSES_KEY, Integer.toString(nativeProcesses.size()));
- listener.testRunEnded(0, mNativeProcessToMemory);
+ listener.testEnded(testDescription, mNativeProcessToMemory);
+ listener.testRunEnded(0, new HashMap<String, String>());
}
/** Samples memory of all processes and logs the memory use. */
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 39ecb7e5a45e..122edbaf078c 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -69,17 +69,12 @@ public class InetDiagSocketTest {
private ConnectivityManager mCm;
private Context mContext;
private final static int SOCKET_TIMEOUT_MS = 100;
- private boolean mInetDiagUdpEnabled;
@Before
public void setUp() throws Exception {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mContext = instrumentation.getTargetContext();
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- int expectedUid = Process.myUid();
- UdpConnection udp = new UdpConnection("127.0.0.1", "127.0.0.2");
- int uid = mCm.getConnectionOwnerUid(udp.protocol, udp.local, udp.remote);
- mInetDiagUdpEnabled = (uid == expectedUid);
}
private class Connection {
@@ -188,11 +183,6 @@ public class InetDiagSocketTest {
tcp.close();
/**
- * TODO: STOPSHIP: Always test for UDP, do not allow opt-out.
- */
- if (!mInetDiagUdpEnabled) return;
-
- /**
* For UDP connections, either a complete match {protocol, local, remote} or a
* partial match {protocol, local} should return a valid UID.
*/
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
index d46facfaba06..86048604e95f 100644
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -44,6 +44,8 @@ public class SharedLogTest {
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
final SharedLog logLevel2b = logTop.forSubComponent("twoB");
logLevel2b.e("2b or not 2b");
+ logLevel2b.e("No exception", null);
+ logLevel2b.e("Wait, here's one", new Exception("Test"));
logLevel2a.w("second post?");
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
@@ -54,6 +56,9 @@ public class SharedLogTest {
final String[] expected = {
" - MARK first post!",
" - [twoB] ERROR 2b or not 2b",
+ " - [twoB] ERROR No exception",
+ // No stacktrace in shared log, only in logcat
+ " - [twoB] ERROR Wait, here's one: Test",
" - [twoA] WARN second post?",
" - still logging",
" - [twoA.three] 3 >> 2",
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e3db7e8a1354..1a053057540f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -79,6 +79,7 @@ import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -248,7 +249,7 @@ public class ConnectivityServiceTest {
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
- MockContext(Context base) {
+ MockContext(Context base, ContentProvider settingsProvider) {
super(base);
mResources = spy(base.getResources());
@@ -260,7 +261,7 @@ public class ConnectivityServiceTest {
});
mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@Override
@@ -1048,7 +1049,9 @@ public class ConnectivityServiceTest {
Looper.prepare();
}
- mServiceContext = new MockContext(InstrumentationRegistry.getContext());
+ FakeSettingsProvider.clearSettingsProvider();
+ mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
+ new FakeSettingsProvider());
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -1086,6 +1089,7 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+ FakeSettingsProvider.clearSettingsProvider();
}
private static int transportToLegacyType(int transport) {
@@ -4532,4 +4536,78 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.disconnect();
mCm.unregisterNetworkCallback(networkCallback);
}
+
+ @Test
+ public void testDataActivityTracking() throws RemoteException {
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ reset(mNetworkManagementService);
+ mCellNetworkAgent.connect(true);
+ networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_MOBILE));
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+
+ // Network switch
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.connect(true);
+ networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_WIFI));
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME));
+
+ // Disconnect wifi and switch back to cell
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ assertNoCallbacks(networkCallback);
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+ verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
+ eq(ConnectivityManager.TYPE_MOBILE));
+
+ // reconnect wifi
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ mWiFiNetworkAgent.connect(true);
+ networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+
+ // Disconnect cell
+ reset(mNetworkManagementService);
+ mCellNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
+ // sent as network being switched. Ensure rule removal for cell will not be triggered
+ // unexpectedly before network being removed.
+ waitForIdle();
+ verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
+ verify(mNetworkManagementService, times(1)).removeNetwork(
+ eq(mCellNetworkAgent.getNetwork().netId));
+
+ // Disconnect wifi
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ reset(mNetworkManagementService);
+ mWiFiNetworkAgent.disconnect();
+ waitFor(cv);
+ verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+
+ // Clean up
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 40d5544dccd8..a6ed9f252008 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -33,6 +33,7 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -75,6 +76,8 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.dhcp.DhcpServer;
+import android.net.dhcp.DhcpServingParams;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
import android.net.util.InterfaceParams;
@@ -85,6 +88,7 @@ import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.INetworkManagementService;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -146,6 +150,7 @@ public class TetheringTest {
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+ @Mock private DhcpServer mDhcpServer;
@Mock private INetd mNetd;
private final MockTetheringDependencies mTetheringDependencies =
@@ -240,6 +245,12 @@ public class TetheringTest {
public INetd getNetdService() {
return mNetd;
}
+
+ @Override
+ public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+ DhcpServingParams params, SharedLog log) {
+ return mDhcpServer;
+ }
};
}
@@ -333,6 +344,7 @@ public class TetheringTest {
mServiceContext = new MockContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
mIntents = new Vector<>();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -343,12 +355,16 @@ public class TetheringTest {
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTetheringDependencies.reset();
- mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
- mLooper.getLooper(), mSystemProperties,
- mTetheringDependencies);
+ mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
}
+ private Tethering makeTethering() {
+ return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
+ mLooper.getLooper(), mSystemProperties,
+ mTetheringDependencies);
+ }
+
@After
public void tearDown() {
mServiceContext.unregisterReceiver(mBroadcastReceiver);
@@ -597,6 +613,18 @@ public class TetheringTest {
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
+ verify(mDhcpServer, times(1)).start();
+ }
+
+ @Test
+ public void workingMobileUsbTethering_IPv4LegacyDhcp() {
+ Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
+ mTethering = makeTethering();
+ final NetworkState upstreamState = buildMobileIPv4UpstreamState();
+ runUsbTethering(upstreamState);
+ sendIPv6TetherUpdates(upstreamState);
+
+ verify(mDhcpServer, never()).start();
}
@Test
@@ -620,6 +648,7 @@ public class TetheringTest {
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mRouterAdvertisementDaemon, times(1)).start();
+ verify(mDhcpServer, times(1)).start();
sendIPv6TetherUpdates(upstreamState);
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -633,6 +662,7 @@ public class TetheringTest {
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mDhcpServer, times(1)).start();
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
TEST_XLAT_MOBILE_IFNAME);
@@ -649,6 +679,7 @@ public class TetheringTest {
runUsbTethering(upstreamState);
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mDhcpServer, times(1)).start();
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
// Then 464xlat comes up
@@ -671,6 +702,8 @@ public class TetheringTest {
// Forwarding was not re-added for v6 (still times(1))
verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ // DHCP not restarted on downstream (still times(1))
+ verify(mDhcpServer, times(1)).start();
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index bb312309b34f..521778484d91 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -225,13 +225,4 @@ public class TetheringConfigurationTest {
final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
assertFalse(cfg.enableLegacyDhcpServer);
}
-
- @Test
- public void testNewDhcpServerDefault() {
- Settings.Global.putString(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, null);
-
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
- // TODO: change to false when new server is promoted to default
- assertTrue(cfg.enableLegacyDhcpServer);
- }
}
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 934847f6eec2..91cd1cba964d 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -492,6 +492,7 @@ def verify_parcelable(clazz):
def verify_protected(clazz):
"""Verify that no protected methods or fields are allowed."""
for m in clazz.methods:
+ if m.name == "finalize": continue
if "protected" in m.split:
error(clazz, m, "M7", "Protected methods not allowed; must be public")
for f in clazz.fields:
@@ -1025,6 +1026,10 @@ def verify_resource_names(clazz):
# Resources defined by files are foo_bar_baz
if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
for f in clazz.fields:
+ if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
+ if f.name.startswith("config_"):
+ error(clazz, f, None, "Expected config name to be config_fooBarBaz style")
+
if re.match("[a-z1-9_]+$", f.name): continue
error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
@@ -1361,6 +1366,60 @@ def verify_clone(clazz):
error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")
+def verify_pfd(clazz):
+ """Verify that android APIs use PFD over FD."""
+ examine = clazz.ctors + clazz.methods
+ for m in examine:
+ if m.typ == "java.io.FileDescriptor":
+ error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
+ if m.typ == "int":
+ if "Fd" in m.name or "FD" in m.name or "FileDescriptor" in m.name:
+ error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
+ for arg in m.args:
+ if arg == "java.io.FileDescriptor":
+ error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
+
+ for f in clazz.fields:
+ if f.typ == "java.io.FileDescriptor":
+ error(clazz, f, "FW11", "Must use ParcelFileDescriptor")
+
+
+def verify_numbers(clazz):
+ """Discourage small numbers types like short and byte."""
+
+ discouraged = ["short","byte"]
+
+ for c in clazz.ctors:
+ for arg in c.args:
+ if arg in discouraged:
+ warn(clazz, c, "FW12", "Should avoid odd sized primitives; use int instead")
+
+ for f in clazz.fields:
+ if f.typ in discouraged:
+ warn(clazz, f, "FW12", "Should avoid odd sized primitives; use int instead")
+
+ for m in clazz.methods:
+ if m.typ in discouraged:
+ warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")
+ for arg in m.args:
+ if arg in discouraged:
+ warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")
+
+
+def verify_singleton(clazz):
+ """Catch singleton objects with constructors."""
+
+ singleton = False
+ for m in clazz.methods:
+ if m.name.startswith("get") and m.name.endswith("Instance") and " static " in m.raw:
+ singleton = True
+
+ if singleton:
+ for c in clazz.ctors:
+ error(clazz, c, None, "Singleton classes should use getInstance() methods")
+
+
+
def is_interesting(clazz):
"""Test if given class is interesting from an Android PoV."""
@@ -1431,6 +1490,9 @@ def examine_clazz(clazz):
verify_tense(clazz)
verify_icu(clazz)
verify_clone(clazz)
+ verify_pfd(clazz)
+ verify_numbers(clazz)
+ verify_singleton(clazz)
def examine_stream(stream):
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 991547916919..56c842805190 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -234,9 +234,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -302,6 +304,13 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
fprintf(out, " event.end();\n");
fprintf(out, " }\n");
+ fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
fprintf(out, " event.end();\n\n");
} else {
if (*arg == JAVA_TYPE_STRING) {
@@ -344,9 +353,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -374,7 +385,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", arg%d", argIndex);
}
@@ -529,10 +541,14 @@ static void write_cpp_usage(
}
}
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& %s_int"
+ fprintf(out, ", const std::map<int, int32_t>& %s_int"
+ ", const std::map<int, int64_t>& %s_long"
", const std::map<int, char const*>& %s_str"
", const std::map<int, float>& %s_float",
- field->name.c_str(), field->name.c_str(), field->name.c_str());
+ field->name.c_str(),
+ field->name.c_str(),
+ field->name.c_str(),
+ field->name.c_str());
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -561,9 +577,11 @@ static void write_cpp_method_header(
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -976,6 +994,7 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att
}
static void write_key_value_map_jni(FILE* out) {
+ fprintf(out, " std::map<int, int32_t> int32_t_map;\n");
fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
fprintf(out, " std::map<int, float> float_map;\n");
fprintf(out, " std::map<int, char const*> string_map;\n\n");
@@ -989,9 +1008,11 @@ static void write_key_value_map_jni(FILE* out) {
fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
+ fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
+ fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
@@ -1000,7 +1021,9 @@ static void write_key_value_map_jni(FILE* out) {
fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
- fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
+ fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
+ fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
+ fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
@@ -1129,7 +1152,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", int64_t_map, string_map, float_map");
+ fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
} else {
const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ce8d71d7ed2a..58c130017024 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -332,9 +332,10 @@ public class WifiConfiguration implements Parcelable {
public String preSharedKey;
/**
- * Up to four WEP keys. Either an ASCII string enclosed in double
- * quotation marks (e.g., {@code "abcdef"}) or a string
- * of hex digits (e.g., {@code 0102030405}).
+ * Four WEP keys. For each of the four values, provide either an ASCII
+ * string enclosed in double quotation marks (e.g., {@code "abcdef"}),
+ * a string of hex digits (e.g., {@code 0102030405}), or an empty string
+ * (e.g., {@code ""}).
* <p/>
* When the value of one of these keys is read, the actual key is
* not returned, just a "*" if the key has a value, or the null
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7a91347102fe..59ba8e7a6177 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1698,9 +1698,7 @@ public class WifiManager {
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get valid results. If there is a remote exception (e.g., either a communication
- * problem with the system service or an exception within the framework) an empty list will be
- * returned.
+ * in order to get valid results.
*/
public List<ScanResult> getScanResults() {
try {